web-dev-qa-db-ja.com

Gedmo Doctrine拡張機能-スラッガブル+翻訳可能なYaml構成

Gedmo doctrine拡張子を持つエンティティを翻訳しようとしています。

https://github.com/Atlantic18/DoctrineExtensions

Ormマッピングファイル(自動生成エンティティ)としてymlを使用しています。

orm.yml:

CS\ContentBundle\Entity\Post:
  type:  entity
  table: posts
  repositoryClass: CS\ContentBundle\Entity\PostRepository
  gedmo:
    soft_deleteable:
      field_name: deleted_at
    translation:
      locale: locale
  fields:
    id:
      type: integer
      length: 11
      id: true
      generator:
        strategy: AUTO
    title:
      type: string
      length: 500
      gedmo:
        - translatable
    slug:
      type: string
      length: 500
      gedmo:
        translatable: {}
        slug:
          separator: -
          fields:
            - title

タイトルは問題なく翻訳できます。しかし、スラッグは機能していません...

通常、デフォルト言語(tr)では、私が生成プロセスなしで自動生成したスラッグ。

エンティティファイル:

<?php

namespace CS\ContentBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Translatable\Translatable;
use Gedmo\Mapping\Annotation as Gedmo;
use APY\DataGridBundle\Grid\Mapping as GRID;

/**
 * Post
 * @Gedmo\SoftDeleteable(fieldName="deleted_at", timeAware=false)
 * @GRID\Source(columns="id,title,is_active,created_at,updated_at")
 */
class Post implements Translatable
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     * @Gedmo\Translatable
     * @GRID\Column(title="Başlık", filterable=true)
     */
    private $title;

    /**
     * @var string
     * @Gedmo\Translatable
     */
    private $slug;

    /**
     * @Gedmo\Locale
     */
    private $locale;

    public function setLocale($locale)
    {
        $this->locale = $locale;
    }


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

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

        return $this;
    }

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

    /**
     * Set slug
     *
     * @param string $slug
     * @return Post
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;

        return $this;
    }

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

ドキュメントには一部があります: https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/sluggable.md#using-translationlistener-to-translate-our-slug

これらのリスナーを適用する方法がわかりません。

スラッグを自動的に翻訳するにはどうすればよいですか?


編集

doctrineおよびstof_doctrine_extensionsのconfig.yml:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   "%database_driver%"
                Host:     "%database_Host%"
                port:     "%database_port%"
                dbname:   "%database_name%"
                user:     "%database_user%"
                password: "%database_password%"
                charset:  UTF8
                mapping_types:
                  enum: string
    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        auto_mapping: true
        metadata_cache_driver: redis
        query_cache_driver: redis
        filters:
            softdeleteable:
                class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
                enabled: true
        mappings:
            StofDoctrineExtensionsBundle: ~
            gedmo_translatable:
                type: annotation
                prefix: Gedmo\Translatable\Entity
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
                alias: GedmoTranslatable # this one is optional and will default to the name set for the mapping
                is_bundle: false
            gedmo_tree:
                type: annotation
                prefix: Gedmo\Tree\Entity
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Tree/Entity"
                alias: GedmoTree # this one is optional and will default to the name set for the mapping
                is_bundle: false

stof_doctrine_extensions:
    default_locale: "%locale%"
    translation_fallback: true
    orm:
        default:
            tree: true
            sluggable: true
            translatable: true
            timestampable: true
            softdeleteable: true
15

少し苦労した後、私はあなたの問題の解決策を見つけることができたと思います。ビジネスに取り掛かりましょう。

まず、Gedmo Doctrine2拡張機能のラッパーであるStofDoctrineExtensionsBundleを使用していることに気付きました。

インストール/使用は簡単に思えたかもしれませんが、長期的には問題が複雑になります。この場合、たとえば、問題を解決するにはリスナーを変更する必要があり、そのバンドルで私が思いつく唯一の解決策は、コードをハッキングしてサービスの優先度を手動で変更することです。これは最初の解決策につながります:

最初の解決策:バンドルをハックします(良いものではありません)

サービスはで見つけることができます

StofDoctrineExtensionsBundle/Resources/config/listeners.xml

だらしないサービスを見つけて変更し、その優先度を上げる必要があります。そうすれば、このサービスは翻訳可能なサービスの前に実行されます。スラッグは最初に作成され、翻訳可能でうまく保存されます。

変更(うまくいくかもしれないと思いますが、試していません):

<service id="stof_doctrine_extensions.listener.sluggable" class="%stof_doctrine_extensions.listener.sluggable.class%" public="false">
    <tag name="kernel.cache_warmer" priority="1" />
    <call method="setAnnotationReader">
        <argument type="service" id="annotation_reader" />
    </call>
</service>

しかし、私はこの解決策が好きではありません。正直なところ、私はラッパーが好きではありません。私がより満足できると思う別の解決策をあなたに与えるつもりです(そして私はそれを試し、うまくいきました)。

2番目の解決策(そして最良の解決策)

まず、StofDoctrineExtensionsBundleを削除します。次に、Gedmo Doctrine2拡張機能をインストールします(実行方法 ここ )。

拡張機能をインストールするには、必要なサービスを含むファイルをバンドルに作成する必要があることに気付くでしょう。それはいいです。そのファイルに移動し、slugableサービスの優先度を変更します。

gedmo.listener.sluggable:
        class: Gedmo\Sluggable\SluggableListener
        tags:
            - { name: doctrine.event_subscriber, connection: default, priority: 1 }
        calls:
            - [ setAnnotationReader, [ @annotation_reader ] ]

そして今、それは準備ができています。

これらはエンティティPostの私のymlとphpです(私はそれらが本当にあなたのものに似ていると思いますが、異なる可能性があります):

[〜#〜] yml [〜#〜]

DSG\AcmeBundle\Entity\Post:
    type:  entity
    table: posts
    gedmo:
        soft_deleteable:
            field_name: deleted_at
        translation:
            locale: locale
    fields:
        id:
            type: integer
            length: 11
            id: true
            generator:
                strategy: AUTO
        title:
            type: string
            length: 255
            gedmo:
                - translatable
        slug:
            type: string
            length: 255
            unique: true
            gedmo:
                translatable: {}
                slug:
                    separator: _
                    style: camel
                    fields:
                        - title

そして[〜#〜] php [〜#〜]

namespace DSG\AcmeBundle\Entity;

use Gedmo\Translatable\Translatable;

class Post implements Translatable
{
    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $title;

    /**
     * @var string
     */
    private $slug;

    /**
     * @var string
     */
    private $locale;

    public function setTranslatableLocale($locale)
    {
        $this->locale = $locale;
    }


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

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

        return $this;
    }

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

    /**
     * Set slug
     *
     * @param string $slug
     * @return Post
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;

        return $this;
    }

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

エンティティを作成してデータベースに保存すると、スラッグが作成され、タイトルとスラッグが翻訳テーブルに保存されます(ロケールを変更した場合)。

試してみると:

$em = $this->getDoctrine()->getEntityManager();
$article = new Post();
$article->setTitle('the title');
$em->persist($article);
$em->flush();

$article = $this->getDoctrine()->getRepository('DSGMDayBundle:Post')->find(1);
$article->setTitle('my title in de');
$article->setTranslatableLocale('de_de'); // change locale
$em->persist($article);
$em->flush();

変換テーブルに2つの行があり、1つはタイトル用で、もう1つはローカルde_deのスラッグ用であることがわかります。

それがお役に立てば幸いです。

4
acontell

私にとって奇妙なこと:エンティティごとのORM構成は2つのファイル(yamlとアノテーション)で行われますか?

リスナーは、適切な順序で適切にロードされているように見えます。多分それはorm.ymlのエンティティフィールド設定です。フィールドで翻訳可能とスラッガブルを反転してみてくださいslug

CS\ContentBundle\Entity\Post:
  type:  entity
  table: posts
  repositoryClass: CS\ContentBundle\Entity\PostRepository
  gedmo:
    soft_deleteable:
      field_name: deleted_at
    translation:
      locale: locale
  fields:
    id:
      type: integer
      length: 11
      id: true
      generator:
        strategy: AUTO
    title:
      type: string
      length: 500
      gedmo:
        - translatable
    slug:
      type: string
      length: 500
      gedmo:
        slug:
          separator: -
          fields:
            - title
        translatable: {}
1
AlterPHP

構成は正しいように見えます。しかし、ベンダーを更新しようとしましたか?一部のファイルが破損している可能性があります。

更新プロセスが機能しない場合は、構成を私のものと完全に比較できますか?

doctrine:
    dbal:
        driver:   "%database_driver%"
        Host:     "%database_Host%"
        port:     "%database_port%"
        dbname:   "%database_name%"
        user:     "%database_user%"
        password: "%database_password%"
        charset:  UTF8
    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        auto_mapping: true
        dql:
            string_functions:
                GroupConcat: DoctrineExtensions\Query\Mysql\GroupConcat
                IF: DoctrineExtensions\Query\Mysql\IfElse
        filters:
            softdeleteable:
                class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
                enabled: true
        mappings:
            StofDoctrineExtensionsBundle: ~
            gedmo_tree:
                type: annotation
                prefix: Gedmo\Tree\Entity
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Tree/Entity"
                alias: GedmoTree
                is_bundle: false
            translatable:
                type: annotation
                alias: Gedmo
                prefix: Gedmo\Translatable\Entity
                # make sure vendor library location is correct
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"

また、services.ymlのgedmo.listener.translatableをオーバーライドしないようにしてください。デフォルトのコードを上書きするコードがある場合は、それを削除します。デフォルト設定:

gedmo.listener.translatable:
        class: Gedmo\Translatable\TranslatableListener
        tags:
            - { name: doctrine.event_subscriber, connection: default }
        calls:
            - [ setAnnotationReader, [ @annotation_reader ] ]
            - [ setDefaultLocale, [ %locale% ] ]
            - [ setTranslationFallback, [ false ] ]

私はStofDoctrineExtensionsBundleをスラッガブルと翻訳可能に使用しましたが、同じ問題がありました。

私はしばらく検索して試しましたが、私のために働く解決策を見つけました:


エンティティ:スラッグフィールドは名前フィールドから生成されます

use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Translatable\Translatable;

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

/**
 * @Gedmo\Translatable
 * @Gedmo\Slug(fields={"name"}, updatable=true)
 * @ORM\Column(type="string", unique=true)
 */
