2017-08-11 4 views
2

Est-ce que quelqu'un a réussi à traduire les entités Sonata Admin sur Symfony 3 (en fait j'utilise 3.3).Traduction d'entités Sonata Admin sur Symfony 3

J'ai essayé différentes solutions, mais aucune n'a vraiment fonctionné. Avec la traduction gedmo, le problème principal est que les traductions sont sauvegardées pour les différentes langues de la base de données, mais dans l'admin (formulaires de fin de liste aussi) le paquet Sonata ne dispense que la traduction locale par défaut. cliqué/choisi. J'ai également essayé avec KNP tarnslation bundle, et avec traduction A2lix, mais ces deux ont le même problème: lorsque vous définissez (dans la classe admin) un champ comme "triable" puis dans la liste des enregistrements lorsque vous essayez de Symfony lance une erreur, car les systèmes de traduction tentent de créer une association avec un autre champ qui n'existe pas! Quoi qu'il en soit, restant sur la Gedmo soultion, le principal problème est que (mettre à part la solution A2lix à cause du problème que j'ai déjà mentionné) je ne sais pas comment définir un champ traduisible dans la classe admin (BlogPostAdmin.php) parce que simplement en utilisant les fichiers de configuration et l'entité et la classe de traduction, ne semble pas fonctionner. Le problème, comme déjà dit, est que les traductions sont sauvegardées dans la base de données, mais ne sont pas affichées dans les listes/formulaires d'administration.

Voici mes fichiers de configuration et entités:

AppKernel.php

<?php 

use Symfony\Component\HttpKernel\Kernel; 
use Symfony\Component\Config\Loader\LoaderInterface; 

class AppKernel extends Kernel 
{ 
    public function registerBundles() 
    { 
     $bundles = [ 
      new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), 
      new Symfony\Bundle\SecurityBundle\SecurityBundle(), 
      new Symfony\Bundle\TwigBundle\TwigBundle(), 
      new Symfony\Bundle\MonologBundle\MonologBundle(), 
      new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), 
      new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), 
      new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), 
      new AppBundle\AppBundle(), 
      /// These are the other bundles the SonataAdminBundle relies on 
      new Sonata\CoreBundle\SonataCoreBundle(), 
      new Sonata\BlockBundle\SonataBlockBundle(), 
      new Knp\Bundle\MenuBundle\KnpMenuBundle(), 
      new Sonata\TranslationBundle\SonataTranslationBundle(), 

      // And finally, the storage and SonataAdminBundle 
      new Sonata\DoctrineORMAdminBundle\SonataDoctrineORMAdminBundle(), 
      new Sonata\AdminBundle\SonataAdminBundle(), 

      // stof [used in Sonata translations] 
      new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), 

      // assetic 
      new Symfony\Bundle\AsseticBundle\AsseticBundle(), 
     ]; 

     if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { 
      $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); 
      $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); 
      $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); 

      if ('dev' === $this->getEnvironment()) { 
       $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); 
       $bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle(); 
      } 
     } 

     return $bundles; 
    } 

    public function getRootDir() 
    { 
     return __DIR__; 
    } 

    public function getCacheDir() 
    { 
     return dirname(__DIR__).'/var/cache/'.$this->getEnvironment(); 
    } 

    public function getLogDir() 
    { 
     return dirname(__DIR__).'/var/logs'; 
    } 

    public function registerContainerConfiguration(LoaderInterface $loader) 
    { 
     $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); 
    } 
} 

config.yml

imports: 
    - { resource: parameters.yml } 
    - { resource: security.yml } 
    - { resource: services.yml } 

# Put parameters here that don't need to change on each machine where the app is deployed 
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration 
parameters: 
    locale: it 

