LupusVagans
LupusVagans

Reputation: 35

Sort a ManyToMany relation by a column of a joined table

Is it possible to order a ManyToMany relation by a column of a joined table in an entity with annotations?

I‘ve already tried to get it work with @ORM\JoinTable and @ORM\JoinColumn but this doesn‘t seem to work.

class Product {
    /**
     * @ORM\ManyToMany(targetEntity="App\Entity\Category")
     * @ORM\OrderBy({"name" = "ASC"})
     */
    private $categories;
}
class Category {
    use Knp\Translatable;
}
class CategoryTranslation {
    use Knp\Translation;
    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;
}

I would like to do something like @OrderBy({"CategoryTranslation.name" = "ASC") in the Product entity. Or is there a way to execute a repository method in the @ManyToMany annotation to manually build a query to select the categories with the right order?

Upvotes: 1

Views: 510

Answers (2)

LupusVagans
LupusVagans

Reputation: 35

I finally solved it the way @ehymel described in his answer but i am using the uasort method of the ArrayIterator object. Im not very happy with this solution because an additional $locale parameter is used in the getter method and i would prefere to order the items with SQL/DQL but not an additional PHP loop. But for the moment it works.

public function getCategories(?string $locale = null)
{
    $iterator = $this->categories->getIterator();
    $iterator->uasort(function (Category $a, Category $b) use ($locale) {
        return ($a->translate($locale)->getName() < $b->translate($locale)->getName()) ? -1 : 1;
    });

    return new ArrayCollection(iterator_to_array($iterator));
}

Upvotes: 1

ehymel
ehymel

Reputation: 1391

Not sure you can do it through annotations, but I've achieved the result you are looking for with a simple uasort function. In your Product entity try something like the following for your getCategories() getter.

public function getCategories()
{
    $categories = $this->categories;

    uasort($catetories, [$this, 'mySortCategories']);

    return $categories;
}

private function mySortCategories(Category $cat1, Category $cat2)
{
    if ($cat1->getName() === $cat2->getName()) {
        return 0;
    }
    return ($cat1->getName() < $cat2->getName()) ? -1 : 1;
}

Upvotes: 2

Related Questions