vendor/doctrine/orm/lib/Doctrine/ORM/Proxy/ProxyFactory.php line 154

Open in your IDE?
  1. <?php
  2. /*
  3.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  4.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  5.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  6.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  7.  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  8.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  9.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  10.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  11.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  12.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  13.  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14.  *
  15.  * This software consists of voluntary contributions made by many individuals
  16.  * and is licensed under the MIT license. For more information, see
  17.  * <http://www.doctrine-project.org>.
  18.  */
  19. namespace Doctrine\ORM\Proxy;
  20. use Closure;
  21. use Doctrine\Common\Proxy\AbstractProxyFactory;
  22. use Doctrine\Common\Proxy\Proxy as BaseProxy;
  23. use Doctrine\Common\Proxy\ProxyDefinition;
  24. use Doctrine\Common\Proxy\ProxyGenerator;
  25. use Doctrine\Common\Util\ClassUtils;
  26. use Doctrine\ORM\EntityManagerInterface;
  27. use Doctrine\ORM\EntityNotFoundException;
  28. use Doctrine\ORM\Persisters\Entity\EntityPersister;
  29. use Doctrine\ORM\UnitOfWork;
  30. use Doctrine\ORM\Utility\IdentifierFlattener;
  31. use Doctrine\Persistence\Mapping\ClassMetadata;
  32. /**
  33.  * This factory is used to create proxy objects for entities at runtime.
  34.  *
  35.  * @deprecated 2.7 This class is being removed from the ORM and won't have any replacement
  36.  */
  37. class ProxyFactory extends AbstractProxyFactory
  38. {
  39.     /** @var EntityManagerInterface The EntityManager this factory is bound to. */
  40.     private $em;
  41.     /** @var UnitOfWork The UnitOfWork this factory uses to retrieve persisters */
  42.     private $uow;
  43.     /** @var string */
  44.     private $proxyNs;
  45.     /**
  46.      * The IdentifierFlattener used for manipulating identifiers
  47.      *
  48.      * @var IdentifierFlattener
  49.      */
  50.     private $identifierFlattener;
  51.     /**
  52.      * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
  53.      * connected to the given <tt>EntityManager</tt>.
  54.      *
  55.      * @param EntityManagerInterface $em           The EntityManager the new factory works for.
  56.      * @param string                 $proxyDir     The directory to use for the proxy classes. It must exist.
  57.      * @param string                 $proxyNs      The namespace to use for the proxy classes.
  58.      * @param bool|int               $autoGenerate The strategy for automatically generating proxy classes. Possible
  59.      *               values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
  60.      */
  61.     public function __construct(EntityManagerInterface $em$proxyDir$proxyNs$autoGenerate AbstractProxyFactory::AUTOGENERATE_NEVER)
  62.     {
  63.         $proxyGenerator = new ProxyGenerator($proxyDir$proxyNs);
  64.         $proxyGenerator->setPlaceholder('baseProxyInterface'Proxy::class);
  65.         parent::__construct($proxyGenerator$em->getMetadataFactory(), $autoGenerate);
  66.         $this->em                  $em;
  67.         $this->uow                 $em->getUnitOfWork();
  68.         $this->proxyNs             $proxyNs;
  69.         $this->identifierFlattener = new IdentifierFlattener($this->uow$em->getMetadataFactory());
  70.     }
  71.     /**
  72.      * {@inheritDoc}
  73.      */
  74.     protected function skipClass(ClassMetadata $metadata)
  75.     {
  76.         return $metadata->isMappedSuperclass
  77.             || $metadata->isEmbeddedClass
  78.             || $metadata->getReflectionClass()->isAbstract();
  79.     }
  80.     /**
  81.      * {@inheritDoc}
  82.      */
  83.     protected function createProxyDefinition($className)
  84.     {
  85.         $classMetadata   $this->em->getClassMetadata($className);
  86.         $entityPersister $this->uow->getEntityPersister($className);
  87.         return new ProxyDefinition(
  88.             ClassUtils::generateProxyClassName($className$this->proxyNs),
  89.             $classMetadata->getIdentifierFieldNames(),
  90.             $classMetadata->getReflectionProperties(),
  91.             $this->createInitializer($classMetadata$entityPersister),
  92.             $this->createCloner($classMetadata$entityPersister)
  93.         );
  94.     }
  95.     /**
  96.      * Creates a closure capable of initializing a proxy
  97.      *
  98.      * @psalm-return Closure(BaseProxy):void
  99.      *
  100.      * @throws EntityNotFoundException
  101.      */
  102.     private function createInitializer(ClassMetadata $classMetadataEntityPersister $entityPersister): Closure
  103.     {
  104.         $wakeupProxy $classMetadata->getReflectionClass()->hasMethod('__wakeup');
  105.         return function (BaseProxy $proxy) use ($entityPersister$classMetadata$wakeupProxy): void {
  106.             $initializer $proxy->__getInitializer();
  107.             $cloner      $proxy->__getCloner();
  108.             $proxy->__setInitializer(null);
  109.             $proxy->__setCloner(null);
  110.             if ($proxy->__isInitialized()) {
  111.                 return;
  112.             }
  113.             $properties $proxy->__getLazyProperties();
  114.             foreach ($properties as $propertyName => $property) {
  115.                 if (! isset($proxy->$propertyName)) {
  116.                     $proxy->$propertyName $properties[$propertyName];
  117.                 }
  118.             }
  119.             $proxy->__setInitialized(true);
  120.             if ($wakeupProxy) {
  121.                 $proxy->__wakeup();
  122.             }
  123.             $identifier $classMetadata->getIdentifierValues($proxy);
  124.             if ($entityPersister->loadById($identifier$proxy) === null) {
  125.                 $proxy->__setInitializer($initializer);
  126.                 $proxy->__setCloner($cloner);
  127.                 $proxy->__setInitialized(false);
  128.                 throw EntityNotFoundException::fromClassNameAndIdentifier(
  129.                     $classMetadata->getName(),
  130.                     $this->identifierFlattener->flattenIdentifier($classMetadata$identifier)
  131.                 );
  132.             }
  133.         };
  134.     }
  135.     /**
  136.      * Creates a closure capable of finalizing state a cloned proxy
  137.      *
  138.      * @psalm-return Closure(BaseProxy):void
  139.      *
  140.      * @throws EntityNotFoundException
  141.      */
  142.     private function createCloner(ClassMetadata $classMetadataEntityPersister $entityPersister): Closure
  143.     {
  144.         return function (BaseProxy $proxy) use ($entityPersister$classMetadata): void {
  145.             if ($proxy->__isInitialized()) {
  146.                 return;
  147.             }
  148.             $proxy->__setInitialized(true);
  149.             $proxy->__setInitializer(null);
  150.             $class      $entityPersister->getClassMetadata();
  151.             $identifier $classMetadata->getIdentifierValues($proxy);
  152.             $original   $entityPersister->loadById($identifier);
  153.             if ($original === null) {
  154.                 throw EntityNotFoundException::fromClassNameAndIdentifier(
  155.                     $classMetadata->getName(),
  156.                     $this->identifierFlattener->flattenIdentifier($classMetadata$identifier)
  157.                 );
  158.             }
  159.             foreach ($class->getReflectionProperties() as $property) {
  160.                 if (! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
  161.                     continue;
  162.                 }
  163.                 $property->setAccessible(true);
  164.                 $property->setValue($proxy$property->getValue($original));
  165.             }
  166.         };
  167.     }
  168. }