API 平台 - 实体翻译,Doctrine Translatable

API Platform - Entity Translation, Doctrine Translatable

我正在尝试添加 KnpLabs Doctrine Behaviors - and precisely, the Translatable Behavior - 在我的 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 行为正常工作的基本"configuration"。

当我尝试更新数据库模式时出现问题:我收到此错误:

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 中,已经有一个 ID 和文档精确说明翻译实体应该只包含我们要翻译的字段...

无论如何,我已经为这个 ArtcleTranslation 实体添加了一个 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;

          /**
           * @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 文档:

一切看起来都很好!但是当我查看数据库时:

在文章 table 中:

在 ArticleTranslation table 中:

我猜肯定是联动的,但是在swagger POST Tab中,型号也不一样

article_translation 型号

我只在两个实体上尝试了 /GET 和 /POST 方法,它们正在工作(我可以在数据库中看到它)但它们之间没有任何关系。

我希望我的 post 不会太长,但我尽量做到更具体!

提前致谢

我认为你做错了。您有一个实体 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){...}
 }

如果现在一切正常,请告诉我。

我做了另一个答案,因为第一个问题是为了解决错误,而不是解释我如何将 Knp Labs Doctrine Translations 与 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,当我们从 api

中获取一些 Article 时,它会自动从 ArticleTranslation 填充

2 - 现在我们要 add/edit 一些翻译:我们需要在 Article 里面填充 newTranslations 属性发送到 api:

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

现在我们正在接收 api 中的新翻译,但它没有保留,因为我们必须调用函数 mergeNewTranslations()。此函数仅获取属性 $newTranslations 内的所有翻译并将其与 $translations 属性合并以保留它。

3 - 我创建了一个名为 TranslatableOverride 的新 trait。我直接将它导入到 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 搭配起来很有魅力。

我没想过一次只翻译一个。目前,我用一大堆翻译来检索我的实体,这绝对是低效的。我想我会在我的覆盖 trait 中添加 getTranslations 的覆盖。