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, привели к совершенно не тому результату, который ожидался.

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

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

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

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


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

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

Похожие вопросы