framework: 
    #esi: ~ 
    translator: { fallbacks: ['%locale%'] } 
    secret: '%secret%' 
    router: 
     resource: '%kernel.project_dir%/app/config/routing.yml' 
     strict_requirements: ~ 
    form: ~ 
    csrf_protection: ~ 
    validation: { enable_annotations: true } 
    #serializer: { enable_annotations: true } 
    templating: 
     engines: ['twig'] 
    default_locale: '%locale%' 
    trusted_hosts: ~ 
    session: 
     # https://symfony.com/doc/current/reference/configuration/framework.html#handler-id 
     handler_id: session.handler.native_file 
     save_path: '%kernel.project_dir%/var/sessions/%kernel.environment%' 
    fragments: ~ 
    http_method_override: true 
    assets: ~ 
    php_errors: 
     log: true 

# Twig Configuration 
twig: 
    debug: '%kernel.debug%' 
    strict_variables: '%kernel.debug%' 

# Doctrine Configuration 
doctrine: 
    dbal: 
     driver: pdo_mysql 
     host: '%database_host%' 
     port: '%database_port%' 
     dbname: '%database_name%' 
     user: '%database_user%' 
     password: '%database_password%' 
     charset: UTF8 
     # if using pdo_sqlite as your database driver: 
     # 1. add the path in parameters.yml 
     #  e.g. database_path: "%kernel.project_dir%/var/data/data.sqlite" 
     # 2. Uncomment database_path in parameters.yml.dist 
     # 3. Uncomment next line: 
     #path: '%database_path%' 

    orm: 
     auto_generate_proxy_classes: '%kernel.debug%' 
     naming_strategy: doctrine.orm.naming_strategy.underscore 
     auto_mapping: true 
#  mappings: 
#   # Doctrine extensions 
#   translatable: 
#    type: annotation 
#    alias: Gedmo 
#    prefix: Gedmo\Translatable\Entity 
#    dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/MappedSuperclass" 

# Swiftmailer Configuration 
swiftmailer: 
    transport: '%mailer_transport%' 
    host: '%mailer_host%' 
    username: '%mailer_user%' 
    password: '%mailer_password%' 
    spool: { type: memory } 

sonata_block: 
    default_contexts: [cms] 
    blocks: 
     # enable the SonataAdminBundle block 
     sonata.admin.block.admin_list: 
      contexts: [admin] 

sonata_translation: 
    locales: [it, en] 
    default_locale: %locale% 
    # here enable the types you need 
    gedmo: 
     enabled: true 
# knplabs: 
#  enabled: true 
    #phpcr: 
    # enabled: true 

sonata_admin: 
    templates: 
     layout: admin/layout.html.twig 

assetic: 
    debug:   '%kernel.debug%' 
    use_controller: '%kernel.debug%' 
    filters: 
     cssrewrite: ~ 

#stof_doctrine_extensions: 
# #default_locale: %locale% 
# orm: 
#  default: 
#   sluggable: true 
#   timestampable: true 

services.yml

# Learn more about services, parameters and containers at 
# https://symfony.com/doc/current/service_container.html 
parameters: 
    locale: 'it' 
    locales: ['it', 'en'] 

services: 
    # default configuration for services in *this* file 
    _defaults: 
     # automatically injects dependencies in your services 
     autowire: true 
     # automatically registers your services as commands, event subscribers, etc. 
     autoconfigure: true 
     # this means you cannot fetch services directly from the container via $container->get() 
     # if you need to do this, you can override this setting on individual services 
     public: false 

    # makes classes in src/AppBundle available to be used as services 
    # this creates a service per class whose id is the fully-qualified class name 
    AppBundle\: 
     resource: '../../src/AppBundle/*' 
     # you can exclude directories or files 
     # but if a service is unused, it's removed anyway 
     exclude: '../../src/AppBundle/{Entity,Repository,Tests}' 

    # controllers are imported separately to make sure they're public 
    # and have a tag that allows actions to type-hint services 
    AppBundle\Controller\: 
     resource: '../../src/AppBundle/Controller' 
     public: true 
     tags: ['controller.service_arguments'] 

    # add more services, or override services that need manual wiring 
    # AppBundle\Service\ExampleService: 
    #  arguments: 
    #   $someArgument: 'some_value' 

    admin.category: 
      class: AppBundle\Admin\CategoryAdmin 
      arguments: [~, AppBundle\Entity\Category, ~] 
      tags: 
       - { name: sonata.admin, manager_type: orm, label: Category } 
      public: true 

    admin.blog_post: 
     class: AppBundle\Admin\BlogPostAdmin 
     arguments: [~, AppBundle\Entity\BlogPost, ~] 
     tags: 
      - { name: sonata.admin, manager_type: orm, label: Blog post } 
     public: true 


    # Doctrine Extension listeners to handle behaviors 
    gedmo.listener.translatable: 
     class: Gedmo\Translatable\TranslatableListener 
     tags: 
      - { name: doctrine.event_subscriber, connection: default } 
     calls: 
      #- [ setAnnotationReader, [ @annotation_reader ] ] 
      - [ setDefaultLocale, [ it ] ] 
      - [ setTranslationFallback, [ false ] ] 
      - [ setPersistDefaultLocaleTranslation, [ false ] ] 

