忽略ManyToOne字段上的Symfony2 Doctrine2 UniqueEntity

时间:2015-09-18 09:55:55

标签: php symfony doctrine-orm

我在OneToManyProject之间有一个Application关系,我想确保2 ApplicationProject内的名称不能相同}。

我尝试按照应有的方式配置我的实体,表单类型和控制器,但我收到了重复条目的Integrity约束违规,所以我认为验证过程会被忽略。

有人能告诉我我错过了什么吗?

我的Application实体是这样的:

namespace App\MainBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use JsonSerializable;

/**
 * @ORM\Entity
 * @ORM\Table(name="application", uniqueConstraints={@ORM\UniqueConstraint(name="IDX_Unique", columns={"name", "project_id"})})
 * @UniqueEntity(
 *      fields={"name", "project"},
 *      message="Name already used in this project.",
 *      groups="application"
 * )
 */
class Application implements JsonSerializable {

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     * @Assert\NotBlank(
     *      message = "Name cannot be empty."
     * )
     * @Assert\Length(
     *      min = "3",
     *      max = "50",
     *      minMessage = "Name is too short. It should have {{ limit }} characters or more.",
     *      maxMessage = "Name is too long. It should have {{ limit }} characters or less."
     * )
     */
    protected $name;

    // other properties ...

    /**
     * @ORM\ManyToOne(targetEntity="Project", inversedBy="applications")
     * @ORM\JoinColumn(name="project_id", referencedColumnName="id")
     */
    protected $project;

    // constructor, methods, getters, setters
}

我的ApplicationType课程如下:

namespace App\MainBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ApplicationType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('name', 'text', array(
            'icon' => 'pencil'
        ));
        $builder->add('description', 'textarea', array(
            'required' => false,
            'icon' => 'info'
        ));
        $builder->add('url', 'url', array(
            'required' => false,
            'icon' => 'link'
        ));
    }

    public function getName() {
        return 'application';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'App\MainBundle\Entity\Application',
            'validation_group' => array('application'),
            'cascade_validation' => true
        ));
    }
}

在我的Controller中,操作如下所示:

/**
 * @Route("/project/{id}/application/add",
 *      name="app_add_application_ajax",
 *      requirements={"_method" = "post"},
 *      options={"expose" = true }
 * )
 * @Secure(roles="ROLE_SUPER_ADMIN")
 * @ParamConverter("project", class="AppMainBundle:Project")
 */
public function addApplicationAction(Project $project, Request $request) {
    $ajaxResponse = array();
    $em = $this->getDoctrine()->getManager();
    if ($request->getMethod() == 'POST' && $request->isXmlHttpRequest()) {
        $formApp = new Application();
        $formApp->setProject($project);
        $form = $this->createForm(new ApplicationType(), $formApp);
        $form->handleRequest($request);
        if ($form->isValid()) {
            $application = $form->getData();
            $em->persist($application);
            $em->flush();
            // build ajax response ...
        } else {
            $ajaxResponse['error'] = $this->getErrorsAsString();
        }
    }
    $response = new Response(json_encode($ajaxResponse));
    $response->headers->set('Content-Type', 'application/json');
    return $response;
}

1 个答案:

答案 0 :(得分:1)

您的问题是您在表单类型中配置了validation_group选项,而Symfony使用的选项是validation_groups。您没有收到有关未知选项的错误,因为您在表单类型的默认选项中设置了此选项,因此您将选项标记为已定义(但它是一个单独的选项)。 因此验证器使用默认组运行,默认组将验证不同的约束(name属性长度的约束在默认组中)。

请注意,您还有第二个问题,一旦运行约束就会出现 您的验证约束与您拥有的数据库约束不匹配。您要求验证器具有唯一的名称和唯一的项目,而不是唯一的元组(名称,项目)。所以你会拒绝太多东西(这个名称将在全球范围内被验证为唯一,而不是每个项目)。 这是因为您使用2个单独的UniqueEntity约束而不是约束,要求多个字段的元组是唯一的。