symfony2自引用实体有验证问题

时间:2013-06-04 22:15:52

标签: validation symfony self-reference

我有一个实体可以拥有与父类型相同的另一个实体(自引用?)。

所以我有一个名为Sweden的容器,然后是另一个名为Stockholm的Container,斯德哥尔摩的$ parent属性是瑞典(这两个是同一类型的实体)。

我有一个验证约束,确保没有两个实体可以具有相同的名称,但是当我为实体选择父级时出现问题,因为验证的工作方式似乎是它继续检查不仅是斯德哥尔摩实体的名称,而且还要检查我为父母选择的整个实体,显然斯德哥尔摩的名字已经在DB中(否则我无法为父母选择它)存在验证错误,似乎是一个问题22 ......

一些代码来说明......有什么想法吗?

实体     

namespace BizTV\ContainerManagementBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

use BizTV\ContainerManagementBundle\Validator\Constraints as BizTVAssert;

use BizTV\UserBundle\Entity\User as user;
use BizTV\ContainerManagementBundle\Entity\Container as Container;

/**
 * BizTV\ContainerManagementBundle\Entity\Container
 * @BizTVAssert\ContainerExists
 * @ORM\Table(name="container")
 * @ORM\Entity
 */
class Container
{

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

    /**
     * @var string $name
     * @Assert\NotBlank(message = "Du måste ange ett namn") 
     * @ORM\Column(name="name", type="string", length=255, nullable=true)
     */
    private $name;

    /**
    * @var object BizTV\BackendBundle\Entity\company
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
    * @ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
    */
    protected $company; 

    /**
    * @var object BizTV\ContainerManagementBundle\Entity\ContainerType
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\ContainerManagementBundle\Entity\ContainerType")
    * @ORM\JoinColumn(name="container_type", referencedColumnName="id", nullable=false)
    */
    protected $containerType;

    /**
    * @var object BizTV\ContainerManagementBundle\Entity\ContainerSize
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\ContainerManagementBundle\Entity\ContainerSize")
    * @ORM\JoinColumn(name="container_size", referencedColumnName="id", nullable=false)
    */
    protected $containerSize;

    /**
     * @ORM\OneToMany(targetEntity="Container", mappedBy="parent")
     */
    private $children;

    /**
     * @ORM\OneToMany(targetEntity="BizTV\ContentManagementBundle\Entity\Content", mappedBy="container")
     * @ORM\OrderBy({"sortOrder" = "ASC"})
     * above code does nothing, thought to use that instead of the current jQuery tinySort but aparently not...
     */
    private $content;

    /**
    * @var object BizTV\ContainerManagementBundle\Entity\Container
    *  
    * @ORM\ManyToOne(targetEntity="Container", inversedBy="children")
    * @ORM\JoinColumn(name="parent", referencedColumnName="id", nullable=true)
    */
    protected $parent;

    /**
    * @var object BizTV\LayoutManagementBundle\Entity\Layout
    *  
    * @ORM\ManyToOne(targetEntity="BizTV\LayoutManagementBundle\Entity\Layout")
    * @ORM\JoinColumn(name="screen_layout", referencedColumnName="id", nullable=true)
    */
    protected $screen_layout;   

    /**
     * @ORM\Column(type="boolean", nullable=true)
     * 
     * This only applies to the monitor containerType, others will always have false here. 
     * The purpose of this bool is the option of never rendering this monitor with a layout (handy for ex. BrfTV servers with lower resolution)
     */
    protected $prohibitLayout;


    /**
     * @ORM\ManyToMany(targetEntity="BizTV\UserBundle\Entity\User", mappedBy="access")
     */
    private $users;

    public function __construct() {
        $this->users = new \Doctrine\Common\Collections\ArrayCollection();
        $this->children = new \Doctrine\Common\Collections\ArrayCollection();
        $this->content = new \Doctrine\Common\Collections\ArrayCollection();
    }


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set company
     *
     * @param BizTV\BackendBundle\Entity\company $company
     */
    public function setCompany(\BizTV\BackendBundle\Entity\company $company)
    {
        $this->company = $company;
    }

    /**
     * Get company
     *
     * @return BizTV\BackendBundle\Entity\company 
     */
    public function getCompany()
    {
        return $this->company;
    }

    /**
     * Set containerType
     *
     * @param BizTV\ContainerManagementBundle\Entity\ContainerType $containerType
     */
    public function setContainerType(\BizTV\ContainerManagementBundle\Entity\ContainerType $containerType)
    {
        $this->containerType = $containerType;
    }

    /**
     * Get containerType
     *
     * @return BizTV\ContainerManagementBundle\Entity\ContainerType 
     */
    public function getContainerType()
    {
        return $this->containerType;
    }

    /**
     * Set parent
     *
     * @param BizTV\ContainerManagementBundle\Entity\Container $parent
     */
    public function setParent(\BizTV\ContainerManagementBundle\Entity\Container $parent = NULL)
    {
        $this->parent = $parent;
    }

    /**
     * Get parent
     *
     * @return BizTV\ContainerManagementBundle\Entity\Container 
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * Set screen_layout
     *
     * @param BizTV\LayoutManagementBundle\Entity\Layout $screenLayout
     */
    public function setScreenLayout(\BizTV\LayoutManagementBundle\Entity\Layout $screenLayout = NULL)
    {
        $this->screen_layout = $screenLayout;
    }

