Sonata admin - Сортировка по переведенному свойству

У меня есть код:

protected function configureListFields(ListMapper $listMapper)
{
    $listMapper
        ->addIdentifier('name')
   [..]

Это свойство перевода (KNP translatable). Я пробовал использовать:

  • translations.name — метка сортируется, но значения отсутствуют
  • name или translate.name - метка не сортируется, но значения в порядке

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


person serek    schedule 29.01.2018    source источник


Ответы (2)


Вы пробовали $listMapper->add('name',null, array('sortable'=>true)) ?

person KelgMak    schedule 30.01.2018
comment
Да, но я получил ошибку: Аргумент 1, переданный в Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery::entityJoin(), должен иметь тип array, null задано - person serek; 31.01.2018

Хорошо, я сделал это.

1) Создайте абстрактный класс администратора:

use Sonata\AdminBundle\Admin\AbstractAdmin as BaseAbstractAdmin;

abstract class AbstractAdmin extends BaseAbstractAdmin { .. }

2) Используйте этот класс в своих классах администратора:

class UserAdmin extends AbstractAdmin { .. }

3) Добавьте это в определение столбца:

->add(
     'fieldName',
      null,
      [
          'sortable'                         => true,
          'sort_field_mapping'               => ['fieldName' => 'id'],
          'sort_parent_association_mappings' => [],
      ]
)

4) Добавьте этот метод в свой абстрактный класс администратора:

protected function prepareQueryForTranslatableColumns($query)
{
    $currentAlias     = $query->getRootAliases()[0];
    $locale           = $this->request->getLocale();
    $parameters       = $this->getFilterParameters();
    $sortBy           = $parameters['_sort_by'];
    $fieldDescription = $this->getListFieldDescription($sortBy);
    $mapping          = $fieldDescription->getAssociationMapping();
    $entityClass      = $mapping['targetEntity'] ?: $this->getClass();

    if ($mapping) {
        $mappings   = $fieldDescription->getParentAssociationMappings();
        $mappings[] = $mapping;

        foreach ($mappings as $parentMapping) {
            $fieldName = $parentMapping['fieldName'];
            $query->leftJoin($currentAlias . '.' . $fieldName, $fieldName);

            $currentAlias = $fieldName;
        }
    }

    $query
        ->leftJoin(
            $currentAlias . '.translations',
            'tr',
            'with',
            'tr.locale = :lang OR
                (NOT EXISTS(SELECT t.id FROM ' . $entityClass . 'Translation t WHERE t.translatable = tr.translatable AND t.locale = :lang)
                AND tr.locale = :lang_default)'
        )
        ->addOrderBy('tr.name', $parameters['_sort_order'])
        ->setParameter(':lang', $locale)
        ->setParameter(':lang_default', 'en');

    return $query;
}

Я использую JOIN для получения переводов для текущей выбранной локали, и, если перевода для текущей локали еще не существует, я добавляю перевод для локали по умолчанию (это причина для использования НЕ СУЩЕСТВУЕТ).

5) Добавьте этот метод в свой класс администратора:

public function createQuery($context = 'list')
{
    $query = parent::createQuery($context);

    if ('list' === $context) {
        $parameters = $this->getFilterParameters();
        $sortBy     = $parameters['_sort_by'];

        if (in_array($sortBy, ['fieldName', 'fieldName.fieldName2', 'fieldName3', ..])) {
            $query = parent::prepareQueryForTranslatableColumns($query);
        }
    }

    return $query;
}
person serek    schedule 02.04.2018
comment
Я добавил новое лучшее решение. - person serek; 07.04.2018