Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Prototype for a proxy extension that avoids loads when calling for a …

…getter that is named after an identifier.
  • Loading branch information...
commit bc4e14a99f26338e83c1e643293074c064bc5bdd 1 parent 85fb1a3
Benjamin Eberlei beberlei authored
20 lib/Doctrine/ORM/Proxy/ProxyFactory.php
@@ -209,6 +209,11 @@ private function _generateMethods(ClassMetadata $class)
209 209
210 210 $methods .= $parameterString . ')';
211 211 $methods .= PHP_EOL . ' {' . PHP_EOL;
  212 + if ($this->isShortIdentifierGetter($method, $class)) {
  213 + $methods .= ' if ($this->__isInitialized__ === false) {' . PHP_EOL;
  214 + $methods .= ' return $this->_identifier["' . lcfirst(substr($method->getName(), 3)) . '"];' . PHP_EOL;
  215 + $methods .= ' }' . PHP_EOL;
  216 + }
212 217 $methods .= ' $this->__load();' . PHP_EOL;
213 218 $methods .= ' return parent::' . $method->getName() . '(' . $argumentString . ');';
214 219 $methods .= PHP_EOL . ' }' . PHP_EOL;
@@ -219,6 +224,21 @@ private function _generateMethods(ClassMetadata $class)
219 224 }
220 225
221 226 /**
  227 + * @param ReflectionMethod $method
  228 + * @param ClassMetadata $class
  229 + * @return bool
  230 + */
  231 + private function isShortIdentifierGetter($method, $class)
  232 + {
  233 + return (
  234 + $method->getNumberOfParameters() == 0 &&
  235 + substr($method->getName(), 0, 3) == "get" &&
  236 + in_array(lcfirst(substr($method->getName(), 3)), $class->identifier, true) &&
  237 + (($method->getEndLine() - $method->getStartLine()) <= 4)
  238 + );
  239 + }
  240 +
  241 + /**
222 242 * Generates the code for the __sleep method for a proxy class.
223 243 *
224 244 * @param $class
6 tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php
@@ -78,7 +78,7 @@ public function testGetReferenceWithPostLoadEventIsDelayedUntilProxyTrigger()
78 78 $reference = $this->_em->getReference('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity', $id);
79 79 $this->assertFalse($reference->postLoadCallbackInvoked);
80 80
81   - $reference->getId(); // trigger proxy load
  81 + $reference->getValue(); // trigger proxy load
82 82 $this->assertTrue($reference->postLoadCallbackInvoked);
83 83 }
84 84
@@ -210,6 +210,10 @@ public function getId() {
210 210 return $this->id;
211 211 }
212 212
  213 + public function getValue() {
  214 + return $this->value;
  215 + }
  216 +
213 217 /** @PrePersist */
214 218 public function doStuffOnPrePersist() {
215 219 $this->prePersistCallbackInvoked = true;
9 tests/Doctrine/Tests/ORM/Functional/Ticket/DDC381Test.php
@@ -31,8 +31,8 @@ public function testCallUnserializedProxyMethods()
31 31
32 32 $entity = $this->_em->getReference('Doctrine\Tests\ORM\Functional\Ticket\DDC381Entity', $persistedId);
33 33
34   - // explicitly load proxy
35   - $id = $entity->getId();
  34 + // explicitly load proxy (getId() does not trigger reload of proxy)
  35 + $id = $entity->getOtherMethod();
36 36
37 37 $data = serialize($entity);
38 38 $entity = unserialize($data);
@@ -55,4 +55,9 @@ public function getId()
55 55 {
56 56 return $this->id;
57 57 }
  58 +
  59 + public function getOtherMethod()
  60 + {
  61 +
  62 + }
58 63 }

0 comments on commit bc4e14a

geoffrey-brier

I don't know why but these lines of code prevent my users being manually authenticated: the User->getId method always return null so when I set a specific UsernamePasswordToken, it fails (the token is destroyed) and my user is not authenticated.
This was not the case in 2.2.x, any ideas?

Christophe Coevoet

which line are you talking about ? The one you commented on is also there in 2.2.x

Eric GELOEN

He talks about the added lines. Can you explain the goal? In our case, the proxy is not initialized and $this->_identifier is null, so the proxy returns null instead of the value.

Christophe Coevoet

the goal is to avoid initializing the proxy when the only thing you care about is the id (to generate an url for instance) as it is already available.

How could you have an uninitialized proxy without identifier ?

Eric GELOEN

We have two User classes representing a Symfony & a Facebook user. These two classes are linked with a OneToOne bidirectionnal association with the owning side (inversedBy) on the Facebook user class.

When I fetch a Facebook user by id and lazy load my user with this code:

$facebookUser = $this->getDoctrine()
   ->getRepository('AcmeFacebookBundle:User')
   ->findOneBy(array('facebookId' => $authResponse->id));

$symfonyUser = $facebookUser->getSymfonyUser();

At this moment, the Symfony user is not initialized and the identifier is null.

Christophe Coevoet

$facebookUser->getSymfonyUser(); never initialized a proxy. A proxy is initialized only when you call a method on it (and as of Doctrine 2.2, it is any method except the getter for the id).

However, I don't see how the identifier could be missing in the proxy object here (except if your mapping is invalid) so the getter for the id will continue working.

Eric GELOEN

Thanks for your answer. There are really no mismatch in my mapping:

@ORM\OneToOne(
   targetEntity = "Acme\UserBundle\Entity\User",
   inversedBy = "facebook"
)

@ORM\OneToOne(
   targetEntity = "Acme\FacebookBundle\Entity\User",
   mappedBy = "user"
)

I don't understand why the identifier is null.

Please sign in to comment.
Something went wrong with that request. Please try again.