Sonata Admin Bundle: можно ли добавить дочерний административный объект, у которого могут быть разные родители?

Я использую сопоставление наследования доктрины, чтобы различные объекты можно было связать с сущностью комментария. Это достигается с помощью различных конкретных «потоков», которые имеют отношение «один ко многим» с комментариями. Итак, если взять в качестве примера элемент «Story», будет связанная сущность «StoryThread», которая может иметь много комментариев.

Все работает нормально, но у меня проблемы с попыткой определить класс CommentAdmin для SonataAdminBundle, который можно использовать в качестве дочернего элемента родительских сущностей. Например, я бы хотел использовать такие маршруты, как:

/admin/bundle/story/story/1/comment/list /admin/bundle/media/gallery/1/comment/list

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

Я пытался использовать SonataNewsBundle в качестве ссылки, потому что они реализовали аналогичный родительский / отношения дочернего администратора между сообщениями и комментариями, но похоже, что это зависит от класса администратора 'comment' (дочерний), который жестко запрограммирован, чтобы знать, что он принадлежит сообщениям, и также кажется, что он должен иметь прямое множество- отношение к одному с родительским объектом, тогда как у меня через отдельную сущность "Thread".

Я надеюсь это имеет смысл! Спасибо за любую помощь.


person RobMasters    schedule 15.05.2012    source источник


Ответы (2)


Хорошо, в конце концов мне удалось заставить это работать. Мне не удалось извлечь выгоду из использования свойства $parentAssociationMapping класса CommentAdmin, поскольку родительский объект комментария является конкретным экземпляром объекта Thread, тогда как родительский класс admin в данном случае является Story (который связан через StoryThread). Кроме того, это должно оставаться динамичным до тех пор, пока я буду добавлять комментарии к другим типам сущностей.

Прежде всего, мне пришлось настроить мой StoryAdmin (и любые другие классы администратора, которые будут иметь CommentAdmin в качестве дочернего элемента) для вызова метода addChild:

acme_story.admin.story:
      class: Acme\Bundle\StoryBundle\Admin\StoryAdmin
      tags:
        - { name: sonata.admin, manager_type: orm, group: content, label: Stories }
      arguments: [null, Acme\Bundle\StoryBundle\Entity\Story, AcmeStoryBundle:StoryAdmin]
      calls:
          - [ addChild, [ @acme_comment.admin.comment ] ]
          - [ setSecurityContext, [ @security.context ] ]

Это позволило мне связать дочерний раздел администратора от администратора истории, в моем случае из бокового меню, например:

protected function configureSideMenu(MenuItemInterface $menu, $action, Admin $childAdmin = null)
{
    // ...other side menu stuff

    $menu->addChild(
        'comments',
        array('uri' => $admin->generateUrl('acme_comment.admin.comment.list', array('id' => $id)))
    );
}

Затем в моем классе CommentAdmin мне пришлось получить доступ к соответствующему объекту Thread на основе родительского объекта (например, StoryThread в этом случае) и установить его как параметр фильтра. По сути, это то, что делается автоматически с использованием свойства $parentAssociationMapping, если родительский объект совпадает с родительским администратором, что, скорее всего, будет, если вы не используете сопоставление наследования. Вот необходимый код от CommentAdmin:

/**
 * @param \Sonata\AdminBundle\Datagrid\DatagridMapper $filter
 */
protected function configureDatagridFilters(DatagridMapper $filter)
{
    $filter->add('thread');
}


/**
 * @return array
 */
public function getFilterParameters()
{
    $parameters = parent::getFilterParameters();

    return array_merge($parameters, array(
        'thread' => array('value' => $this->getThread()->getId())
    ));
}

public function getNewInstance()
{
    $comment = parent::getNewInstance();

    $comment->setThread($this->getThread());
    $comment->setAuthor($this->securityContext->getToken()->getUser());

    return $comment;
}

/**
 * @return CommentableInterface
 */
protected function getParentObject()
{
    return $this->getParent()->getObject($this->getParent()->getRequest()->get('id'));
}

/**
 * @return object Thread
 */
protected function getThread()
{
    /** @var $threadRepository ThreadRepository */
    $threadRepository = $this->em->getRepository($this->getParentObject()->getThreadEntityName());

    return $threadRepository->findOneBy(array(
        $threadRepository->getObjectColumn() => $this->getParentObject()->getId()
    ));
}

/**
 * @param \Doctrine\ORM\EntityManager $em
 */
public function setEntityManager($em)
{
    $this->em = $em;
}

/**
 * @param \Symfony\Component\Security\Core\SecurityContextInterface $securityContext
 */
public function setSecurityContext(SecurityContextInterface $securityContext)
{
    $this->securityContext = $securityContext;
}
person RobMasters    schedule 16.05.2012
comment
Привет, @RobMasters! Я что-то делаю не так или не понял ваш код, возможно, перепутал: комментарий, пост, ветка, история. Не могли бы вы добавить больше деталей или даже целые классы администратора и соответствующие объекты? Мой getParent() в дочернем админке возвращается null. Спасибо? - person Cassiano; 19.02.2015
comment
Извините, но я не могу. Этому вопросу почти 3 года, и я почти так долго не работал с этим кодом. Если у вас возникла конкретная проблема, то, вероятно, лучше задать новый вопрос и предоставить свой код. - person RobMasters; 20.02.2015

Альтернатива вашему коду для прямых связанных сущностей:

 public function getParentAssociationMapping()
 {
    // we grab our entity manager
    $em = $this->modelManager->getEntityManager('acme\Bundle\Entity\acme'); 

    // we get our parent object table name
    $className = $em->getClassMetadata(get_class($this->getParent()->getObject($this->getParent()->getRequest()->get('id'))))->getTableName();

    // we return our class name ( i lower it because my tables first characted uppercased )
    return strtolower( $className );
 }

убедитесь, что ваша переменная reverseBy соответствует $ className для правильной работы

person Charles-Antoine Fournel    schedule 19.09.2014