Сортировка коллекции @OneToMany ArrayCollection доктрины по полю

Близкий вопрос был введите сюда описание ссылки, но мне нужна более глубокая сортировка:

/**
 * @var ArrayCollection[SubjectTag]
 *
 * @ORM\OneToMany(targetEntity = "SubjectTag", mappedBy = "subject")
 * @ORM\OrderBy({"position" = "ASC"})
 * @Assert\Valid()
 */
protected $subjectTags;

В subjectTag у меня есть:

/**
 * @var ArrayCollection[tag]
 *
 * @ORM\OneToMany(targetEntity = "Tag", mappedBy = "subject")
 * @ORM\OrderBy({"name" = "ASC"})
 * @Assert\Valid()
 */
protected $tags;

Теперь я хочу отсортировать по SubjectTag.tags. Как я могу это сделать?

Обновлено:

Entity1.php: /** * @ORM\ManyToOne(targetEntity="Entity2", referencedColumnName="id", nullable=false) * @Утверждение\Действительно() */ защищенный объект $entity2;

Entity2.php: /** * @ORM\ManyToOne(targetEntity="Entity3", referencedColumnName="id", nullable=false) * @Утверждение\Действительно() */ защищенный объект $entity3;

Entity3.php:

/**
 * @ORM\Column(type = "integer", nullable=true)
 */
protected $position;

А теперь .. Я хочу иметь в Entity1 Entity2 отсортированные по положению. Как я могу сделать это по умолчанию?

Я предлагаю вам сделать собственный запрос в вашем репозитории, чтобы сделать что-то более гибкое. Эта аннотация позволяет вам быстро получить порядок результатов по свойству, не добавляя subjectTags к исходному результату запроса, но у вас возникнет проблема n+1, если вы все равно захотите упорядочить по $tags. Если вы дадите более подробную информацию, я смогу показать вам, как это сделать, в ответе.

Florian Hermann 10.04.2019 11:30

@FlorianHermann, не могли бы вы привести пример с этими пользовательскими запросами и запустить его в сущности? или может я что-то не так понимаю?

WEBCENTER 10.04.2019 11:44
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
1
2
484
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Как объяснялось в моем предыдущем комментарии, вы должны выполнить собственный запрос в своем классе репозитория, соответствующем вашей базовой сущности (вы не указали его имя).

Итак, в вашем классе App\Repository\"YourBaseENtityName"Repository вы делаете что-то вроде этого.

public function findOrderByTags()
{
    return $this
        ->createQueryBuilder('baseEntityAlias')
        ->addSelect('st')
        ->addSelect('t')
        ->leftJoin('baseEntityAlias.subjectTags', 'st')
        ->leftJoin('st.tags', 't')
        ->orderBy('st.position', 'ASC')
        ->addOrderBy('t.name', 'ASC')
        ->getQuery()
        ->getResult();
}

Более того, я не уверен в том, какой заказ вы хотите выполнить на основе вашего вопроса. Здесь теги baseEntity->subjectTags будут упорядочены по их позициям, а затем теги baseEntity->subjectTags-> будут упорядочены по имени.

Теперь вы можете вызвать этот метод из вашего базового класса репозитория сущностей.

Надеюсь, это будет полезно для вас.


Обновлено: Вот способ ввести поведение по умолчанию для вашего queryBuilder и повторно использовать его.

/**
 * In your EntityRepository add a method to init your query builder
 */
public function createDefaultQueryBuilder(string $alias = 'a')
{
    return $this
        ->createQueryBuilder($alias)
        ->addSelect('st')
        ->addSelect('t')
        ->leftJoin('baseEntityAlias.subjectTags', 'st')
        ->leftJoin('st.tags', 't')
        ->orderBy('st.position', 'ASC')
        ->addOrderBy('t.name', 'ASC');
}

/**
 * In this example, I override the default find method. I don't recommend it thought
 */
public function find($id, $lockMode = null, $lockVersion = null)
{
    return $this
        ->createDefaultQueryBuilder()
        ->where('a.id = :id')
        ->setParameter('id', $id)
        ->getQuery()
        ->getOneOrNullResult();
}

Как вы можете видеть, я повторно использую метод createDefaultQueryBuilder, чтобы получить поведение по умолчанию с subjectTags и тегами, инициализированными в отношении и упорядоченными в правильном порядке.

Но теперь мне нужно сделать $entity->findOrderByTags(), чтобы отсортировать все теги по положению, верно? Разве я не могу просто отсортировать сущности? Я имею в виду, что если я получу список сущностей, мне нужно сделать foreach, а затем заменить теги в сущности на то, что я получаю от findOrderByTags?

WEBCENTER 10.04.2019 15:20

может быть, мне нужно только установить порядок по умолчанию для объекта? Является ли это возможным?

WEBCENTER 10.04.2019 15:22

Для этого нет способа получить поведение по умолчанию. Я рекомендую вам делать только настраиваемый запрос в вашем EntityRepository и использовать для него метод для вашего поведения по умолчанию. Я отредактирую этот ответ, чтобы показать вам, как это сделать.

Florian Hermann 10.04.2019 16:58

Спасибо, но, как вы упоминаете в ответе, переопределение метода поиска по умолчанию - это не то, что вы рекомендовали, так что же? :)

WEBCENTER 11.04.2019 08:32

Я рекомендую вам не переопределять поиск по умолчанию, а создать свой собственный метод с именем, например, findOneWithDetailsById(int $id) и вызывать только этот. Это ваша ответственность организовать это.

Florian Hermann 11.04.2019 12:16

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