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
少し苦労した後、私はあなたの問題の解決策を見つけることができたと思います。ビジネスに取り掛かりましょう。
まず、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のスラッグ用であることがわかります。
それがお役に立てば幸いです。
私にとって奇妙なこと:エンティティごとの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: {}
構成は正しいように見えます。しかし、ベンダーを更新しようとしましたか?一部のファイルが破損している可能性があります。
更新プロセスが機能しない場合は、構成を私のものと完全に比較できますか?
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: true
https://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();
}
この例が誰かに役立つことを願っています。