source: pro-violet-viettel/sourcecode/application/libraries/Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php @ 361

Last change on this file since 361 was 345, checked in by quyenla, 11 years ago

collaborator page

File size: 11.0 KB
Line 
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 LGPL. For more information, see
17 * <http://www.doctrine-project.org>.
18 */
19
20namespace Doctrine\Common\Persistence\Mapping;
21
22use Doctrine\Common\Cache\Cache;
23
24/**
25 * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the
26 * metadata mapping informations of a class which describes how a class should be mapped
27 * to a relational database.
28 *
29 * This class was abstracted from the ORM ClassMetadataFactory
30 *
31 * @since   2.2
32 * @author  Benjamin Eberlei <kontakt@beberlei.de>
33 * @author  Guilherme Blanco <guilhermeblanco@hotmail.com>
34 * @author  Jonathan Wage <jonwage@gmail.com>
35 * @author  Roman Borschel <roman@code-factory.org>
36 */
37abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
38{
39    /**
40     * Salt used by specific Object Manager implementation.
41     *
42     * @var string
43     */
44    protected $cacheSalt = "\$CLASSMETADATA";
45
46    /**
47     * @var \Doctrine\Common\Cache\Cache
48     */
49    private $cacheDriver;
50
51    /**
52     * @var array
53     */
54    private $loadedMetadata = array();
55
56    /**
57     * @var bool
58     */
59    protected $initialized = false;
60
61    /**
62     * @var ReflectionService
63     */
64    private $reflectionService;
65
66    /**
67     * Sets the cache driver used by the factory to cache ClassMetadata instances.
68     *
69     * @param Doctrine\Common\Cache\Cache $cacheDriver
70     */
71    public function setCacheDriver(Cache $cacheDriver = null)
72    {
73        $this->cacheDriver = $cacheDriver;
74    }
75
76    /**
77     * Gets the cache driver used by the factory to cache ClassMetadata instances.
78     *
79     * @return Doctrine\Common\Cache\Cache
80     */
81    public function getCacheDriver()
82    {
83        return $this->cacheDriver;
84    }
85
86    /**
87     * Return an array of all the loaded metadata currently in memory.
88     *
89     * @return array
90     */
91    public function getLoadedMetadata()
92    {
93        return $this->loadedMetadata;
94    }
95
96    /**
97     * Forces the factory to load the metadata of all classes known to the underlying
98     * mapping driver.
99     *
100     * @return array The ClassMetadata instances of all mapped classes.
101     */
102    public function getAllMetadata()
103    {
104        if ( ! $this->initialized) {
105            $this->initialize();
106        }
107
108        $driver = $this->getDriver();
109        $metadata = array();
110        foreach ($driver->getAllClassNames() as $className) {
111            $metadata[] = $this->getMetadataFor($className);
112        }
113
114        return $metadata;
115    }
116
117    /**
118     * Lazy initialization of this stuff, especially the metadata driver,
119     * since these are not needed at all when a metadata cache is active.
120     *
121     * @return void
122     */
123    abstract protected function initialize();
124
125    /**
126     * Get the fully qualified class-name from the namespace alias.
127     *
128     * @param string $namespaceAlias
129     * @param string $simpleClassName
130     * @return string
131     */
132    abstract protected function getFqcnFromAlias($namespaceAlias, $simpleClassName);
133
134    /**
135     * Return the mapping driver implementation.
136     *
137     * @return MappingDriver
138     */
139    abstract protected function getDriver();
140
141    /**
142     * Wakeup reflection after ClassMetadata gets unserialized from cache.
143     *
144     * @param ClassMetadata $class
145     * @param ReflectionService $reflService
146     * @return void
147     */
148    abstract protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService);
149
150    /**
151     * Initialize Reflection after ClassMetadata was constructed.
152     *
153     * @param ClassMetadata $class
154     * @param ReflectionSErvice $reflService
155     * @return void
156     */
157    abstract protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService);
158
159    /**
160     * Gets the class metadata descriptor for a class.
161     *
162     * @param string $className The name of the class.
163     * @return Doctrine\Common\Persistence\Mapping\ClassMetadata
164     */
165    public function getMetadataFor($className)
166    {
167        if ( ! isset($this->loadedMetadata[$className])) {
168            $realClassName = $className;
169
170            // Check for namespace alias
171            if (strpos($className, ':') !== false) {
172                list($namespaceAlias, $simpleClassName) = explode(':', $className);
173                $realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
174
175                if (isset($this->loadedMetadata[$realClassName])) {
176                    // We do not have the alias name in the map, include it
177                    $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
178
179                    return $this->loadedMetadata[$realClassName];
180                }
181            }
182
183            if ($this->cacheDriver) {
184                if (($cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt)) !== false) {
185                    $this->loadedMetadata[$realClassName] = $cached;
186                    $this->wakeupReflection($cached, $this->getReflectionService());
187                } else {
188                    foreach ($this->loadMetadata($realClassName) as $loadedClassName) {
189                        $this->cacheDriver->save(
190                            $loadedClassName . $this->cacheSalt, $this->loadedMetadata[$loadedClassName], null
191                        );
192                    }
193                }
194            } else {
195                $this->loadMetadata($realClassName);
196            }
197
198            if ($className != $realClassName) {
199                // We do not have the alias name in the map, include it
200                $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
201            }
202        }
203
204        return $this->loadedMetadata[$className];
205    }
206
207    /**
208     * Checks whether the factory has the metadata for a class loaded already.
209     *
210     * @param string $className
211     * @return boolean TRUE if the metadata of the class in question is already loaded, FALSE otherwise.
212     */
213    public function hasMetadataFor($className)
214    {
215        return isset($this->loadedMetadata[$className]);
216    }
217
218    /**
219     * Sets the metadata descriptor for a specific class.
220     *
221     * NOTE: This is only useful in very special cases, like when generating proxy classes.
222     *
223     * @param string $className
224     * @param ClassMetadata $class
225     */
226    public function setMetadataFor($className, $class)
227    {
228        $this->loadedMetadata[$className] = $class;
229    }
230
231    /**
232     * Get array of parent classes for the given entity class
233     *
234     * @param string $name
235     * @return array $parentClasses
236     */
237    protected function getParentClasses($name)
238    {
239        // Collect parent classes, ignoring transient (not-mapped) classes.
240        $parentClasses = array();
241        foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
242            if ( ! $this->getDriver()->isTransient($parentClass)) {
243                $parentClasses[] = $parentClass;
244            }
245        }
246        return $parentClasses;
247    }
248
249    /**
250     * Loads the metadata of the class in question and all it's ancestors whose metadata
251     * is still not loaded.
252     *
253     * @param string $name The name of the class for which the metadata should get loaded.
254     * @param array  $tables The metadata collection to which the loaded metadata is added.
255     */
256    protected function loadMetadata($name)
257    {
258        if ( ! $this->initialized) {
259            $this->initialize();
260        }
261
262        $loaded = array();
263
264        $parentClasses = $this->getParentClasses($name);
265        $parentClasses[] = $name;
266
267        // Move down the hierarchy of parent classes, starting from the topmost class
268        $parent = null;
269        $rootEntityFound = false;
270        $visited = array();
271        $reflService = $this->getReflectionService();
272        foreach ($parentClasses as $className) {
273            if (isset($this->loadedMetadata[$className])) {
274                $parent = $this->loadedMetadata[$className];
275                if (isset($parent->isMappedSuperclass) && $parent->isMappedSuperclass === false) {
276                    $rootEntityFound = true;
277                    array_unshift($visited, $className);
278                }
279                continue;
280            }
281
282            $class = $this->newClassMetadataInstance($className);
283            $this->initializeReflection($class, $reflService);
284
285            $this->doLoadMetadata($class, $parent, $rootEntityFound);
286
287            $this->loadedMetadata[$className] = $class;
288
289            $parent = $class;
290
291            if (isset($parent->isMappedSuperclass) && $class->isMappedSuperclass === false) {
292                $rootEntityFound = true;
293                array_unshift($visited, $className);
294            }
295
296            $this->wakeupReflection($class, $reflService);
297
298            $loaded[] = $className;
299        }
300
301        return $loaded;
302    }
303
304    /**
305     * Actually load the metadata from the underlying metadata
306     *
307     * @param ClassMetadata $class
308     * @param ClassMetadata $parent
309     * @param bool $rootEntityFound
310     * @return void
311     */
312    abstract protected function doLoadMetadata($class, $parent, $rootEntityFound);
313
314    /**
315     * Creates a new ClassMetadata instance for the given class name.
316     *
317     * @param string $className
318     * @return ClassMetadata
319     */
320    abstract protected function newClassMetadataInstance($className);
321
322    /**
323     * Check if this class is mapped by this Object Manager + ClassMetadata configuration
324     *
325     * @param $class
326     * @return bool
327     */
328    public function isTransient($class)
329    {
330        if ( ! $this->initialized) {
331            $this->initialize();
332        }
333
334        return $this->getDriver()->isTransient($class);
335    }
336
337    /**
338     * Set reflectionService.
339     *
340     * @param ReflectionService $reflectionService
341     */
342    public function setReflectionService(ReflectionService $reflectionService)
343    {
344        $this->reflectionService = $reflectionService;
345    }
346
347    /**
348     * Get the reflection service associated with this metadata factory.
349     *
350     * @return ReflectionService
351     */
352    public function getReflectionService()
353    {
354        if ($this->reflectionService === null) {
355            $this->reflectionService = new RuntimeReflectionService();
356        }
357        return $this->reflectionService;
358    }
359}
Note: See TracBrowser for help on using the repository browser.