Skip to content

Instantly share code, notes, and snippets.

@Itach1Uchixa
Last active September 12, 2018 09:37
Show Gist options
  • Save Itach1Uchixa/83fedd850e4705b0b51589afaefdfdf1 to your computer and use it in GitHub Desktop.
Save Itach1Uchixa/83fedd850e4705b0b51589afaefdfdf1 to your computer and use it in GitHub Desktop.
Custom collections with doctrine 2
<?php
// clean but complex way
namespace YourDomain\Entities
{
use Doctrine\Common\Collections\Collection as DoctrineCollection;
/** @MappedSuperclass */
class SomeEntity
{
/**
* @var CustomCollectionInterface
* @OneToManyWhatever(doctrineAnnotationCode)
*/
protected $customCollection;
// keep in mind: further in code we will access to collection using this accessor
protected function getCustomCollection(): CustomCollection
{
return $this->customCollection;
}
}
interface CustomCollectionInterface
{
// collection methods ...
}
}
namespace YourDomain\Infrastructure\ORM\Doctrine
{
use YourDomain\Entities\CustomCollectionInterface;
use Doctrine\Common\Collections\Collection as DoctrineCollection;
// the idea is repository will return this entity
// only when inserting we will have to replace our domain's SomeEntity to this entity
class SomeEntityProxy extends SomeEntity
{
/**
* @var DoctrineImplOfCustomCollection
*/
protected $customCollectionCache;
// little override
protected function getCustomCollection(): CustomCollection
{
if (is_null($this->customCollectionCache) && $this->customCollection instanceof DoctrineCollection) {
$this->customCollectionCache = new DoctrineImplOfCustomCollection($this->customCollection);
}
return $this->customCollectionCache ?? parent::getCustomCollection();
}
}
class DoctrineImplOfCustomCollection implements CustomCollectionInterface
{
/**
* @var DoctrineCollection
*/
protected $items;
public function __construct(DoctrineCollection $collection)
{
// as we will work with reference it will not load all items
$this->items = $collection;
}
// collection methods ...
}
}
<?php
// simple way of using custon collection with doctrine 2
use Doctrine\Common\Collections\Collection as DoctrineCollection;
class SomeEntity
{
/**
* @var CustomCollection
* @OneToManyWhatever(doctrineAnnotationCode)
*/
protected $customCollection;
/**
* @var CustomCollection
*/
protected $customCollectionCache;
// keep in mind: further in code we will access to collection using this accessor
protected function getCustomCollection(): CustomCollection
{
if (is_null($this->customCollectionCache) && $this->customCollection instanceof DoctrineCollection) {
$this->customCollectionCache = CustomCollection::fromCollection($this->customCollection);
}
return $this->customCollectionCache ?? $this->customCollection;
}
}
class CustomCollection
{
/**
* @var Item[]
*/
protected $items;
public function __construct(Item ...$items)
{
$this->items = $items;
}
public static function fromCollection(DoctrineCollection $collection): self
{
$instance = new static();
// our custom collection will reference doctrine's for updates to work
// now you can add, remove items from array and updates will be persisted
// we can use our collection's items property as simple array
// because doctrine's collection is array accessable (isset and etc. functions will work)
// if you need more than just generic array functions then read clean_but_complex.php file in this gist
$instance->items = $collection;
return $instance;
}
// collection logic ...
}
@Arkemlar
Copy link

The simple method is close to my approach https://gist.github.com/Arkemlar/d1dca641e9f6932d37d052af3265a71d
(Sinсe I published this gist I found some bugs/stupid code, but had lack of time to transfer fixes from project code to gist.)

The complex metod seems wierd - overcomplicated and not reliable since Doctrine always will return its own proxy instances (like in case of loading entities through *ToMany relations using collection).

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