Security update to Drupal 8.4.6
[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     private const AUTOGENERATE_MODES = [
73         self::AUTOGENERATE_NEVER,
74         self::AUTOGENERATE_ALWAYS,
75         self::AUTOGENERATE_FILE_NOT_EXISTS,
76         self::AUTOGENERATE_EVAL,
77     ];
78
79     /**
80      * @var \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory
81      */
82     private $metadataFactory;
83
84     /**
85      * @var \Doctrine\Common\Proxy\ProxyGenerator the proxy generator responsible for creating the proxy classes/files.
86      */
87     private $proxyGenerator;
88
89     /**
90      * @var int Whether to automatically (re)generate proxy classes.
91      */
92     private $autoGenerate;
93
94     /**
95      * @var \Doctrine\Common\Proxy\ProxyDefinition[]
96      */
97     private $definitions = [];
98
99     /**
100      * @param \Doctrine\Common\Proxy\ProxyGenerator                     $proxyGenerator
101      * @param \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory $metadataFactory
102      * @param bool|int                                                  $autoGenerate
103      *
104      * @throws \Doctrine\Common\Proxy\Exception\InvalidArgumentException When auto generate mode is not valid.
105      */
106     public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate)
107     {
108         $this->proxyGenerator  = $proxyGenerator;
109         $this->metadataFactory = $metadataFactory;
110
111         $this->autoGenerate = (int)$autoGenerate;
112
113         if ( ! in_array($this->autoGenerate, self::AUTOGENERATE_MODES, true)) {
114             throw InvalidArgumentException::invalidAutoGenerateMode($autoGenerate);
115         }
116     }
117
118     /**
119      * Gets a reference proxy instance for the entity of the given type and identified by
120      * the given identifier.
121      *
122      * @param  string $className
123      * @param  array  $identifier
124      *
125      * @return \Doctrine\Common\Proxy\Proxy
126      *
127      * @throws \Doctrine\Common\Proxy\Exception\OutOfBoundsException
128      */
129     public function getProxy($className, array $identifier)
130     {
131         $definition = isset($this->definitions[$className])
132             ? $this->definitions[$className]
133             : $this->getProxyDefinition($className);
134         $fqcn       = $definition->proxyClassName;
135         $proxy      = new $fqcn($definition->initializer, $definition->cloner);
136
137         foreach ($definition->identifierFields as $idField) {
138             if (! isset($identifier[$idField])) {
139                 throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField);
140             }
141
142             $definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]);
143         }
144
145         return $proxy;
146     }
147
148     /**
149      * Generates proxy classes for all given classes.
150      *
151      * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata[] $classes The classes (ClassMetadata instances)
152      *                                                                      for which to generate proxies.
153      * @param string $proxyDir The target directory of the proxy classes. If not specified, the
154      *                         directory configured on the Configuration of the EntityManager used
155      *                         by this factory is used.
156      * @return int Number of generated proxies.
157      */
158     public function generateProxyClasses(array $classes, $proxyDir = null)
159     {
160         $generated = 0;
161
162         foreach ($classes as $class) {
163             if ($this->skipClass($class)) {
164                 continue;
165             }
166
167             $proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir);
168
169             $this->proxyGenerator->generateProxyClass($class, $proxyFileName);
170
171             $generated += 1;
172         }
173
174         return $generated;
175     }
176
177     /**
178      * Reset initialization/cloning logic for an un-initialized proxy
179      *
180      * @param \Doctrine\Common\Proxy\Proxy $proxy
181      *
182      * @return \Doctrine\Common\Proxy\Proxy
183      *
184      * @throws \Doctrine\Common\Proxy\Exception\InvalidArgumentException
185      */
186     public function resetUninitializedProxy(Proxy $proxy)
187     {
188         if ($proxy->__isInitialized()) {
189             throw InvalidArgumentException::unitializedProxyExpected($proxy);
190         }
191
192         $className  = ClassUtils::getClass($proxy);
193         $definition = isset($this->definitions[$className])
194             ? $this->definitions[$className]
195             : $this->getProxyDefinition($className);
196
197         $proxy->__setInitializer($definition->initializer);
198         $proxy->__setCloner($definition->cloner);
199
200         return $proxy;
201     }
202
203     /**
204      * Get a proxy definition for the given class name.
205      *
206      * @param string $className
207      *
208      * @return ProxyDefinition
209      */
210     private function getProxyDefinition($className)
211     {
212         $classMetadata = $this->metadataFactory->getMetadataFor($className);
213         $className     = $classMetadata->getName(); // aliases and case sensitivity
214
215         $this->definitions[$className] = $this->createProxyDefinition($className);
216         $proxyClassName                = $this->definitions[$className]->proxyClassName;
217
218         if ( ! class_exists($proxyClassName, false)) {
219             $fileName  = $this->proxyGenerator->getProxyFileName($className);
220
221             switch ($this->autoGenerate) {
222                 case self::AUTOGENERATE_NEVER:
223                     require $fileName;
224                     break;
225
226                 case self::AUTOGENERATE_FILE_NOT_EXISTS:
227                     if ( ! file_exists($fileName)) {
228                         $this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
229                     }
230                     require $fileName;
231                     break;
232
233                 case self::AUTOGENERATE_ALWAYS:
234                     $this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
235                     require $fileName;
236                     break;
237
238                 case self::AUTOGENERATE_EVAL:
239                     $this->proxyGenerator->generateProxyClass($classMetadata, false);
240                     break;
241             }
242         }
243
244         return $this->definitions[$className];
245     }
246
247     /**
248      * Determine if this class should be skipped during proxy generation.
249      *
250      * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $metadata
251      *
252      * @return bool
253      */
254     abstract protected function skipClass(ClassMetadata $metadata);
255
256     /**
257      * @param string $className
258      *
259      * @return ProxyDefinition
260      */
261     abstract protected function createProxyDefinition($className);
262 }