I’m using Doctrine ODM and trying to make a custom mapping type but I’m having some problems.
My mapping type is similar the the collection type but it works with an ArrayCollection instead:
<?php
class ArrayCollectionType extends Type
{
public function convertToDatabaseValue($value)
{
return $value !== null ? array_values($value->toArray()) : null;
}
public function convertToPHPValue($value)
{
return $value !== null ? new ArrayCollection($value) : null;
}
public function closureToMongo()
{
return '$return = $value !== null ? array_values($value->toArray()) : null;';
}
public function closureToPHP()
{
return '$return = $value !== null ? new \Doctrine\Common\Collections\ArrayCollection($value) : null;';
}
}
However when ever I update the document, it doesn’t write changes from the collection; the initial persist works fine. I did some mild debugging to find out that the UnitOfWork isn’t (re)computing the changes.
Here is my test code:
Document:
<?php
namespace Application\Blog\Domain\Document;
use Cob\Stdlib\String,
Doctrine\Common\Collections\ArrayCollection;
/**
* Blog category
*
* @Document(repositoryClass="Application\Blog\Domain\Repository\BlogRepository", collection="blog")
*/
class Category
{
/**
* @Id
*/
private $id;
/**
* @Field(type="arraycollection")
*/
private $slugs;
public function __construct()
{
$this->slugs = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getSlugs()
{
return $this->slugs;
}
public function addSlug($slug)
{
$this->slugs->add($slug);
}
}
Service:
<?php
$category = new Category("Test");
$category->addSlug("testing-slug");
$category->addSlug("another-test");
$this->dm->persist($category);
$this->dm->flush();
$this->dm->clear();
unset($category);
$category = $this->dm->getRepository("Application\Blog\Domain\Document\Category")->findOneBy(array("name" => "Test"));
$category->addSlug("is-it-working");
$this->dm->persist($category);
$this->dm->flush();
var_dump($category->getSlugs());
Expected result:
object(Doctrine\Common\Collections\ArrayCollection)[237]
private '_elements' =>
array
0 => string 'testing-slug' (length=12)
1 => string 'another-test' (length=12)
2 => string 'is-it-working' (length=13)
Actual result
object(Doctrine\Common\Collections\ArrayCollection)[237]
private '_elements' =>
array
0 => string 'testing-slug' (length=12)
1 => string 'another-test' (length=12)
I tried implementing a different change tracking policy but I couldn’t get up updates working.
In the end, I realised it wasn’t detecting changes because objects are passed by reference. So simple updates of the document were going undetected because it was the same reference when comparing against the original document.
The solution is to clone the object when making changes:
In retrospect, although using a change tracking policy of “notify” is more cumbersome, I think it is still a better solution. But for now I will just clone and refactor at a later date.