Skip to content

Instantly share code, notes, and snippets.

@marijn
Created April 3, 2012 16:53
Show Gist options
  • Save marijn/2293613 to your computer and use it in GitHub Desktop.
Save marijn/2293613 to your computer and use it in GitHub Desktop.
An example on sorting Doctrine\Common\Collection\ArrayCollection elements
<?php
$collection = new Doctrine\Common\Collection\ArrayCollection();
// add objects to the collection that contain a getCreated method returning a DateTime instance
$iterator = $collection->getIterator();
$iterator->uasort(function ($first, $second) {
if ($first === $second) {
return 0;
}
return (float) $first->getCreated()->format("U.u") < (float) $second->getCreated()->format("U.u") ? -1 : 1;
});
@calumbrodie
Copy link

Why cast to float? You can use the gt directly with the DateTime objects...

return (bool) $first->getCreated() < $second->getCreated();

@umpirsky
Copy link

And back to array collection with:

new ArrayCollection(iterator_to_array($iterator));

@marijn
Copy link
Author

marijn commented Aug 3, 2014

@calumbrodie: Sorry, I never saw your response. I believe the cast was there because the milliseconds were otherwise not taken into account. I'm not sure though.

@marijn
Copy link
Author

marijn commented Aug 3, 2014

@umpirsky: Sorry, I never saw your response. Thanks that's a nice addition.

@AdamReece-WebBox
Copy link

Better late than never... This may be of use to someone else.

Thanks for the above advice. I put it in a PostLoad life-cycle callback so this is done implicitly after the entity is loaded. Obviously you wouldn't need an OrderBy at all as the sort logic is just being shifted from SQL to PHP.

In my case I have a bunch of "thing", of which is many-to-many with Region. There is a ThingRegion entity sitting between the two with independent properties about their relationship, so my link is really one-to-many-to-one rather than a logical many-to-many.

I needed the regions to be sorted by name from the thing perspective, so did this in the Thing class:

/**
 * @ORM\PostLoad
 * @return void
 */
public function sortThingRegions()
{
    if (!($this->thingRegions instanceof \Doctrine\Common\Collections\Collection)) {
        return;
    }

    $iterator = $this->thingRegions->getIterator();

    $iterator->uasort(function($a, $b){

        if ($a === $b) {
            return 0;
        }

        return $a->getRegion()->getName() < $b->getRegion()->getName() ? -1 : 1;

    });

    $this->thingRegions = new ArrayCollection(iterator_to_array($iterator));
}

Afterwhich getThingRegions() returns a collection sorted as intended. You could also add PrePersist and PreUpdate life-cycle callbacks if you want the sort to happen just before saving, if that matters.

(Name of "Thing" obscured to protect client identity.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment