将 Doctrine Entity 中的子项过滤为 属性 和 mutate/hydrate 表单输入

Filter children in Doctrine Entity as property and mutate/hydrate form input

我正在使用 Symfony 3.2 和 Doctrine 2.5 开发一个带有 API 端点的文章数据库。在请求正文中,我有一个作者:

{
   "article": {
       "title": "Some article",
       "author": {
           "email": "someone@something.com",
           "name": "Howard Wedothis"
       }
   }
}

我想存储一个带有日期时间、文章 ID 和作者 ID 的更新实体。目前,为了做到这一点,我必须 post 以下内容:

{
    "article": {
        "title": "Some article",
        "updates": [{
            "author": {
                "email": "someone@something.com",
                "name": "Howard Wedothis"
            }
        }]
    }
}

这不像 IMO 那样优雅。

第一个问题: mutate/hydrate 简单作者字段并存储针对文章和作者的更新的最佳方法是什么?作者和文章是 ManyToMany,但我想避免 post 主要出于可读性原因而使用一个数组。

第二个问题:是否可以为createdlastUpdated的文章实体添加属性,分别显示来自没有将存储库注入实体的文章?

$article->getCreated() // returns first Update
$article->getLastUpdated() // returns last Update

第二个问题的答案——使用Lifecycle Callbacks

<?php

use Doctrine\ORM\Mapping as ORM;

/** 
 * @ORM\HasLifecycleCallbacks
 */
class Author
{
    ...

    /**
     * @ORM\Column(type="datetime")
     */
    protected $createdAt;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $updatedAt;

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

    /**
     * Set createdAt.
     *
     * @param \DateTime $createdAt
     *
     * @return this
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;

        return $this;
    }

    /**
     * Get createdAt.
     *
     * @return \DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }

    /**
     * Set modifiedAt.
     *
     * @param \DateTime $updatedAt
     *
     * @return Article
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt.
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

    ...

    /**
     * @ORM\PrePersist
     * @ORM\PreUpdate
     */
    public function updatedTimestamps()
    {
        $this->setUpdatedAt(new \DateTime(date('Y-m-d H:i:s')));

        if ($this->getCreatedAt() == null) {
            $this->setCreatedAt(new \DateTime(date('Y-m-d H:i:s')));
        }
    }
}

http://symfony.com/doc/current/doctrine/lifecycle_callbacks.html http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#lifecycle-events

关于您的请求示例,插入请求和更新请求应该具有相同的格式。 updates 键让你的生活变得复杂。

使用 POST 方法插入文章和 PUT(发送完整的文章对象)或 PATCH(仅发送要更新的字段)。

https://knpuniversity.com/screencast/rest/put-versus-post

https://knpuniversity.com/screencast/symfony-rest/patch-programmer

最后,我按照@Matko 的建议,通过添加作者并在更新时覆盖作者并使用生命周期事件在 PrePersist 和 PreUpdated 上创建新的更新实体来解决这个问题。

请求数据:

{
   "article": {
       "title": "Some article",
       "author": {
           "email": "someone@something.com",
           "name": "Howard Wedothis"
       }
   }
}

Article.php:

/**
 * @ORM\Entity
 * @ORM\Table(name="articles")
 * @ORM\HasLifecycleCallbacks
 */
class Article
{
    /**
     * @return Update
     */
    public function getCreated(): Update
    {
        return $this->updates->first();
    }

    /**
     * @return Update
     */
    public function getLastUpdated(): Update
    {
        return $this->updates->last();
    }

    /**
     * @ORM\PrePersist
     * @ORM\PreUpdate
     */
    public function addUpdate(): void
    {
        $update = new Update();
        $update->setAuthor($this->getAuthor());
        $update->setArticle($this);
        $this->updates->add($update);
    }
}

此方法确实会使实体的作者无效,但会保留文章历史记录。