Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: doctrine/doctrine2
...
head fork: juzna/doctrine2
Checking mergeability… Don't worry, you can still create the pull request.
  • 8 commits
  • 13 files changed
  • 0 commit comments
  • 1 contributor
View
20 lib/Doctrine/ORM/EntityManager.php
@@ -28,6 +28,7 @@
Doctrine\ORM\Mapping\ClassMetadataFactory,
Doctrine\ORM\Query\ResultSetMapping,
Doctrine\ORM\Proxy\ProxyFactory,
+ Doctrine\ORM\Proxy\ProxyFactoryInterface,
Doctrine\ORM\Query\FilterCollection;
/**
@@ -93,7 +94,7 @@ class EntityManager implements ObjectManager
/**
* The proxy factory used to create dynamic proxies.
*
- * @var \Doctrine\ORM\Proxy\ProxyFactory
+ * @var \Doctrine\ORM\Proxy\ProxyFactoryInterface
*/
private $proxyFactory;
@@ -743,14 +744,27 @@ public function newHydrator($hydrationMode)
/**
* Gets the proxy factory used by the EntityManager to create entity proxies.
*
- * @return ProxyFactory
+ * @return ProxyFactoryInterface
*/
public function getProxyFactory()
{
return $this->proxyFactory;
}
- /**
+
+ /**
+ * Changes the proxy factory used by the EntityManager to create entity proxies.
+ *
+ * @param \Doctrine\ORM\Proxy\ProxyFactoryInterface $proxy
+ * @return EntityManager
+ */
+ public function setProxyFactory(ProxyFactoryInterface $proxy)
+ {
+ $this->proxyFactory = $proxy;
+ return $this;
+ }
+
+ /**
* Helper method to initialize a lazy loading proxy or persistent collection.
*
* This method is a no-op for other objects
View
2  lib/Doctrine/ORM/EntityRepository.php
@@ -100,7 +100,7 @@ public function clear()
/**
* Finds an entity by its primary key / identifier.
*
- * @param $id The identifier.
+ * @param int|array|mixed $id The identifier.
* @param int $lockMode
* @param int $lockVersion
* @return object The entity.
View
6 lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php
@@ -233,9 +233,15 @@ private function _getEntity(array $data, $dqlAlias)
}
$this->_hints['fetchAlias'] = $dqlAlias;
+ if ($this->_rsm->isPartial) $this->_hints[Query::HINT_PARTIAL_UNINITIALIZED] = true;
$entity = $this->_uow->createEntity($className, $data, $this->_hints);
+ if ($this->_rsm->isPartial && ($pf = $this->_em->getProxyFactory()) instanceof \Doctrine\ORM\Proxy\UninitializedProxyFactory) {
+ /** @var \Doctrine\ORM\Proxy\UninitializedProxyFactory $pf */
+ $pf->addPartialObject($entity);
+ }
+
//TODO: These should be invoked later, after hydration, because associations may not yet be loaded here.
if (isset($this->_ce[$className]->lifecycleCallbacks[Events::postLoad])) {
$this->_ce[$className]->invokeLifecycleCallbacks(Events::postLoad, $entity);
View
8 lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
@@ -505,7 +505,7 @@ class ClassMetadataInfo implements ClassMetadata
/**
* The ReflectionProperty instances of the mapped class.
*
- * @var array
+ * @var \ReflectionProperty[]
*/
public $reflFields = array();
@@ -544,7 +544,7 @@ 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)
{
@@ -554,8 +554,8 @@ public function getReflectionProperty($name)
/**
* Gets the ReflectionProperty for the single identifier field.
*
- * @return ReflectionProperty
- * @throws BadMethodCallException If the class has a composite identifier.
+ * @return \ReflectionProperty
+ * @throws \BadMethodCallException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
View
1  lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
@@ -534,6 +534,7 @@ public function getAllClassNames()
foreach ($iterator as $file) {
$sourceFile = realpath($file[0]);
+ if(!preg_match('/\bclass\s+/', file_get_contents($sourceFile))) continue;
require_once $sourceFile;
View
10 lib/Doctrine/ORM/Proxy/ProxyFactory.php
@@ -31,7 +31,7 @@
* @author Giorgio Sironi <piccoloprincipeazzurro@gmail.com>
* @since 2.0
*/
-class ProxyFactory
+class ProxyFactory implements ProxyFactoryInterface
{
/** The EntityManager this factory is bound to. */
private $_em;
@@ -73,14 +73,6 @@ public function __construct(EntityManager $em, $proxyDir, $proxyNs, $autoGenerat
$this->_proxyNamespace = $proxyNs;
}
- /**
- * Gets a reference proxy instance for the entity of the given type and identified by
- * the given identifier.
- *
- * @param string $className
- * @param mixed $identifier
- * @return object
- */
public function getProxy($className, $identifier)
{
$fqn = ClassUtils::generateProxyClassName($className, $this->_proxyNamespace);
View
49 lib/Doctrine/ORM/Proxy/ProxyFactoryInterface.php
@@ -0,0 +1,49 @@
+<?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 LGPL. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\ORM\Proxy;
+
+/**
+ * This factory is used to create proxy objects for entities at runtime.
+ *
+ * @author Jan Dolecek <juzna.cz@gmail.com>
+ * @since 2.1
+ */
+interface ProxyFactoryInterface
+{
+ /**
+ * Gets a reference proxy instance for the entity of the given type and identified by
+ * the given identifier.
+ *
+ * @param string $className
+ * @param mixed $identifier
+ * @return object
+ */
+ function getProxy($className, $identifier);
+
+ /**
+ * 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 EntityManager used
+ * by this factory is used.
+ */
+ function generateProxyClasses(array $classes, $toDir = null);
+}
View
144 lib/Doctrine/ORM/Proxy/UninitializedProxyFactory.php
@@ -0,0 +1,144 @@
+<?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 LGPL. For more information, see
+ * <http://www.doctrine-project.org>.
+ */
+
+namespace Doctrine\ORM\Proxy;
+
+use Doctrine\ORM\EntityManager,
+ Doctrine\ORM\Mapping\ClassMetadata,
+ Doctrine\ORM\Mapping\AssociationMapping;
+
+/**
+ * This factory is used to create proxy objects with special uninitialized values
+ * See http://blog.juzna.cz/2011/06/lazy-loading-in-php/
+ *
+ * @author Jan Dolecek <juzna.cz@gmail.com>
+ */
+class UninitializedProxyFactory implements ProxyFactoryInterface, \Nette\Diagnostics\IBarPanel
+{
+ /** The EntityManager this factory is bound to. */
+ private $_em;
+ private $_initialized = array();
+ private $_partials = array(); // oid -> true
+
+ protected function __construct(EntityManager $em)
+ {
+ $this->_em = $em;
+ }
+
+ public function addPartialObject($object) {
+ $this->_partials[spl_object_hash($object)] = true;
+ }
+
+ public function isPartial($object) {
+ return isset($this->_partials[spl_object_hash($object)]);
+ }
+
+ /**
+ * Create proxy factory and register it as initializer
+ *
+ * @param \Doctrine\ORM\EntityManager $em
+ * @param bool $registerInitializer
+ * @return UninitializedProxyFactory
+ */
+ public static function create(EntityManager $em, $registerInitializer = true)
+ {
+ $ret = new static($em);
+ if($registerInitializer) {
+ spl_initialize_register(array($ret, '_initialize'));
+ \Nette\Diagnostics\Debugger::$bar->addPanel($ret);
+ }
+ return $ret;
+ }
+
+ /**
+ *
+ * @param string $className
+ * @param array $identifier
+ * @return object
+ */
+ public function getProxy($className, $identifier)
+ {
+ /** @var \Doctrine\ORM\Mapping\ClassMetadata $classMetaData */
+ $classMetaData = $this->_em->getClassMetadata($className);
+
+ $obj = $classMetaData->newInstance();
+
+ foreach($classMetaData->reflFields as $fieldName => $fieldReflection) {
+ $fieldReflection->setValue($obj, isset($identifier[$fieldName]) ? $identifier[$fieldName] : uninitialized);
+ }
+
+ return $obj;
+ }
+
+ public function generateProxyClasses(array $classes, $toDir = null)
+ {
+ // void
+ }
+
+ /**
+ * Magic method to lazy-load uninitialized values
+ * @param $obj
+ * @param $propertyName
+ * @return
+ */
+ public function _initialize($obj, $propertyName) {
+ $className = get_class($obj);
+
+ /** @var \Doctrine\ORM\Mapping\ClassMetadata $classMetaData */
+ if(!$classMetaData = $this->_em->getClassMetadata($className)) return; // we don't know how to hydrate it
+ if($this->isPartial($obj)) {
+ trigger_error("Accessed uninitialized property of a partially-loaded object", E_USER_NOTICE);
+ $classMetaData->reflFields[$propertyName]->setValue(null);
+ }
+
+ // Create identifier
+ $identifier = array();
+ foreach($classMetaData->getIdentifierFieldNames() as $fieldName) {
+ $ref = $classMetaData->reflFields[$fieldName];
+ if (!$ref->isInitialized($obj)) throw new \Exception("Primary key is not initialized");
+ $identifier[$fieldName] = $ref->getValue($obj);
+ }
+
+ $this->_initialized[] = array($className, $identifier);
+
+ $this->_em->getUnitOfWork()->getEntityPersister($className)->load($identifier, $obj);
+ }
+
+ /**
+ * Renders HTML code for custom tab.
+ *
+ * @return string
+ */
+ function getTab() {
+ return count($this->_initialized) . ' lazy-loads';
+ }
+
+ /**
+ * Renders HTML code for custom panel.
+ *
+ * @return string
+ */
+ function getPanel() {
+ if(!$this->_initialized) return;
+
+ return '<pre>' . var_export($this->_initialized, true);
+ }
+
+
+}
View
5 lib/Doctrine/ORM/Query.php
@@ -109,6 +109,11 @@
const HINT_LOCK_MODE = 'doctrine.lockMode';
/**
+ * @var string
+ */
+ const HINT_PARTIAL_UNINITIALIZED = 'doctrine.partial.uninitialized';
+
+ /**
* @var integer $_state The current state of this query.
*/
private $_state = self::STATE_CLEAN;
View
5 lib/Doctrine/ORM/Query/ResultSetMapping.php
@@ -119,6 +119,11 @@ class ResultSetMapping
public $isIdentifierColumn = array();
/**
+ * @var bool Contains partial select
+ */
+ public $isPartial = false;
+
+ /**
* Adds an entity result to this ResultSetMapping.
*
* @param string $class The class name of the entity.
View
1  lib/Doctrine/ORM/Query/SqlWalker.php
@@ -1154,6 +1154,7 @@ public function walkSelectExpression($selectExpression)
if ($expr instanceof AST\PartialObjectExpression) {
$dqlAlias = $expr->identificationVariable;
$partialFieldSet = $expr->partialFieldSet;
+ $this->_rsm->isPartial = true;
} else {
$dqlAlias = $expr;
$partialFieldSet = array();
View
1  lib/Doctrine/ORM/Tools/Console/Command/RunDqlCommand.php
@@ -78,6 +78,7 @@ protected function configure()
*/
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
{
+ /** @var \Doctrine\ORM\EntityManager $em */
$em = $this->getHelper('em')->getEntityManager();
if (($dql = $input->getArgument('dql')) === null) {
View
6 lib/Doctrine/ORM/UnitOfWork.php
@@ -2349,6 +2349,12 @@ public function createEntity($className, array $data, &$hints = array())
return $entity;
}
+ // Fill-in with UNINITIALIZED special values
+ if (isset($hints[Query::HINT_PARTIAL_UNINITIALIZED])) {
+ foreach($class->fieldMappings as $field => $fieldMapping) $class->reflFields[$field]->setValue($entity, UNINITIALIZED);
+ }
+
+
foreach ($data as $field => $value) {
if (isset($class->fieldMappings[$field])) {
$class->reflFields[$field]->setValue($entity, $value);

No commit comments for this range

Something went wrong with that request. Please try again.