[DDC-3234] Empty properties when filtering collections Created: 30/Jul/14  Updated: 31/Jul/14

Status: Open
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.5, 2.4.2
Fix Version/s: 2.x
Security Level: All

Type: Bug Priority: Major
Reporter: Diogo Domanski de Souza Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: Collection, Criteria, orm
Environment:

PHP 5.5.9, Nginx 1.4.6, PHP FPM, Zend Framework 2.3.1, Linux Ubuntu 14.04



 Description   

I'm facing some troubles when filtering an entity association (ArrayCollection) by using Criteria.

The scenario is the following: I have 3 entities:

User.php
<?php

namespace Entity;

use Doctrine\ORM\Mapping as ORM;
use \Doctrine\Common\Collections\Criteria;
use Zend\Stdlib\Hydrator;

/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="Entity\UserRepository")
 * @ORM\HasLifecycleCallbacks
 * @author domanski
 */
class User implements \Serializable {
	/**
	 *
	 * @ORM\Id
	 * @ORM\Column(name="id", type="integer", nullable=false)
	 * @ORM\GeneratedValue(strategy="AUTO")
	 * @var integer
	 */
	private $id;

	/**
	 * @ORM\Column(name="delete_date", type="datetime")
	 * @var \DateTime
	 */
	private $deleteDate;
	
	public function __construct(array $options = array()) {
		if (!empty($options))
			$this->hydrate($options);
	}

	public function hydrate(array $options = array(), \Doctrine\ORM\EntityManager $em = null) {
		$hydrator = new Hydrator\ClassMethods();
		$hydrator->hydrate($options, $this);
	}

	/**
	 * 
	 * @return int
	 */
	public function getId() {
		return $this->id;
	}

	/**
	 * 
	 * @param int $id
	 * @return \Entity\User
	 */
	public function setId($id) {
		$this->id = $id;
		return $this;
	}

	/**
	 * 
	 * @return \DateTime
	 */
	public function getDeleteDate() {
		return $this->deleteDate;
	}

	/**
	 * @param \DateTime|null $deleteDate
	 * @return \Entity\User
	 */
	public function setDeleteDate($deleteDate = null) {
		$this->deleteDate = $deleteDate;
		return $this;
	}

	/**
	 * 
	 * @return array
	 */
	public function toArray() {
		$result = array(
			'id' => $this->getId(),
			'delete_date' => $this->getDeleteDate()
		);

		return $result;
	}

}
FieldWorker.php
<?php

namespace Entity;

use Doctrine\ORM\Mapping as ORM;
use \Doctrine\Common\Collections\Criteria;

use Zend\Stdlib\Hydrator;

/**
 * Description of FieldWorker
 *
 * @ORM\Entity(repositoryClass="Entity\FieldWorkerRepository")
 * @ORM\Table(name="field_worker")
 * @ORM\HasLifecycleCallbacks
 * @author domanski
 */
class FieldWorker {
	
	/**
	 * This attribute must exist so the inverse join with any other entity can work
	 * 
	 * @ORM\Id
	 * @ORM\Column(type="integer", name="user_id")
	 * @var string
	 */
	protected $id;
	
	/**
	 * 
	 * @ORM\OneToOne(targetEntity="Entity\User")
	 * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
	 * @var \Entity\User
	 */
	protected $user;
	
	public function __construct($options = array()) {		
		if(!empty($options))
			$this->hydrate($options);
	}
	
	public function hydrate(array $options = array(), \Doctrine\ORM\EntityManager $em = null) {
		if(!empty($em)) {
			// user
			if(isset($options['user']))
				$options['user'] = $em->getReference('Entity\User', $options['user']);
			else if(isset($options['user_id']))
				$options['user'] = $em->getReference('Entity\User', $options['user_id']);
						
		}
		
		$hydrator = new Hydrator\ClassMethods();
		$hydrator->hydrate($options, $this);
	}

	/**
	 * 
	 * @return \Entity\User
	 */
	public function getUser() {
		return $this->user;
	}

	/**
	 * 
	 * @param \Entity\User $user
	 * @return \Entity\FieldWorker
	 */
	public function setUser(\Entity\User $user) {
		$this->user = $user;
		$this->id = $user->getId();
		return $this;
	}
	
	/**
	 * 
	 * @return array
	 */
	public function toArray() {
		return $this->getUser()->toArray();
	}
}
Stage.php
<?php

namespace Obra\Entity;

