Сортировка отношения ManyToMany по столбцу объединенной таблицы

Можно ли упорядочить отношение ManyToMany по столбцу объединенной таблицы в сущности с аннотациями?

Я уже пытался заставить его работать с @ORM\JoinTable и @ORM\JoinColumn, но, похоже, это не работает.

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;
}

Я хотел бы сделать что-то вроде @OrderBy({"CategoryTranslation.name" = "ASC") в объекте Product. Или есть способ выполнить метод репозитория в аннотации @ManyToMany, чтобы вручную создать запрос для выбора категорий в правильном порядке?

Я бы сказал, что единственный способ добиться этого (в db) - использовать DQL. CategoryTranslation.name «волшебным образом» требует, чтобы перевод всегда был соединен (что, по иронии судьбы, вероятно, так и есть). Однако ассоциация по умолчанию, по-видимому, называется translations, так что вы можете попробовать translations.name и посмотреть, приживется ли она. тем не менее, один ко многим, как известно, неуклюж, когда дело доходит до подполей, поэтому я уверен, что это не сработает.

Jakumi 10.05.2019 07:59

@Jakumi Я провел несколько тестов, и, к сожалению, как вы упомянули, ни один из двух методов не работал. Я бы все же предпочел сортировать категории с помощью аннотаций (SQL), а не выполнять дополнительный цикл с PHP в геттере. Знаете ли вы, есть ли способ выполнить метод репозитория для получения категорий? Или, может быть, я мог бы написать пользовательскую аннотацию, чтобы расширить аннотацию Doctrine @OrderBy.

LupusVagans 11.05.2019 09:33

Я бы, наверное, попробовал так: symfonycasts.com/screencast/doctrine-relations/… внутри Product::getCategories и надеюсь, что translations.name там работает. Однако имейте в виду, что это имеет смысл только при работе только с одним продуктом, иначе вы рискуете получить проблему n+1. Но по сути, с проблемой n+1 вам просто нужно использовать критерии в другом месте (в специальной функции репозитория для продуктов).

Jakumi 11.05.2019 11:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
3
340
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Не уверен, что вы можете сделать это с помощью аннотаций, но я добился нужного вам результата с помощью простой функции uasort. В вашей сущности Product попробуйте что-то вроде следующего для вашего getCategories() геттера.

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;
}

Хотя я бы предпочел способ решения этой проблемы с помощью аннотаций, в настоящее время это единственное решение, которое я нашел и сработало для меня. Спасибо @ehymel. Для дальнейшего использования и людей, у которых есть такая же проблема, я сам опубликовал ответ, чтобы показать, как я наконец решил ее.

LupusVagans 11.05.2019 09:38

Наконец-то я решил это так, как @ehymel описал в своем ответе, но я использую метод uasort объекта ArrayIterator. Я не очень доволен этим решением, потому что в методе получения используется дополнительный параметр $locale, и я бы предпочел упорядочивать элементы с помощью SQL/DQL, а не дополнительного цикла PHP. Но на данный момент это работает.

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));
}

Другие вопросы по теме