Overriding the ObjectIdentityRetrievalStrategy to check if a domain object is a Doctrine proxy

I created this issue because my ACL checks were failing. It turns out that the ObjectIdentityRetrievalStrategy fails for Doctrine proxies because internally, get_class is used and this will return the class of the Doctrine proxy, not the class of the entity.

So, here is how to create your own strategy to override the default:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
<?php
 
namespace Jbi\CoreBundle\Security\Acl\Domain;
 
use Symfony\Component\Security\Acl\Exception\InvalidDomainObjectException;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
 
use Doctrine\ORM\EntityManager;
 
/**
* Strategy to be used for retrieving object identities from domain objects
* where the domain object may be a Doctrine proxy.
*/
class ObjectIdentityRetrievalStrategy implements ObjectIdentityRetrievalStrategyInterface
{
/**
* @var \Doctrine\ORM\EntityManager $em
*/
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* {@inheritDoc}
*/
public function getObjectIdentity($domainObject)
{
try {
if ($domainObject instanceof \Doctrine\ORM\Proxy\Proxy) {
return $this->fromDomainObject($domainObject);
}
return ObjectIdentity::fromDomainObject($domainObject);
} catch (InvalidDomainObjectException $failed) {
return null;
}
}
private function fromDomainObject($domainObject)
{
if (!is_object($domainObject)) {
throw new InvalidDomainObjectException('$domainObject must be an object.');
}
 
try {
if ($domainObject instanceof DomainObjectInterface) {
return new ObjectIdentity($domainObject->getObjectIdentifier(), $this->em->getClassMetadata(get_class($domainObject))->getName());
} elseif (method_exists($domainObject, 'getId')) {
return new ObjectIdentity($domainObject->getId(), $this->em->getClassMetadata(get_class($domainObject))->getName());
}
} catch (\InvalidArgumentException $invalid) {
throw new InvalidDomainObjectException($invalid->getMessage(), 0, $invalid);
}
 
throw new InvalidDomainObjectException('$domainObject must either implement the DomainObjectInterface, or have a method named "getId".');
}
}
view raw gistfile1.aw This Gist brought to you by GitHub.

Then, in your services file, register and override the default service, passing the entity manager as an argument and with your new class:

1 2 3
<service id="security.acl.object_identity_retrieval_strategy" class="Jbi\CoreBundle\Security\Acl\Domain\ObjectIdentityRetrievalStrategy" public="false">
<argument type="service" id="doctrine.orm.entity_manager" />
</service>
view raw gistfile1.xml This Gist brought to you by GitHub.

3 thoughts on “Overriding the ObjectIdentityRetrievalStrategy to check if a domain object is a Doctrine proxy

  1. Thank you very much for sharing this!
    I just wonder why is this not part of Symfony’s core already?
    I really like Symfony, but more I get deep in it more I find odd things, like not being able to handle form errors in a controller if you don’t set the option ‘error_bubbling’ to true to every field of the form type.
    Some things are expected and are really annoying when you find yourself stucked for this kind of nonsense.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>