【问题标题】:Doctrine 2 Sortable教义 2 可排序
【发布时间】:2010-11-18 17:33:19
【问题描述】:

客户需要根据需要更改商品的顺序,这意味着我需要一些“订单”或“顺序”列来保存每个商品的实际位置。

如何使用 Doctrine 2 来实现这一点?

【问题讨论】:

  • 您找到解决方案了吗?我现在正在寻找这个,想知道你最终使用的是什么?

标签: php doctrine-orm jquery-ui-sortable


【解决方案1】:

我会使用 Doctrine 的 event system 来实现它。要添加行为,我通常会编写一个事件订阅者并使用我的实体类实现的接口来强制执行规则。我在某处的服务对象中保存的实际逻辑(您需要自己处理)。

use Doctrine\Common\EventSubscriber,
    Doctrine\ORM\Events,
    Doctrine\ORM\Event\LifecycleEventArgs,
    Doctrine\ORM\Event\PreUpdateEventArgs;


class SortableBehavior implements EventSubscriber
{
   public function getSubscribedEvents()
   {
      return array(Events::prePersist, Events::preUpdate);
   }

   public function prePersist(LifeCycleEventsArgs $args)
   {
     // the entity being persisted
     $entity = $args->getEntity();
     if ($entity instanceof SortableInterface) {
        //perform sorting magic
     }
   }

   public function preUpdate(preUpdateEventsArgs $args)
   {
     // the entity being updated
     $entity = $args->getEntity();
     if ($entity instanceof SortableInterface) {
        //perform sorting magic
     }
   }
}

在引导您的应用时不要忘记注册订阅者:

$eventManager = $entityManager->getEventManager();
$eventManager->addEventSubscriber(new SortableBehavior());

【讨论】:

  • 所以排序魔法是获取存储库,然后是所有其他实体并增加(或减少)其中一些实体的 sort_order 值?性能呢?我需要再次加载并保存所有实体。如果没有 Doctrine,我可以使用单个 UPDATE sql 查询。
  • 如果要采取UPDATE查询方式,可以使用D2的NativeQuery对象。作为 ORM,Doctrine 的默认方法是使用您的实体,这将涉及首先从数据库中获取它们。使用 Doctrine 提供的各种缓存可以提高性能。
【解决方案2】:

在 GitHub 上有一个不错的存储库,其中包含 Doctrine 的各种扩展,其中一个只是一个可排序的功能。

检查一下: https://github.com/l3pp4rd/DoctrineExtensions

Sortable documentation

