web-dev-qa-db-fra.com

"usort" une Doctrine \ Common \ Collections \ ArrayCollection?

Dans divers cas, je dois trier un Doctrine\Common\Collections\ArrayCollection selon une propriété de l'objet. Sans trouver une méthode pour le faire tout de suite, je fais ceci:

// $collection instanceof Doctrine\Common\Collections\ArrayCollection
$array = $collection->getValues();
usort($array, function($a, $b){
    return ($a->getProperty() < $b->getProperty()) ? -1 : 1 ;
});

$collection->clear();
foreach ($array as $item) {
    $collection->add($item);
}

Je suppose que ce n'est pas le meilleur moyen lorsque vous devez tout copier dans le tableau natif PHP et inversement. Je me demande s'il y a une meilleure façon "d'usorter" un Doctrine\Common\Collections\ArrayCollection. Dois-je manquer un doc?

47
luiges90

Pour trier une collection existante, vous recherchez la méthode ArrayCollection :: getIterator () qui renvoie un ArrayIterator. Exemple:

$iterator = $collection->getIterator();
$iterator->uasort(function ($a, $b) {
    return ($a->getPropery() < $b->getProperty()) ? -1 : 1;
});
$collection = new ArrayCollection(iterator_to_array($iterator));

Le moyen le plus simple serait de laisser la requête dans le référentiel gérer votre tri.

Imaginez que vous ayez une SuperEntity avec une relation ManyToMany avec des entités de catégorie.

Ensuite, par exemple, créer une méthode de référentiel comme celle-ci:

// Vendor/YourBundle/Entity/SuperEntityRepository.php

public function findByCategoryAndOrderByName($category)
{
    return $this->createQueryBuilder('e')
        ->where('e.category = :category')
        ->setParameter('category', $category)
        ->orderBy('e.name', 'ASC')
        ->getQuery()
        ->getResult()
    ;
}

... facilite le tri.

J'espère que ça t'as aidé.

92

Depuis Doctrine 2.3 vous pouvez utiliser Criteria API

Par exemple:

<?php

public function getSortedComments()
{
    $criteria = Criteria::create()
      ->orderBy(array("created_at" => Criteria::ASC));

    return $this->comments->matching($criteria);
}

Remarque: cette solution nécessite un accès public à la propriété $createdAt Ou à une méthode getter publique getCreatedAt().

45
ioleo

Si vous avez un champ ArrayCollection, vous pouvez commander avec des annotations. par exemple:

Supposons qu'une entité nommée Society possède de nombreuses licences. Vous pourriez utiliser

/**
* @ORM\OneToMany(targetEntity="License", mappedBy="society")
* @ORM\OrderBy({"endDate" = "DESC"})
**/
private $licenses;

Cela ordonnera ArrayCollection par endDate (champ datetime) dans l'ordre desc.

Voir Doctrine: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#orderby =

20
akrz