private $slug;

config.yml:ここでpersist_default_translation: truehttps://github.com/Atlantic18/DoctrineExtensions/issues/を設定する必要があります542#issuecomment-1298355

parameters:
    locale: en

doctrine:
    orm:
        auto_generate_proxy_classes: '%kernel.debug%'
        naming_strategy: doctrine.orm.naming_strategy.underscore
        auto_mapping: true
        mappings:
            gedmo_translatable:
                type: annotation
                prefix: Gedmo\Translatable\Entity
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
                alias: GedmoTranslatable # (optional) it will default to the name set for the mapping
                is_bundle: false
            gedmo_translator:
                type: annotation
                prefix: Gedmo\Translator\Entity
                dir: "%kernel.root_dir%/../vendor/gedmo/doctrine-extensions/lib/Gedmo/Translator/Entity"
                alias: GedmoTranslator # (optional) it will default to the name set for the mapping
                is_bundle: false

stof_doctrine_extensions:
    default_locale: '%locale%'
    translation_fallback: true
    persist_default_translation: true    # I think this does the trick
    orm:
        default:
            sluggable: true
            translatable: true

DefaultController現在のロケールの正しいエンティティを返すクエリを呼び出すためにParamConverterを使用します

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;

/**
 * @Route("/entry/{slug}", name="entry_detail")
 * @ParamConverter("entry", class="AppBundle:Entry", options={"repository_method" = "findOneByCriteria"})
 */
public function entryDetailAction(Request $request, Entry $entry)
{
    return $this->render('frontend/entry.html.twig', [
        'entry' => $entry,
    ]);
}

エンティティリポジトリとクエリメソッドを使用してエンティティを返す

/**
 * Find an entry by criteria
 * Need this special function, because of translatable
 * https://github.com/stof/StofDoctrineExtensionsBundle/issues/232
 *
 * @param $params
 * @return mixed
 */
public function findOneByCriteria(array $params)
{
    $query = $this->createQueryBuilder('e');
    $i = 0;
    foreach ($params as $column => $value) {
        if ($i < 1) {
            $query->where("e.$column = :$column");
        } else {
            $query->andWhere("e.$column = :$column");
        }
        $query->setParameter($column, $value);
        $i++;
    }
    $query = $query->getQuery();
    $query->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker');
    return $query->getOneOrNullResult();
}

この例が誰かに役立つことを願っています。

0
Fabian