Created
January 14, 2016 16:37
-
-
Save mRoca/8ea898204501b2430d38 to your computer and use it in GitHub Desktop.
Gedmo translatable field
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\ModuleContractBundle\Form; | |
| use Symfony\Component\Form\AbstractType; | |
| use Symfony\Component\Form\FormBuilderInterface; | |
| use Symfony\Component\OptionsResolver\OptionsResolverInterface; | |
| class CategoryType extends AbstractType | |
| { | |
| public function buildForm(FormBuilderInterface $builder, array $options) | |
| { | |
| $builder | |
| ->add( | |
| 'name_trans', | |
| 'translatable_field', | |
| array( | |
| 'field' => 'name', | |
| 'label' => 'contract.category.name', | |
| ) | |
| ); | |
| } | |
| public function setDefaultOptions(OptionsResolverInterface $resolver) | |
| { | |
| $resolver->setDefaults( | |
| array( | |
| 'data_class' => 'App\ModuleContractBundle\Entity\Category' | |
| ) | |
| ); | |
| } | |
| public function getName() | |
| { | |
| return 'app_modulecontractbundle_category'; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\ApplicationBundle\Form\Type; | |
| use Symfony\Component\DependencyInjection\ContainerInterface; | |
| use Symfony\Component\Form\AbstractType; | |
| use Symfony\Component\Form\FormBuilderInterface; | |
| use Symfony\Component\OptionsResolver\OptionsResolverInterface; | |
| use App\ApplicationBundle\EventListener\Form\TranslatedFieldSubscriber; | |
| class TranslatableFieldType extends AbstractType | |
| { | |
| protected $container; | |
| protected $defaultLocale; | |
| public function __construct(ContainerInterface $container, $defaultLocale) | |
| { | |
| $this->container = $container; | |
| $this->defaultLocale = $defaultLocale; | |
| } | |
| /** | |
| * {@inheritDoc} | |
| */ | |
| public function buildForm(FormBuilderInterface $builder, array $options) | |
| { | |
| if (null === $options['field']) { | |
| $options['field'] = $builder->getName(); | |
| } | |
| $subscriber = new TranslatedFieldSubscriber( | |
| $builder->getFormFactory(), | |
| $this->container->get('doctrine.orm.entity_manager'), | |
| $this->container->get('validator'), | |
| $this->container->get('App.application.service.culture_helper')->getAvailableLocales(), | |
| $this->defaultLocale, | |
| $options | |
| ); | |
| $builder->addEventSubscriber($subscriber); | |
| } | |
| /** | |
| * {@inheritDoc} | |
| */ | |
| public function getName() | |
| { | |
| return 'translatable_field'; | |
| } | |
| /** | |
| * {@inheritDoc} | |
| */ | |
| public function setDefaultOptions(OptionsResolverInterface $resolver) | |
| { | |
| $resolver->setDefaults( | |
| array( | |
| // Options | |
| 'field' => null, // Set to form builder name if empty | |
| 'translation_class' => null, // Use $entity::TRANSLATION_CLASS or Gedmo\Translatable\Entity\Translation if empty | |
| 'field_type' => 'text', | |
| // FormType | |
| 'mapped' => false, | |
| 'field_options' => array(), | |
| ) | |
| ); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| namespace App\ApplicationBundle\EventListener\Form; | |
| use Doctrine\ORM\EntityManagerInterface; | |
| use Gedmo\Translatable\Entity\MappedSuperclass\AbstractPersonalTranslation; | |
| use Gedmo\Translatable\Entity\Repository\TranslationRepository; | |
| use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |
| use Symfony\Component\Form\FormEvent; | |
| use Symfony\Component\Form\FormEvents; | |
| use Symfony\Component\Form\FormFactoryInterface; | |
| use Symfony\Component\Validator\Constraint; | |
| use Symfony\Component\Validator\Mapping\ClassMetadata; | |
| use Symfony\Component\Validator\ValidatorInterface; | |
| use App\ApplicationBundle\Entity\Translatable\AbstractTranslatable; | |
| class TranslatedFieldSubscriber implements EventSubscriberInterface | |
| { | |
| const DEFAULT_TRANSLATION_CLASS = 'Gedmo\Translatable\Entity\Translation'; | |
| protected $formFactory; | |
| protected $em; | |
| protected $validator; | |
| protected $locales; | |
| protected $options; | |
| protected $field; | |
| protected $translationClass; | |
| public function __construct(FormFactoryInterface $formFactory, EntityManagerInterface $em, ValidatorInterface $validator, Array $locales, $defaultLocale, Array $options) | |
| { | |
| $this->formFactory = $formFactory; | |
| $this->em = $em; | |
| $this->validator = $validator; | |
| $this->locales = $locales; | |
| $this->defaultLocale = $defaultLocale; | |
| $this->options = $options; | |
| $this->field = $options['field']; | |
| $this->translationClass = $options['translation_class']; | |
| } | |
| public static function getSubscribedEvents() | |
| { | |
| return array( | |
| FormEvents::PRE_SET_DATA => 'preSetData', | |
| FormEvents::POST_SUBMIT => 'postSubmit', | |
| ); | |
| } | |
| /** | |
| * @param AbstractTranslatable|object $entity | |
| * @return string | |
| */ | |
| protected function getTranslationClass($entity) | |
| { | |
| if (null !== $this->translationClass) { | |
| return $this->translationClass; | |
| } | |
| if ($entity instanceof AbstractTranslatable) { | |
| $translationClass = $entity::TRANSLATION_CLASS; | |
| if (null === $translationClass) { | |
| throw new \InvalidArgumentException('The AbstractTranslatable entity must define a TRANSLATION_CLASS'); | |
| } | |
| return $translationClass; | |
| } | |
| return self::DEFAULT_TRANSLATION_CLASS; | |
| } | |
| /** | |
| * @param AbstractTranslatable|object $entity | |
| * @return TranslationRepository | |
| */ | |
| protected function getTranslationRepository($entity) | |
| { | |
| $repository = $this->em->getRepository($this->getTranslationClass($entity)); | |
| if (!$repository instanceof TranslationRepository) { | |
| throw new \InvalidArgumentException('The repository must be a TranslationRepository'); | |
| } | |
| return $repository; | |
| } | |
| /** | |
| * @param AbstractTranslatable|object $entity | |
| * @return array | |
| */ | |
| protected function getTranslations($entity) | |
| { | |
| if ($entity instanceof AbstractTranslatable) { | |
| return $entity->findTranslations($this->defaultLocale); | |
| } | |
| return $this->getTranslationRepository($entity)->findTranslations($entity); | |
| } | |
| /** | |
| * @param AbstractTranslatable|object $entity | |
| * @param string $field | |
| * @return string | |
| */ | |
| protected function getDefaultTranslation($entity, $field) | |
| { | |
| if (!$entity instanceof AbstractTranslatable) { | |
| return null; | |
| } | |
| // Entity not yet persisted | |
| if (null === $this->em->getUnitOfWork()->getSingleIdentifierValue($entity)) { | |
| return null; | |
| } | |
| $entity->setTranslatableLocale($this->defaultLocale); | |
| $this->em->refresh($entity); | |
| $getter = 'get'.ucfirst($field); | |
| return method_exists($entity, $getter) ? call_user_func(array($entity, $getter)) : null; | |
| } | |
| /** | |
| * @param AbstractTranslatable|object $entity | |
| * @param string $field | |
| * @param array $data | |
| */ | |
| protected function setTranslations($entity, $field, $data) | |
| { | |
| if ($entity instanceof AbstractTranslatable) { | |
| $entity->setTranslatableLocale($this->defaultLocale); | |
| foreach ($data as $locale => $content) { | |
| /** @var AbstractPersonalTranslation $translation */ | |
| $translationClass = $this->getTranslationClass($entity); | |
| $translation = new $translationClass(); | |
| $translation->setField($field); | |
| $translation->setLocale($locale); | |
| $translation->setContent($content); | |
| $entity->addTranslation($translation); | |
| } | |
| return; | |
| } | |
| $repository = $this->getTranslationRepository($entity); | |
| foreach ($data as $locale => $content) { | |
| $repository->translate($entity, $this->field, $locale, $content); | |
| } | |
| } | |
| /** | |
| * @param AbstractTranslatable|object $entity | |
| * @param string $field | |
| * @return Constraint[] | |
| */ | |
| protected function getConstraintsForMember($entity, $field) | |
| { | |
| /** @var ClassMetadata $metadata */ | |
| $metadata = $this->validator->getMetadataFor($entity); | |
| $constraints = array(); | |
| foreach ($metadata->getPropertyMetadata($field) as $member) { | |
| $constraints += $member->getConstraints(); | |
| } | |
| return $constraints; | |
| } | |
| public function preSetData(FormEvent $event) | |
| { | |
| $form = $event->getForm(); | |
| $entity = $form->getParent()->getData(); | |
| $translations = $this->getTranslations($entity); | |
| foreach ($this->locales as $locale) { | |
| $data = isset($translations[$locale], $translations[$locale][$this->field]) ? $translations[$locale][$this->field] : null; | |
| if (null === $data && $locale === $this->defaultLocale) { | |
| $data = $this->getDefaultTranslation($entity, $this->field); | |
| } | |
| $form->add( | |
| $this->formFactory->createNamed( | |
| $locale, | |
| $this->options['field_type'], | |
| $data, | |
| array( | |
| 'label' => $locale, | |
| 'auto_initialize' => false, | |
| 'constraints' => $this->getConstraintsForMember($entity, $this->field), // Caution with unicity constraint | |
| ) | |
| ) | |
| ); | |
| } | |
| return; | |
| } | |
| public function postSubmit(FormEvent $event) | |
| { | |
| $data = $event->getData(); | |
| $entity = $event->getForm()->getParent()->getData(); | |
| $this->setTranslations($entity, $this->field, $data); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment