"Fossies" - the Fresh Open Source Software Archive

Member "Symfony/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php" (22 Jul 2017, 13280 Bytes) of package /linux/www/Symfony_Standard_Vendors_3.4.39.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbstractClassMetadataFactory.php" see the Fossies "Dox" file reference documentation.

    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 
   20 namespace Doctrine\Common\Persistence\Mapping;
   21 
   22 use Doctrine\Common\Cache\Cache;
   23 use Doctrine\Common\Util\ClassUtils;
   24 use ReflectionException;
   25 
   26 /**
   27  * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
   28  * metadata mapping informations of a class which describes how a class should be mapped
   29  * to a relational database.
   30  *
   31  * This class was abstracted from the ORM ClassMetadataFactory.
   32  *
   33  * @since  2.2
   34  * @author Benjamin Eberlei <kontakt@beberlei.de>
   35  * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
   36  * @author Jonathan Wage <jonwage@gmail.com>
   37  * @author Roman Borschel <roman@code-factory.org>
   38  */
   39 abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
   40 {
   41     /**
   42      * Salt used by specific Object Manager implementation.
   43      *
   44      * @var string
   45      */
   46     protected $cacheSalt = '$CLASSMETADATA';
   47 
   48     /**
   49      * @var \Doctrine\Common\Cache\Cache|null
   50      */
   51     private $cacheDriver;
   52 
   53     /**
   54      * @var ClassMetadata[]
   55      */
   56     private $loadedMetadata = [];
   57 
   58     /**
   59      * @var bool
   60      */
   61     protected $initialized = false;
   62 
   63     /**
   64      * @var ReflectionService|null
   65      */
   66     private $reflectionService = null;
   67 
   68     /**
   69      * Sets the cache driver used by the factory to cache ClassMetadata instances.
   70      *
   71      * @param \Doctrine\Common\Cache\Cache $cacheDriver
   72      *
   73      * @return void
   74      */
   75     public function setCacheDriver(Cache $cacheDriver = null)
   76     {
   77         $this->cacheDriver = $cacheDriver;
   78     }
   79 
   80     /**
   81      * Gets the cache driver used by the factory to cache ClassMetadata instances.
   82      *
   83      * @return \Doctrine\Common\Cache\Cache|null
   84      */
   85     public function getCacheDriver()
   86     {
   87         return $this->cacheDriver;
   88     }
   89 
   90     /**
   91      * Returns an array of all the loaded metadata currently in memory.
   92      *
   93      * @return ClassMetadata[]
   94      */
   95     public function getLoadedMetadata()
   96     {
   97         return $this->loadedMetadata;
   98     }
   99 
  100     /**
  101      * Forces the factory to load the metadata of all classes known to the underlying
  102      * mapping driver.
  103      *
  104      * @return array The ClassMetadata instances of all mapped classes.
  105      */
  106     public function getAllMetadata()
  107     {
  108         if ( ! $this->initialized) {
  109             $this->initialize();
  110         }
  111 
  112         $driver = $this->getDriver();
  113         $metadata = [];
  114         foreach ($driver->getAllClassNames() as $className) {
  115             $metadata[] = $this->getMetadataFor($className);
  116         }
  117 
  118         return $metadata;
  119     }
  120 
  121     /**
  122      * Lazy initialization of this stuff, especially the metadata driver,
  123      * since these are not needed at all when a metadata cache is active.
  124      *
  125      * @return void
  126      */
  127     abstract protected function initialize();
  128 
  129     /**
  130      * Gets the fully qualified class-name from the namespace alias.
  131      *
  132      * @param string $namespaceAlias
  133      * @param string $simpleClassName
  134      *
  135      * @return string
  136      */
  137     abstract protected function getFqcnFromAlias($namespaceAlias, $simpleClassName);
  138 
  139     /**
  140      * Returns the mapping driver implementation.
  141      *
  142      * @return \Doctrine\Common\Persistence\Mapping\Driver\MappingDriver
  143      */
  144     abstract protected function getDriver();
  145 
  146     /**
  147      * Wakes up reflection after ClassMetadata gets unserialized from cache.
  148      *
  149      * @param ClassMetadata     $class
  150      * @param ReflectionService $reflService
  151      *
  152      * @return void
  153      */
  154     abstract protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService);
  155 
  156     /**
  157      * Initializes Reflection after ClassMetadata was constructed.
  158      *
  159      * @param ClassMetadata     $class
  160      * @param ReflectionService $reflService
  161      *
  162      * @return void
  163      */
  164     abstract protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService);
  165 
  166     /**
  167      * Checks whether the class metadata is an entity.
  168      *
  169      * This method should return false for mapped superclasses or embedded classes.
  170      *
  171      * @param ClassMetadata $class
  172      *
  173      * @return boolean
  174      */
  175     abstract protected function isEntity(ClassMetadata $class);
  176 
  177     /**
  178      * Gets the class metadata descriptor for a class.
  179      *
  180      * @param string $className The name of the class.
  181      *
  182      * @return ClassMetadata
  183      *
  184      * @throws ReflectionException
  185      * @throws MappingException
  186      */
  187     public function getMetadataFor($className)
  188     {
  189         if (isset($this->loadedMetadata[$className])) {
  190             return $this->loadedMetadata[$className];
  191         }
  192 
  193         // Check for namespace alias
  194         if (strpos($className, ':') !== false) {
  195             list($namespaceAlias, $simpleClassName) = explode(':', $className, 2);
  196 
  197             $realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
  198         } else {
  199             $realClassName = ClassUtils::getRealClass($className);
  200         }
  201 
  202         if (isset($this->loadedMetadata[$realClassName])) {
  203             // We do not have the alias name in the map, include it
  204             return $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
  205         }
  206 
  207         $loadingException = null;
  208 
  209         try {
  210             if ($this->cacheDriver) {
  211                 if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) instanceof ClassMetadata) {
  212                     $this->loadedMetadata[$realClassName] = $cached;
  213 
  214                     $this->wakeupReflection($cached, $this->getReflectionService());
  215                 } else {
  216                     foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
  217                         $this->cacheDriver->save(
  218                             $loadedClassName . $this->cacheSalt,
  219                             $this->loadedMetadata[$loadedClassName],
  220                             null
  221                         );
  222                     }
  223                 }
  224             } else {
  225                 $this->loadMetadata($realClassName);
  226             }
  227         } catch (MappingException $loadingException) {
  228             if (! $fallbackMetadataResponse = $this->onNotFoundMetadata($realClassName)) {
  229                 throw $loadingException;
  230             }
  231 
  232             $this->loadedMetadata[$realClassName] = $fallbackMetadataResponse;
  233         }
  234 
  235         if ($className !== $realClassName) {
  236             // We do not have the alias name in the map, include it
  237             $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
  238         }
  239 
  240         return $this->loadedMetadata[$className];
  241     }
  242 
  243     /**
  244      * Checks whether the factory has the metadata for a class loaded already.
  245      *
  246      * @param string $className
  247      *
  248      * @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise.
  249      */
  250     public function hasMetadataFor($className)
  251     {
  252         return isset($this->loadedMetadata[$className]);
  253     }
  254 
  255     /**
  256      * Sets the metadata descriptor for a specific class.
  257      *
  258      * NOTE: This is only useful in very special cases, like when generating proxy classes.
  259      *
  260      * @param string        $className
  261      * @param ClassMetadata $class
  262      *
  263      * @return void
  264      */
  265     public function setMetadataFor($className, $class)
  266     {
  267         $this->loadedMetadata[$className] = $class;
  268     }
  269 
  270     /**
  271      * Gets an array of parent classes for the given entity class.
  272      *
  273      * @param string $name
  274      *
  275      * @return array
  276      */
  277     protected function getParentClasses($name)
  278     {
  279         // Collect parent classes, ignoring transient (not-mapped) classes.
  280         $parentClasses = [];
  281         foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
  282             if ( ! $this->getDriver()->isTransient($parentClass)) {
  283                 $parentClasses[] = $parentClass;
  284             }
  285         }
  286         return $parentClasses;
  287     }
  288 
  289     /**
  290      * Loads the metadata of the class in question and all it's ancestors whose metadata
  291      * is still not loaded.
  292      *
  293      * Important: The class $name does not necesarily exist at this point here.
  294      * Scenarios in a code-generation setup might have access to XML/YAML
  295      * Mapping files without the actual PHP code existing here. That is why the
  296      * {@see Doctrine\Common\Persistence\Mapping\ReflectionService} interface
  297      * should be used for reflection.
  298      *
  299      * @param string $name The name of the class for which the metadata should get loaded.
  300      *
  301      * @return array
  302      */
  303     protected function loadMetadata($name)
  304     {
  305         if ( ! $this->initialized) {
  306             $this->initialize();
  307         }
  308 
  309         $loaded = [];
  310 
  311         $parentClasses = $this->getParentClasses($name);
  312         $parentClasses[] = $name;
  313 
  314         // Move down the hierarchy of parent classes, starting from the topmost class
  315         $parent = null;
  316         $rootEntityFound = false;
  317         $visited = [];
  318         $reflService = $this->getReflectionService();
  319         foreach ($parentClasses as $className) {
  320             if (isset($this->loadedMetadata[$className])) {
  321                 $parent = $this->loadedMetadata[$className];
  322                 if ($this->isEntity($parent)) {
  323                     $rootEntityFound = true;
  324                     array_unshift($visited, $className);
  325                 }
  326                 continue;
  327             }
  328 
  329             $class = $this->newClassMetadataInstance($className);
  330             $this->initializeReflection($class, $reflService);
  331 
  332             $this->doLoadMetadata($class, $parent, $rootEntityFound, $visited);
  333 
  334             $this->loadedMetadata[$className] = $class;
  335 
  336             $parent = $class;
  337 
  338             if ($this->isEntity($class)) {
  339                 $rootEntityFound = true;
  340                 array_unshift($visited, $className);
  341             }
  342 
  343             $this->wakeupReflection($class, $reflService);
  344 
  345             $loaded[] = $className;
  346         }
  347 
  348         return $loaded;
  349     }
  350 
  351     /**
  352      * Provides a fallback hook for loading metadata when loading failed due to reflection/mapping exceptions
  353      *
  354      * Override this method to implement a fallback strategy for failed metadata loading
  355      *
  356      * @param string $className
  357      *
  358      * @return \Doctrine\Common\Persistence\Mapping\ClassMetadata|null
  359      */
  360     protected function onNotFoundMetadata($className)
  361     {
  362         return null;
  363     }
  364 
  365     /**
  366      * Actually loads the metadata from the underlying metadata.
  367      *
  368      * @param ClassMetadata      $class
  369      * @param ClassMetadata|null $parent
  370      * @param bool               $rootEntityFound
  371      * @param array              $nonSuperclassParents All parent class names
  372      *                                                 that are not marked as mapped superclasses.
  373      *
  374      * @return void
  375      */
  376     abstract protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents);
  377 
  378     /**
  379      * Creates a new ClassMetadata instance for the given class name.
  380      *
  381      * @param string $className
  382      *
  383      * @return ClassMetadata
  384      */
  385     abstract protected function newClassMetadataInstance($className);
  386 
  387     /**
  388      * {@inheritDoc}
  389      */
  390     public function isTransient($class)
  391     {
  392         if ( ! $this->initialized) {
  393             $this->initialize();
  394         }
  395 
  396         // Check for namespace alias
  397         if (strpos($class, ':') !== false) {
  398             list($namespaceAlias, $simpleClassName) = explode(':', $class, 2);
  399             $class = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
  400         }
  401 
  402         return $this->getDriver()->isTransient($class);
  403     }
  404 
  405     /**
  406      * Sets the reflectionService.
  407      *
  408      * @param ReflectionService $reflectionService
  409      *
  410      * @return void
  411      */
  412     public function setReflectionService(ReflectionService $reflectionService)
  413     {
  414         $this->reflectionService = $reflectionService;
  415     }
  416 
  417     /**
  418      * Gets the reflection service associated with this metadata factory.
  419      *
  420      * @return ReflectionService
  421      */
  422     public function getReflectionService()
  423     {
  424         if ($this->reflectionService === null) {
  425             $this->reflectionService = new RuntimeReflectionService();
  426         }
  427         return $this->reflectionService;
  428     }
  429 }