BlogPost.php

<?php 

namespace AppBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Sonata\TranslationBundle\Model\Gedmo\AbstractPersonalTranslatable; 
use Gedmo\Mapping\Annotation as Gedmo; 
use Sonata\TranslationBundle\Model\Gedmo\TranslatableInterface; 
use Doctrine\Common\Collections\ArrayCollection; 
use Sonata\TranslationBundle\Model\Gedmo\AbstractPersonalTranslation; 
use Sonata\TranslationBundle\Traits\Gedmo\PersonalTranslatableTrait; 

/** 
* BlogPost 
* 
* @ORM\Table(name="blog_post") 
* @ORM\Entity(repositoryClass="AppBundle\Repository\BlogPostRepository") 
* @Gedmo\TranslationEntity(class="AppBundle\Entity\Translations\BlogPostTr") 
* @ORM\HasLifecycleCallbacks 
*/ 

class BlogPost implements TranslatableInterface 
{ 
    use PersonalTranslatableTrait; 

    /** 
    * Post locale 
    * Used locale to override Translation listener's locale 
    * 
    * @Gedmo\Locale 
    */ 
    protected $locale; 

    /** 
    * @ORM\ManyToOne(targetEntity="Category", inversedBy="blogPosts") 
    */ 
    private $category; 

    public function setCategory(Category $category) 
    { 
     $this->category = $category; 
    } 

    public function getCategory() 
    { 
     return $this->category; 
    } 

    /** 
    * @var int 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="title", type="string", length=255) 
    * @Gedmo\Translatable 
    */ 
    private $title; 

    /** 
    * @var string 
    * 
    * @ORM\Column(name="body", type="text") 
    * @Gedmo\Translatable 
    */ 
    private $body; 

    /** 
    * @var bool 
    * 
    * @ORM\Column(name="draft", type="boolean") 
    */ 
    private $draft = false; 


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

    /** 
    * Set title 
    * 
    * @param string $title 
    * 
    * @return BlogPost 
    */ 
    public function setTitle($title) 
    { 
     $this->title = $title; 

     return $this; 
    } 

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

    /** 
    * Set body 
    * 
    * @param string $body 
    * 
    * @return BlogPost 
    */ 
    public function setBody($body) 
    { 
     $this->body = $body; 

     return $this; 
    } 

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

    /** 
    * Set draft 
    * 
    * @param boolean $draft 
    * 
    * @return BlogPost 
    */ 
    public function setDraft($draft) 
    { 
     $this->draft = $draft; 

     return $this; 
    } 

    /** 
    * Get draft 
    * 
    * @return bool 
    */ 
    public function getDraft() 
    { 
     return $this->draft; 
    } 

    // TRANSLATION 
    /** 
    * @ORM\OneToMany(targetEntity="AppBundle\Entity\Translations\BlogPostTr", mappedBy="object", cascade={"persist", "remove"}) 
    */ 
    protected $translations; 


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

    public function getTranslations() 
    { 
     return $this->translations; 
    } 

    public function addTranslation(AbstractPersonalTranslation $t) 
    { 
     $this->translations->add($t); 
     $t->setObject($this); 
    } 

    public function removeTranslation(AbstractPersonalTranslation $t) 
    { 
     $this->translations->removeElement($t); 
    } 

