Подтвердить что ты не робот

Расширения доктрины Gedmo - Sluggable + Переводимая конфигурация Yaml

Я пытаюсь перевести сущности с расширениями доктрин gedmo.

https://github.com/Atlantic18/DoctrineExtensions

Я использую yml как файл сопоставления orm (автогенерирующие объекты).

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), slug автоматически генерируется без какого-либо процесса генерации.

Файл сущности:

<?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

Я не знаю, как применять этих слушателей.

Что я должен сделать, чтобы автоматически перевести пул?


ИЗМЕНИТЬ

My config.yml для доктрины и 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
4b9b3361

Ответ 1

После немного борется, я думаю, мне удалось найти решение вашей проблемы. Позвольте перейти к делу.

Прежде всего, я заметил, что вы используете StofDoctrineExtensionsBundle, который является оберткой расширений Gedmo Doctrine2.

Казалось бы, проще было установить/использовать, но в конечном итоге это усложняет ситуацию. В этом случае, например, чтобы решить вашу проблему, вам нужно изменить слушателей, и с этим пакетом единственным решением, которое я могу придумать, является взломать код и изменить приоритет службы вручную. Это приводит к первому решению:

Первое решение: взломать узел (не очень хороший)

Сервисы можно найти в

StofDoctrineExtensionsBundle/Ресурсы/конфигурации/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>

Однако мне не нравится это решение. Честно говоря, мне не нравятся обертки. Я дам вам другое решение, которое я нахожу более удовлетворительным (и я попробовал его и работал).

Второе решение (и самое лучшее)

Прежде всего, избавитесь от StofDoctrineExtensionsBundle. Во-вторых, установите расширения Gedmo Doctrine2 (как это сделать здесь).

Вы заметите, что для установки расширений вам нужно было создать файл в вашем комплекте, содержащий необходимые сервисы. Это хорошо. Перейдите к этому файлу и измените приоритет для sluggable service:

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

И теперь он готов.

Это мои 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();

Вы увидите, что ваша таблица переводов получает две строки: одну для заголовка, а другую для slug для локального de_de.

Надеюсь, что это поможет и добрым.

Ответ 2

Что-то странное для меня: Ваша ORM-конфигурация сущностью выполняется в 2 файлах (yaml и аннотация)?

Слушатели выглядят хорошо загруженными в правильном порядке. Возможно, это поле объекта config в 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: {}

Ответ 3

Ваши конфигурации выглядят правильно. Однако вы пытались обновить поставщиков? Возможно, некоторые файлы могут быть повреждены.

Если процесс обновления не работает, можете ли вы полностью сравнить конфигурации с моим:

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"

И убедитесь, что вы не переопределяете gedmo.listener.translatable на своих сервисах .yml. Если есть код, который переопределяет значение по умолчанию, удалите его. Конфигурация по умолчанию:

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

Ответ 4

Я использую StofDoctrineExtensionsBundle для sluggable и translatable и имеет ту же проблему.

Я искал и пробовал некоторое время и нашел решение для меня:


Entity: поле пули генерируется из поля имени

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-12983553

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();
}

Я надеюсь, что этот пример поможет кому-то.