0
votes

I have a website built with Symfony 2.8 and Gedmo Translatable.

In order to use HINT_INNER_JOIN and filter items which don't have a translation I had to set persist_default_translation to true:

stof_doctrine_extensions:
    default_locale: '%locale%' # TODO: what does it happen when removing this line?
    translation_fallback: true
    persist_default_translation: true
    orm:
        default:
            timestampable: true
            blameable: true
            translatable: true

Unfortunately this caused that my existing translations for the default language are no more persisted (and they appear empty).

I would need to force re-save all of my entities to generate the default locale again.

How can I do that? I tried with clone and persist but it creates a duplicate of the entity.

Is it possible to force Doctrine to update all the fields again?

1
How about creating a doctrine migration, findAll your entities which are translatable, loop over them, persist and finaly flush them? Or even simplier write a SQL-Query which updates the default language field, put it as well in a migration an execute it?Fabian Schmick
I ended up making a custom command.StockBreak

1 Answers

0
votes

I ended up creating a custom command to migrate all the translations. I created a fake translation called "kr" and then updated all the record with "kr" to "fr" with an SQL query.

I used reflection and other "black magic" to get the properties with the Translatable annotation, maybe this could help someone with the same problem. Here is the code:

class NormalizeTranslationsCommand extends ContainerAwareCommand
{
    protected function configure()
    {
        $this
            // the name of the command (the part after "app/console")
            ->setName('app:normalize-translations')

            // the short description shown while running "php app/console list"
            ->setDescription('Normalizes the translations.')

            // the full command description shown when running the command with
            // the "--help" option
            ->setHelp('This command allows you to normalize the translations...')
        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        // all the translatable classes
        $classes = [
            Entities\MyClass1::class,
            Entities\MyClass2::class,
        ];

        foreach ($classes as $class) {
            $this->processClass($class, $output);
        }
    }

    private function processClass($class, $output)
    {
        $output->writeln(sprintf('Processing class <info>%s</info>', $class));

        // gets all the properties
        $properties = $this->getProperties($class);

        // gets the translatable properties
        $translatableProperties = $this->getTranslatableProperties($properties, $class);
        $output->writeln(sprintf('Found %d translatable properties: %s', count($translatableProperties), implode(', ', $translatableProperties)));

        $defaultLanguage = 'kr'; // fake language
        $em = $this->getContainer()->get('doctrine')->getManager();
        $repository = $em->getRepository('Gedmo\\Translatable\\Entity\\Translation');
        $items = $em->getRepository($class)->findAll();
        $propertyAccessor = PropertyAccess::createPropertyAccessor();

        foreach ($items as $item) {
            foreach ($translatableProperties as $translatableProperty) {
                $value = $propertyAccessor->getValue($item, $translatableProperty);
                $repository->translate($item, $translatableProperty, $defaultLanguage, $value);
            }

            $em->flush();
        }
    }

    private function getProperties($class)
    {
        $phpDocExtractor = new PhpDocExtractor();
        $reflectionExtractor = new ReflectionExtractor();

        // array of PropertyListExtractorInterface
        $listExtractors = array($reflectionExtractor);

        // array of PropertyTypeExtractorInterface
        $typeExtractors = array($phpDocExtractor, $reflectionExtractor);

        // array of PropertyDescriptionExtractorInterface
        $descriptionExtractors = array($phpDocExtractor);

        // array of PropertyAccessExtractorInterface
        $accessExtractors = array($reflectionExtractor);

        $propertyInfo = new PropertyInfoExtractor(
            $listExtractors,
            $typeExtractors,
            $descriptionExtractors,
            $accessExtractors
        );

        return $propertyInfo->getProperties($class);
    }

    private function getTranslatableProperties($properties, $class)
    {
        $translatableProperties = [];

        // https://gist.github.com/Swop/5990316
        $annotationReader = new AnnotationReader();

        foreach ($properties as $property) {
            try {
                $reflectionProperty = new \ReflectionProperty($class, $property);
                $propertyAnnotations = $annotationReader->getPropertyAnnotations($reflectionProperty);

                foreach ($propertyAnnotations as $propertyAnnotation) {
                    if ($propertyAnnotation instanceof Translatable) {
                        // this property is translatable
                        $translatableProperties[] = $property;
                    }
                }
            } catch (\ReflectionException $e) {
                // missing property
                continue;
            }
        }

        return $translatableProperties;
    }
}