0

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

所以我有一个叫Sweden的容器,然后是另一个叫Stockholm的Container,Stockholm的$parent属性是Sweden(这两个是同一种实体)。

我有一个验证约束,可以确保没有两个实体可以具有相同的名称,但是当我为一个实体选择父级时会出现问题,因为验证的工作方式似乎是它不仅会继续检查实体 Stockholm 的名称,但还会检查我为父级选择的整个实体,显然 Stockholm 的名称已经在数据库中(否则我无法为父级选择它)存在验证错误,似乎一个catch22问题...

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

实体

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;
    }
}
4

2 回答 2

0

我相信你的关系倒退了;

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

除非您打算让许多父母只有一个孩子,并且该孩子属于许多父母。

于 2013-06-04T23:57:33.440 回答
0

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

symfony2 对子实体的验证防止编辑父实体

于 2013-09-13T05:45:42.130 回答