    public function setTranslations($translations) 
    { 
     $this->translations = $translations; 
    } 

    /** 
    * Sets translatable locale 
    * 
    * @param string $locale 
    */ 
    public function setTranslatableLocale($locale) 
    { 
     $this->locale = $locale; 
    } 
} 

BlogPostTr.php

<?php 
namespace AppBundle\Entity\Translations; 

use Doctrine\ORM\Mapping as ORM; 
use Sonata\TranslationBundle\Model\Gedmo\AbstractPersonalTranslation; 

/** 
* @ORM\Entity 
* @ORM\Table(name="blog_post_translation", 
*  uniqueConstraints={@ORM\UniqueConstraint(name="lookup_unique_idx", columns={ 
*   "locale", "object_id", "field" 
*  })} 
*) 
*/ 
class BlogPostTr extends AbstractPersonalTranslation 
{ 
    /** 
    * Convinient constructor 
    * 
    * @param string $locale 
    * @param string $field 
    * @param string $content 
    */ 
    public function __construct($locale = null, $field = null, $content = null) 
    { 
     $this->setLocale($locale); 
     $this->setField($field); 
     $this->setContent($content); 
    } 

    /** 
    * @ORM\ManyToOne(targetEntity="AppBundle\Entity\BlogPost", inversedBy="translations") 
    * @ORM\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE") 
    */ 
    protected $object; 
} 

BlogPostAdmin.php

<?php 

namespace AppBundle\Admin; 

use Sonata\AdminBundle\Admin\AbstractAdmin; 
use Sonata\AdminBundle\Datagrid\ListMapper; 
use Sonata\AdminBundle\Form\FormMapper; 

class BlogPostAdmin extends AbstractAdmin 
{ 
    protected function configureFormFields(FormMapper $formMapper) 
    { 
     $formMapper 
      ->tab('Post') 
      ->with('Content', array('class' => 'col-md-9')) 
      ->add('title', 'text') 
//   ->add('title', 'translatable_field', array(
//    'allow_extra_fields' => true, 
//    'field' => 'title', 
//    'personal_translation' => 'AppBundle\Entity\Translations\BlogPostTr', 
//    'property_path' => 'translations', 
//   )) 
      ->add('body', 'textarea') 
      ->end() 
      ->end() 
      ->tab('Publishing options') 
      ->with('Meta data', array('class' => 'col-md-3')) 
      ->add('category', 'sonata_type_model', array(
       'class' => 'AppBundle\Entity\Category', 
       'property' => 'name', 
      )) 
      ->end() 
      ->end(); 
    } 





// protected function configureDatagridFilters(DatagridMapper $datagridMapper) 
// { 
//  $datagridMapper->add('title'); 
// } 

    protected function configureListFields(ListMapper $listMapper) 
    { 
     $listMapper->addIdentifier('title'); 
    } 

    public function toString($object) 
    { 
     return $object instanceof BlogPost 
      ? $object->getTitle() 
      : 'Blog Post'; // shown in the breadcrumb on the create view 
    } 
} 

S'il vous plaît aider!

Répondre

1

J'ai eu le même problème. En fait, j'ai eu deux problèmes:

  1. Entités Sonata ne sont pas en œuvre \ TranslationBundle \ Model \ Gedmo \ TranslatableInterface. Et même si c'est ajouté plus tard, le cache de symfony doit être effacé.

  2. J'ai trouvé que pendant l'installation de Sonata Admin ou l'un des bundles de sonata, j'ai ajouté DoctrineExtensionListener comme shown here. À l'intérieur de cet écouteur, Gedmo initie les paramètres régionaux actuels et, bien sûr, il ne sait rien de SonataTranslateBundle.

Je recommande de vider (debug) locale symfony à partir des paramètres de requête, traduction locale sonate et gedmo locale initiée et vérifier que ceux-ci sont synchronisés. En fin de compte, j'ai configuré les paramètres régionaux comme stored in user session et mis à jour DoctrineExtensionListener pour utiliser les paramètres régionaux de la session.