AbstractProxyFactory.php 7.8 KB

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