Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[Common 2.4+] DCOM-96 compliance as of doctrine/common#168 #506

Closed
wants to merge 1 commit into from

3 participants

@Ocramius
Owner

Followup for #445 (branch was messed up) (needs "doctrine/common": "2.4" to work, so the build won't pass for now)

lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php
((17 lines not shown))
*
- * @param object $document
- * @return array
+ * Since MongoDB only allows exactly one identifier field this returns an array with the identifier field as a key.
@jmikola Owner
jmikola added a note

Should this be line-wrapped like previous documentation?

@Ocramius Owner
Ocramius added a note

@jmikola not sure what you mean here

@jmikola Owner
jmikola added a note

Document lines tend to get wrapped for an 80-character column size.

@Ocramius Owner
Ocramius added a note

@jmikola ah, I see :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@jmikola
Owner

@Ocramius: I updated to doctrine/common 2.4 in master. Can you rebase this?

Feel free to ignore all of the docblock changes (ClassMetadataInfo had many of them). I prefer not to use {@inheritDoc} to pull in interface documentation, since it's ambiguous.

@jwage
Owner

@Ocramius can you rebase this?

@jmikola
Owner

@jwage: I talked about it with him in IRC some weeks ago and I believe the conclusion was that it'd probably be better off redone from scratch.

@Ocramius
Owner

This was already merged/handled as it seems. GIT is only very very (VERY) confused about the diffs for some reason.

@Ocramius Ocramius closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 4, 2013
  1. @Ocramius
