lenny4 / doctrine-merge-persistent-collection-bundle
更新实体时合并持久化集合
1.2.0
2023-12-05 20:10 UTC
Requires
- php: ^8.1
- doctrine/orm: ^2.13
- symfony/config: ^6.1
- symfony/dependency-injection: ^6.1
- symfony/http-kernel: ^6.1
Requires (Dev)
- api-platform/core: ^3.2
- dama/doctrine-test-bundle: ^7.1
- doctrine/doctrine-bundle: ^2.7
- doctrine/doctrine-fixtures-bundle: ^3.4
- doctrine/doctrine-migrations-bundle: ^3.2
- nelmio/cors-bundle: ^2.2
- phpdocumentor/reflection-docblock: ^5.3
- phpstan/phpdoc-parser: ^1.7
- phpunit/phpunit: ^10
- rector/rector: dev-main
- roave/security-advisories: dev-latest
- symfony/asset: ^6.1
- symfony/browser-kit: ^6.1
- symfony/css-selector: ^6.1
- symfony/dotenv: ^6.1
- symfony/expression-language: ^6.1
- symfony/flex: ^2.2
- symfony/framework-bundle: ^6.1
- symfony/http-client: ^6.1
- symfony/maker-bundle: ^1.45
- symfony/phpunit-bridge: ^6.1
- symfony/property-access: ^6.1
- symfony/property-info: ^6.1
- symfony/proxy-manager-bridge: ^6.1
- symfony/runtime: ^6.1
- symfony/security-bundle: ^6.1
- symfony/serializer: ^6.1
- symfony/twig-bundle: ^6.1
- symfony/validator: ^6.1
- symfony/yaml: ^6.1
Conflicts
README
更新实体时合并持久化集合
如果您使用 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; } }
它如何工作?
假设您有两个实体 Father
和 Son
作为 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 时如何更新一个儿子
用例(示例)
- 添加一个儿子
PUT /api/fathers/1
{ "name": "father2", "sons": [ { "name": "son1", "age": 10 }, { "name": "son2", "age": 20 }, { "name": "son3", "age": 30 } ] }
这将更改父亲的名称为 father2
并添加一个儿子。结果
- 更新 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)。有关更多信息,请参阅 许可证文件