AbstractProxyFactory.php 7.8 KB

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