diff options
author | polo <ordipolo@gmx.fr> | 2024-08-13 23:45:21 +0200 |
---|---|---|
committer | polo <ordipolo@gmx.fr> | 2024-08-13 23:45:21 +0200 |
commit | bf6655a534a6775d30cafa67bd801276bda1d98d (patch) | |
tree | c6381e3f6c81c33eab72508f410b165ba05f7e9c /vendor/doctrine/orm/src/Proxy | |
parent | 94d67a4b51f8e62e7d518cce26a526ae1ec48278 (diff) | |
download | AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.zip |
VERSION 0.2 doctrine ORM et entités
Diffstat (limited to 'vendor/doctrine/orm/src/Proxy')
-rw-r--r-- | vendor/doctrine/orm/src/Proxy/Autoloader.php | 86 | ||||
-rw-r--r-- | vendor/doctrine/orm/src/Proxy/DefaultProxyClassNameResolver.php | 35 | ||||
-rw-r--r-- | vendor/doctrine/orm/src/Proxy/InternalProxy.php | 18 | ||||
-rw-r--r-- | vendor/doctrine/orm/src/Proxy/NotAProxyClass.php | 22 | ||||
-rw-r--r-- | vendor/doctrine/orm/src/Proxy/ProxyFactory.php | 439 |
5 files changed, 600 insertions, 0 deletions
diff --git a/vendor/doctrine/orm/src/Proxy/Autoloader.php b/vendor/doctrine/orm/src/Proxy/Autoloader.php new file mode 100644 index 0000000..1013e73 --- /dev/null +++ b/vendor/doctrine/orm/src/Proxy/Autoloader.php | |||
@@ -0,0 +1,86 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\ORM\Proxy; | ||
6 | |||
7 | use Closure; | ||
8 | |||
9 | use function file_exists; | ||
10 | use function ltrim; | ||
11 | use function spl_autoload_register; | ||
12 | use function str_replace; | ||
13 | use function str_starts_with; | ||
14 | use function strlen; | ||
15 | use function substr; | ||
16 | |||
17 | use const DIRECTORY_SEPARATOR; | ||
18 | |||
19 | /** | ||
20 | * Special Autoloader for Proxy classes, which are not PSR-0 compliant. | ||
21 | */ | ||
22 | final class Autoloader | ||
23 | { | ||
24 | /** | ||
25 | * Resolves proxy class name to a filename based on the following pattern. | ||
26 | * | ||
27 | * 1. Remove Proxy namespace from class name. | ||
28 | * 2. Remove namespace separators from remaining class name. | ||
29 | * 3. Return PHP filename from proxy-dir with the result from 2. | ||
30 | * | ||
31 | * @psalm-param class-string $className | ||
32 | * | ||
33 | * @throws NotAProxyClass | ||
34 | */ | ||
35 | public static function resolveFile(string $proxyDir, string $proxyNamespace, string $className): string | ||
36 | { | ||
37 | if (! str_starts_with($className, $proxyNamespace)) { | ||
38 | throw new NotAProxyClass($className, $proxyNamespace); | ||
39 | } | ||
40 | |||
41 | // remove proxy namespace from class name | ||
42 | $classNameRelativeToProxyNamespace = substr($className, strlen($proxyNamespace)); | ||
43 | |||
44 | // remove namespace separators from remaining class name | ||
45 | $fileName = str_replace('\\', '', $classNameRelativeToProxyNamespace); | ||
46 | |||
47 | return $proxyDir . DIRECTORY_SEPARATOR . $fileName . '.php'; | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * Registers and returns autoloader callback for the given proxy dir and namespace. | ||
52 | * | ||
53 | * @param Closure(string, string, class-string): void|null $notFoundCallback Invoked when the proxy file is not found. | ||
54 | * | ||
55 | * @return Closure(string): void | ||
56 | */ | ||
57 | public static function register( | ||
58 | string $proxyDir, | ||
59 | string $proxyNamespace, | ||
60 | Closure|null $notFoundCallback = null, | ||
61 | ): Closure { | ||
62 | $proxyNamespace = ltrim($proxyNamespace, '\\'); | ||
63 | |||
64 | $autoloader = /** @param class-string $className */ static function (string $className) use ($proxyDir, $proxyNamespace, $notFoundCallback): void { | ||
65 | if ($proxyNamespace === '') { | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | if (! str_starts_with($className, $proxyNamespace)) { | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | $file = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className); | ||
74 | |||
75 | if ($notFoundCallback && ! file_exists($file)) { | ||
76 | $notFoundCallback($proxyDir, $proxyNamespace, $className); | ||
77 | } | ||
78 | |||
79 | require $file; | ||
80 | }; | ||
81 | |||
82 | spl_autoload_register($autoloader); | ||
83 | |||
84 | return $autoloader; | ||
85 | } | ||
86 | } | ||
diff --git a/vendor/doctrine/orm/src/Proxy/DefaultProxyClassNameResolver.php b/vendor/doctrine/orm/src/Proxy/DefaultProxyClassNameResolver.php new file mode 100644 index 0000000..1345f2e --- /dev/null +++ b/vendor/doctrine/orm/src/Proxy/DefaultProxyClassNameResolver.php | |||
@@ -0,0 +1,35 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\ORM\Proxy; | ||
6 | |||
7 | use Doctrine\Persistence\Mapping\ProxyClassNameResolver; | ||
8 | use Doctrine\Persistence\Proxy; | ||
9 | |||
10 | use function strrpos; | ||
11 | use function substr; | ||
12 | |||
13 | /** | ||
14 | * Class-related functionality for objects that might or not be proxy objects | ||
15 | * at the moment. | ||
16 | */ | ||
17 | final class DefaultProxyClassNameResolver implements ProxyClassNameResolver | ||
18 | { | ||
19 | public function resolveClassName(string $className): string | ||
20 | { | ||
21 | $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); | ||
22 | |||
23 | if ($pos === false) { | ||
24 | return $className; | ||
25 | } | ||
26 | |||
27 | return substr($className, $pos + Proxy::MARKER_LENGTH + 2); | ||
28 | } | ||
29 | |||
30 | /** @return class-string */ | ||
31 | public static function getClass(object $object): string | ||
32 | { | ||
33 | return (new self())->resolveClassName($object::class); | ||
34 | } | ||
35 | } | ||
diff --git a/vendor/doctrine/orm/src/Proxy/InternalProxy.php b/vendor/doctrine/orm/src/Proxy/InternalProxy.php new file mode 100644 index 0000000..7c1d833 --- /dev/null +++ b/vendor/doctrine/orm/src/Proxy/InternalProxy.php | |||
@@ -0,0 +1,18 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\ORM\Proxy; | ||
6 | |||
7 | use Doctrine\Persistence\Proxy; | ||
8 | |||
9 | /** | ||
10 | * @internal | ||
11 | * | ||
12 | * @template T of object | ||
13 | * @template-extends Proxy<T> | ||
14 | */ | ||
15 | interface InternalProxy extends Proxy | ||
16 | { | ||
17 | public function __setInitialized(bool $initialized): void; | ||
18 | } | ||
diff --git a/vendor/doctrine/orm/src/Proxy/NotAProxyClass.php b/vendor/doctrine/orm/src/Proxy/NotAProxyClass.php new file mode 100644 index 0000000..689cc3e --- /dev/null +++ b/vendor/doctrine/orm/src/Proxy/NotAProxyClass.php | |||
@@ -0,0 +1,22 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\ORM\Proxy; | ||
6 | |||
7 | use Doctrine\ORM\Exception\ORMException; | ||
8 | use InvalidArgumentException; | ||
9 | |||
10 | use function sprintf; | ||
11 | |||
12 | final class NotAProxyClass extends InvalidArgumentException implements ORMException | ||
13 | { | ||
14 | public function __construct(string $className, string $proxyNamespace) | ||
15 | { | ||
16 | parent::__construct(sprintf( | ||
17 | 'The class "%s" is not part of the proxy namespace "%s"', | ||
18 | $className, | ||
19 | $proxyNamespace, | ||
20 | )); | ||
21 | } | ||
22 | } | ||
diff --git a/vendor/doctrine/orm/src/Proxy/ProxyFactory.php b/vendor/doctrine/orm/src/Proxy/ProxyFactory.php new file mode 100644 index 0000000..b2d114a --- /dev/null +++ b/vendor/doctrine/orm/src/Proxy/ProxyFactory.php | |||
@@ -0,0 +1,439 @@ | |||
1 | <?php | ||
2 | |||
3 | declare(strict_types=1); | ||
4 | |||
5 | namespace Doctrine\ORM\Proxy; | ||
6 | |||
7 | use Closure; | ||
8 | use Doctrine\ORM\EntityManagerInterface; | ||
9 | use Doctrine\ORM\EntityNotFoundException; | ||
10 | use Doctrine\ORM\ORMInvalidArgumentException; | ||
11 | use Doctrine\ORM\Persisters\Entity\EntityPersister; | ||
12 | use Doctrine\ORM\UnitOfWork; | ||
13 | use Doctrine\ORM\Utility\IdentifierFlattener; | ||
14 | use Doctrine\Persistence\Mapping\ClassMetadata; | ||
15 | use Doctrine\Persistence\Proxy; | ||
16 | use ReflectionProperty; | ||
17 | use Symfony\Component\VarExporter\ProxyHelper; | ||
18 | |||
19 | use function array_combine; | ||
20 | use function array_flip; | ||
21 | use function array_intersect_key; | ||
22 | use function assert; | ||
23 | use function bin2hex; | ||
24 | use function chmod; | ||
25 | use function class_exists; | ||
26 | use function dirname; | ||
27 | use function file_exists; | ||
28 | use function file_put_contents; | ||
29 | use function filemtime; | ||
30 | use function is_bool; | ||
31 | use function is_dir; | ||
32 | use function is_int; | ||
33 | use function is_writable; | ||
34 | use function ltrim; | ||
35 | use function mkdir; | ||
36 | use function preg_match_all; | ||
37 | use function random_bytes; | ||
38 | use function rename; | ||
39 | use function rtrim; | ||
40 | use function str_replace; | ||
41 | use function strpos; | ||
42 | use function strrpos; | ||
43 | use function strtr; | ||
44 | use function substr; | ||
45 | use function ucfirst; | ||
46 | |||
47 | use const DIRECTORY_SEPARATOR; | ||
48 | |||
49 | /** | ||
50 | * This factory is used to create proxy objects for entities at runtime. | ||
51 | */ | ||
52 | class ProxyFactory | ||
53 | { | ||
54 | /** | ||
55 | * Never autogenerate a proxy and rely that it was generated by some | ||
56 | * process before deployment. | ||
57 | */ | ||
58 | public const AUTOGENERATE_NEVER = 0; | ||
59 | |||
60 | /** | ||
61 | * Always generates a new proxy in every request. | ||
62 | * | ||
63 | * This is only sane during development. | ||
64 | */ | ||
65 | public const AUTOGENERATE_ALWAYS = 1; | ||
66 | |||
67 | /** | ||
68 | * Autogenerate the proxy class when the proxy file does not exist. | ||
69 | * | ||
70 | * This strategy causes a file_exists() call whenever any proxy is used the | ||
71 | * first time in a request. | ||
72 | */ | ||
73 | public const AUTOGENERATE_FILE_NOT_EXISTS = 2; | ||
74 | |||
75 | /** | ||
76 | * Generate the proxy classes using eval(). | ||
77 | * | ||
78 | * This strategy is only sane for development, and even then it gives me | ||
79 | * the creeps a little. | ||
80 | */ | ||
81 | public const AUTOGENERATE_EVAL = 3; | ||
82 | |||
83 | /** | ||
84 | * Autogenerate the proxy class when the proxy file does not exist or | ||
85 | * when the proxied file changed. | ||
86 | * | ||
87 | * This strategy causes a file_exists() call whenever any proxy is used the | ||
88 | * first time in a request. When the proxied file is changed, the proxy will | ||
89 | * be updated. | ||
90 | */ | ||
91 | public const AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED = 4; | ||
92 | |||
93 | private const PROXY_CLASS_TEMPLATE = <<<'EOPHP' | ||
94 | <?php | ||
95 | |||
96 | namespace <namespace>; | ||
97 | |||
98 | /** | ||
99 | * DO NOT EDIT THIS FILE - IT WAS CREATED BY DOCTRINE'S PROXY GENERATOR | ||
100 | */ | ||
101 | class <proxyShortClassName> extends \<className> implements \<baseProxyInterface> | ||
102 | { | ||
103 | <useLazyGhostTrait> | ||
104 | |||
105 | public function __isInitialized(): bool | ||
106 | { | ||
107 | return isset($this->lazyObjectState) && $this->isLazyObjectInitialized(); | ||
108 | } | ||
109 | |||
110 | public function __serialize(): array | ||
111 | { | ||
112 | <serializeImpl> | ||
113 | } | ||
114 | } | ||
115 | |||
116 | EOPHP; | ||
117 | |||
118 | /** The UnitOfWork this factory uses to retrieve persisters */ | ||
119 | private readonly UnitOfWork $uow; | ||
120 | |||
121 | /** @var self::AUTOGENERATE_* */ | ||
122 | private $autoGenerate; | ||
123 | |||
124 | /** The IdentifierFlattener used for manipulating identifiers */ | ||
125 | private readonly IdentifierFlattener $identifierFlattener; | ||
126 | |||
127 | /** @var array<class-string, Closure> */ | ||
128 | private array $proxyFactories = []; | ||
129 | |||
130 | /** | ||
131 | * Initializes a new instance of the <tt>ProxyFactory</tt> class that is | ||
132 | * connected to the given <tt>EntityManager</tt>. | ||
133 | * | ||
134 | * @param EntityManagerInterface $em The EntityManager the new factory works for. | ||
135 | * @param string $proxyDir The directory to use for the proxy classes. It must exist. | ||
136 | * @param string $proxyNs The namespace to use for the proxy classes. | ||
137 | * @param bool|self::AUTOGENERATE_* $autoGenerate The strategy for automatically generating proxy classes. | ||
138 | */ | ||
139 | public function __construct( | ||
140 | private readonly EntityManagerInterface $em, | ||
141 | private readonly string $proxyDir, | ||
142 | private readonly string $proxyNs, | ||
143 | bool|int $autoGenerate = self::AUTOGENERATE_NEVER, | ||
144 | ) { | ||
145 | if (! $proxyDir) { | ||
146 | throw ORMInvalidArgumentException::proxyDirectoryRequired(); | ||
147 | } | ||
148 | |||
149 | if (! $proxyNs) { | ||
150 | throw ORMInvalidArgumentException::proxyNamespaceRequired(); | ||
151 | } | ||
152 | |||
153 | if (is_int($autoGenerate) ? $autoGenerate < 0 || $autoGenerate > 4 : ! is_bool($autoGenerate)) { | ||
154 | throw ORMInvalidArgumentException::invalidAutoGenerateMode($autoGenerate); | ||
155 | } | ||
156 | |||
157 | $this->uow = $em->getUnitOfWork(); | ||
158 | $this->autoGenerate = (int) $autoGenerate; | ||
159 | $this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory()); | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * @param class-string $className | ||
164 | * @param array<mixed> $identifier | ||
165 | */ | ||
166 | public function getProxy(string $className, array $identifier): InternalProxy | ||
167 | { | ||
168 | $proxyFactory = $this->proxyFactories[$className] ?? $this->getProxyFactory($className); | ||
169 | |||
170 | return $proxyFactory($identifier); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * Generates proxy classes for all given classes. | ||
175 | * | ||
176 | * @param ClassMetadata[] $classes The classes (ClassMetadata instances) for which to generate proxies. | ||
177 | * @param string|null $proxyDir The target directory of the proxy classes. If not specified, the | ||
178 | * directory configured on the Configuration of the EntityManager used | ||
179 | * by this factory is used. | ||
180 | * | ||
181 | * @return int Number of generated proxies. | ||
182 | */ | ||
183 | public function generateProxyClasses(array $classes, string|null $proxyDir = null): int | ||
184 | { | ||
185 | $generated = 0; | ||
186 | |||
187 | foreach ($classes as $class) { | ||
188 | if ($this->skipClass($class)) { | ||
189 | continue; | ||
190 | } | ||
191 | |||
192 | $proxyFileName = $this->getProxyFileName($class->getName(), $proxyDir ?: $this->proxyDir); | ||
193 | $proxyClassName = self::generateProxyClassName($class->getName(), $this->proxyNs); | ||
194 | |||
195 | $this->generateProxyClass($class, $proxyFileName, $proxyClassName); | ||
196 | |||
197 | ++$generated; | ||
198 | } | ||
199 | |||
200 | return $generated; | ||
201 | } | ||
202 | |||
203 | protected function skipClass(ClassMetadata $metadata): bool | ||
204 | { | ||
205 | return $metadata->isMappedSuperclass | ||
206 | || $metadata->isEmbeddedClass | ||
207 | || $metadata->getReflectionClass()->isAbstract(); | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * Creates a closure capable of initializing a proxy | ||
212 | * | ||
213 | * @return Closure(InternalProxy, array):void | ||
214 | * | ||
215 | * @throws EntityNotFoundException | ||
216 | */ | ||
217 | private function createLazyInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister, IdentifierFlattener $identifierFlattener): Closure | ||
218 | { | ||
219 | return static function (InternalProxy $proxy, array $identifier) use ($entityPersister, $classMetadata, $identifierFlattener): void { | ||
220 | $original = $entityPersister->loadById($identifier); | ||
221 | |||
222 | if ($original === null) { | ||
223 | throw EntityNotFoundException::fromClassNameAndIdentifier( | ||
224 | $classMetadata->getName(), | ||
225 | $identifierFlattener->flattenIdentifier($classMetadata, $identifier), | ||
226 | ); | ||
227 | } | ||
228 | |||
229 | if ($proxy === $original) { | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | $class = $entityPersister->getClassMetadata(); | ||
234 | |||
235 | foreach ($class->getReflectionProperties() as $property) { | ||
236 | if (! $property || isset($identifier[$property->getName()]) || ! $class->hasField($property->getName()) && ! $class->hasAssociation($property->getName())) { | ||
237 | continue; | ||
238 | } | ||
239 | |||
240 | $property->setValue($proxy, $property->getValue($original)); | ||
241 | } | ||
242 | }; | ||
243 | } | ||
244 | |||
245 | private function getProxyFileName(string $className, string $baseDirectory): string | ||
246 | { | ||
247 | $baseDirectory = $baseDirectory ?: $this->proxyDir; | ||
248 | |||
249 | return rtrim($baseDirectory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . InternalProxy::MARKER | ||
250 | . str_replace('\\', '', $className) . '.php'; | ||
251 | } | ||
252 | |||
253 | private function getProxyFactory(string $className): Closure | ||
254 | { | ||
255 | $skippedProperties = []; | ||
256 | $class = $this->em->getClassMetadata($className); | ||
257 | $identifiers = array_flip($class->getIdentifierFieldNames()); | ||
258 | $filter = ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED | ReflectionProperty::IS_PRIVATE; | ||
259 | $reflector = $class->getReflectionClass(); | ||
260 | |||
261 | while ($reflector) { | ||
262 | foreach ($reflector->getProperties($filter) as $property) { | ||
263 | $name = $property->name; | ||
264 | |||
265 | if ($property->isStatic() || (($class->hasField($name) || $class->hasAssociation($name)) && ! isset($identifiers[$name]))) { | ||
266 | continue; | ||
267 | } | ||
268 | |||
269 | $prefix = $property->isPrivate() ? "\0" . $property->class . "\0" : ($property->isProtected() ? "\0*\0" : ''); | ||
270 | |||
271 | $skippedProperties[$prefix . $name] = true; | ||
272 | } | ||
273 | |||
274 | $filter = ReflectionProperty::IS_PRIVATE; | ||
275 | $reflector = $reflector->getParentClass(); | ||
276 | } | ||
277 | |||
278 | $className = $class->getName(); // aliases and case sensitivity | ||
279 | $entityPersister = $this->uow->getEntityPersister($className); | ||
280 | $initializer = $this->createLazyInitializer($class, $entityPersister, $this->identifierFlattener); | ||
281 | $proxyClassName = $this->loadProxyClass($class); | ||
282 | $identifierFields = array_intersect_key($class->getReflectionProperties(), $identifiers); | ||
283 | |||
284 | $proxyFactory = Closure::bind(static function (array $identifier) use ($initializer, $skippedProperties, $identifierFields, $className): InternalProxy { | ||
285 | $proxy = self::createLazyGhost(static function (InternalProxy $object) use ($initializer, $identifier): void { | ||
286 | $initializer($object, $identifier); | ||
287 | }, $skippedProperties); | ||
288 | |||
289 | foreach ($identifierFields as $idField => $reflector) { | ||
290 | if (! isset($identifier[$idField])) { | ||
291 | throw ORMInvalidArgumentException::missingPrimaryKeyValue($className, $idField); | ||
292 | } | ||
293 | |||
294 | assert($reflector !== null); | ||
295 | $reflector->setValue($proxy, $identifier[$idField]); | ||
296 | } | ||
297 | |||
298 | return $proxy; | ||
299 | }, null, $proxyClassName); | ||
300 | |||
301 | return $this->proxyFactories[$className] = $proxyFactory; | ||
302 | } | ||
303 | |||
304 | private function loadProxyClass(ClassMetadata $class): string | ||
305 | { | ||
306 | $proxyClassName = self::generateProxyClassName($class->getName(), $this->proxyNs); | ||
307 | |||
308 | if (class_exists($proxyClassName, false)) { | ||
309 | return $proxyClassName; | ||
310 | } | ||
311 | |||
312 | if ($this->autoGenerate === self::AUTOGENERATE_EVAL) { | ||
313 | $this->generateProxyClass($class, null, $proxyClassName); | ||
314 | |||
315 | return $proxyClassName; | ||
316 | } | ||
317 | |||
318 | $fileName = $this->getProxyFileName($class->getName(), $this->proxyDir); | ||
319 | |||
320 | switch ($this->autoGenerate) { | ||
321 | case self::AUTOGENERATE_FILE_NOT_EXISTS_OR_CHANGED: | ||
322 | if (file_exists($fileName) && filemtime($fileName) >= filemtime($class->getReflectionClass()->getFileName())) { | ||
323 | break; | ||
324 | } | ||
325 | // no break | ||
326 | case self::AUTOGENERATE_FILE_NOT_EXISTS: | ||
327 | if (file_exists($fileName)) { | ||
328 | break; | ||
329 | } | ||
330 | // no break | ||
331 | case self::AUTOGENERATE_ALWAYS: | ||
332 | $this->generateProxyClass($class, $fileName, $proxyClassName); | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | require $fileName; | ||
337 | |||
338 | return $proxyClassName; | ||
339 | } | ||
340 | |||
341 | private function generateProxyClass(ClassMetadata $class, string|null $fileName, string $proxyClassName): void | ||
342 | { | ||
343 | $i = strrpos($proxyClassName, '\\'); | ||
344 | $placeholders = [ | ||
345 | '<className>' => $class->getName(), | ||
346 | '<namespace>' => substr($proxyClassName, 0, $i), | ||
347 | '<proxyShortClassName>' => substr($proxyClassName, 1 + $i), | ||
348 | '<baseProxyInterface>' => InternalProxy::class, | ||
349 | ]; | ||
350 | |||
351 | preg_match_all('(<([a-zA-Z]+)>)', self::PROXY_CLASS_TEMPLATE, $placeholderMatches); | ||
352 | |||
353 | foreach (array_combine($placeholderMatches[0], $placeholderMatches[1]) as $placeholder => $name) { | ||
354 | $placeholders[$placeholder] ?? $placeholders[$placeholder] = $this->{'generate' . ucfirst($name)}($class); | ||
355 | } | ||
356 | |||
357 | $proxyCode = strtr(self::PROXY_CLASS_TEMPLATE, $placeholders); | ||
358 | |||
359 | if (! $fileName) { | ||
360 | if (! class_exists($proxyClassName)) { | ||
361 | eval(substr($proxyCode, 5)); | ||
362 | } | ||
363 | |||
364 | return; | ||
365 | } | ||
366 | |||
367 | $parentDirectory = dirname($fileName); | ||
368 | |||
369 | if (! is_dir($parentDirectory) && ! @mkdir($parentDirectory, 0775, true)) { | ||
370 | throw ORMInvalidArgumentException::proxyDirectoryNotWritable($this->proxyDir); | ||
371 | } | ||
372 | |||
373 | if (! is_writable($parentDirectory)) { | ||
374 | throw ORMInvalidArgumentException::proxyDirectoryNotWritable($this->proxyDir); | ||
375 | } | ||
376 | |||
377 | $tmpFileName = $fileName . '.' . bin2hex(random_bytes(12)); | ||
378 | |||
379 | file_put_contents($tmpFileName, $proxyCode); | ||
380 | @chmod($tmpFileName, 0664); | ||
381 | rename($tmpFileName, $fileName); | ||
382 | } | ||
383 | |||
384 | private function generateUseLazyGhostTrait(ClassMetadata $class): string | ||
385 | { | ||
386 | $code = ProxyHelper::generateLazyGhost($class->getReflectionClass()); | ||
387 | $code = substr($code, 7 + (int) strpos($code, "\n{")); | ||
388 | $code = substr($code, 0, (int) strpos($code, "\n}")); | ||
389 | $code = str_replace('LazyGhostTrait;', str_replace("\n ", "\n", 'LazyGhostTrait { | ||
390 | initializeLazyObject as private; | ||
391 | setLazyObjectAsInitialized as public __setInitialized; | ||
392 | isLazyObjectInitialized as private; | ||
393 | createLazyGhost as private; | ||
394 | resetLazyObject as private; | ||
395 | } | ||
396 | |||
397 | public function __load(): void | ||
398 | { | ||
399 | $this->initializeLazyObject(); | ||
400 | } | ||
401 | '), $code); | ||
402 | |||
403 | return $code; | ||
404 | } | ||
405 | |||
406 | private function generateSerializeImpl(ClassMetadata $class): string | ||
407 | { | ||
408 | $reflector = $class->getReflectionClass(); | ||
409 | $properties = $reflector->hasMethod('__serialize') ? 'parent::__serialize()' : '(array) $this'; | ||
410 | |||
411 | $code = '$properties = ' . $properties . '; | ||
412 | unset($properties["\0" . self::class . "\0lazyObjectState"]); | ||
413 | |||
414 | '; | ||
415 | |||
416 | if ($reflector->hasMethod('__serialize') || ! $reflector->hasMethod('__sleep')) { | ||
417 | return $code . 'return $properties;'; | ||
418 | } | ||
419 | |||
420 | return $code . '$data = []; | ||
421 | |||
422 | foreach (parent::__sleep() as $name) { | ||
423 | $value = $properties[$k = $name] ?? $properties[$k = "\0*\0$name"] ?? $properties[$k = "\0' . $reflector->name . '\0$name"] ?? $k = null; | ||
424 | |||
425 | if (null === $k) { | ||
426 | trigger_error(sprintf(\'serialize(): "%s" returned as member variable from __sleep() but does not exist\', $name), \E_USER_NOTICE); | ||
427 | } else { | ||
428 | $data[$k] = $value; | ||
429 | } | ||
430 | } | ||
431 | |||
432 | return $data;'; | ||
433 | } | ||
434 | |||
435 | private static function generateProxyClassName(string $className, string $proxyNamespace): string | ||
436 | { | ||
437 | return rtrim($proxyNamespace, '\\') . '\\' . Proxy::MARKER . '\\' . ltrim($className, '\\'); | ||
438 | } | ||
439 | } | ||