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.
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>.
20
namespace Doctrine\Common\Proxy;
22
use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory;
23
use Doctrine\Common\Proxy\Exception\InvalidArgumentException;
24
use Doctrine\Common\Proxy\Exception\OutOfBoundsException;
25
use Doctrine\Common\Util\ClassUtils;
26
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
29
* Abstract factory for proxy objects.
31
* @author Benjamin Eberlei <kontakt@beberlei.de>
33
abstract class AbstractProxyFactory
36
* Never autogenerate a proxy and rely that it was generated by some
37
* process before deployment.
41
const AUTOGENERATE_NEVER = 0;
44
* Always generates a new proxy in every request.
46
* This is only sane during development.
50
const AUTOGENERATE_ALWAYS = 1;
53
* Autogenerate the proxy class when the proxy file does not exist.
55
* This strategy causes a file exists call whenever any proxy is used the
56
* first time in a request.
60
const AUTOGENERATE_FILE_NOT_EXISTS = 2;
63
* Generate the proxy classes using eval().
65
* This strategy is only sane for development, and even then it gives me
66
* the creeps a little.
70
const AUTOGENERATE_EVAL = 3;
73
* @var \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory
75
private $metadataFactory;
78
* @var \Doctrine\Common\Proxy\ProxyGenerator the proxy generator responsible for creating the proxy classes/files.
80
private $proxyGenerator;
83
* @var bool Whether to automatically (re)generate proxy classes.
85
private $autoGenerate;
88
* @var \Doctrine\Common\Proxy\ProxyDefinition[]
90
private $definitions = array();
93
* @param \Doctrine\Common\Proxy\ProxyGenerator $proxyGenerator
94
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadataFactory $metadataFactory
95
* @param bool|int $autoGenerate
97
public function __construct(ProxyGenerator $proxyGenerator, ClassMetadataFactory $metadataFactory, $autoGenerate)
99
$this->proxyGenerator = $proxyGenerator;
100
$this->metadataFactory = $metadataFactory;
101
$this->autoGenerate = (int)$autoGenerate;
105
* Gets a reference proxy instance for the entity of the given type and identified by
106
* the given identifier.
108
* @param string $className
109
* @param array $identifier
111
* @return \Doctrine\Common\Proxy\Proxy
113
* @throws \Doctrine\Common\Proxy\Exception\OutOfBoundsException
115
public function getProxy($className, array $identifier)
117
$definition = isset($this->definitions[$className])
118
? $this->definitions[$className]
119
: $this->getProxyDefinition($className);
120
$fqcn = $definition->proxyClassName;
121
$proxy = new $fqcn($definition->initializer, $definition->cloner);
123
foreach ($definition->identifierFields as $idField) {
124
if (! isset($identifier[$idField])) {
125
throw OutOfBoundsException::missingPrimaryKeyValue($className, $idField);
128
$definition->reflectionFields[$idField]->setValue($proxy, $identifier[$idField]);
135
* Generates proxy classes for all given classes.
137
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata[] $classes The classes (ClassMetadata instances)
138
* for which to generate proxies.
139
* @param string $proxyDir The target directory of the proxy classes. If not specified, the
140
* directory configured on the Configuration of the EntityManager used
141
* by this factory is used.
142
* @return int Number of generated proxies.
144
public function generateProxyClasses(array $classes, $proxyDir = null)
148
foreach ($classes as $class) {
149
if ($this->skipClass($class)) {
153
$proxyFileName = $this->proxyGenerator->getProxyFileName($class->getName(), $proxyDir);
155
$this->proxyGenerator->generateProxyClass($class, $proxyFileName);
164
* Reset initialization/cloning logic for an un-initialized proxy
166
* @param \Doctrine\Common\Proxy\Proxy $proxy
168
* @return \Doctrine\Common\Proxy\Proxy
170
* @throws \Doctrine\Common\Proxy\Exception\InvalidArgumentException
172
public function resetUninitializedProxy(Proxy $proxy)
174
if ($proxy->__isInitialized()) {
175
throw InvalidArgumentException::unitializedProxyExpected($proxy);
178
$className = ClassUtils::getClass($proxy);
179
$definition = isset($this->definitions[$className])
180
? $this->definitions[$className]
181
: $this->getProxyDefinition($className);
183
$proxy->__setInitializer($definition->initializer);
184
$proxy->__setCloner($definition->cloner);
190
* Get a proxy definition for the given class name.
192
* @return ProxyDefinition
194
private function getProxyDefinition($className)
196
$classMetadata = $this->metadataFactory->getMetadataFor($className);
197
$className = $classMetadata->getName(); // aliases and case sensitivity
199
$this->definitions[$className] = $this->createProxyDefinition($className);
200
$proxyClassName = $this->definitions[$className]->proxyClassName;
202
if ( ! class_exists($proxyClassName, false)) {
203
$fileName = $this->proxyGenerator->getProxyFileName($className);
205
switch ($this->autoGenerate) {
206
case self::AUTOGENERATE_NEVER:
210
case self::AUTOGENERATE_FILE_NOT_EXISTS:
211
if ( ! file_exists($fileName)) {
212
$this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
217
case self::AUTOGENERATE_ALWAYS:
218
$this->proxyGenerator->generateProxyClass($classMetadata, $fileName);
222
case self::AUTOGENERATE_EVAL:
223
$this->proxyGenerator->generateProxyClass($classMetadata, false);
228
return $this->definitions[$className];
232
* Determine if this class should be skipped during proxy generation.
234
* @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $metadata
237
abstract protected function skipClass(ClassMetadata $metadata);
240
* @return ProxyDefinition
242
abstract protected function createProxyDefinition($className);