Doctrine嵌入文档按键维护顺序

时间:2016-05-26 20:04:41

标签: php symfony sorting doctrine arraycollection

我在symfony2中有一个带有嵌入文档的mongodb文档:

/** 
 * @MongoDB\EmbedMany(targetDocument="Restriction")
 */
private $restrictions = array();

public function __construct()
{
    $this->restrictions = new \Doctrine\Common\Collections\ArrayCollection();
}

限制文档有两个属性。 from_pos和长度。我希望这个数组总是按from_pos排序,因此在整个应用程序中,我将始终确保此列表已排序。

有一种简单的方法可以自动执行此操作吗?我的意思是,调用addRestriction函数,这将自动保存在按我想要的键排序的mongodb数据库中。

目前,addRestriction函数只是将新文档添加到列表的末尾。

/**
 * Add restriction
 *
 * @param MyBundle\Document\Restriction $restriction
 */
public function addRestriction(\MyBundle\Document\Restriction $restriction)
{
    $this->restrictions[] = $restriction;
}

我可以更新此功能以将限制插入所需位置,但我想知道是否有最简单的方法。

1 个答案:

答案 0 :(得分:0)

解决方案是使用自定义集合。

http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/custom-collections.html

这是我开发的SortedCollection类。添加元素时,只需将其放在正确的位置并切片其他元素。

<?php

use Doctrine\Common\Collections\ArrayCollection;

/**
 * Array collection with elements alwais in order
 */
class SortedCollection extends ArrayCollection{

    /**
     * Interrnal flag to avoid recursive call to reindex function while reindexing
     * @var boolean
     */
    protected $reindexing = false;

    public function add($value){
        $it = $this->getIterator();
        while($it->valid() && $it->current()->compareTo($value) < 0){
            $it->next();
        }

        // slice elements
        $prev = $value;
        while ($it->valid()){
            // Save current element
            $aux = $it->current();

            // Add previous element
            $this->offsetSet($it->key(), $prev);

            // Set previous element to current for next iteration
            $prev = $aux;
            $it->next();
        }

        // Add final element
        parent::add($prev);

        return true;
    }
}

在Document中,只需在构造函数中设置SortedCollection类。

<?php

class MyDocument
{
    /** 
     * @MongoDB\EmbedMany(
     *     collectionClass="SortedCollection",
     *     targetDocument="...."
     * )
     */
    private $sorted_list = array();

    public function __construct()
    {
        $this->sorted_list = new SortedCollection();
    }
}