【讨论】:

    【解决方案3】:

    添加另一列:

    排序: 类型:整数(4) 默认值:10

    现在将该条目从 10 更改为其他任何值都会将其移动到结果集中,这将通过以下方式检索:

    $this->result = Doctrine_Core::getTable('CustomerTable') ->createQuery('a')->orderBy("a.sort_order asc, a.id desc")->execute();

    【讨论】:

    • 不。不是我的意思。我有像 1、2、3、4、5 这样的顺序。现在用户(使用拖放)例如将项目 2 移动到位置 4,所以我需要进行如下更改:2->4、3->2、 4->3
    • 您仍然需要一个排序列来存储该订单。我会将排序列设置为默认主键 id,然后在您拖动它们时交换排序列值。
    • 当然可以,但是如何自动进行这些更改呢?理想的方法是设置 $entity->order = 5; $em->flush();其他实体应该会自动更改。
    • 自动?意思是如果 $entity->order == 5 它在第 5 位?你必须有一些其他值来比较它,否则 $entity->order = 5 并没有多大意义。
    • 嗯。你根本没有得到它。我想更改订单,而不是检索有序数据。所以真的只有一个“=”。你甚至使用 Doctrine 2 吗?!
    【解决方案4】:

    您可以自动检索按给定字段排序的集合:

    http://www.doctrine-project.org/projects/orm/2.0/docs/reference/association-mapping/en#ordering-to-many-collections

    这样您就可以使用“sort_order”列定义顺序。然后,出于性能原因,您需要一些方法来使用 DQL 更新语句正确更新排序列,即“moveTo($pos, $entity)”并发出相关数量的更新。

    但是,如果您必须在同一请求中迭代集合,因为顺序已更改,这可以解决一半的问题。然而,这很少见,因此通常可以忽略。

    【讨论】:

    • 我知道,正如你所说,我正在使用“sort_order”列,但最好不要编写这些更新方法并使用一些学说行为来自动化它。
    【解决方案5】:

    我对 EventSubscriber 进行了一些测试,但无法使其正常工作,因此我决定直接将代码添加到我的课程中 (q&d)。我使用 Zend 框架,所以如果您有不同的解决方案,请更改实体管理器的获取。

    它的工作原理如下:

    1. 创建实体时使用 getLast() 并最后添加新实体 ($last_entity->getSort() + 1)
    2. 将 sortUp 和 sortDown 函数及其子程序添加到实体代码中
    3. 在您希望排序的所有 DQL 查询中添加“排序 ASC”

    实体代码如下:

    /**
     * Searches for the element above and switches them
     * with eachother. Performs a EntityManager::flush()
     * to save the results after the switch.
     */
    public function sortUp() {
    
        try {
            $em = \Zend_Registry::get("entitymanager");
    
            $class_name = get_class($this);
            $dql = "SELECT ut FROM $class_name ut WHERE ut.inactive IS NULL AND ut.inactive IS NULL AND ut.sort < '" . $this->getSort() . "' ORDER BY ut.sort DESC";
            $query = $em->createQuery($dql);
            $query->setMaxResults(1);
            $ut = $query->getResult();
        } catch (Exception $exc) {
            throw new Exception("Error when looking for sortable partner: " . $exc->getMessage());
        }
    
        if (count($ut)) {
            $this->_switchSortAndSave($ut[0]);
        }
    }
    
    /**
     * Searches for the element below and switches them
     * with eachother. Performs a EntityManager::flush()
     * to save the results after the switch.
     */
    public function sortDown() {
        try {
            $em = \Zend_Registry::get("entitymanager");
    
            $class_name = get_class($this);
            $dql = "SELECT ut FROM $class_name ut WHERE ut.inactive IS NULL AND ut.sort > '" . $this->getSort() . "' ORDER BY ut.sort ASC";
            $query = $em->createQuery($dql);
            $query->setMaxResults(1);
            $ut = $query->getResult();
        } catch (Exception $exc) {
            throw new Exception("Error when looking for sortable partner: " . $exc->getMessage());
        }
    
    
        if (count($ut)) {
            $this->_switchSortAndSave($ut[0]);
        }
    }
    
    private function _switchSortAndSave(\Entities\Usertype $switch_entity) {
        $new_sort = $switch_entity->getSort();
        $switch_entity->setSort($this->getSort());
        $this->setSort($new_sort);
    
        $em = \Zend_Registry::get("entitymanager");
        $em->persist($switch_entity);
        $em->persist($this);
        $em->flush();
    }
    
    /**
     * Looks for the last entry according to sort order
     * and returns that if found.
     * 
     * @return Entity|null
     */
    public static function findLast() {
        try {
            $em = \Zend_Registry::get("entitymanager");
    
            $class_name = get_called_class();
            $dql = "SELECT ut FROM $class_name ut ORDER BY ut.sort DESC";
            $query = $em->createQuery($dql);
            $query->setMaxResults(1);
            $ut = $query->getResult();
        } catch (Exception $exc) {
            throw new Exception("Error when searching for last $class_name: " . $exc->getMessage());
        }
    
        if (count($ut))
            return $ut[0];
        else
            return null;
    }
    

    我对这个解决方案不太满意,所以如果有人为 Doctrine 2 提供了一个不错的 Sortable,请分享 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-13
      • 2015-09-04
      • 1970-01-01
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      • 2012-07-20
      相关资源
      最近更新 更多