use Doctrine\ORM\Mapping as ORM;
use Zend\Stdlib\Hydrator;
use Doctrine\Common\Collections\Criteria;

/**
 * Description of Stage
 *
 * @ORM\Table(name="stage")
 * @ORM\Entity(repositoryClass="Entity\StageRepository")
 * @ORM\HasLifecycleCallbacks
 * @author domanski
 */
class Stage {

	/**
	 *
	 * @ORM\Id
	 * @ORM\Column(name="id", type="integer", nullable=false)
	 * @ORM\GeneratedValue(strategy="AUTO")
	 * @var integer
	 */
	private $id;

	/**
	 * @ORM\ManyToMany(targetEntity="Entity\FieldWorker")
	 * @ORM\JoinTable(name="stage_field_worker",
	 * 		joinColumns={@ORM\JoinColumn(name="stage_id", referencedColumnName="id")},
	 * 		inverseJoinColumns={@ORM\JoinColumn(name="field_worker_id", referencedColumnName="user_id")}
	 * 	)
	 * @var \Doctrine\Common\Collections\ArrayCollection
	 */
	private $fieldWorkers;

	public function __construct(array $options = array()) {
		$this->fieldWorkers = new \Doctrine\Common\Collections\ArrayCollection();

		if (!empty($options))
			$this->hydrate($options);
	}

	public function hydrate(array $options = array(), \Doctrine\ORM\EntityManager $em = null) {
		$hydrator = new Hydrator\ClassMethods();
		$hydrator->hydrate($options, $this);
	}

	/**
	 * 
	 * @return int
	 */
	public function getId() {
		return $this->id;
	}

	/**
	 * 
	 * @param int $id
	 * @return \Entity\Stage
	 */
	public function setId($id) {
		$this->id = $id;
		return $this;
	}

	/**
	 * 
	 * @return \Doctrine\Common\Collections\ArrayCollection
	 */
	public function getFieldWorkers() {
		$criteria = Criteria::create()
				->where(Criteria::expr()->isNull("user.deleteDate"))
				->orderBy(array("user.name" => Criteria::ASC));

		return $this->fieldWorkers->matching($criteria);
	}

	/**
	 * 
	 * @return \Entity\Stage
	 */
	public function clearFieldWorkers() {
		$this->fieldWorkers->clear();
		return $this;
	}

	/**
	 * 
	 * @param \Entity\FieldWorker $fieldWorker
	 * @return \Entity\Stage
	 */
	public function addFiscal(\Entity\FieldWorker $fieldWorker) {
		$this->fieldWorkers->add($fieldWorker);
		return $this;
	}

	/**
	 * 
	 * @return array
	 */
	public function toArray() {
		$result = array(
			"id" => $this->getId(),
			"field_workers" => array()
		);

		foreach ($this->getFieldWorkers() as $fieldWorker) {
			$result['field_workers'][] = $fieldWorker->toArray();
		}

		return $result;
	}
}

The problem is that whenever the Stage::getFieldWorkers() method is invoked, the list of associated field workers is returned correctly, however if I try to retrieve the respective user of any field worker, it is NULL.

For example:

$stageEntity = $em->getRerefence('Entity\Stage', 1);
$fieldWorkers = $stageEntity->getFieldWorkers();

foreach($fieldWorkers as $fieldWorker) {
   $userId = $fieldWorker->getUser()->getId(); // This throws an error message saying that the result of getUser() is NULL
}

Another example would be if I try to call $stageEntity->toArray() (because it does the same thing as show above).

The database tables are as following:

Database tables creation
CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `delete_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `field_worker` (
  `user_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`user_id`),
  CONSTRAINT `fk_field_worker_user1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `stage` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE `stage_field_worker` (
  `stage_id` int(10) unsigned NOT NULL,
  `field_worker_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`stage_id`,`field_worker_id`),
  KEY `fk_stage_field_worker_stage_idx` (`stage_id`),
  KEY `fk_stage_field_worker_field_worker_idx` (`field_worker_id`),
  CONSTRAINT `fk_stage_field_worker_field_worker` FOREIGN KEY (`field_worker_id`) REFERENCES `field_worker` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_stage_field_worker_stage` FOREIGN KEY (`stage_id`) REFERENCES `stage` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` SET `id` = 1;
INSERT INTO `field_worker` SET `user_id` = 1;
INSERT INTO `stage` SET `id` = 1;
INSERT INTO `stage_field_worker` SET `stage_id` = 1, `field_worker_id` = 1;

