Платформа API - Перевод сущностей, возможность перевода доктрины

Я пытаюсь добавить Поведение доктрины KnpLabs - а точнее, Переводимое поведение - на одну из сущностей в моем проекте платформы API.

Вот что я сделал до сих пор:

    namespace App\Entity;

    use Doctrine\ORM\Mapping as ORM;
    use Knp\DoctrineBehaviors\Model as ORMBehaviors;
    use ApiPlatform\Core\Annotation\ApiResource;

    /**
    * @ORM\Entity(repositoryClass = "App\Repository\ArticleRepository")
    * @ApiResource
    */
    class Article
    {
        use ORMBehaviors\Translatable\Translation,
            ORMBehaviors\Timestampable\Timestampable
        ;

        /**
        * @ORM\Id
        * @ORM\GeneratedValue
        * @ORM\Column(type = "integer")
        */
        protected $id;

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

А вот перевод сущности:

    namespace App\Entity;

    use Doctrine\ORM\Mapping as ORM;
    use Knp\DoctrineBehaviors\Model as ORMBehaviors;
    use ApiPlatform\Core\Annotation\ApiResource;
    use App\Traits as CustomTraits;

    /**
     * @ORM\Entity(repositoryClass = "App\Repository\ArticleTranslationRepository")
     * @ApiResource
     */
     class ArticleTranslation
     {
          use ORMBehaviors\Translatable\Translatable;

          /**
           * @var string
           * 
           * @ORM\Column(name = "someFieldToTranslate", type = "string", length=255, nullable=true)
           */
           private $someFieldToTranslate;

           public function getSomeFieldToTranslate(){...}
           public function setSomeFieldToTranslate($someFieldToTranslate){...}
     }

Вот базовая «конфигурация» для работы Translatable Behavior в соответствии с документом.

Проблемы начинаются, когда я пытаюсь обновить схему БД: я получил эту ошибку:

No identifier/primary key specified for Entity "App\Entity\ArticleTranslation". Every Entity must have an identifier/primary key in . (which is being imported from "/Sites/bookshop-api/config/routes/api_platform.yaml"). Make sure there is a
loader supporting the "api_platform" type.

Однако в Translatable Traits уже есть идентификатор и документация, в которой указано, что объект перевода должен иметь только поля, которые мы хотим перевести ...

В любом случае, я присвоил этому объекту ArtcleTranslation идентификатор, чтобы избавиться от ошибки:

    namespace App\Entity;

    use Doctrine\ORM\Mapping as ORM;
    use Knp\DoctrineBehaviors\Model as ORMBehaviors;
    use ApiPlatform\Core\Annotation\ApiResource;
    use App\Traits as CustomTraits;

    /**
     * @ORM\Entity(repositoryClass = "App\Repository\ArticleTranslationRepository")
     * @ApiResource
     */
     class ArticleTranslation
     {
          use ORMBehaviors\Translatable\Translatable;

          /**
           * @ORM\Id
           * @ORM\GeneratedValue
           * @ORM\Column(type = "integer")
           */
           protected $id;


          /**
           * @var string
           * 
           * @ORM\Column(name = "content", type = "string", length=255, nullable=true)
           */
           private $content;

           public function getContent(){...}
           public function setContent($someContent){...}
     }

Отсюда никаких ошибок при обновлении схемы БД. Идеально ! Теперь я могу взглянуть на документацию Swagger:

Платформа API - Перевод сущностей, возможность перевода доктрины

Все выглядит нормально! Но когда я взгляну на БД:

В таблице статей:

  • нет "местного" поля
  • нет "пустого" поля

В таблице перевода статьи:

  • нет поля "translatable_id"
  • нет "currentLocal"
  • нет defaultLocal

Я думаю, это должно быть связано, но на вкладке POST swagger модель тоже другая.

Платформа API - Перевод сущностей, возможность перевода доктриныarticle_translation модель

Я пробовал только методы / GET и / POST для обоих объектов, они работают (я вижу это в БД), но между ними нет связи.

Надеюсь, мой пост не слишком длинный, но я постарался быть более конкретным!

заранее спасибо

Вы смогли найти решение? Я столкнулся с той же проблемой. Спасибо за любую помощь

Tahir 22.06.2018 10:27

@Tahir все еще не нашел решения ..

skytorner 25.06.2018 10:26

В моем случае подписчик не был зарегистрирован в списке пакетов. Нам необходимо зарегистрировать пакет подписчиков, как указано в документация. После исправления я получил все столбцы в db. Хотя я застрял в том, как я могу отправлять / получать переводы с использованием конечных точек по умолчанию.

Tahir 25.06.2018 10:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
2 237
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я думаю, ты ошибся. У вас есть объект Article, который должен быть translatable, и вы хотите перевести некоторые поля, которые будут translations?

Таким образом, вы должны сделать наоборот: поставить use ORMBehaviors\Translatable\Translatable на Article и use ORMBehaviors\Translatable\Translation на ArticleTranslation.

Исправление для вашей сущности Article:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use ApiPlatform\Core\Annotation\ApiResource;

/**
* @ORM\Entity(repositoryClass = "App\Repository\ArticleRepository")
* @ApiResource
*/
class Article
{
    use ORMBehaviors\Translatable\Translatable,
        ORMBehaviors\Timestampable\Timestampable
    ;

    /**
    * @ORM\Id
    * @ORM\GeneratedValue
    * @ORM\Column(type = "integer")
    */
    protected $id;

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

и исправление для вашего объекта ArticleTranslation:

    namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Knp\DoctrineBehaviors\Model as ORMBehaviors;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Traits as CustomTraits;

/**
 * @ORM\Entity(repositoryClass = "App\Repository\ArticleTranslationRepository")
 * @ApiResource
 */
 class ArticleTranslation
 {
      use ORMBehaviors\Translatable\Translation;

      /**
       * @var string
       * 
       * @ORM\Column(name = "someFieldToTranslate", type = "string", length=255, nullable=true)
       */
       private $someFieldToTranslate;

       public function getSomeFieldToTranslate(){...}
       public function setSomeFieldToTranslate($someFieldToTranslate){...}
 }

Дай мне знать, если сейчас все в порядке.

Спасибо за ответ! Я сейчас в другом проекте, но я посмотрю как можно скорее! Кстати, вы могли использовать knplabsBehaviour с платформой Api?

skytorner 06.07.2018 13:32

Да, это работает. У меня просто беда на POST и PUT. Я думаю, что поле newTranslations не обрабатывается API-платформой. Но я найду решение / трюк.

Maël 06.07.2018 13:39

Вы нашли решение с помощью POST / PUT? Есть ли другой способ интегрировать перевод сущностей в ApiPlatform? Я ищу решение, в котором объект (например, статья) в GET предоставит либо контент с возможностью выбора перевода с помощью ключа локали, либо путем передачи языкового стандарта и в ответ получит контент на языке, указанном локалью. Не нашел пока лучшего решения :(

xoxn-- 1'w3k4n 22.08.2018 08:25

Я дал новый полный ответ.

Maël 29.08.2018 08:35
Ответ принят как подходящий

Я ответил еще раз, поскольку первый вопрос заключался в устранении ошибки, а не в объяснении того, как я интегрировал переводы доктрины Knp Labs с платформой Api.

Резюме :

У нас есть объект Article, некоторые поля которого переведены внутри ArticleTranslation. Мы хотим получить объект через Api platform с его переводами, и мы хотим добавить или обновить переводы через api.

Что я сделал :

Объект 1 -Article имеет use ORMBehaviors\Translatable\Translatable. Если мы заглянем внутрь этого trait, у него есть 2 атрибута: $translations и $newTranslations. Нам нужно раскрыть эти атрибуты внутри объекта Article:

class Article {
    use ORMBehaviors\Translatable\Translatable;

    protected $translations;
    protected $newTranslations;
}

Теперь у нас есть новый атрибут translations, который автоматически заполняется из ArticleTranslation, когда мы получаем немного Article из api.

2 - Теперь мы хотим добавить / отредактировать некоторые переводы: нам нужно заполнить атрибут newTranslations внутри Article, когда мы отправляем в api:

"newTranslations": {
    "en": {
      "description": "Firstname"
    },
    "fr": {
      "description": "Prénom"
    }
}

Теперь мы получаем новые переводы в api, но они не сохраняются, потому что мы должны вызвать функцию mergeNewTranslations(). Эта функция просто берет все переводы внутри атрибута $newTranslations и объединяет их с атрибутом $translations, чтобы сохранить его.

3 - Я создал новый trait, который назвал TranslatableOverride. Я импортировал его прямо на свой объект рядом с ORMBehaviors\Translatable\Translation:

trait TranslatableOverride
{

    /**
     * Set collection of new translations.
     *
     * @return ArrayCollection
     */
    public function setNewTranslations($newTranslations)
    {
        if ($newTranslations) {
            foreach ($newTranslations as $locale => $translations) {
                foreach ($translations as $key => $value) {
                    $tr = $this->translate($locale);
                    $setter = 'set' . ucfirst($key);
                    if (method_exists($tr, $setter)) {
                        $tr->{$setter}($value);
                    }
                }
            }

            $this->mergeNewTranslations();
        }
    }
}

Не уверен, что это красиво, но с api-platform работает как шарм.

Я не думал о том, чтобы получать только один перевод за раз. На данный момент я извлекаю свои объекты с целой кучей переводов, что определенно неэффективно. Думаю, я добавлю переопределение для getTranslations в свой переопределение trait.

Спасибо @ Maël за то, что нашли время ответить на этот пост, я попробую ваше решение, когда смогу!

skytorner 04.09.2018 19:14

Другие вопросы по теме