我的形式如下:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$factory = $builder->getFormFactory();
$builder->add('name');
$builder->add('description');
$builder->add('manufacturers', null, array(
'required' => false
));
$builder->add('departments', 'collection', array(
'type' => new Department
));
}
我对形式表示调用实体类的验证:
if (!$valid) {
$this->context->addViolationAtSubPath('departments', $constraint->message);
}
这只会在子路径添加一个“全球性”的错误的形式,而不是错误。 我想这是因为部门是一家集嵌入另一个FormType。
如果我改变departments
到其他的领域之一,它工作正常。
我怎样才能得到这个错误出现在正确的地方? 我相信它会正常工作,如果我的错误是在集合中的一个单一的实体,从而在孩子的形式呈现,但我的标准是,违反发生,如果没有集合中的实体被标记为活动的,因此需要要在父级别。
默认情况下,形式可以选择“error_bubbling”设置为true
,这将导致你刚才所描述的行为。 如果你希望他们保持自己的错误,你可以关闭此选项个别形式。
$builder->add('departments', 'collection', array(
'type' => new Department,
'error_bubbling' => false,
));
我一直在Symfony的3.3,在这里我想验证整个集合,但错误传递给适当的集合元素/场这个问题摔跤。 集合被添加到由此形式:
$form->add('grades', CollectionType::class,
[
'label' => 'student.grades.label',
'allow_add' => true,
'allow_delete' => true,
'entry_type' => StudentGradeType::class,
'attr' => [
'class' => 'gradeList',
'help' => 'student.grades.help',
],
'entry_options' => [
'systemYear' => $form->getConfig()->getOption('systemYear'),
],
'constraints' => [
new Grades(),
],
]
);
该StudentGradeType是:
<?php
namespace Busybee\Management\GradeBundle\Form;
use Busybee\Core\CalendarBundle\Entity\Grade;
use Busybee\Core\SecurityBundle\Form\DataTransformer\EntityToStringTransformer;
use Busybee\Core\TemplateBundle\Type\SettingChoiceType;
use Busybee\Management\GradeBundle\Entity\StudentGrade;
use Busybee\People\StudentBundle\Entity\Student;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class StudentGradeType extends AbstractType
{
/**
* @var ObjectManager
*/
private $om;
/**
* StaffType constructor.
*
* @param ObjectManager $om
*/
public function __construct(ObjectManager $om)
{
$this->om = $om;
}
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('status', SettingChoiceType::class,
[
'setting_name' => 'student.enrolment.status',
'label' => 'grades.label.status',
'placeholder' => 'grades.placeholder.status',
'attr' => [
'help' => 'grades.help.status',
],
]
)
->add('student', HiddenType::class)
->add('grade', EntityType::class,
[
'class' => Grade::class,
'choice_label' => 'gradeYear',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('g')
->orderBy('g.year', 'DESC')
->addOrderBy('g.sequence', 'ASC');
},
'placeholder' => 'grades.placeholder.grade',
'label' => 'grades.label.grade',
'attr' => [
'help' => 'grades.help.grade',
],
]
);
$builder->get('student')->addModelTransformer(new EntityToStringTransformer($this->om, Student::class));
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefaults(
[
'data_class' => StudentGrade::class,
'translation_domain' => 'BusybeeStudentBundle',
'systemYear' => null,
'error_bubbling' => true,
]
);
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'grade_by_student';
}
}
和验证的样子:
namespace Busybee\Management\GradeBundle\Validator\Constraints; use Busybee\Core\CalendarBundle\Entity\Year; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; class GradesValidator extends ConstraintValidator { public function validate($value, Constraint $constraint) { if (empty($value)) return; $current = 0; $year = []; foreach ($value->toArray() as $q=>$grade) { if (empty($grade->getStudent()) || empty($grade->getGrade())) { $this->context->buildViolation('student.grades.empty') ->addViolation(); return $value; } if ($grade->getStatus() === 'Current') { $current++; if ($current > 1) { $this->context->buildViolation('student.grades.current') ->atPath('['.strval($q).']') // could do a single atPath with a value of "[".strval($q)."].status" ->atPath('status') // full path = children['grades'].data[1].status ->addViolation(); return $value; } } $gy = $grade->getGradeYear(); if (! is_null($gy)) { $year[$gy] = empty($year[$gy]) ? 1 : $year[$gy] + 1 ; if ($year[$gy] > 1) { $this->context->buildViolation('student.grades.year') ->atPath('['.strval($q).']') ->atPath('grade') ->addViolation(); return $value; } } } } }
这导致错误被添加到字段中集合作为每附着图像的元件。
克雷格
我有非常相似的情况。 我有一个自定义表单CollectionType(与DataTransformers内,等...),我需要一个二选一的元素和标记他们的什么是错的,并打印在视图。
我作出这样的解决方案在ConstraintValidator(我自定义的验证):
验证器必须靶向CLASS_CONSTRAINT工作或的PropertyPath不起作用。
public function validate($value, Constraint $constraint) {
/** @var Form $form */
$form = $this->context->getRoot();
$studentsForm = $form->get("students"); //CollectionType's name in the root Type
$rootPath = $studentsForm->getPropertyPath()->getElement(0);
/** @var Form $studentForm */
foreach($studentsForm as $studentForm){
//Iterate over the items in the collection type
$studentPath = $studentForm->getPropertyPath()->getElement(0);
//Get the data typed on the item (in my case, it use an DataTransformer and i can get an User object from the child TextType)
/** @var User $user */
$user = $studentForm->getData();
//Validate your data
$email = $user->getEmail();
$user = $userRepository->findByEmailAndCentro($email, $centro);
if(!$user){
//If your data is wrong build the violation from the propertyPath getted from the item Type
$this->context->buildViolation($constraint->message)
->atPath($rootPath)
->atPath(sprintf("[%s]", $studentPath))
->atPath("email") //That last is the name property on the item Type
->addViolation();
}
}
}
只是我验证agains集合中的表单元素和构建是错误的集合中使用的PropertyPath从项目的违规行为。