2
votes

I have several Entities in SonataAdminBundle (Question, Article, News), to which I want to connect tags. I made it by a Many-To-Many relation with Tag entity for each of the entities. But for this it was necessary to create several intermediate junction tables, which is inconvenient.

I found a bundle FPNTagBundle, which allows to specify the junction table with an extra field ResourceType. This is just what I need, I did the same once in another project.

But FPNTagBundle establishes communication through separate TagManager, and does not work in SonataAdmin.

What do you advice me? How to implement this task?

Maybe not to worry, and leave a several separate junction tables? However, I will still be other half a dozen entities for tagging ... And I'm afraid that the search by tags in all tagged entities will be difficult to do - it will run across multiple tables.

1

1 Answers

3
votes

The solve is in Saving hooks.

/**
 * @return FPN\TagBundle\Entity\TagManager
 */
protected function getTagManager() {
    return $this->getConfigurationPool()->getContainer()
        ->get('fpn_tag.tag_manager');
}

public function postPersist($object) {
    $this->getTagManager()->saveTagging($object);
}

public function postUpdate($object) {
    $this->getTagManager()->saveTagging($object);
}

public function preRemove($object) {
    $this->getTagManager()->deleteTagging($object);
    $this->getDoctrine()->getManager()->flush();
}

My Admin class:

protected function configureFormFields(FormMapper $formMapper)
{
    $tags = $this->hasSubject()
        ? $this->getTagManager()->loadTagging($this->getSubject())
        : array();

    $formMapper
        // other fields
        ->add('tags', 'entity', array('class'=>'AppBundle:Tag', 'choices' => $tags, 'multiple' => true, 'attr'=>array('style'=>'width: 100%;')))
    ;
}

And one known bug in SonataAdminBundle - when perform batch delete (in the list view) the hooks preRemove/postRemove do not run. We need to extend standart CRUD controller:

namespace App\AppBundle\Controller;

use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;

class CRUDController extends Controller
{
    public function batchActionDelete(ProxyQueryInterface $query)
    {
        if (method_exists($this->admin, 'preRemove')) {
            foreach ($query->getQuery()->iterate() as $object) {                
                $this->admin->preRemove($object[0]);
            }
        }

        $response = parent::batchActionDelete($query);

        if (method_exists($this->admin, 'postRemove')) {
            foreach ($query->getQuery()->iterate() as $object) {                
                $this->admin->postRemove($object[0]);
            }
        }

        return $response;
    }

}