Можно ли упорядочить отношение 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, чтобы вручную создать запрос для выбора категорий в правильном порядке?
@Jakumi Я провел несколько тестов, и, к сожалению, как вы упомянули, ни один из двух методов не работал. Я бы все же предпочел сортировать категории с помощью аннотаций (SQL), а не выполнять дополнительный цикл с PHP в геттере. Знаете ли вы, есть ли способ выполнить метод репозитория для получения категорий? Или, может быть, я мог бы написать пользовательскую аннотацию, чтобы расширить аннотацию Doctrine @OrderBy.
Я бы, наверное, попробовал так: symfonycasts.com/screencast/doctrine-relations/… внутри Product::getCategories и надеюсь, что translations.name там работает. Однако имейте в виду, что это имеет смысл только при работе только с одним продуктом, иначе вы рискуете получить проблему n+1. Но по сути, с проблемой n+1 вам просто нужно использовать критерии в другом месте (в специальной функции репозитория для продуктов).






Не уверен, что вы можете сделать это с помощью аннотаций, но я добился нужного вам результата с помощью простой функции 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. Для дальнейшего использования и людей, у которых есть такая же проблема, я сам опубликовал ответ, чтобы показать, как я наконец решил ее.
Наконец-то я решил это так, как @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));
}
Я бы сказал, что единственный способ добиться этого (в db) - использовать DQL.
CategoryTranslation.name«волшебным образом» требует, чтобы перевод всегда был соединен (что, по иронии судьбы, вероятно, так и есть). Однако ассоциация по умолчанию, по-видимому, называетсяtranslations, так что вы можете попробоватьtranslations.nameи посмотреть, приживется ли она. тем не менее, один ко многим, как известно, неуклюж, когда дело доходит до подполей, поэтому я уверен, что это не сработает.