Open ghost opened 12 years ago
The best way is to use a datatransformer i work on that at the moment
@gimler Any progress on that datatransformer you could share?
:+1:
I looked into writing a "data transformer" class for this bundle, but I don't think this can work. Data transformers only convert one value to another value. Thus, they only get the value of a specific field and do not have a reference to the object itself. However, the way the TagBundle works would require such a reference to the object (for methods such as "addTag($fooTag, $object)", "saveTagging($object)" or "loadTagging($object)".).
I wrote a bundle to handle the "plain text"-to-"tag object" transformation in forms when using the SonataAdminBundle. https://github.com/mweimerskirch/MWTagAdminBundle It's just a prototype though. Depends on #13.
In order to make the transformation work I push the entire object through the transformer instead of just the "tags" field. I'm not sure this is the best solution, but it's the only one I got to work.
I now have an integration of FPNTagBundle with a CRUD form, using a DataTransformer and a custom form widget - a simple text field for now. This code is part of a showcase I prepared for a workshop, so please adapt the namespaces to your own bundle.
The DataTransformer looks like this:
<?php
/**
* @see http://symfony.com/doc/current/cookbook/form/data_transformers.html
*/
namespace FUxCon2013\ProjectsBundle\Form;
use Symfony\Component\Form\DataTransformerInterface;
class TagsTransformer implements DataTransformerInterface
{
private $tagManager;
public function __construct($tagManager)
{ $this->tagManager = $tagManager; }
public function transform($tags)
{ return join(', ', $tags->toArray()); }
public function reverseTransform($tags)
{
return $this->tagManager->loadOrCreateTags(
$this->tagManager->splitTagNames($tags)
);
}
}
With this, I implement a custom widget like so:
<?php
namespace FUxCon2013\ProjectsBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use DoctrineExtensions\Taggable\TagManager;
class TagsType extends AbstractType
{
public function __construct(TagManager $tagManager)
{ $this->tagManager = $tagManager; }
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new TagsTransformer($this->tagManager);
$builder->addModelTransformer($transformer);
}
public function getParent()
{ return 'text'; }
public function getName()
{ return 'tags_entry'; }
}
Once you have registered this new type in app/config/config.yml:
services:
fuxcon2013.form.tags_entry:
class: FUxCon2013\ProjectsBundle\Form\TagsType
arguments: [ "@fpn_tag.tag_manager" ]
tags:
- { name: form.type, alias: tags_entry }
... you can use it in your edit form:
<?php
namespace FUxCon2013\ProjectsBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ProjectType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('tags', 'tags_entry');
}
}
Good luck with tagging, Olav
This transformer is ok but you still need to invoke loadTagging($entity) before crating form and saveTagging($entity) after flushing entity. What is more, transformer require setTags method in entity:
public function setTags($tags) {
$this->tags->clear();
foreach($tags as $tag) {
$this->tags->add($tag);
}
}
I'm having a issue here where if I don't update the taggable entity the tags don't get updated. Say my entity has a name. If I leave name the same, but send a new tag with the entity when i persist the entity no update is done so postUpdate isn't run. If I do change name then the entity is updated, postUpdate called and the tags are updated correctly. @Matzz Is this what your setTags function on the entity is for? Where/When should I call it?
What you could do is to listen on the onFlush events to call the method saveTagging on the entity.
You could take a look at the wrapper of this bundle done by fogs : https://github.com/fogs/tagging-bundle and its doctrine event subscriber : https://github.com/fogs/tagging-bundle/blob/master/EventListener/TaggableSubscriber.php
Wish I'd seen your comment earlier @oschettler as I ended up writing exactly the same code, minus names and inconsequential style differences and then coming here to complain that the functionality wasn't part of the bundle already.
@Matzz The transformer itself that @oschettler posted doesn't require the setTags()
method. The entity and form components of symfony require the setTags()
method. @jbouzekri's solution is a great one for saving the tags after flushing automatically. Another idea for functionality that maybe ought to be part of the bundle by default.
@oschettler, your solution may work, but I don't think the data transformer should be responsable of creating new tags. What happens if there are some form errors? You have already persisted those tags.
Which is the best practise to handle forms? I have a taggable Entity and i want a field how i can add tags to this entity in a form.