Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

currentLocale not being set from Request #13

Closed
south634 opened this issue Nov 20, 2015 · 4 comments
Closed

currentLocale not being set from Request #13

south634 opened this issue Nov 20, 2015 · 4 comments

Comments

@south634
Copy link

I may be having a similar issue to what was mentioned here: #3

Basically, currentLocale is not being automatically set from the Request for me.

I need to manually set it in my Controller for things to work:

$locale = $this->get('request')->getLocale();

$product = new Product();
$product->setCurrentLocale($locale);

If don't set it manually, I get the exception: 'No locale has been set and currentLocale is empty'

I noticed in previous issue #3 that you mentioned that both Prezent\Doctrine\TranslatableBundle\EventListener\LocaleListener and Prezent\Doctrine\Translatable\EventListener\TranslatableListener should appear in app/cache/[env]/ProjectContainer.

In my app/cache/dev/appDevDebugProjectContainer.php I see this:

    /**
     * Gets the 'prezent_doctrine_translatable.listener' service.
     *
     * This service is shared.
     * This method always returns the same instance of the service.
     *
     * @return \Prezent\Doctrine\Translatable\EventListener\TranslatableListener A Prezent\Doctrine\Translatable\EventListener\TranslatableListener instance.
     */
    protected function getPrezentDoctrineTranslatable_ListenerService()
    {
        $this->services['prezent_doctrine_translatable.listener'] = $instance = new \Prezent\Doctrine\Translatable\EventListener\TranslatableListener($this->get('prezent_doctrine_translatable.metadata_factory'));

        $instance->setCurrentLocale('en');
        $instance->setFallbackLocale('en');

        return $instance;
    }

    /**
     * Gets the 'prezent_doctrine_translatable.listener.locale' service.
     *
     * This service is shared.
     * This method always returns the same instance of the service.
     *
     * @return \Prezent\Doctrine\TranslatableBundle\EventListener\LocaleListener A Prezent\Doctrine\TranslatableBundle\EventListener\LocaleListener instance.
     */
    protected function getPrezentDoctrineTranslatable_Listener_LocaleService()
    {
        return $this->services['prezent_doctrine_translatable.listener.locale'] = new \Prezent\Doctrine\TranslatableBundle\EventListener\LocaleListener($this->get('prezent_doctrine_translatable.listener'));
    }

Below is my code for the translatable and translation entities which I am using to test this bundle. Please let me know if there is anything I might be doing wrong, or if more information is needed.

Translatable entity Product.php:

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Prezent\Doctrine\Translatable\Annotation as Prezent;
use Prezent\Doctrine\Translatable\Entity\AbstractTranslatable;
use AppBundle\Entity\ProductTranslation;

/**
 * @ORM\Entity
 */
class Product extends AbstractTranslatable
{

    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @Prezent\Translations(targetEntity="AppBundle\Entity\ProductTranslation")
     */
    protected $translations;

    /**
     * @Prezent\CurrentLocale
     */
    private $currentLocale;

    private $currentTranslation;

    public function __construct()
    {
        $this->translations = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    public function setCurrentLocale($locale)
    {
        $this->currentLocale = $locale;

        return $this;
    }

    public function getCurrentLocale()
    {
        return $this->currentLocale;
    }

    /**
     * Translation helper method
     */
    public function translate($locale = null)
    {
        if (null === $locale) {
            $locale = $this->currentLocale;
        }

        if (!$locale) {
            throw new \RuntimeException('No locale has been set and currentLocale is empty');
        }

        if ($this->currentTranslation && $this->currentTranslation->getLocale() === $locale) {
            return $this->currentTranslation;
        }

        if (!$translation = $this->translations->get($locale)) {
            $translation = new ProductTranslation();
            $translation->setLocale($locale);
            $this->addTranslation($translation);
        }

        $this->currentTranslation = $translation;
        return $translation;
    }

    /**
     * Set name
     *
     * @param string $name
     */
    public function setName($name)
    {
        $this->translate()->setName($name);
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->translate()->getName();
    }

    /**
     * Set color
     *
     * @param string $color
     */
    public function setColor($color)
    {
        $this->translate()->setColor($color);
    }

    /**
     * Get color
     *
     * @return string 
     */
    public function getColor()
    {
        return $this->translate()->getColor();
    }

}

Translation entity ProductTranslation.php:

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Prezent\Doctrine\Translatable\Annotation as Prezent;
use Prezent\Doctrine\Translatable\Entity\AbstractTranslation;

/**
 * @ORM\Entity
 */
class ProductTranslation extends AbstractTranslation
{

    /**
     * @Prezent\Translatable(targetEntity="AppBundle\Entity\Product")
     */
    protected $translatable;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $color;

    /**
     * Set name
     *
     * @param string $name
     * @return ProductTranslation
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set color
     *
     * @param string $color
     * @return ProductTranslation
     */
    public function setColor($color)
    {
        $this->color = $color;

        return $this;
    }

    /**
     * Get color
     *
     * @return string 
     */
    public function getColor()
    {
        return $this->color;
    }

}
@sandermarechal
Copy link
Member

Can you verify that both listeners are actually executed? The LocaleListener should be executed first (it copies the locale from the request to the translatable listener) and the translatable listener should be executed second (it copies the locale to the entity when loaded).

One thing that comes to mind is that the translatable listener is only attached to the "default" entity manager. Are you using a different entity manager?

@south634
Copy link
Author

south634 commented Dec 1, 2015

Hi sandermarechal, thank you for your reply.

When loading a translatable entity for editing, both listeners are indeed executed, and currentLocale is successfully set. I guess that the issue I was having is when trying to add a new translatable entity.

The currentLocale not set exception occurs when injecting the new entity into createForm:

$product = new Product();

$form = $this->createForm($formType, $product);

Looking inside the TranslatableListener, it seems that currentLocale is set on the "postLoad" event. Since the entity is not loaded from the database in the above example, the "postLoad" event does not fire for it, and currentLocale is not set.

So it seems that I should set currentLocale manually for new entities like so:

$product = new Product();
$product->setCurrentLocale($locale);

$form = $this->createForm($formType, $product);

It works, but I would still get problems when adding a collection of translatable entities in a OneToMany relationship with the Product. Is there a better way to do it? I noticed you mentioned the a2lix Translation Bundle: https://github.com/Prezent/doctrine-translatable-bundle/blob/master/Resources/doc/index.md#integration-with-forms-and-sonata-admin

Is this the answer for what I need?

@sandermarechal
Copy link
Member

I don't think the a2lix bundle sets your locale automatically for new entities in one-to-many relationships, but it should work for the rest I think.

I think you should use the empty_data option of your form to create your new entities and set the correct locale. Something like this:

use Symfony\Component\HttpFoundation\RequestStack;

class YourEntityFormType extends AbstractType
{
    public function __construct(RequestStack $requestStack)
    {
        $this->requestStack = $requestStack;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // $builder->addStuff();
    }

    public function configureOptions(OptionsResolverInterface $resolver)
    {
        $resolver
            ->setDefaults([
                'data_class' => YourEntity::class,
                'empty_data' => function () {
                    $o = new YourClass();
                    $o->setCurrentLocale(
                        $this->requestStack->getCurrentRequest()->attributes->get('_locale')
                    );

                    return $o;
                },
            ])
        ;
    }
}

@south634
Copy link
Author

south634 commented Dec 2, 2015

You are awesome man, thank you!

I had not made use of the empty_data option before, and seeing your suggestion now got me reading up about it in the Symfony cookbook. Looks like a really useful option which I have been overlooking.

I tested your suggestion, and it works like a charm.

Thanks for taking the time to help me out on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants