34

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; 
Matt Welander
  • 8,234
  • 24
  • 88
  • 138
  • For now I have solved my particular problem with TinySort jQuery plugin (http://tinysort.sjeiti.com/), but it would be nicer to have the data come out right if I can. – Matt Welander Jan 11 '13 at 17:00

4 Answers4

75

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.

Community
  • 1
  • 1
Luke
  • 3,333
  • 2
  • 28
  • 44
  • Seem that that guy didn't get it to work either, he ended up with a twig extension to get it rendered in a sorted manner in the view... – Matt Welander Jan 11 '13 at 17:05
  • Since the linked question also remains unresolved, perhaps this is not an instance where I can use the ORM OrderBy? I added it like you said, but nothing changes (I also tried writing a field name that doesn't exist, still no error or nothing, so is it even included/a valid command?). – Matt Welander Jan 11 '13 at 17:27
  • Yes orderBy is a valid command, I have used it in a micro cms I have written in Symfony2 http://lrotherfield.com/blog/order-by-onetomany-relationships-symfony2/. Here is the start of the entity: http://pastie.org/5682072 and as you can see the children relationship is ordered by the lft column. This is working in my entity, maybe you could paste up your whole entity for me? – Luke Jan 14 '13 at 09:57
  • You need to join the content table in your fetch query for the annotation to work, see edits above – Luke Jan 14 '13 at 12:19
  • Ah, that's why we don't get it to work :-) thanks, I'll read up on that, great link. – Matt Welander Jan 15 '13 at 15:49
  • orderBy seemed to work fine for me in my .yml entity definition http://docs.doctrine-project.org/en/latest/tutorials/ordered-associations.html – targnation Apr 07 '13 at 02:17
  • $this->course = $em->getRepository('UnswCamsBundle:Course')->find($course); with @ORM\OrderBy({"number" = "ASC"}) works fine for me. – Interlated Jan 06 '16 at 01:34
  • @Interlated thanks for the update, this answer is 3 years old so it may be that there is no requirement for joins anymore which is why you have it working. May be worth checking the source for how the annotation works :) – Luke Jan 06 '16 at 12:41
  • In fact you can write @ORM\OrderBy({"date" = "ASC", "time" = "ASC"}) for multiple criteria ordering. – Yasmany Hernandez Hernandez Jan 12 '16 at 21:20
24

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.

Wouter van Vliet
  • 1,484
  • 11
  • 20
  • fyi: `Criteria` can't handle relations, only properties of the concerning entity itself. – NDM Jul 16 '15 at 08:39
  • This was easiest and efficient way to sort my self referencing MenuTree entity that is fetched EAGERly – jmwierzbicki Oct 13 '17 at 12:07
  • Additionnal notice: if your property is private and has a public accessor, you have to write your property's string FullCased because the matching() method, to guess the public accessor method name, adds a "get" in front of the name of your property, without Uppercasing-it. – bohr Nov 09 '17 at 15:58
16

You can write

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

for multiple criteria ordering.

Gottlieb Notschnabel
  • 9,408
  • 18
  • 74
  • 116
2

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();
        }
    }
?>
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
HelpNeeder
  • 6,383
  • 24
  • 91
  • 155