After hours trying to understand what was wrong, I decided to make a test and modify the Stage::getFieldWorkers() method by removing the filtering Criteria:

public function getFieldWorkers() {
    return $this->fieldWorkers;
}

By simply doing that, the getUser() method started to return an entity of type User (as expected).

I am not a Doctrine ORM expert, but there seems to be something wrong with ArrayCollection filtering (matching() method)



 Comments   
Comment by Diogo Domanski de Souza [ 30/Jul/14 ]

The same problem occurs with QueryBuilder. For example:

StageRepository.php
<?php

namespace Entity;

use Doctrine\ORM\EntityRepository;

/**
 * Description of StageRepository
 *
 * @author domanski
 */
class StageRepository extends EntityRepository 
{

	public function findByFieldWorkerId($fieldWorkerId) {
		$qb = $this->getEntityManager()->createQueryBuilder()
			->select('s')
			->from('Entity\Stage', 's')
			->innerJoin('s.fieldWorkers', 'f')
			->innerJoin('f.user', 'u', \Doctrine\ORM\Query\Expr\Join::WITH, "u.deleteDate IS NULL AND u.id = :field_worker_id")
				->setParameter('field_worker_id', $fieldWorkerId);

		return $qb->getQuery()->getResult();
	 }
}

If I try to iterate over the result of StageRepository::findByFieldWorkerId() and call toArray() of any element, I get the same error. I've even tried to remove the inner join with User entity from query:

	public function findByFieldWorkerId($fieldWorkerId) {
		$qb = $this->getEntityManager()->createQueryBuilder()
			->select('s')
			->from('Entity\Stage', 's')
			->innerJoin('s.fieldWorkers', 'f');

		return $qb->getQuery()->getResult();
	 }
Comment by Marco Pivetta [ 30/Jul/14 ]

I suspect that something is wrong in your mappings then...

Comment by Diogo Domanski de Souza [ 31/Jul/14 ]

Hi Marco,

The mappings are shown above. The only thing I did was to omit some entities/tables properties/columns that don't have to see with the associations - except the field worker (table and Entity) and stage_field_worker table, that are fully presented.

Maybe is important to notice that the field_worker table has only one column (user_id) that is primary key and foreign key (referencing user.id).

Thanks for you support

Comment by Marco Pivetta [ 31/Jul/14 ]

Diogo Domanski de Souza we can't debug this as it is. We'd need a functional test case to be added to https://github.com/doctrine/doctrine2/tree/0650bb954f5e8d05776f99abd04c81948413299f/tests/Doctrine/Tests/ORM/Functional/Ticket first, in order to see the failure

Comment by Diogo Domanski de Souza [ 31/Jul/14 ]

Marco Pivetta is there any documentation (tutorial, instructions, guide, etc) that I can use to learn how to write the functional test cases that I need?

Comment by Marco Pivetta [ 31/Jul/14 ]

Diogo Domanski de Souza you need to look at the existing ones.

For running the test suite:

git clone git@github.com:doctrine/doctrine2.git
cd doctrine2 
curl -s https://getcomposer.org/installer | php --
./composer.phar install
./vendor/bin/phpunit




[DDC-3183] Add JsonSerializable to Collections Created: 22/Jun/14  Updated: 22/Jun/14

Status: Open
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 3.0
Fix Version/s: 3.0
Security Level: All

Type: New Feature Priority: Major
Reporter: Gabriel Bull Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: collection, orm


 Description   

Implement this:

http://www.php.net/manual/fr/class.jsonserializable.php

Can't really make this claim if Doctrine is not implementing basic interfaces for collections:

> The missing (SPL) Collection/Array/OrderedMap interface.






[DDC-2826] Add support for mapping collections of embeddable objects Created: 28/Nov/13  Updated: 08/Feb/14

Status: Open
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: None
Fix Version/s: None
Security Level: All

Type: New Feature Priority: Major
Reporter: songoko songowan Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 1
Labels: collection, orm, value-objects


 Description   

In Hibernate we can do something like this:

    @Entity
    public class User {
       [...]
       public String getLastname() { ...}
    
       @ElementCollection
       @CollectionTable(name="Addresses", joinColumns=@JoinColumn(name="user_id"))
       @AttributeOverrides({
          @AttributeOverride(name="street1", column=@Column(name="fld_street"))
       })
       public Set<Address> getAddresses() { ... } 
    }
    
    @Embeddable
    public class Address {
       public String getStreet1() {...}
       [...]
    }

