lenny4/doctrine-merge-persistent-collection-bundle

更新实体时合并持久化集合


README

更新实体时合并持久化集合

Latest Version on Packagist Tests Total Downloads

如果您使用 ApiPlatform 并且不想在更新实体及其子项时发送多个请求,这个包非常有用。

安装

您可以通过 composer 安装此包

composer require lenny4/doctrine-merge-persistent-collection-bundle

用法

<?php

namespace App\Controller;

use Lenny4\DoctrineMergePersistentCollectionBundle\DoctrineMergePersistentCollection;
use Lenny4\DoctrineMergePersistentCollectionBundle\Entity\Father;
use Lenny4\DoctrineMergePersistentCollectionBundle\Entity\Son;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;

class PutFatherController extends AbstractController
{
    public function __invoke(Father $data, DoctrineMergePersistentCollection $doctrineMergePersistentCollection): Father
    {
        $doctrineMergePersistentCollection->merge(
            $data->getSons(),
            static function (Son $son1, Son $son2) {
                return $son1->getName() === $son2->getName();
            },
            static function (Son $son1, Son $son2) {
                $son1->setAge($son2->getAge());
            },
        );
        return $data;
    }
}

它如何工作?

假设您有两个实体 FatherSon 作为 ApiResource

#[ApiResource(
    collectionOperations: [
        'get',
    ],
    itemOperations: [
        'get',
        'put' => [
            'controller' => PutFatherController::class,
        ],
    ],
    attributes: [
        'denormalization_context' => ['groups' => ['w-father']],
    ],
)]
#[ORM\Entity(repositoryClass: FatherRepository::class)]
class Father
{
    #[ORM\Column]
    #[ORM\GeneratedValue]
    #[ORM\Id]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Groups(['w-father'])]
    private ?string $name = null;

    /**
     * @var Collection<int, Son>|Son[]
     */
    #[ORM\OneToMany(mappedBy: 'father', targetEntity: Son::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
    #[Groups(['w-father'])]
    private Collection $sons;

    // getters setters
}
#[ApiResource()]
#[ORM\Entity(repositoryClass: SonRepository::class)]
class Son
{
    #[ORM\Column]
    #[ORM\GeneratedValue]
    #[ORM\Id]
    private ?int $id = null;

    #[ORM\Column(length: 255)]
    #[Groups(['w-father'])]
    private ?string $name = null;

    #[ORM\Column]
    #[Groups(['w-father'])]
    private ?int $age = null;

    #[ORM\JoinColumn(nullable: false)]
    #[ORM\ManyToOne(inversedBy: 'sons')]
    private ?Father $father = null;

    // getters setters
}

数据库中有这些数据

假设您想通过一个请求将 Father 的名称从 father1 更改为 father2,并且只更新一个子项 son1 的年龄。仅使用 ApiPlatform 是目前不可能的。但通过此 Bundle,您可以通过在用法中调用 doctrineMergePersistentCollection->merge 来实现。

  • 函数的第一个参数接受一个 PersistentCollection,它对应于父亲的所有儿子
  • 第二个参数是一个可调用对象,它定义了两个儿子如何相同(在我们的例子中是名称 $son1->getName() === $son2->getName()
  • 第二个参数是一个可调用对象,它定义了当 $son1->getName() === $son2->getName() 返回 true 时如何更新一个儿子

用例(示例)

  1. 添加一个儿子 PUT /api/fathers/1
{
    "name": "father2",
    "sons": [
        {
            "name": "son1",
            "age": 10
        },
        {
            "name": "son2",
            "age": 20
        },
        {
            "name": "son3",
            "age": 30
        }
    ]
}

这将更改父亲的名称为 father2 并添加一个儿子。结果

  1. 更新 son2 的年龄 PUT /api/fathers/1
{
    "name": "father2",
    "sons": [
        {
            "name": "son1",
            "age": 10
        },
        {
            "name": "son2",
            "age": 30
        }
    ]
}

这将更改父亲的名称为 father2 并更新 son2 的年龄。结果

测试

docker-compose up
./runc composer test

变更日志

有关最近更改的更多信息,请参阅 CHANGELOG

许可证

MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件