Matt Welander
Matt Welander

Reputation: 8548

how to sort an entity's arrayCollection in symfony2

I have an entity "container" with this property

/**
 * @ORM\OneToMany(targetEntity="BizTV\ContentManagementBundle\Entity\Content", mappedBy="container")
 */
private $content;

the property is an array collection...

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

...with these two standard methods

/**
 * Add content
 *
 * @param BizTV\ContentManagementBundle\Entity\Content $content
 */
public function addContent(\BizTV\ContentManagementBundle\Entity\Content $content)
{
    $this->content[] = $content;
}

/**
 * Get content
 *
 * @return Doctrine\Common\Collections\Collection 
 */
public function getContent()
{
    return $this->content;
}

Now my question is, is there a smooth way to build a sorting feature into this, perhaps on the getContent() call? I am no php wiz and certainly not seasoned in symfony2 but I learn as I go.

The content entity itself has a sorting INT like this that I want to sort it on:

/**
 * @var integer $sortOrder
 *
 * @ORM\Column(name="sort_order", type="integer")
 */
private $sortOrder; 

Upvotes: 35

Views: 58954

Answers (4)

HelpNeeder
HelpNeeder

Reputation: 6480

You can also sort ArrayCollection by Criteria property orderBy like so:

<?php
    namespace App/Service;

    use Doctrine\Common\Collections\ArrayCollection;
    use Doctrine\Common\Collections\Criteria;

    /**
     * Class SortService
     *
     * @package App\Service
     */
    class SortService {
        /**
         * @param SomeAbstractObject $object
         * @return SomeCollectionItem[]
         */
        public function sorted(SomeAbstractObject $object): array {
            /** $var ArrayCollection|SomeCollectionItem[] */
            $collection = $object->getCollection();

            // convert normal array to array collection object
            if(\is_array(collection)) {
                $collection = new ArrayCollection(collection);
            }

            // order collection items by position property
            $orderBy = (Criteria::create())->orderBy([
                'position' => Criteria::ASC,
            ]);

            // return sorted SomeCollectionItem array
            return $collection->matching($orderBy)->toArray();
        }
    }
?>

Upvotes: 3

Wouter van Vliet
Wouter van Vliet

Reputation: 1524

If you want to be sure that you always get your relations in the order based on current property values, you can do something like this:

$sort = new Criteria(null, ['Order' => Criteria::ASC]);
return $this->yourCollectionProperty->matching($sort);

Use that for example if you've changed the Order property. Works great for a "Last modified date" as well.

Upvotes: 24

You can write

@ORM\OrderBy({"date" = "ASC", "time" = "ASC"})

for multiple criteria ordering.

Upvotes: 16

Luke
Luke

Reputation: 3353

You should be able to use the @ORM\OrderBy statement which allows you to specify columns to order collections on:

/**
 * @ORM\OneToMany(targetEntity="BizTV\ContentManagementBundle\Entity\Content", mappedBy="container")
 * @ORM\OrderBy({"sort_order" = "ASC"})
 */
private $content;

In fact this may be a duplicate of How to OrderBy on OneToMany/ManyToOne

Edit

Checking for implementation advice it appears that you must fetch the tables with a join query to the collection in order for the @ORM\OrderBy annotation to work: http://www.krueckeberg.org/notes/d2.html

This means that you must write a method in the repository to return the container with the contents table joined.

Upvotes: 77

Related Questions