7eb216bfc57ef675ce4ed23f6d681ab2567d4b92
[yaffs-website] / vendor / doctrine / common / lib / Doctrine / Common / Proxy / AbstractProxyFactory.php
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\Proxy;
21
22 use Doctrine\Common\Persistence\Mapping\ClassMetadata;
23 use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
24 use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
25 use Doctrine\Common\Proxy\Exception\OutOfBoundsException;
26 use Doctrine\Common\Util\ClassUtils;
27
28 /**
29  * Abstract factory for proxy objects.
30  *
31  * @author Benjamin Eberlei <kontakt@beberlei.de>
32  */
33 abstract class AbstractProxyFactory
34 {
35     /**
36      * Never autogenerate a proxy and rely that it was generated by some
37      * process before deployment.
38      *
39      * @var integer
40      */
41     const AUTOGENERATE_NEVER = 0;
42
43     /**
44      * Always generates a new proxy in every request.
45      *
46      * This is only sane during development.
47      *
48      * @var integer
49      */
50     const AUTOGENERATE_ALWAYS = 1;
51
52     /**
53      * Autogenerate the proxy class when the proxy file does not exist.
54      *
55      * This strategy causes a file exists call whenever any proxy is used the
56      * first time in a request.
57      *
58      * @var integer
59      */
60     const AUTOGENERATE_FILE_NOT_EXISTS = 2;
61
62     /**
63      * Generate the proxy classes using eval().
64      *
65      * This strategy is only sane for development, and even then it gives me
66      * the creeps a little.
67      *
68      * @var integer
69      */
70     const AUTOGENERATE_EVAL = 3;
71
72     /**
73      * @var \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory
74      */
75     private $metadataFactory;
76
77     /**
78      * @var \Doctrine\Common\Proxy\ProxyGenerator the proxy generator responsible for creating the proxy classes/files.
79      */
80     private $proxyGenerator;
81
82     /**
83      * @var bool Whether to automatically (re)generate proxy classes.
84      */
85     private $autoGenerate;
86
87     /**
88      * @var \Doctrine\Common\Proxy\ProxyDefinition[]
89      */
90     private $definitions = [];
91
92     /**
93      * @param \Doctrine\Common\Proxy\ProxyGenerator                     $proxyGenerator
94      * @param \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory $metadataFactory
95      * @param bool|int                                                  $autoGenerate
96      */
97     public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate)
98     {
99         $this->proxyGenerator  = $proxyGenerator;
100         $this->metadataFactory = $metadataFactory;
101         $this->autoGenerate    = (int)$autoGenerate;
102     }
103
104     /**
105      * Gets a reference proxy instance for the entity of the given type and identified by
106      * the given identifier.
107      *
108      * @param  string $className
109      * @param  array  $identifier
110      *
111      * @return \Doctrine\Common\Proxy\Proxy
112      *
113      * @throws \Doctrine\Common\Proxy\Exception\OutOfBoundsException
114      */
115     public function getProxy($className, array $identifier)
116     {
117         $definition = isset($this->definitions[$className])
118             ? $this->definitions[$className]
119             : $this->getProxyDefinition($className);
120         $fqcn       = $definition->proxyClassName;
121         $proxy      = new $fqcn($definition->initializer, $definition->cloner);
122
123         foreach ($definition->identifierFields as $idField) {
124             if (! isset($identifier[$idField])) {
125                 throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField);
126             }
127
128             $definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]);
129         }
130
131         return $proxy;
132     }
133
134     /**
135      * Generates proxy classes for all given classes.
136      *
137      * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata[] $classes The classes (ClassMetadata instances)
138      *                                                                      for which to generate proxies.
139      * @param string $proxyDir The target directory of the proxy classes. If not specified, the
140      *                         directory configured on the Configuration of the EntityManager used
141      *                         by this factory is used.
142      * @return int Number of generated proxies.
143      */
144     public function generateProxyClasses(array $classes, $proxyDir = null)
145     {
146         $generated = 0;
147
148         foreach ($classes as $class) {
149             if ($this->skipClass($class)) {
150                 continue;
151             }
152
153             $proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir);
154
155             $this->proxyGenerator->generateProxyClass($class, $proxyFileName);
156
157             $generated += 1;
158         }
159
160         return $generated;
161     }
162
163     /**
164      * Reset initialization/cloning logic for an un-initialized proxy
165      *
166      * @param \Doctrine\Common\Proxy\Proxy $proxy
167      *
168      * @return \Doctrine\Common\Proxy\Proxy
169      *
170      * @throws \Doctrine\Common\Proxy\Exception\InvalidArgumentException
171      */
172     public function resetUninitializedProxy(Proxy $proxy)
173     {
174         if ($proxy->__isInitialized()) {
175             throw InvalidArgumentException::unitializedProxyExpected($proxy);
176         }
177
178         $className  = ClassUtils::getClass($proxy);
179         $definition = isset($this->definitions[$className])
180             ? $this->definitions[$className]
181             : $this->getProxyDefinition($className);
182
183         $proxy->__setInitializer($definition->initializer);
184         $proxy->__setCloner($definition->cloner);
185
186         return $proxy;
187     }
188
189     /**
190      * Get a proxy definition for the given class name.
191      *
192      * @param string $className
193      *
194      * @return ProxyDefinition
195      */
196     private function getProxyDefinition($className)
197     {
198         $classMetadata = $this->metadataFactory->getMetadataFor($className);
199         $className     = $classMetadata->getName(); // aliases and case sensitivity
200
201         $this->definitions[$className] = $this->createProxyDefinition($className);
202         $proxyClassName                = $this->definitions[$className]->proxyClassName;
203
204         if ( ! class_exists($proxyClassName, false)) {
205             $fileName  = $this->proxyGenerator->getProxyFileName($className);
206
207             switch ($this->autoGenerate) {
208                 case self::AUTOGENERATE_NEVER:
209                     require $fileName;
210                     break;
211
212                 case self::AUTOGENERATE_FILE_NOT_EXISTS:
213                     if ( ! file_exists($fileName)) {
214                         $this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
215                     }
216                     require $fileName;
217                     break;
218
219                 case self::AUTOGENERATE_ALWAYS:
220                     $this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
221                     require $fileName;
222                     break;
223
224                 case self::AUTOGENERATE_EVAL:
225                     $this->proxyGenerator->generateProxyClass($classMetadata, false);
226                     break;
227             }
228         }
229
230         return $this->definitions[$className];
231     }
232
233     /**
234      * Determine if this class should be skipped during proxy generation.
235      *
236      * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $metadata
237      *
238      * @return bool
239      */
240     abstract protected function skipClass(ClassMetadata $metadata);
241
242     /**
243      * @param string $className
244      *
245      * @return ProxyDefinition
246      */
247     abstract protected function createProxyDefinition($className);
248 }