    /**
     * Get screen_layout
     *
     * @return BizTV\LayoutManagementBundle\Entity\Layout 
     */
    public function getScreenLayout()
    {
        return $this->screen_layout;
    }

    public function getSelectLabel()
    {
        if (isset($this->parent)) {
            return $this->name . ' (' . $this->parent->getName() . ')';
        }
        else {
            return $this->name;
        }
    }

    /**
     * Add users
     *
     * @param BizTV\UserBundle\Entity\User $users
     */
    public function addUser(\BizTV\UserBundle\Entity\User $users)
    {
        $this->users[] = $users;
    }

    /**
     * Get users
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getUsers()
    {
        return $this->users;
    }

    /**
     * Add children
     *
     * @param BizTV\ContainerManagementBundle\Entity\Container $children
     */
    public function addContainer(\BizTV\ContainerManagementBundle\Entity\Container $children)
    {
        $this->children[] = $children;
    }

    /**
     * Get children
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getChildren()
    {
        return $this->children;
    }





    /**
     * Add content
     *
     * @param BizTV\ContentManagementBundle\Entity\Content $content
     */
    public function addContent(\BizTV\ContentManagementBundle\Entity\Content $content)
    {
        $this->content[] = $content;
    }

    /**
     * Get content
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * Set containerSize
     *
     * @param BizTV\ContainerManagementBundle\Entity\ContainerSize $containerSize
     */
    public function setContainerSize(\BizTV\ContainerManagementBundle\Entity\ContainerSize $containerSize)
    {
        $this->containerSize = $containerSize;
    }

    /**
     * Get containerSize
     *
     * @return BizTV\ContainerManagementBundle\Entity\ContainerSize 
     */
    public function getContainerSize()
    {
        return $this->containerSize;
    }    


    /**
     * Set prohibitLayout
     *
     * @param boolean $prohibitLayout
     */
    public function setProhibitLayout($prohibitLayout)
    {
        $this->prohibitLayout = $prohibitLayout;
    }

    /**
     * Get prohibitLayout
     *
     * @return boolean 
     */
    public function getProhibitLayout()
    {
        return $this->prohibitLayout;
    }
}

表     

namespace BizTV\ContainerManagementBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

use Doctrine\ORM\EntityRepository;


class ContainerBuildingType extends AbstractType
{

    function __construct(\BizTV\BackendBundle\Entity\company $company, \BizTV\ContainerManagementBundle\Entity\ContainerType $parentType) {
        $this->parentType = $parentType;    
        $this->company = $company;
    }


    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('name', 'text', array('label' => 'Namn på fastighet '));

        $parentType = $this->parentType;
        $company = $this->company;

        $builder->add('parent', 'entity', array(
        'label' => 'Välj ett geografiskt område för fastigheten ',
        'class' => 'BizTVContainerManagementBundle:Container','property'=>'name',
        'query_builder' => function(EntityRepository $er) use ($parentType, $company) {
            return $er->createQueryBuilder('u')
                ->where('u.containerType = :type', 'u.company = :company')
                ->setParameters( array('type' => $parentType, 'company' => $company) )
                ->orderBy('u.name', 'ASC');
            },
        ));

    }

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

约束     

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class ContainerExists extends Constraint
{
    public $message = 'Namnet är upptaget, vänligen välj ett annat.';

    public function validatedBy()
    {
        return 'containerExists';
    }

    public function getTargets()
    {
        return self::CLASS_CONSTRAINT;
    }

}

验证     

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Doctrine\ORM\EntityManager as EntityManager;

class ContainerExistsValidator extends ConstraintValidator
{

    private $container;
    private $em;

    public function __construct(Container $container, EntityManager $em) {
        $this->container = $container;
        $this->em = $em;
    }   

    public function isValid($object, Constraint $constraint)
    {

        $em = $this->em;
        $container = $this->container;

        $company = $this->container->get('security.context')->getToken()->getUser()->getCompany();

        $parent = $object->getParent();

        //Fetch entities with same name in the same container
        $repository = $em->getRepository('BizTVContainerManagementBundle:Container');
        $query = $repository->createQueryBuilder('c')
            ->where('c.company = :company and c.parent = :parent')
            ->setParameters(array('company' => $company, 'parent' => $parent))
            ->orderBy('c.name', 'ASC')
            ->getQuery();
        $containers = $query->getResult();      

        foreach ($containers as $g) {

            echo "testing ".$g->getName()." against ".$object->getName()."<br/>";

            if ( $g->getName() == $object->getName() ) {    

                $this->setMessage('Namnet '.$object->getName().' är upptaget, vänligen välj ett annat');
                return false;
            }
        }

        return true;
    }
}

2 个答案:

答案 0 :(得分:0)

我相信你的关系会倒退;

您的父母应该是OneToMany,您的孩子应该是ManyToOne

除非你打算让很多父母只有1个孩子而且那个孩子属于很多父母。

答案 1 :(得分:0)

类似问题的答案也解决了这个问题:

symfony2 validation of child entity prevents editing of parent entity