客户需要根据需要更改项目的顺序,这意味着我需要一些“订单”或“序列”列来保存每个项目的实际位置。
如何使用 Doctrine 2 来实现这一点?
客户需要根据需要更改项目的顺序,这意味着我需要一些“订单”或“序列”列来保存每个项目的实际位置。
如何使用 Doctrine 2 来实现这一点?
GitHub 上有一个不错的存储库,其中包含 Doctrine 的各种扩展,其中一个只是一个可排序的功能。
我会使用 Doctrine 的事件系统来实现它。要添加行为,我通常会编写一个事件订阅者并使用我的实体类实现的接口来执行规则。我将实际逻辑保存在某处的服务对象中(为此,您需要自己做)。
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());
添加另一列:
排序: 类型:整数(4) 默认值:10
现在将该条目从 10 更改为其他任何内容都会将其移动到结果集中,这将通过以下方式检索:
$this->result = Doctrine_Core::getTable('CustomerTable') ->createQuery('a')->orderBy("a.sort_order asc, a.id desc")->execute();
您可以自动检索按给定字段排序的集合:
这样,您可以使用“sort_order”列定义顺序。然后,出于性能原因,您需要一些方法来使用 DQL 更新语句正确更新排序列,即“moveTo($pos, $entity)”并发出相关数量的更新。
但是,如果您必须在同一请求中迭代集合,因为顺序已更改,这解决了您的一半问题。然而,这很少见,因此通常可以忽略。
我对 EventSubscriber 进行了一些测试,但无法使其正常工作,因此我决定直接将代码添加到我的课程中(q&d)。我使用 Zend 框架,因此如果您有不同的解决方案,请更改实体管理器的获取。
它的工作原理如下:
实体代码如下:
/**
* 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,请分享:)