Sortable behavior will maintain a position field for ordering entities.
Features:
- Automatic handling of position index
- Group entity ordering by one or more fields
- Can be nested with other behaviors
- Annotation, Yaml and Xml mapping support for extensions
Note:
- Public Sortable repository is available on github
- Last update date: 2012-01-02
Portability:
- Sortable is now available as Bundle ported to Symfony2 by Christophe Coevoet, together with all other extensions
This article will cover the basic installation and functionality of Sortable behavior
Content:
- Including the extension
- Entity example
- Yaml mapping example
- Xml mapping example
- Basic usage examples
- Custom comparison method
Read the documentation or check the example code on how to setup and use the extensions in most optimized way.
- @Gedmo\Mapping\Annotation\SortableGroup it will use this field for grouping
- @Gedmo\Mapping\Annotation\SortablePosition it will use this column to store position index
Note: that Sortable interface is not necessary, except in cases there you need to identify entity as being Sortable. The metadata is loaded only once then cache is activated
Note: that you should register SortableRepository (or a subclass) as the repository in the Entity annotation to benefit from its query methods.
<?php
namespace Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name="items")
* @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
*/
class Item
{
/** @ORM\Id @ORM\GeneratedValue @ORM\Column(type="integer") */
private $id;
/**
* @ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
* @Gedmo\SortablePosition
* @ORM\Column(name="position", type="integer")
*/
private $position;
/**
* @Gedmo\SortableGroup
* @ORM\Column(name="category", type="string", length=128)
*/
private $category;
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function setPosition($position)
{
$this->position = $position;
}
public function getPosition()
{
return $this->position;
}
public function setCategory($category)
{
$this->category = $category;
}
public function getCategory()
{
return $this->category;
}
}
Yaml mapped Item: /mapping/yaml/Entity.Item.dcm.yml
---
Entity\Item:
type: entity
table: items
id:
id:
type: integer
generator:
strategy: AUTO
fields:
name:
type: string
length: 64
position:
type: integer
gedmo:
- sortablePosition
category:
type: string
length: 128
gedmo:
- sortableGroup
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:gedmo="http://gediminasm.org/schemas/orm/doctrine-extensions-mapping">
<entity name="Entity\Item" table="items">
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
</id>
<field name="name" type="string" length="128">
</field>
<field name="position" type="integer">
<gedmo:sortable-position/>
</field>
<field name="category" type="string" length="128">
<gedmo:sortable-group />
</field>
</entity>
</doctrine-mapping>
<?php
// By default, items are appended to the sorting list
$item1 = new Item();
$item1->setName('item 1');
$item1->setCategory('category 1');
$this->em->persist($item1);
$item2 = new Item();
$item2->setName('item 2');
$item2->setCategory('category 1');
$this->em->persist($item2);
$this->em->flush();
echo $item1->getPosition();
// prints: 0
echo $item2->getPosition();
// prints: 1
<?php
$item1 = new Item();
$item1->setName('item 1');
$item1->setCategory('category 1');
$this->em->persist($item1);
$item2 = new Item();
$item2->setName('item 2');
$item2->setCategory('category 1');
$this->em->persist($item2);
$item0 = new Item();
$item0->setName('item 0');
$item0->setCategory('category 1');
$item0->setPosition(0);
$this->em->persist($item0);
$this->em->flush();
$repo = $this->em->getRepository('Entity\\Item');
$items = $repo->getBySortableGroupsQuery(array('category' => 'category 1'))->getResult();
foreach ($items as $item) {
echo "{$item->getPosition()}: {$item->getName()}\n";
}
// prints:
// 0: item 0
// 1: item 1
// 2: item 2
<?php
$item1 = new Item();
$item1->setName('item 1');
$item1->setCategory('category 1');
$this->em->persist($item1);
$item2 = new Item();
$item2->setName('item 2');
$item2->setCategory('category 1');
$this->em->persist($item2);
$this->em->flush();
// Update the position of item2
$item2->setPosition(0);
$this->em->persist($item2);
$this->em->flush();
$repo = $this->em->getRepository('Entity\\Item');
$items = $repo->getBySortableGroupsQuery(array('category' => 'category 1'))->getResult();
foreach ($items as $item) {
echo "{$item->getPosition()}: {$item->getName()}\n";
}
// prints:
// 0: item 2
// 1: item 1
If you want to use a foreign key / relation as sortable group, you have to put @Gedmo\SortableGroup annotation on ManyToOne annotation:
/**
* @Gedmo\SortableGroup
* @ORM\ManyToOne(targetEntity="Item", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $parent;
To move an item at the end of the list, you can set the position to -1
:
$item2->setPosition(-1);
Sortable works by comparing objects in the same group to see how they should be positioned. From time to time you may want to customize the way these objects are compared by simply implementing the Doctrine\Common\Comparable interface
<?php
namespace Entity;
use Doctrine\Common\Comparable;
/**
* @ORM\Table(name="items")
* @ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
*/
class Item implements Comparable
{
public function compareTo($other)
{
// return 1 if this object is considered greater than the compare value
// return -1 if this object is considered less than the compare value
// return 0 if this object is considered equal to the compare value
}
}