This page is out of date. Refresh to see the latest.
View
2  composer.json
@@ -14,7 +14,7 @@
"require": {
"php": ">=5.3.2",
"symfony/console": ">=2.0-dev,<2.3-dev",
- "doctrine/common": ">=2.2.0,<2.5-dev",
+ "doctrine/common": ">=2.4,<2.5-dev",
"doctrine/mongodb": "1.0.*"
},
"require-dev": {
View
5 lib/Doctrine/ODM/MongoDB/DocumentManager.php
@@ -185,7 +185,7 @@ protected function __construct(Connection $conn = null, Configuration $config =
/**
* Gets the proxy factory used by the DocumentManager to create document proxies.
*
- * @return ProxyFactory
+ * @return \Doctrine\ODM\MongoDB\Proxy\ProxyFactory
*/
public function getProxyFactory()
{
@@ -545,6 +545,7 @@ public function flush($document = null, array $options = array())
*/
public function getReference($documentName, $identifier)
{
+ /* @var $class \Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo */
$class = $this->metadataFactory->getMetadataFor($documentName);
// Check identity map first, if its already in there just return it.
@@ -552,7 +553,7 @@ public function getReference($documentName, $identifier)
return $document;
}
- $document = $this->proxyFactory->getProxy($class->name, $identifier);
+ $document = $this->proxyFactory->getProxy($class->name, array($class->identifier => $identifier));
$this->unitOfWork->registerManaged($document, $identifier, array());
return $document;
View
2  lib/Doctrine/ODM/MongoDB/DocumentNotFoundException.php
@@ -30,6 +30,8 @@ class DocumentNotFoundException extends MongoDBException
{
public static function documentNotFound($className, $identifier)
{
+ $identifier = is_array($identifier) ? reset($identifier) : $identifier;
+
return new self(sprintf('The "%s" document with identifier "%s" could not be found.', $className, $identifier));
}
}
View
2  lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadata.php
@@ -44,7 +44,7 @@ class ClassMetadata extends ClassMetadataInfo
/**
* The ReflectionProperty instances of the mapped class.
*
- * @var array
+ * @var \ReflectionProperty[]
*/
public $reflFields = array();
View
162 lib/Doctrine/ODM/MongoDB/Mapping/ClassMetadataInfo.php
@@ -22,7 +22,6 @@
use InvalidArgumentException;
use Doctrine\ODM\MongoDB\Mapping\MappingException;
use Doctrine\ODM\MongoDB\LockException;
-use Doctrine\ODM\MongoDB\Proxy\Proxy;
/**
* A <tt>ClassMetadata</tt> instance holds all the object-document mapping metadata
@@ -237,7 +236,7 @@ class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMet
/**
* The ReflectionProperty instances of the mapped class.
*
- * @var array
+ * @var \ReflectionProperty[]
*/
public $reflFields = array();
@@ -265,7 +264,7 @@ class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMet
/**
* READ-ONLY: The ID generator used for generating IDs for this class.
*
- * @var AbstractIdGenerator
+ * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator
*/
public $idGenerator;
@@ -392,7 +391,7 @@ class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMet
/**
* The ReflectionClass instance of the mapped class.
*
- * @var ReflectionClass
+ * @var \ReflectionClass
*/
public $reflClass;
@@ -409,28 +408,23 @@ public function __construct($documentName)
}
/**
- * Gets the ReflectionClass instance of the mapped class.
- *
- * @return ReflectionClass
+ * {@inheritDoc}
*/
public function getReflectionClass()
{
if ( ! $this->reflClass) {
$this->reflClass = new \ReflectionClass($this->name);
}
+
return $this->reflClass;
}
/**
- * Checks whether a field is part of the identifier/primary key field(s).
- *
- * @param string $fieldName The field name
- * @return boolean TRUE if the field is part of the table identifier/primary key field(s),
- * FALSE otherwise.
+ * {@inheritDoc}
*/
public function isIdentifier($fieldName)
{
- return $this->identifier === $fieldName ? true : false;
+ return $this->identifier === $fieldName;
}
/**
@@ -445,22 +439,21 @@ public function setIdentifier($identifier)
}
/**
- * Gets the mapped identifier field of this class.
+ * {@inheritDoc}
*
- * @return string $identifier
+ * Since MongoDB only allows exactly one identifier field
+ * this will always return an array with only one value
*/
public function getIdentifier()
{
- return $this->identifier;
+ return array($this->identifier);
}
/**
- * Get identifier field names of this class.
+ * {@inheritDoc}
*
- * Since MongoDB only allows exactly one identifier field this is a proxy
- * to {@see getIdentifier()} and returns an array.
- *
- * @return array
+ * Since MongoDB only allows exactly one identifier field
+ * this will always return an array with only one value
*/
public function getIdentifierFieldNames()
{
@@ -468,9 +461,7 @@ public function getIdentifierFieldNames()
}
/**
- * Checks whether the class has a (mapped) field with a certain name.
- *
- * @return boolean
+ * {@inheritDoc}
*/
public function hasField($fieldName)
{
@@ -490,6 +481,8 @@ public function setInheritanceType($type)
/**
* Checks whether a mapped field is inherited from an entity superclass.
*
+ * @param string $fieldName
+ *
* @return boolean TRUE if the field is inherited, FALSE otherwise.
*/
public function isInheritedField($fieldName)
@@ -500,7 +493,7 @@ public function isInheritedField($fieldName)
/**
* Registers a custom repository class for the document class.
*
- * @param string $mapperClassName The class name of the custom mapper.
+ * @param string $repositoryClassName The class name of the custom repository.
*/
public function setCustomRepositoryClass($repositoryClassName)
{
@@ -511,8 +504,9 @@ public function setCustomRepositoryClass($repositoryClassName)
* Dispatches the lifecycle event of the given document to the registered
* lifecycle callbacks and lifecycle listeners.
*
- * @param string $event The lifecycle event.
- * @param Document $document The Document on which the event occurred.
+ * @param string $lifecycleEvent The lifecycle event.
+ * @param object $document The document on which the event occurred.
+ * @param array $arguments Arguments to be passed to the callbacks
*/
public function invokeLifecycleCallbacks($lifecycleEvent, $document, array $arguments = null)
{
@@ -529,6 +523,7 @@ public function invokeLifecycleCallbacks($lifecycleEvent, $document, array $argu
* Whether the class has any attached lifecycle listeners or callbacks for a lifecycle event.
*
* @param string $lifecycleEvent
+ *
* @return boolean
*/
public function hasLifecycleCallbacks($lifecycleEvent)
@@ -576,7 +571,8 @@ public function setLifecycleCallbacks(array $callbacks)
* Sets the discriminator field name.
*
* @param string $discriminatorField
- * @see getDiscriminatorField()
+ *
+ * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException
*/
public function setDiscriminatorField($discriminatorField)
{
@@ -594,6 +590,8 @@ public function setDiscriminatorField($discriminatorField)
* Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
*
* @param array $map
+ *
+ * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException
*/
public function setDiscriminatorMap(array $map)
{
@@ -751,7 +749,8 @@ public function getReflectionProperties()
* Gets a ReflectionProperty for a specific field of the mapped class.
*
* @param string $name
- * @return ReflectionProperty
+ *
+ * @return \ReflectionProperty
*/
public function getReflectionProperty($name)
{
@@ -759,9 +758,7 @@ public function getReflectionProperty($name)
}
/**
- * The name of this Document class.
- *
- * @return string $name The Document class name.
+ * {@inheritDoc}
*/
public function getName()
{
@@ -811,7 +808,9 @@ public function getCollection()
/**
* Sets the collection this Document is mapped to.
*
- * @param string $collection The collection name.
+ * @param string $name
+ *
+ * @throws \InvalidArgumentException
*/
public function setCollection($name)
{
@@ -952,6 +951,10 @@ public function setDistance($distance)
* Map a field.
*
* @param array $mapping The mapping information.
+ *
+ * @return array
+ *
+ * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException
*/
public function mapField(array $mapping)
{
@@ -1147,7 +1150,7 @@ public function mapManyReference(array $mapping)
* Adds a field mapping without completing/validating it.
* This is mainly used to add inherited field mappings to derived classes.
*
- * @param array $mapping
+ * @param array $fieldMapping
*/
public function addInheritedFieldMapping(array $fieldMapping)
{
@@ -1177,10 +1180,9 @@ public function hasEmbed($fieldName)
}
/**
- * Checks whether the class has a mapped association (embed or reference) with the given field name.
+ * {@inheritDoc}
*
- * @param string $fieldName
- * @return boolean
+ * Checks whether the class has a mapped association (embed or reference) with the given field name.
*/
public function hasAssociation($fieldName)
{
@@ -1188,11 +1190,10 @@ public function hasAssociation($fieldName)
}
/**
+ * {@inheritDoc}
+ *
* Checks whether the class has a mapped reference or embed for the specified field and
* is a single valued association.
- *
- * @param string $fieldName
- * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
*/
public function isSingleValuedAssociation($fieldName)
{
@@ -1200,11 +1201,10 @@ public function isSingleValuedAssociation($fieldName)
}
/**
+ * {@inheritDoc}
+ *
* Checks whether the class has a mapped reference or embed for the specified field and
* is a collection valued association.
- *
- * @param string $fieldName
- * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
*/
public function isCollectionValuedAssociation($fieldName)
{
@@ -1266,7 +1266,7 @@ public function isCollectionValuedEmbed($fieldName)
/**
* Sets the ID generator used to generate IDs for instances of this class.
*
- * @param AbstractIdGenerator $generator
+ * @param \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator $generator
*/
public function setIdGenerator($generator)
{
@@ -1317,32 +1317,26 @@ public function setIdentifierValue($document, $id)
*/
public function getIdentifierValue($document)
{
- if ($document instanceof Proxy && !$document->__isInitialized()) {
- return $document->__identifier__;
- }
return $this->reflFields[$this->identifier]->getValue($document);
}
/**
- * Get identifier values of this document.
- *
- * Since MongoDB only allows exactly one identifier field this is a proxy
- * to {@see getIdentifierValue()} and returns an array with the identifier
- * field as a key.
+ * {@inheritDoc}
*
- * @param object $document
- * @return array
+ * Since MongoDB only allows exactly one identifier field this returns an array
+ * with the identifier field as a key.
*/
- public function getIdentifierValues($document)
+ public function getIdentifierValues($object)
{
- return array($this->identifier => $this->getIdentifierValue($document));
+ return array($this->identifier => $this->getIdentifierValue($object));
}
/**
* Get the document identifier object.
*
* @param string $document
- * @return MongoId $id The MongoID object.
+ *
+ * @return \MongoId $id The MongoID object.
*/
public function getIdentifierObject($document)
{
@@ -1371,9 +1365,6 @@ public function setFieldValue($document, $field, $value)
*/
public function getFieldValue($document, $field)
{
- if ($document instanceof Proxy && $field === $this->identifier && !$document->__isInitialized()) {
- return $document->__identifier__;
- }
return $this->reflFields[$field]->getValue($document);
}
@@ -1381,7 +1372,10 @@ public function getFieldValue($document, $field)
* Gets the mapping of a field.
*
* @param string $fieldName The field name.
+ *
* @return array The field mapping.
+ *
+ * @throws MappingException
*/
public function getFieldMapping($fieldName)
{
@@ -1395,6 +1389,7 @@ public function getFieldMapping($fieldName)
* Check if the field is not null.
*
* @param string $fieldName The field name
+ *
* @return boolean TRUE if the field is not null, FALSE otherwise.
*/
public function isNullable($fieldName)
@@ -1443,8 +1438,7 @@ public function isInheritanceTypeNone()
/**
* Checks whether the mapped class uses the SINGLE_COLLECTION inheritance mapping strategy.
*
- * @return boolean TRUE if the class participates in a SINGLE_COLLECTION inheritance mapping,
- * FALSE otherwise.
+ * @return boolean
*/
public function isInheritanceTypeSingleCollection()
{
@@ -1454,8 +1448,7 @@ public function isInheritanceTypeSingleCollection()
/**
* Checks whether the mapped class uses the COLLECTION_PER_CLASS inheritance mapping strategy.
*
- * @return boolean TRUE if the class participates in a COLLECTION_PER_CLASS inheritance mapping,
- * FALSE otherwise.
+ * @return boolean
*/
public function isInheritanceTypeCollectionPerClass()
{
@@ -1465,7 +1458,7 @@ public function isInheritanceTypeCollectionPerClass()
/**
* Sets the mapped subclasses of this class.
*
- * @param array $subclasses The names of all mapped subclasses.
+ * @param string[] $subclasses The names of all mapped subclasses.
*/
public function setSubclasses(array $subclasses)
{
@@ -1482,10 +1475,13 @@ public function setSubclasses(array $subclasses)
* Sets the parent class names.
* Assumes that the class names in the passed array are in the order:
* directParent -> directParentParent -> directParentParentParent ... -> root.
+ *
+ * @param string[] $classNames
*/
public function setParentClasses(array $classNames)
{
$this->parentClasses = $classNames;
+
if (count($classNames) > 0) {
$this->rootDocumentName = array_pop($classNames);
}
@@ -1536,13 +1532,16 @@ public function isIdGeneratorNone()
* value to use depending on the column type.
*
* @param array $mapping The version field mapping array
+ *
+ * @throws \Doctrine\ODM\MongoDB\LockException
*/
public function setVersionMapping(array &$mapping)
{
if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') {
throw LockException::invalidVersionFieldType($mapping['type']);
}
- $this->isVersioned = true;
+
+ $this->isVersioned = true;
$this->versionField = $mapping['fieldName'];
}
@@ -1572,12 +1571,15 @@ public function setVersionField($versionField)
* value to use depending on the column type.
*
* @param array $mapping The version field mapping array
+ *
+ * @throws \Doctrine\ODM\MongoDB\LockException
*/
public function setLockMapping(array &$mapping)
{
if ($mapping['type'] !== 'int') {
throw LockException::invalidLockFieldType($mapping['type']);
}
+
$this->isLockable = true;
$this->lockField = $mapping['fieldName'];
}
@@ -1604,11 +1606,7 @@ public function setLockField($lockField)
}
/**
- * A numerically indexed list of field names of this persistent class.
- *
- * This array includes identifier fields if present on this class.
- *
- * @return array
+ * {@inheritDoc}
*/
public function getFieldNames()
{
@@ -1616,11 +1614,7 @@ public function getFieldNames()
}
/**
- * A numerically indexed list of association names of this persistent class.
- *
- * This array includes identifier associations if present on this class.
- *
- * @return array
+ * {@inheritDoc}
*/
public function getAssociationNames()
{
@@ -1628,10 +1622,7 @@ public function getAssociationNames()
}
/**
- * Gets the type of a field.
- *
- * @param string $fieldName
- * @return Doctrine\DBAL\Types\Type
+ * {@inheritDoc}
*/
public function getTypeOfField($fieldName)
{
@@ -1640,10 +1631,7 @@ public function getTypeOfField($fieldName)
}
/**
- * Returns the target class name of the given association.
- *
- * @param string $assocName
- * @return string
+ * {@inheritDoc}
*/
public function getAssociationTargetClass($assocName)
{
@@ -1655,8 +1643,7 @@ public function getAssociationTargetClass($assocName)
}
/**
- * @param string $fieldName
- * @return bool
+ * {@inheritDoc}
*/
public function isAssociationInverseSide($fieldName)
{
@@ -1664,8 +1651,7 @@ public function isAssociationInverseSide($fieldName)
}
/**
- * @param string $fieldName
- * @return string
+ * {@inheritDoc}
*/
public function getAssociationMappedByTargetField($fieldName)
{
View
2  lib/Doctrine/ODM/MongoDB/Persisters/DocumentPersister.php
@@ -172,7 +172,7 @@ public function addInsert($document)
/**
* Gets the ClassMetadata instance of the document class this persister is used for.
*
- * @return Doctrine\ODM\MongoDB\Mapping\ClassMetadata
+ * @return \Doctrine\ODM\MongoDB\Mapping\ClassMetadata
*/
public function getClassMetadata()
{
View
2  lib/Doctrine/ODM/MongoDB/Proxy/Proxy.php
@@ -19,7 +19,7 @@
namespace Doctrine\ODM\MongoDB\Proxy;
-use Doctrine\Common\Persistence\Proxy as BaseProxy;
+use Doctrine\Common\Proxy\Proxy as BaseProxy;
/**
* Document Proxy interface.
View
49 lib/Doctrine/ODM/MongoDB/Proxy/ProxyException.php
@@ -1,49 +0,0 @@
-<?php
-/*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This software consists of voluntary contributions made by many individuals
- * and is licensed under the MIT license. For more information, see
- * <http://www.doctrine-project.org>.
- */
-
-namespace Doctrine\ODM\MongoDB\Proxy;
-
-use Doctrine\ODM\MongoDB\MongoDBException;
-
-/**
- * MongoDB ODM Proxy Exception
- *
- * @since 1.0
- * @author Benjamin Eberlei <kontakt@beberlei.de>
- * @author Jonathan H. Wage <jonwage@gmail.com>
- * @author Roman Borschel <roman@code-factory.org>
- * @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
- */
-class ProxyException extends MongoDBException
-{
- public static function proxyDirectoryRequired()
- {
- return new self("You must configure a proxy directory. See docs for details");
- }
-
- public static function proxyDirectoryNotWritable()
- {
- return new self("Your proxy directory must be writable.");
- }
-
- public static function proxyNamespaceRequired()
- {
- return new self("You must configure a proxy namespace. See docs for details");
- }
-}
View
444 lib/Doctrine/ODM/MongoDB/Proxy/ProxyFactory.php
@@ -19,8 +19,17 @@
namespace Doctrine\ODM\MongoDB\Proxy;
+use Doctrine\Common\Proxy\AbstractProxyFactory;
+use Doctrine\Common\Proxy\ProxyDefinition;
use Doctrine\ODM\MongoDB\DocumentManager;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
+use Doctrine\ODM\MongoDB\DocumentNotFoundException;
+use Doctrine\Common\Proxy\ProxyGenerator;
+use Doctrine\Common\Util\ClassUtils;
+use Doctrine\Common\Proxy\Proxy as BaseProxy;
+use Doctrine\Common\Persistence\Mapping\ClassMetadata as BaseClassMetadata;
+use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
+use ReflectionProperty;
/**
* This factory is used to create proxy objects for documents at runtime.
@@ -29,384 +38,185 @@
* @author Jonathan H. Wage <jonwage@gmail.com>
* @author Roman Borschel <roman@code-factory.org>
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
+ * @author Marco Pivetta <ocramius@gmail.com>
*/
-class ProxyFactory
+class ProxyFactory extends AbstractProxyFactory
{
/**
- * Marker for Proxy class names.
- *
- * @var string
+ * @var \Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory
*/
- const MARKER = '__CG__';
-
- /** The DocumentManager this factory is bound to. */
- private $dm;
- /** Whether to automatically (re)generate proxy classes. */
- private $autoGenerate;
- /** The namespace that contains all proxy classes. */
- private $proxyNamespace;
- /** The directory that contains all proxy classes. */
- private $proxyDir;
+ private $metadataFactory;
/**
- * Used to match very simple id methods that don't need
- * to be proxied since the identifier is known.
- *
- * @var string
+ * @var \Doctrine\ODM\MongoDB\UnitOfWork The UnitOfWork this factory is bound to.
*/
- const PATTERN_MATCH_ID_METHOD = '((public\s)?(function\s{1,}%s\s?\(\)\s{1,})\s{0,}{\s{0,}return\s{0,}\$this->%s;\s{0,}})i';
+ private $uow;
/**
- * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
- * connected to the given <tt>DocumentManager</tt>.
- *
- * @param DocumentManager $dm The DocumentManager the new factory works for.
- * @param string $proxyDir The directory to use for the proxy classes. It must exist.
- * @param string $proxyNs The namespace to use for the proxy classes.
- * @param boolean $autoGenerate Whether to automatically generate proxy classes.
+ * @var string The namespace that contains all proxy classes.
*/
- public function __construct(DocumentManager $dm, $proxyDir, $proxyNs, $autoGenerate = false)
- {
- if ( ! $proxyDir) {
- throw ProxyException::proxyDirectoryRequired();
- }
- if ( ! $proxyNs) {
- throw ProxyException::proxyNamespaceRequired();
- }
- $this->dm = $dm;
- $this->proxyDir = $proxyDir;
- $this->autoGenerate = $autoGenerate;
- $this->proxyNamespace = $proxyNs;
- }
+ private $proxyNamespace;
/**
- * Gets a reference proxy instance for the document of the given type and identified by
- * the given identifier.
+ * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
+ * connected to the given <tt>DocumentManager</tt>.
*
- * @param string $className
- * @param mixed $identifier
- * @return object
+ * @param \Doctrine\ODM\MongoDB\DocumentManager $documentManager The DocumentManager the new factory works for.
+ * @param string $proxyDir The directory to use for the proxy classes. It
+ * must exist.
+ * @param string $proxyNamespace The namespace to use for the proxy classes.
+ * @param boolean $autoGenerate Whether to automatically generate proxy classes.
*/
- public function getProxy($className, $identifier)
+ public function __construct(DocumentManager $documentManager, $proxyDir, $proxyNamespace, $autoGenerate = false)
{
- $fqn = self::generateProxyClassName($className, $this->proxyNamespace);
-
- if (! class_exists($fqn, false)) {
- $fileName = $this->getProxyFileName($className);
- if ($this->autoGenerate) {
- $this->generateProxyClass($this->dm->getClassMetadata($className), $fileName, self::$proxyClassTemplate);
- }
- require $fileName;
- }
-
- if ( ! $this->dm->getMetadataFactory()->hasMetadataFor($fqn)) {
- $this->dm->getMetadataFactory()->setMetadataFor($fqn, $this->dm->getClassMetadata($className));
- }
+ $this->metadataFactory = $documentManager->getMetadataFactory();
+ $this->uow = $documentManager->getUnitOfWork();
+ $this->proxyNamespace = $proxyNamespace;
+ $proxyGenerator = new ProxyGenerator($proxyDir, $proxyNamespace);
- $documentPersister = $this->dm->getUnitOfWork()->getDocumentPersister($className);
+ $proxyGenerator->setPlaceholder('baseProxyInterface', 'Doctrine\ODM\MongoDB\Proxy\Proxy');
- return new $fqn($documentPersister, $identifier);
+ parent::__construct($proxyGenerator, $this->metadataFactory, $autoGenerate);
}
/**
- * Generate the Proxy file name
- *
- * @param string $className
- * @return string
+ * {@inheritDoc}
*/
- private function getProxyFileName($className)
+ public function skipClass(BaseClassMetadata $class)
{
- return $this->proxyDir . DIRECTORY_SEPARATOR . '__CG__' . str_replace('\\', '', $className) . '.php';
+ /* @var $class \Doctrine\ODM\Mongodb\Mapping\ClassMetadataInfo */
+ return $class->isMappedSuperclass || $class->getReflectionClass()->isAbstract();
}
/**
- * Generates proxy classes for all given classes.
- *
- * @param array $classes The classes (ClassMetadata instances) for which to generate proxies.
- * @param string $toDir The target directory of the proxy classes. If not specified, the
- * directory configured on the Configuration of the DocumentManager used
- * by this factory is used.
+ * {@inheritDoc}
*/
- public function generateProxyClasses(array $classes, $toDir = null)
+ public function createProxyDefinition($className)
{
- $proxyDir = $toDir ?: $this->proxyDir;
- $proxyDir = rtrim($proxyDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
- foreach ($classes as $class) {
- /* @var $class ClassMetadata */
- if ($class->isMappedSuperclass) {
- continue;
- }
-
- $proxyFileName = $this->getProxyFileName($class->name);
- $this->generateProxyClass($class, $proxyFileName, self::$proxyClassTemplate);
- }
- }
-
- /**
- * Generates a proxy class file.
- *
- * @param $class
- * @param $proxyClassName
- * @param $file The path of the file to write to.
- */
- private function generateProxyClass($class, $fileName, $file)
- {
- $methods = $this->generateMethods($class);
- $sleepImpl = $this->generateSleep($class);
- $cloneImpl = $class->reflClass->hasMethod('__clone') ? 'parent::__clone();' : ''; // hasMethod() checks case-insensitive
-
- $placeholders = array(
- '<namespace>',
- '<proxyClassName>', '<className>',
- '<methods>', '<sleepImpl>', '<cloneImpl>'
+ /* @var $classMetadata \Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo */
+ $classMetadata = $this->metadataFactory->getMetadataFor($className);
+ $documentPersister = $this->uow->getDocumentPersister($className);
+ $reflectionId = $classMetadata->reflFields[$classMetadata->identifier];
+
+ return new ProxyDefinition(
+ ClassUtils::generateProxyClassName($className, $this->proxyNamespace),
+ $classMetadata->getIdentifierFieldNames(),
+ $classMetadata->getReflectionProperties(),
+ $this->createInitializer($classMetadata, $documentPersister, $reflectionId),
+ $this->createCloner($classMetadata, $documentPersister, $reflectionId)
);
-
- $className = ltrim($class->name, '\\');
- $proxyClassName = self::generateProxyClassName($class->name, $this->proxyNamespace);
- $parts = explode('\\', strrev($proxyClassName), 2);
- $proxyClassNamespace = strrev($parts[1]);
- $proxyClassName = strrev($parts[0]);
-
- $replacements = array(
- $proxyClassNamespace,
- $proxyClassName,
- $className,
- $methods,
- $sleepImpl,
- $cloneImpl
- );
-
- $file = str_replace($placeholders, $replacements, $file);
-
- $parentDirectory = dirname($fileName);
-
- if ( ! is_dir($parentDirectory)) {
- if (false === @mkdir($parentDirectory, 0775, true)) {
- throw ProxyException::proxyDirectoryNotWritable();
- }
- } else if ( ! is_writable($parentDirectory)) {
- throw ProxyException::proxyDirectoryNotWritable();
- }
-
- file_put_contents($fileName, $file, LOCK_EX);
}
/**
- * Generates the methods of a proxy class.
+ * Generates a closure capable of initializing a proxy
+ *
+ * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
+ * @param \Doctrine\ODM\MongoDB\Persisters\DocumentPersister $documentPersister
+ * @param \ReflectionProperty $reflectionId
*
- * @param ClassMetadata $class
- * @return string The code of the generated methods.
+ * @return \Closure
+ *
+ * @throws \Doctrine\ODM\MongoDB\DocumentNotFoundException
*/
- private function generateMethods(ClassMetadata $class)
- {
- $methods = '';
-
- $methodNames = array();
- foreach ($class->reflClass->getMethods() as $method) {
- /* @var $method ReflectionMethod */
- if ($method->isConstructor() || in_array(strtolower($method->getName()), array("__sleep", "__clone")) || isset($methodNames[$method->getName()])) {
- continue;
- }
- $methodNames[$method->getName()] = true;
-
- if ($method->isPublic() && ! $method->isFinal() && ! $method->isStatic()) {
- $methods .= "\n" . ' public function ';
- if ($method->returnsReference()) {
- $methods .= '&';
+ private function createInitializer(
+ BaseClassMetadata $classMetadata,
+ DocumentPersister $documentPersister,
+ ReflectionProperty $reflectionId
+ ) {
+
+ if ($classMetadata->getReflectionClass()->hasMethod('__wakeup')) {
+ return function (BaseProxy $proxy) use ($documentPersister, $reflectionId) {
+ $proxy->__setInitializer(null);
+ $proxy->__setCloner(null);
+
+ if ($proxy->__isInitialized()) {
+ return;
}
- $methods .= $method->getName() . '(';
- $firstParam = true;
- $parameterString = $argumentString = '';
-
- foreach ($method->getParameters() as $param) {
- if ($firstParam) {
- $firstParam = false;
- } else {
- $parameterString .= ', ';
- $argumentString .= ', ';
- }
- // We need to pick the type hint class too
- if (($paramClass = $param->getClass()) !== null) {
- $parameterString .= '\\' . $paramClass->getName() . ' ';
- } else if ($param->isArray()) {
- $parameterString .= 'array ';
- }
+ $properties = $proxy->__getLazyProperties();
- if ($param->isPassedByReference()) {
- $parameterString .= '&';
+ foreach ($properties as $propertyName => $property) {
+ if ( ! isset($proxy->$propertyName)) {
+ $proxy->$propertyName = $properties[$propertyName];
}
+ }
- $parameterString .= '$' . $param->getName();
- $argumentString .= '$' . $param->getName();
+ $proxy->__setInitialized(true);
+ $proxy->__wakeup();
- if ($param->isDefaultValueAvailable()) {
- $parameterString .= ' = ' . var_export($param->getDefaultValue(), true);
- }
+ $id = $reflectionId->getValue($proxy);
+
+ if (null === $documentPersister->load($id, $proxy)) {
+ throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
}
+ };
+ }
- $methods .= $parameterString . ')';
- $methods .= "\n" . ' {' . "\n";
- if ($this->isShortIdentifierGetter($method, $class)) {
- $identifier = lcfirst(substr($method->getName(), 3));
+ return function (BaseProxy $proxy) use ($documentPersister, $reflectionId) {
+ $proxy->__setInitializer(null);
+ $proxy->__setCloner(null);
- $methods .= ' if ($this->__isInitialized__ === false) {' . "\n";
- $methods .= ' return $this->__identifier__;' . "\n";
- $methods .= ' }' . "\n";
- }
- $methods .= ' $this->__load();' . "\n";
- $methods .= ' return parent::' . $method->getName() . '(' . $argumentString . ');';
- $methods .= "\n" . ' }' . "\n";
+ if ($proxy->__isInitialized()) {
+ return;
}
- }
- return $methods;
- }
+ $properties = $proxy->__getLazyProperties();
- /**
- * Check if the method is a short identifier getter.
- *
- * What does this mean? For proxy objects the identifier is already known,
- * however accessing the getter for this identifier usually triggers the
- * lazy loading, leading to a query that may not be necessary if only the
- * ID is interesting for the userland code (for example in views that
- * generate links to the document, but do not display anything else).
- *
- * @param ReflectionMethod $method
- * @param ClassMetadata $class
- * @return bool
- */
- private function isShortIdentifierGetter($method, $class)
- {
- $identifier = lcfirst(substr($method->getName(), 3));
- $cheapCheck = (
- $method->getNumberOfParameters() == 0 &&
- substr($method->getName(), 0, 3) == "get" &&
- $class->identifier === $identifier &&
- $class->hasField($identifier) &&
- (($method->getEndLine() - $method->getStartLine()) <= 4)
- && in_array($class->fieldMappings[$identifier]['type'], array('id', 'custom_id'))
- );
+ foreach ($properties as $propertyName => $property) {
+ if ( ! isset($proxy->$propertyName)) {
+ $proxy->$propertyName = $properties[$propertyName];
+ }
+ }
- if ($cheapCheck) {
- $code = file($method->getDeclaringClass()->getFileName());
- $code = trim(implode(" ", array_slice($code, $method->getStartLine() - 1, $method->getEndLine() - $method->getStartLine() + 1)));
+ $proxy->__setInitialized(true);
- $pattern = sprintf(self::PATTERN_MATCH_ID_METHOD, $method->getName(), $identifier);
+ $id = $reflectionId->getValue($proxy);
- if (preg_match($pattern, $code)) {
- return true;
+ if (null === $documentPersister->load($id, $proxy)) {
+ throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
}
- }
- return false;
+ };
}
/**
- * Generates the code for the __sleep method for a proxy class.
+ * Generates a closure capable of finalizing a cloned proxy
+ *
+ * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
+ * @param \Doctrine\ODM\MongoDB\Persisters\DocumentPersister $documentPersister
+ * @param \ReflectionProperty $reflectionId
*
- * @param $class
- * @return string
+ * @return \Closure
+ *
+ * @throws \Doctrine\ODM\MongoDB\DocumentNotFoundException
*/
- private function generateSleep(ClassMetadata $class)
- {
- $sleepImpl = '';
-
- if ($class->reflClass->hasMethod('__sleep')) {
- $sleepImpl .= "return array_merge(array('__isInitialized__'), parent::__sleep());";
- } else {
- $sleepImpl .= "return array('__isInitialized__', ";
- $first = true;
-
- foreach ($class->getReflectionProperties() as $name => $prop) {
- if ($first) {
- $first = false;
- } else {
- $sleepImpl .= ', ';
- }
-
- $sleepImpl .= "'" . $name . "'";
+ private function createCloner(
+ BaseClassMetadata $classMetadata,
+ DocumentPersister $documentPersister,
+ ReflectionProperty $reflectionId
+ ) {
+ return function (BaseProxy $proxy) use ($documentPersister, $classMetadata, $reflectionId) {
+ if ($proxy->__isInitialized()) {
+ return;
}
- $sleepImpl .= ');';
- }
-
- return $sleepImpl;
- }
-
- /** Proxy class code template */
- private static $proxyClassTemplate =
-'<?php
-
-namespace <namespace>;
+ $proxy->__setInitialized(true);
+ $proxy->__setInitializer(null);
-use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
-
-/**
- * THIS CLASS WAS GENERATED BY THE DOCTRINE ODM. DO NOT EDIT THIS FILE.
- */
-class <proxyClassName> extends \<className> implements \Doctrine\ODM\MongoDB\Proxy\Proxy
-{
- private $__documentPersister__;
- public $__identifier__;
- public $__isInitialized__ = false;
- public function __construct(DocumentPersister $documentPersister, $identifier)
- {
- $this->__documentPersister__ = $documentPersister;
- $this->__identifier__ = $identifier;
- }
- /** @private */
- public function __load()
- {
- if (!$this->__isInitialized__ && $this->__documentPersister__) {
- $this->__isInitialized__ = true;
-
- if (method_exists($this, "__wakeup")) {
- // call this after __isInitialized__to avoid infinite recursion
- // but before loading to emulate what ClassMetadata::newInstance()
- // provides.
- $this->__wakeup();
- }
+ $id = $reflectionId->getValue($proxy);
+ $original = $documentPersister->load($id);
- if ($this->__documentPersister__->load($this->__identifier__, $this) === null) {
- throw \Doctrine\ODM\MongoDB\DocumentNotFoundException::documentNotFound(get_class($this), $this->__identifier__);
+ if (null === $original) {
+ throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
}
- unset($this->__documentPersister__, $this->__identifier__);
- }
- }
-
- /** @private */
- public function __isInitialized()
- {
- return $this->__isInitialized__;
- }
-
- <methods>
- public function __sleep()
- {
- <sleepImpl>
- }
+ foreach ($classMetadata->getReflectionClass()->getProperties() as $reflectionProperty) {
+ $propertyName = $reflectionProperty->getName();
- public function __clone()
- {
- if (!$this->__isInitialized__ && $this->__documentPersister__) {
- $this->__isInitialized__ = true;
- $class = $this->__documentPersister__->getClassMetadata();
- $original = $this->__documentPersister__->load($this->__identifier__);
- if ($original === null) {
- throw \Doctrine\ODM\MongoDB\MongoDBException::documentNotFound(get_class($this), $this->__identifier__);
- }
- foreach ($class->reflFields AS $field => $reflProperty) {
- $reflProperty->setValue($this, $reflProperty->getValue($original));
+ if ($classMetadata->hasField($propertyName) || $classMetadata->hasAssociation($propertyName)) {
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($proxy, $reflectionProperty->getValue($original));
+ }
}
- unset($this->__documentPersister__, $this->__identifier__);
- }
- <cloneImpl>
- }
-}';
-
- public static function generateProxyClassName($className, $proxyNamespace)
- {
- return rtrim($proxyNamespace, '\\') . '\\'.self::MARKER.'\\' . ltrim($className, '\\');
+ };
}
}
View
11 lib/Doctrine/ODM/MongoDB/UnitOfWork.php
@@ -1990,9 +1990,14 @@ private function doMerge($document, array &$visited, $prevManagedCopy = null, $a
$prop->setValue($managedCopy, $other);
} else {
$targetDocument = isset($assoc2['targetDocument']) ? $assoc2['targetDocument'] : get_class($other);
- $targetClass = $this->dm->getClassMetadata($targetDocument);
- $id = $targetClass->getIdentifierValue($other);
- $proxy = $this->dm->getProxyFactory()->getProxy($targetDocument, $id);
+ /* @var $targetClass \Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo */
+ $targetClass = $this->dm->getClassMetadata($targetDocument);
+ $id = $targetClass->getIdentifierValue($other);
+ $proxy = $this->dm->getProxyFactory()->getProxy(
+ $targetDocument,
+ array($targetClass->identifier => $id)
+ );
+
$prop->setValue($managedCopy, $proxy);
$this->registerManaged($proxy, $id, array());
}
View
13 tests/Doctrine/ODM/MongoDB/Tests/Functional/DetachedDocumentTest.php
@@ -6,6 +6,7 @@
use Documents\CmsPhonenumber;
use Documents\CmsAddress;
use Doctrine\ODM\MongoDB\UnitOfWork;
+use Doctrine\ODM\MongoDB\Proxy\Proxy;
class DetachedDocumentTest extends \Doctrine\ODM\MongoDB\Tests\BaseTest
{
@@ -114,15 +115,15 @@ public function testUninitializedLazyAssociationsAreIgnoredOnMerge()
$this->dm->clear();
$address2 = $this->dm->find(get_class($address), $address->id);
- $this->assertTrue($address2->user instanceof \Doctrine\ODM\MongoDB\Proxy\Proxy);
- $this->assertFalse($address2->user->__isInitialized__);
+ $this->assertTrue($address2->user instanceof Proxy);
+ $this->assertFalse($address2->user->__isInitialized());
$detachedAddress2 = unserialize(serialize($address2));
- $this->assertTrue($detachedAddress2->user instanceof \Doctrine\ODM\MongoDB\Proxy\Proxy);
- $this->assertFalse($detachedAddress2->user->__isInitialized__);
+ $this->assertTrue($detachedAddress2->user instanceof Proxy);
+ $this->assertFalse($detachedAddress2->user->__isInitialized());
$managedAddress2 = $this->dm->merge($detachedAddress2);
- $this->assertTrue($managedAddress2->user instanceof \Doctrine\ODM\MongoDB\Proxy\Proxy);
+ $this->assertTrue($managedAddress2->user instanceof Proxy);
$this->assertFalse($managedAddress2->user === $detachedAddress2->user);
- $this->assertFalse($managedAddress2->user->__isInitialized__);
+ $this->assertFalse($managedAddress2->user->__isInitialized());
}
}
Something went wrong with that request. Please try again.