Basically a collection of value objects is mapped to a new table. Currently Doctrine2 is on its way to support value objects

However, this implementation won't support mapping a collection of objects to a new table and the only way to circumvent this issue is to treat the address an an entity and use an one-to-many unidirectional relationship through a many-to-many join table



 Comments   
Comment by Doctrine Bot [ 08/Feb/14 ]

A related Github Pull-Request [GH-835] was closed:
https://github.com/doctrine/doctrine2/pull/835





[DDC-2552] [GH-722] Support for order by association (for 2.3 branch) Created: 15/Jul/13  Updated: 15/Jul/13  Resolved: 15/Jul/13

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.3
Fix Version/s: None
Security Level: All

Type: Bug Priority: Major
Reporter: Doctrine Bot Assignee: Benjamin Eberlei
Resolution: Invalid Votes: 0
Labels: collection, orm
Environment:

Symfony 2.3



 Description   

This issue is created automatically through a Github pull request on behalf of naitsirch:

Url: https://github.com/doctrine/doctrine2/pull/722

Message:

I need to `@OrderBy` an association, which does not work in `2.3` but I found the pull request https://github.com/doctrine/doctrine2/pull/549 by @FabioBatSilva who has implemented this in branch `2.4`.

I have copied the code, adjusted it for `2.3` and tested it in a real life application

The original pull request is related to Doctrine Issue #2241(http://www.doctrine-project.org/jira/browse/DDC-2241).
The ordering of associations has been implemented in Doctrine Issue #195(http://www.doctrine-project.org/jira/browse/DDC-195).

Please integrate this into `2.3` because `2.4` is not stable until now and thus it is not usable for many people.



 Comments   
Comment by Doctrine Bot [ 15/Jul/13 ]

A related Github Pull-Request [GH-722] was closed:
https://github.com/doctrine/doctrine2/pull/722

Comment by Christian Stoller [ 15/Jul/13 ]

