Chris@0
|
1 <?php
|
Chris@0
|
2 /*
|
Chris@0
|
3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
Chris@0
|
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
Chris@0
|
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
Chris@0
|
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
Chris@0
|
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
Chris@0
|
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
Chris@0
|
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
Chris@0
|
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
Chris@0
|
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
Chris@0
|
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
Chris@0
|
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
Chris@0
|
14 *
|
Chris@0
|
15 * This software consists of voluntary contributions made by many individuals
|
Chris@0
|
16 * and is licensed under the MIT license. For more information, see
|
Chris@0
|
17 * <http://www.doctrine-project.org>.
|
Chris@0
|
18 */
|
Chris@0
|
19
|
Chris@0
|
20 namespace Doctrine\Common\Proxy;
|
Chris@0
|
21
|
Chris@0
|
22 use Doctrine\Common\Persistence\Mapping\ClassMetadata;
|
Chris@0
|
23 use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
|
Chris@0
|
24 use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
|
Chris@0
|
25 use Doctrine\Common\Proxy\Exception\OutOfBoundsException;
|
Chris@0
|
26 use Doctrine\Common\Util\ClassUtils;
|
Chris@0
|
27
|
Chris@0
|
28 /**
|
Chris@0
|
29 * Abstract factory for proxy objects.
|
Chris@0
|
30 *
|
Chris@0
|
31 * @author Benjamin Eberlei <kontakt@beberlei.de>
|
Chris@0
|
32 */
|
Chris@0
|
33 abstract class AbstractProxyFactory
|
Chris@0
|
34 {
|
Chris@0
|
35 /**
|
Chris@0
|
36 * Never autogenerate a proxy and rely that it was generated by some
|
Chris@0
|
37 * process before deployment.
|
Chris@0
|
38 *
|
Chris@0
|
39 * @var integer
|
Chris@0
|
40 */
|
Chris@0
|
41 const AUTOGENERATE_NEVER = 0;
|
Chris@0
|
42
|
Chris@0
|
43 /**
|
Chris@0
|
44 * Always generates a new proxy in every request.
|
Chris@0
|
45 *
|
Chris@0
|
46 * This is only sane during development.
|
Chris@0
|
47 *
|
Chris@0
|
48 * @var integer
|
Chris@0
|
49 */
|
Chris@0
|
50 const AUTOGENERATE_ALWAYS = 1;
|
Chris@0
|
51
|
Chris@0
|
52 /**
|
Chris@0
|
53 * Autogenerate the proxy class when the proxy file does not exist.
|
Chris@0
|
54 *
|
Chris@0
|
55 * This strategy causes a file exists call whenever any proxy is used the
|
Chris@0
|
56 * first time in a request.
|
Chris@0
|
57 *
|
Chris@0
|
58 * @var integer
|
Chris@0
|
59 */
|
Chris@0
|
60 const AUTOGENERATE_FILE_NOT_EXISTS = 2;
|
Chris@0
|
61
|
Chris@0
|
62 /**
|
Chris@0
|
63 * Generate the proxy classes using eval().
|
Chris@0
|
64 *
|
Chris@0
|
65 * This strategy is only sane for development, and even then it gives me
|
Chris@0
|
66 * the creeps a little.
|
Chris@0
|
67 *
|
Chris@0
|
68 * @var integer
|
Chris@0
|
69 */
|
Chris@0
|
70 const AUTOGENERATE_EVAL = 3;
|
Chris@0
|
71
|
Chris@0
|
72 /**
|
Chris@0
|
73 * @var \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory
|
Chris@0
|
74 */
|
Chris@0
|
75 private $metadataFactory;
|
Chris@0
|
76
|
Chris@0
|
77 /**
|
Chris@0
|
78 * @var \Doctrine\Common\Proxy\ProxyGenerator the proxy generator responsible for creating the proxy classes/files.
|
Chris@0
|
79 */
|
Chris@0
|
80 private $proxyGenerator;
|
Chris@0
|
81
|
Chris@0
|
82 /**
|
Chris@0
|
83 * @var bool Whether to automatically (re)generate proxy classes.
|
Chris@0
|
84 */
|
Chris@0
|
85 private $autoGenerate;
|
Chris@0
|
86
|
Chris@0
|
87 /**
|
Chris@0
|
88 * @var \Doctrine\Common\Proxy\ProxyDefinition[]
|
Chris@0
|
89 */
|
Chris@0
|
90 private $definitions = [];
|
Chris@0
|
91
|
Chris@0
|
92 /**
|
Chris@0
|
93 * @param \Doctrine\Common\Proxy\ProxyGenerator $proxyGenerator
|
Chris@0
|
94 * @param \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory $metadataFactory
|
Chris@0
|
95 * @param bool|int $autoGenerate
|
Chris@0
|
96 */
|
Chris@0
|
97 public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate)
|
Chris@0
|
98 {
|
Chris@0
|
99 $this->proxyGenerator = $proxyGenerator;
|
Chris@0
|
100 $this->metadataFactory = $metadataFactory;
|
Chris@0
|
101 $this->autoGenerate = (int)$autoGenerate;
|
Chris@0
|
102 }
|
Chris@0
|
103
|
Chris@0
|
104 /**
|
Chris@0
|
105 * Gets a reference proxy instance for the entity of the given type and identified by
|
Chris@0
|
106 * the given identifier.
|
Chris@0
|
107 *
|
Chris@0
|
108 * @param string $className
|
Chris@0
|
109 * @param array $identifier
|
Chris@0
|
110 *
|
Chris@0
|
111 * @return \Doctrine\Common\Proxy\Proxy
|
Chris@0
|
112 *
|
Chris@0
|
113 * @throws \Doctrine\Common\Proxy\Exception\OutOfBoundsException
|
Chris@0
|
114 */
|
Chris@0
|
115 public function getProxy($className, array $identifier)
|
Chris@0
|
116 {
|
Chris@0
|
117 $definition = isset($this->definitions[$className])
|
Chris@0
|
118 ? $this->definitions[$className]
|
Chris@0
|
119 : $this->getProxyDefinition($className);
|
Chris@0
|
120 $fqcn = $definition->proxyClassName;
|
Chris@0
|
121 $proxy = new $fqcn($definition->initializer, $definition->cloner);
|
Chris@0
|
122
|
Chris@0
|
123 foreach ($definition->identifierFields as $idField) {
|
Chris@0
|
124 if (! isset($identifier[$idField])) {
|
Chris@0
|
125 throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField);
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 $definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]);
|
Chris@0
|
129 }
|
Chris@0
|
130
|
Chris@0
|
131 return $proxy;
|
Chris@0
|
132 }
|
Chris@0
|
133
|
Chris@0
|
134 /**
|
Chris@0
|
135 * Generates proxy classes for all given classes.
|
Chris@0
|
136 *
|
Chris@0
|
137 * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata[] $classes The classes (ClassMetadata instances)
|
Chris@0
|
138 * for which to generate proxies.
|
Chris@0
|
139 * @param string $proxyDir The target directory of the proxy classes. If not specified, the
|
Chris@0
|
140 * directory configured on the Configuration of the EntityManager used
|
Chris@0
|
141 * by this factory is used.
|
Chris@0
|
142 * @return int Number of generated proxies.
|
Chris@0
|
143 */
|
Chris@0
|
144 public function generateProxyClasses(array $classes, $proxyDir = null)
|
Chris@0
|
145 {
|
Chris@0
|
146 $generated = 0;
|
Chris@0
|
147
|
Chris@0
|
148 foreach ($classes as $class) {
|
Chris@0
|
149 if ($this->skipClass($class)) {
|
Chris@0
|
150 continue;
|
Chris@0
|
151 }
|
Chris@0
|
152
|
Chris@0
|
153 $proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir);
|
Chris@0
|
154
|
Chris@0
|
155 $this->proxyGenerator->generateProxyClass($class, $proxyFileName);
|
Chris@0
|
156
|
Chris@0
|
157 $generated += 1;
|
Chris@0
|
158 }
|
Chris@0
|
159
|
Chris@0
|
160 return $generated;
|
Chris@0
|
161 }
|
Chris@0
|
162
|
Chris@0
|
163 /**
|
Chris@0
|
164 * Reset initialization/cloning logic for an un-initialized proxy
|
Chris@0
|
165 *
|
Chris@0
|
166 * @param \Doctrine\Common\Proxy\Proxy $proxy
|
Chris@0
|
167 *
|
Chris@0
|
168 * @return \Doctrine\Common\Proxy\Proxy
|
Chris@0
|
169 *
|
Chris@0
|
170 * @throws \Doctrine\Common\Proxy\Exception\InvalidArgumentException
|
Chris@0
|
171 */
|
Chris@0
|
172 public function resetUninitializedProxy(Proxy $proxy)
|
Chris@0
|
173 {
|
Chris@0
|
174 if ($proxy->__isInitialized()) {
|
Chris@0
|
175 throw InvalidArgumentException::unitializedProxyExpected($proxy);
|
Chris@0
|
176 }
|
Chris@0
|
177
|
Chris@0
|
178 $className = ClassUtils::getClass($proxy);
|
Chris@0
|
179 $definition = isset($this->definitions[$className])
|
Chris@0
|
180 ? $this->definitions[$className]
|
Chris@0
|
181 : $this->getProxyDefinition($className);
|
Chris@0
|
182
|
Chris@0
|
183 $proxy->__setInitializer($definition->initializer);
|
Chris@0
|
184 $proxy->__setCloner($definition->cloner);
|
Chris@0
|
185
|
Chris@0
|
186 return $proxy;
|
Chris@0
|
187 }
|
Chris@0
|
188
|
Chris@0
|
189 /**
|
Chris@0
|
190 * Get a proxy definition for the given class name.
|
Chris@0
|
191 *
|
Chris@0
|
192 * @param string $className
|
Chris@0
|
193 *
|
Chris@0
|
194 * @return ProxyDefinition
|
Chris@0
|
195 */
|
Chris@0
|
196 private function getProxyDefinition($className)
|
Chris@0
|
197 {
|
Chris@0
|
198 $classMetadata = $this->metadataFactory->getMetadataFor($className);
|
Chris@0
|
199 $className = $classMetadata->getName(); // aliases and case sensitivity
|
Chris@0
|
200
|
Chris@0
|
201 $this->definitions[$className] = $this->createProxyDefinition($className);
|
Chris@0
|
202 $proxyClassName = $this->definitions[$className]->proxyClassName;
|
Chris@0
|
203
|
Chris@0
|
204 if ( ! class_exists($proxyClassName, false)) {
|
Chris@0
|
205 $fileName = $this->proxyGenerator->getProxyFileName($className);
|
Chris@0
|
206
|
Chris@0
|
207 switch ($this->autoGenerate) {
|
Chris@0
|
208 case self::AUTOGENERATE_NEVER:
|
Chris@0
|
209 require $fileName;
|
Chris@0
|
210 break;
|
Chris@0
|
211
|
Chris@0
|
212 case self::AUTOGENERATE_FILE_NOT_EXISTS:
|
Chris@0
|
213 if ( ! file_exists($fileName)) {
|
Chris@0
|
214 $this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
|
Chris@0
|
215 }
|
Chris@0
|
216 require $fileName;
|
Chris@0
|
217 break;
|
Chris@0
|
218
|
Chris@0
|
219 case self::AUTOGENERATE_ALWAYS:
|
Chris@0
|
220 $this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
|
Chris@0
|
221 require $fileName;
|
Chris@0
|
222 break;
|
Chris@0
|
223
|
Chris@0
|
224 case self::AUTOGENERATE_EVAL:
|
Chris@0
|
225 $this->proxyGenerator->generateProxyClass($classMetadata, false);
|
Chris@0
|
226 break;
|
Chris@0
|
227 }
|
Chris@0
|
228 }
|
Chris@0
|
229
|
Chris@0
|
230 return $this->definitions[$className];
|
Chris@0
|
231 }
|
Chris@0
|
232
|
Chris@0
|
233 /**
|
Chris@0
|
234 * Determine if this class should be skipped during proxy generation.
|
Chris@0
|
235 *
|
Chris@0
|
236 * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $metadata
|
Chris@0
|
237 *
|
Chris@0
|
238 * @return bool
|
Chris@0
|
239 */
|
Chris@0
|
240 abstract protected function skipClass(ClassMetadata $metadata);
|
Chris@0
|
241
|
Chris@0
|
242 /**
|
Chris@0
|
243 * @param string $className
|
Chris@0
|
244 *
|
Chris@0
|
245 * @return ProxyDefinition
|
Chris@0
|
246 */
|
Chris@0
|
247 abstract protected function createProxyDefinition($className);
|
Chris@0
|
248 }
|