I'm trying to translate entities with gedmo doctrine extensions.
https://github.com/Atlantic18/DoctrineExtensions
I'm using yml as orm mapping file (auto generating entities).
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
I can translate the title without a problem. But slug is not working...
Normally, on default language (tr), slug auto generated without any generation process by me.
Entity file:
<?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;
}
}
There is a part in documentation: https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/sluggable.md#using-translationlistener-to-translate-our-slug
I don't know how to apply these listeners.
What should i do to translate the slug automatically?
My config.yml for doctrine and stof_doctrine_extensions:
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
After a bit of struggling, I think I've managed to find a solution to your problem. Let's get down to business.
First of all, I've noticed you're using StofDoctrineExtensionsBundle which is a wrapper of the Gedmo Doctrine2 extensions.
It might have seemed easier to install/use but in the long run it complicates matters. In this case, for example, in order to solve your problem you have to modify listeners and with that bundle the only solution I can come up with is to hack the code and change the priority of the service manually. This leads to the first solution:
First solution: hack the bundle (not a good one)
The services can be found in
StofDoctrineExtensionsBundle/Resources/config/listeners.xml
You need to find and modify the sluggable service and increase its priority. That way, this service will execute before the translatable service. The slug would be created first and translatable would store it nicely.
Modification (haven't tried it though I think it might work):
<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>
However, I don't like this solution. To be honest, I don't like wrappers. I'm going to give you another solution that I find more satisfactory (and I tried it and works).
Second solution (and the best one)
First off, get rid of StofDoctrineExtensionsBundle. Secondly, install Gedmo Doctrine2 extensions (how to do it here).
You'll notice that in order to install the extensions you had to create a file in your bundle containing the necessary services. That is good. Go to that file and modify the priority for the sluggable service:
gedmo.listener.sluggable:
class: Gedmo\Sluggable\SluggableListener
tags:
- { name: doctrine.event_subscriber, connection: default, priority: 1 }
calls:
- [ setAnnotationReader, [ @annotation_reader ] ]
And now it is ready.
These are my yml and php for the entity Post (I think they are really similar to yours but can differ):
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
And the 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;
}
}
When you create and entity and store it in the database, it will create the slug and store the title and the slug in the translation table (if you change the locale).
If you try:
$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();
You'll see that your translation table gets two rows, one for the title and the other for the slug for the local de_de.
Hope it helps and kind regards.