Can be closed (see https://github.com/doctrine/doctrine2/pull/722#issuecomment-20960237)





[DDC-2303] @param wrong in Doctrine\ORM\PersistentCollection::__constructor Edit Created: 18/Feb/13  Updated: 26/Feb/13  Resolved: 26/Feb/13

Status: Closed
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: None
Fix Version/s: None
Security Level: All

Type: Bug Priority: Major
Reporter: Torsten Granek Assignee: Marco Pivetta
Resolution: Invalid Votes: 0
Labels: collection

Attachments: JPEG File screenshot-1.jpg    

 Description   

When i try to generate a new PersistentCollection like this:
###############################################
$collection = new ArrayCollection();
new \Doctrine\ORM\PersistentCollection(
$this->getEntityManager(),
new ClassMetadata(''),
$collection
);
###############################################
i get an typ hinting error like
"Expected array, got "Doctrine\Common\Collections\ArrayCollection"

This could be fixed by changing the type hinting for the Doctrine\ORM\PersistentCollection::__constructor
_From:_
###############################################
/**

  • Creates a new persistent collection.
    *
  • @param EntityManager $em The EntityManager the collection will be associated with.
  • @param ClassMetadata $class The class descriptor of the entity type of this collection.
  • @param array $coll The collection elements.
    */
    public function __construct(EntityManager $em, $class, $coll)
    {
                                                                                              1. _To:_
                                                                                                ###############################################
                                                                                                /**

  • Creates a new persistent collection.
    *
  • @param EntityManager $em The EntityManager the collection will be associated with.
  • @param ClassMetadata $class The class descriptor of the entity type of this collection.
  • @param \ArrayAccess $coll The collection elements.
    */
    public function __construct(EntityManager $em, $class, $coll)
    {
    ###############################################


 Comments   
Comment by Torsten Granek [ 18/Feb/13 ]

When i try to generate a new PersistentCollection like this:


     $collection = new ArrayCollection();
     new \Doctrine\ORM\PersistentCollection(
				$this->getEntityManager(),
				new ClassMetadata(''),
				 $collection
			);

I get an typ hinting error like
"Expected array, got "Doctrine\Common\Collections\ArrayCollection"

This could be fixed by changing the type hinting for the Doctrine\ORM\PersistentCollection::__constructor
_From:_

     /**
     * Creates a new persistent collection.
     *
     * @param EntityManager $em    The EntityManager the collection will be associated with.
     * @param ClassMetadata $class The class descriptor of the entity type of this collection.
     * @param array       $coll  The collection elements.
     */
    public function __construct(EntityManager $em, $class, $coll)
    {

_To:_

     /**
     * Creates a new persistent collection.
     *
     * @param EntityManager $em    The EntityManager the collection will be associated with.
     * @param ClassMetadata $class The class descriptor of the entity type of this collection.
     * @param \ArrayAccess $coll  The collection elements.
     */
    public function __construct(EntityManager $em, $class, $coll)
    {

Comment by Christophe Coevoet [ 18/Feb/13 ]

There is no typehint in the PersistentCollection constructor. So the issue cannot come from this place (the phpdoc is wrong btw, it expects a Collection, not an array)

Please give the full error, i.e. the message and the location so that we can know where it happens.

Comment by Torsten Granek [ 20/Feb/13 ]

There error is not in the function declaration, it is in the @param in the doc block of the constructor.

Using PHPStorm as IDE i got this error thrown by the IDE it self, not php. (Screenshot will be attached)

Using ZF2 the error is on line 121 at:
vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php

Comment by Torsten Granek [ 20/Feb/13 ]

Using PHPStorm as IDE i got "Expected array, got "Doctrine\Common\Collections\ArrayCollection" thrown by the IDE it self, not php.

Comment by Torsten Granek [ 20/Feb/13 ]

Using PHPStorm as IDE i got "Expected array, got "Doctrine\Common\Collections\ArrayCollection" thrown by the IDE it self, not php.

Comment by Marco Pivetta [ 26/Feb/13 ]

The correct type hint here is `Doctrine\Common\Collections\Collection`.

I'm closing this as invalid, since you shouldn't instantiate a persistent collection on your own. Consider opening a pull request at https://github.com/doctrine/doctrine2 instead if you want to fix the typehint.





[DDC-2255] [Doctrine-Bridge][Console] Entity, Getters and Setters Generating Bug detected in Symfony 2 Framework Created: 24/Jan/13  Updated: 24/Jan/13  Resolved: 24/Jan/13

Status: Closed
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: None
Fix Version/s: None
Security Level: All

Type: Bug Priority: Major
Reporter: Ala Eddine Khefifi Assignee: Marco Pivetta
Resolution: Invalid Votes: 0
Labels: collection


 Description   

Bug found when generation the Entity, Getters and Setters by using the Command:

> php app/console doctrine:generate:entities YourBundleBundle:YourEntity 

In the situation you have a OneToMany relation in the Entity and you did implement the __construct(), then the Console Wont generate the ArrayCollection() !
In the case you did not implement the __construct(), then everything will goes fine when generating them,
Example:

/**
 * @ORM\OneToMany(targetEntity=" YourBundleBundle \Entity\ YourEntity ", mappedBy=" YourEntity ")
 */
private $YourAttribut;

public function __construct()
{
  $this-> YourAttribut = new \Doctrine\Common\Collections\ArrayCollection();
} 
// But in the case you did implement the __construct() before using the Command, let say like this:

public function __construct()
{
  $this-> YourOtherAttribut = a_value;
} 

In this case, when using the Command to generate Entity, Getters and Setters, the Console Wont generate the ArrayCollection() of the OneToMany relations in the __construct() !



 Comments   
Comment by Marco Pivetta [ 24/Jan/13 ]

Ala Eddine Khefifi This is expected behavior, since the generator should not change already existing methods

Comment by Ala Eddine Khefifi [ 24/Jan/13 ]

but it could override them and add missing instruction that should be added within the code, otherwise it leads to a dis-function and non stable relations !!

Comment by Marco Pivetta [ 24/Jan/13 ]

No, that is not up to the generator. Entity generation and fixing your broken existing code are different things. You should not rely on the generator to handle this kind of problems, the generator just gives you a kick-start, but after that, you are on your own.





[DDC-2220] Add joins to Collection Filtering API Created: 03/Jan/13  Updated: 11/Sep/13  Resolved: 11/Sep/13

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: 2.3.1
Fix Version/s: None
Security Level: All

Type: Improvement Priority: Major
Reporter: Oleg Namaka Assignee: Benjamin Eberlei
Resolution: Won't Fix Votes: 2
Labels: api, collection, filtering


 Description   

The recently added collection filtering API only goes half way in achieving a full fledged solution to filter huge collections. It still lacks joins. Look at the next two snippets:

    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('storeId', $store->getId()))
        ->andWhere(Criteria::expr()->eq('Category', 20))
        ->orderBy(array('popularity' => 'DESC'));
    return $this->BrandCategories->matching($criteria);

This piece of code works but what if there is a need to filter the BrandCategories collection by Categories with some extra criteria:

    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('storeId', $store->getId()))
        ->andWhere(Criteria::expr()->eq('Category', 20))
        ->andWhere(Criteria::expr()->eq('Category.name', 'Electronics'))
        ->orderBy(array('popularity' => 'DESC'));
    return $this->BrandCategories->matching($criteria);

That would not work.

Ideally we should have a possibility to join other entities, the Category entity in our case here:

    $criteria = Criteria::create()
        ->where(Criteria::expr()->eq('storeId', $store->getId()))
        ->andWhere(Criteria::expr()->eq('Category', 20))
        ->innerJoin(Criteria::expr()->field('Category', 'Category'))
        ->andWhere(Criteria::expr()->eq('Category.name', 'Electronics'))
        ->orderBy(array('popularity' => 'DESC'));
    return $this->BrandCategories->matching($criteria);

What do you think about it, does it make sense to add such functionality?



 Comments   
Comment by Benjamin Eberlei [ 11/Sep/13 ]

This is not a good idea, because the API has to be small to allow many different implementations, for example the in memory implementation on ArrayCollection, or the implementaiton on MongoDB ODM.





[DDC-2217] Return a lazy collection from PersistentCollection::match($criteria) Created: 31/Dec/12  Updated: 16/May/14  Resolved: 16/May/14

Status: Resolved
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: None
Fix Version/s: 2.5
Security Level: All

Type: Improvement Priority: Major
Reporter: Christophe Coevoet Assignee: Guilherme Blanco
Resolution: Fixed Votes: 8
Labels: collection


 Description   

In 2.3, PersistentCollection::match() has been implemented by doing the query directly. But sometimes, the only meaningful information about the matched collection would be its length. In this case, it would be great to handle it in the same way than extra lazy collections are handled: the matched collection would be initialized lazily, and could do the count in an extra lazy way (if the original collection was extra lazy).
This would of course not change anything in the case where the original collection was already initialized.



 Comments   
Comment by Maciej Klemarczyk [ 20/Sep/13 ]

It will be very usefull, for example to compute count of rows.

In 300 rows, you do not want fetch data from database to compute length of this.

Function matching(Criteria $criteria) fetch too many data for just compute count of rows.

Comment by Christophe Coevoet [ 21/Sep/13 ]

This is exactly the use case I add in mind actually

Comment by Michaƫl Gallego [ 12/Oct/13 ]

+1 on this one! This is absolutely needed when we use the Selectable API as the abstraction for some libraries.





[DDC-2185] Better explain DQL "WITH" and implications for the collection filtering API Created: 04/Dec/12  Updated: 17/Dec/12

Status: Open
Project: Doctrine 2 - ORM
Component/s: Documentation, DQL
Affects Version/s: 2.2
Fix Version/s: None
Security Level: All

Type: Documentation Priority: Major
Reporter: Matthias Pigulla Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: collection, documentation, dql, filtering


 Description   

Available documentation is a bit thin regarding the "WITH" clause on JOIN expressions. Only a single example is provided in

http://docs.doctrine-project.org/en/2.1/reference/dql-doctrine-query-language.html#dql-select-examples

WITH seems to allow to only "partially" load a collection, so the collection in memory does not fully represent the associations available in the database.

The resulting collection is marked as "initialized" and it seems there is no way to tell later on whether/how (with which expression) the collection has been initialized.

When using the collection filtering API, the "initialized" flag on the collection will lead to in-memory processing. If a collection has been loaded WITH a restricting clause and another filter is applied later, results may not be what one might expect.

I assume this is by design (no idea how the collection could be "partially" loaded and behave correctly under all conditions), so filing it as a documentation issue.



 Comments   
Comment by Matthias Pigulla [ 17/Dec/12 ]

An additional observation:

If you eager-load a collection using WITH, for the resulting entities that collection is marked as initialized as described above.

Should you happen to come across the same entity during hydration in another (later) context where you explicitly eager load the same association without the WITH restriction (or with another one), the collection on that (existing) entity won't be re-initialized and still contains the associated objects found during the first query.





Generated at Fri Aug 01 15:59:07 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.