vyshkant
@vyshkant
developer

Как использовать дочерний класс сущности или класс-декоратор в SonataAdminBundle (Symfony3, Doctrine ORM)?

Здравствуйте!

Возникла необходимость отображать в админке (SonataAdminBundle) не голые данные, а немного модифицированные. Например, в списке сущностей отображать сконкатенированные поля, или в формах ManyToOne и ManyToMany отображать что-то особенное (а не просто одно из полей сущности).

Реализовывается это, в общем-то, довольно просто: в соответствующих методах Admin-класса вместо наименований свойств указываем наименования своих методов:

// в Admin-классе MyEntity
    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper
//            ->addIdentifier('name')
            ->addIndentifier('someCustomField')
        ;
    }

// в стороннем Admin-классе, добавляя сущность MyEntity по связи ManyToOne
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
//                    ->add('foo', ModelType::class, array(
//                        'class' => MyEntity::class,
//                        'property' => 'name'
//                    ))
                    ->add('foo', ModelType::class, array(
                        'class' => MyEntity::class,
                        'property' => 'someOtherCustomField'
                    ))
        ;
    }

// в Entity-классе
    public function getSomeCustomField()
    {
        return $this->name . ' foo';
    }

    public function getSomeOtherCustomField()
    {
        return $this->name . ' bar';
    }


Возникает вполне естественное желание вынести эти методы куда-то в другое место (или даже в другие места), потому что они непосредственного отношения к сущности MyEntity не имеют (а имеют отношение к представлению этой сущности разных частях админки).

Я сделал вот что: вынес эти методы в класс MyEntityAdminDecorator, сделав его наследником класса-сущности MyEntity;

/**
 * @ORM\Table(name="my_entity")
 * @ORM\Entity
 */
class MyEntity
{

}

class MyEntityAdminDecorator extends MyEntity
{

}


Далее, в кофигурации сервиса админки для MyEntity я заменил аргумент MyEntity на MyEntityAdminDecorator:
my_entity_sonata_admin_service:
    class: MyBundle\Admin\MyEntityAdmin
    arguments: [~, MyBundle\Entity\MyEntityAdminDecorator, ~] # было MyEntity
    tags:
        - name: sonata.admin
          manager_type: orm


Далее, я попробовал зайти в админку и увидел сообщение об ошибке:
An exception has been thrown during the rendering of a template ("Unable to generate a URL for the named route "..." as such route does not exist.").


Я добавил в класс MyEntityAdmin два поля:
class MyEntityAdmin extends AbstractAdmin
{
    protected $baseRouteName = 'sonata_my_entity';
    protected $baseRoutePattern = 'my-entity';
    //...


После этого админка загрузилась и я попытался зайти на страницу списка сущностей, однако это у меня не получилось:
No entity manager defined for class MyBundle\Entity\MyEntityAdminDecorator


Т.е. Doctrine ORM (ВНЕЗАПНО) считает, что это какая-то совершенно другая сущность, для которой нет mapping-информации.

Я использую аннотации (в классе MyEntity), но попытки перейти на xml или yml ничего не принесли: пришлось бы дублировать информацию в MyEntity.orm.xml и MyEntityAdminDecorator.orm.xml.

Действия, описанные в мануале по классам-декораторам в Doctrine ORM, привели к совершенно не тому результату, который ожидался.

Вопрос: как справиться с этой ошибкой? Или как другим способом решить описанную выше задачу?

Спасибо.
  • Вопрос задан
  • 634 просмотра
Пригласить эксперта
Ответы на вопрос 1
@shaqster
Symfony3 Guru
Т.е. Doctrine ORM (ВНЕЗАПНО) считает, что это какая-то совершенно другая сущность, для которой нет mapping-информации.

Пардоньте, а как ЕЩЕ ей реагировать? Вы создали новую сущность в папке для сущностей и аннотировали ее сущностью. От того, что она маппится с таблицы, с которой уже маппится другая сущность, доктрине ни жарко, ни холодно.
Действия, описанные в мануале по классам-декораторам в Doctrine ORM, привели к совершенно не тому результату, который ожидался.

Разумеется, ведь статья немного не про вашу проблему. И кроме этого, вы упустили прямо таки ключевой кусок, а именно:
** @MappedSuperclass */
abstract class Decorator extends Component


По решению проблемы выше уже написали: вам нужно сделать свой шаблон для поля. Ковырньте бандл типа SonataNews, там точно были кастомные шаблоны для листа.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы