Sunday, 15 April 2012

symfony2 - Combining @Gedmo\NestedTree and @ORM\UniqueEntity -



symfony2 - Combining @Gedmo\NestedTree and @ORM\UniqueEntity -

i'm creating folder construction implemented nestedtree behaviour. furthermore, don't want 2 folders may have same name if siblings. this, utilize combination of @uniqueentity , @uniqueconstraint annotations, not work.

first entity (stripped minimum since 100% identical nestedtree defaults) :

class="lang-php prettyprint-override">/** * @orm\entity * @gedmo\tree(type="nested") * @orm\entity(repositoryclass="gedmo\tree\entity\repository\nestedtreerepository") * @uniqueentity(fields={"parent", "name"}) * @orm\table(uniqueconstraints={@orm\uniqueconstraint(name="uniq_url", columns={"parent_id", "name"})}) */ class folder { /** * @orm\column(type="string", nullable=false) */ protected $name; /** * @gedmo\treeparent * @orm\manytoone(targetentity="folder", inversedby="children") * @orm\joincolumn(name="parent_id", referencedcolumnname="id", ondelete="set null") */ protected $parent; } first seek (ignorenull = true)

when create 2 folders same name, have integrity constraint violation, meaning @uniqueconstraints in database worked @uniqueentity didn't :

integrity constraint violation: 1062 duplicate entry 'name_of_folder' key 'uniq_url' second seek (ignorenull = false)

i tried ignorenull key set false (the default true) :

class="lang-php prettyprint-override">@uniqueentity(fields={"parent", "name"}, ignorenull=false)

but error :

warning: reflectionproperty::getvalue() expects parameter 1 object, null given in vendor/doctrine/orm/lib/doctrine/orm/mapping/classmetadatainfo.php line 670

i've nailed error downwards these lines in symfony\bridge\doctrine\validator\constraints\uniqueentityvalidator :

class="lang-php prettyprint-override"> $criteria[$fieldname] = $class->reflfields[$fieldname]->getvalue($entity); if ($constraint->ignorenull && null === $criteria[$fieldname]) { return; } if ($class->hasassociation($fieldname)) { /* ensure proxy initialized before using reflection * read identifiers. necessary because wrapped * getter methods in proxy beingness bypassed. */ $em->initializeobject($criteria[$fieldname]); $relatedclass = $em->getclassmetadata($class->getassociationtargetclass($fieldname)); //problem $relatedid = $relatedclass->getidentifiervalues($criteria[$fieldname]); if (count($relatedid) > 1) { throw new constraintdefinitionexception( "associated entities not allowed have more 1 identifier field " . "part of unique constraint in: " . $class->getname() . "#" . $fieldname ); } $criteria[$fieldname] = array_pop($relatedid); }

the problem appears on line marked //problem. appears $criteria[$fieldname] === null reason of error.

so here am, not knowing do... have thought on what's going on ?

thank you.

there no easy way out of situation. went own way , created validator :

entity class="lang-php prettyprint-override">/** * @orm\entity(repositoryclass="ibiz\doctrineextensionsbundle\entity\repository\nestedtreerepository") * @gedmo\tree(type="nested") * @orm\table(uniqueconstraints={@orm\uniqueconstraint(name="uniq_url", columns={"parent_id", "name"})}) * @ibizassert\uniquepath("getname") */ class folder { /** * @orm\column(type="string", nullable=false) */ protected $name; public function getname() { homecoming $this->name; } } validator/constraints/uniquepath.php class="lang-php prettyprint-override">namespace ibiz\doctrineextensionsbundle\validator\constraints; utilize symfony\component\validator\constraint; /** * @annotation */ class uniquepath extends constraint { public $em = null; public $errormethod = null; public $message = 'the name "%name%" exists.'; public $service = 'ibiz.validator.unique_path'; public function validatedby() { homecoming $this->service; } public function getrequiredoptions() { homecoming array('errormethod'); } public function getdefaultoption() { homecoming 'errormethod'; } public function gettargets() { homecoming self::class_constraint; } } validator/constraints/uniquepathvalidator.php class="lang-php prettyprint-override">namespace ibiz\doctrineextensionsbundle\validator\constraints; utilize doctrine\common\persistence\managerregistry; utilize symfony\component\validator\constraint; utilize symfony\component\validator\constraintvalidator; utilize symfony\component\validator\exception\constraintdefinitionexception; utilize symfony\component\validator\exception\unexpectedtypeexception; class uniquepathvalidator extends constraintvalidator { private $registry; public function __construct(managerregistry $registry) { $this->registry = $registry; } public function validate($entity, constraint $constraint) { if ($constraint->errormethod === null) { throw new constraintdefinitionexception('errormethod should set'); } else if (!is_string($constraint->errormethod)) { throw new unexpectedtypeexception($constraint->errormethod, 'string'); } if ($constraint->em) { $em = $this->registry->getmanager($constraint->em); } else { $em = $this->registry->getmanagerforclass(get_class($entity)); } $classname = $this->context->getclassname(); $repo = $em->getrepository($classname); $count = $repo->getsamenamesiblingscount($entity); if ($count != 0) { $this->context->addviolation($constraint->message, array('%name%' => $entity->{$constraint->errormethod}())); } } } entity/repository/nestedtreerepository.php class="lang-php prettyprint-override">namespace ibiz\doctrineextensionsbundle\entity\repository; utilize gedmo\tree\entity\repository\nestedtreerepository baserepository; class nestedtreerepository extends baserepository { public function getsamenamesiblingscountquerybuilder($node) { $meta = $this->getclassmetadata(); if (!$node instanceof $meta->name) { throw new invalidargumentexception("node not related repository"); } $config = $this->listener->getconfiguration($this->_em, $meta->name); $qb = $this->_em->createquerybuilder(); $qb->select($qb->expr()->count('n.id')) ->from($config['useobjectclass'], 'n'); if ($node->getparent() === null) { $qb->where($qb->expr()->andx( $qb->expr()->eq('n.name', ':name'), $qb->expr()->isnull('n.parent') )) ->setparameters(array( 'name' => $node->getname(), )); } else { $qb->leftjoin('n.parent', 'p') ->where($qb->expr()->andx( $qb->expr()->eq('n.name', ':name'), $qb->expr()->eq('p.name', ':parent') )) ->setparameters(array( 'name' => $node->getname(), 'parent' => $node->getparent()->getname(), )); } homecoming $qb; } public function getsamenamesiblingscountquery($node) { homecoming $this->getsamenamesiblingscountquerybuilder($node)->getquery(); } public function getsamenamesiblingscount($node) { homecoming $this->getsamenamesiblingscountquery($node)->getsinglescalarresult(); } }

symfony2 doctrine2 doctrine-extensions

No comments:

Post a Comment