我可以通过 API 平台获取违规条目的 IRI 吗?
Can I get the violated entry's IRI with API Platform?
我有一个使用 symfony/api
(API 平台)的 Symfony 5 项目和一个带有 UniqueEntity
约束的实体(见下文。我省略了字段注释以便更好地理解它们与此处无关。):
/**
* @ORM\Entity(repositoryClass=CartItemRepository::class)
* @ApiResource(
* collectionOperations={"get","post"},
* itemOperations={"get","patch"},
* normalizationContext={"groups"={"cart_item:read"}}
* )
* @UniqueEntity(fields={"product","cart"})
*/
class CartItem
{
private $id;
private $product;
private $quantity;
private $cart;
/* ... */
}
假设我有一些数据:
----------------------------------------
| id | product_id | cart_id | quantity |
| 1 | 3 | 2 | 1 |
| 2 | 2 | 2 | 2 |
----------------------------------------
现在,如果我发送此 POST 请求:
{
"product": "/api/products/3",
"quantity": 1,
"cart": "/api/carts/2"
}
我当然会期待此 400
响应,因为插入此条目会破坏 [product_id,cart_id]
的唯一性,因为 ID 1 已使用 [3,2]
:
{
"@context": "/api/contexts/ConstraintViolationList",
"@type": "ConstraintViolationList",
"hydra:title": "An error occurred",
"hydra:description": "product: This value is already used.",
"violations": [
{
"propertyPath": "product",
"message": "This value is already used."
}
]
}
我的问题是:我是否有办法获取本应“重复”的实体的 IRI 或 ID?(在这里,ID 应该是为 1,则 IRI 为 /api/cart_items/1
)。我想用这个实现的是重现 MySQL 的 ON DUPLICATE KEY UPDATE quantity = quantity + :quantity
行为,方法是检测此错误并在发生时发送 PATCH
请求,但发送 PATCH
请求,我需要 IRI,或者至少需要我要修补的项目的 ID。
编辑:
我在 Profiler 中看到它是可见的(请参阅下面的 cause
字段)但我无法进入 API 的响应...
Symfony\Component\Validator\ConstraintViolation {#2332 ▼
-message: "This value is already used."
-messageTemplate: "This value is already used."
-parameters: [▶]
-plural: null
-root: App\Entity\CartItem {#675 ▼
-id: null
-product: App\Entity\Product {#1888 …}
-quantity: 1
-cart: App\Entity\Cart {#2119 …}
}
-propertyPath: "product"
-invalidValue: App\Entity\Product {#1888 …}
-constraint: Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity {#2130 …}
-code: "23bd9dbf-6b9b-41cd-a99e-4844bcf3077f"
-cause: [▼
App\Entity\CartItem {#2330 ▼
-id: 2
-product: App\Entity\Product {#1888 …}
-quantity: 2
-cart: App\Entity\Cart {#2119 …}
}
]
}
在这种情况下,我总是使用 API 过滤器 (https://api-platform.com/docs/core/filters/)。在发送 POST 请求之前,发送 GET 请求以检查实体是否存在。例如,为过滤器添加注释:
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
/**
* @ORM\Entity(repositoryClass=CartItemRepository::class)
* @ApiResource(
* collectionOperations={"get","post"},
* itemOperations={"get","patch"},
* normalizationContext={"groups"={"cart_item:read"}}
* )
* @UniqueEntity(fields={"product","cart"})
*
* @ApiFilter(SearchFilter::class, properties={"product": "exact", "cart": "exact"})
*/
class CartItem
{
private $id;
private $product;
private $quantity;
private $cart;
/* ... */
}
并使用 URL 获取现有实体,如下所示:GET /cart_items?product=3&cart=2
您应该获取一个集合。因此,如果 "hydra:totalItems" > 0
来自响应,您可以从 "hydra:member"[0]
检索 iri
您需要 create your custom @Assert, because it is the only way 才能使用处理该作业的两项服务:
- CartItemRepository,
- IriConverterInterface
首先,创建约束 class MyUniqueCartItem。向 class 声明其用法,以便您可以在验证期间访问所有属性:
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
然后,创建 MyUniqueCartItemValidator,并将之前的两个服务自动连接到它。使用 CartItemRepository 检查实体是否已经存在,并使用 IriConverterInterface 检索 IRI:
public function validate($value, Constraint $constraint)
{
// i make it short, just take look ath the doc
$criteria = ['cart' => $value->getCart(), 'product' => $value->getProduct()]
$duplicated = $this->cartItemRepository->findOneBy($criteria);
if ($duplicated !== null) {
$iri = $this->iriConverterInterface->getIriFromItem($duplicated);
$this->context->buildViolation("Duplicated entity : $iri" )
->atPath('whatever')
->addViolation();
}
}
请注意,您可以通过向其添加一些属性来使 MyUniqueCartItem 成为通用约束 MyUniqueEntity存储库。在 MyUniqueEntityValidator 中,将 CartItemRepository 替换为 EntityManagerInterface 并获取存储库:
$repository = $this->entityManger->getRepository($constraint->entityClass);
我有一个使用 symfony/api
(API 平台)的 Symfony 5 项目和一个带有 UniqueEntity
约束的实体(见下文。我省略了字段注释以便更好地理解它们与此处无关。):
/**
* @ORM\Entity(repositoryClass=CartItemRepository::class)
* @ApiResource(
* collectionOperations={"get","post"},
* itemOperations={"get","patch"},
* normalizationContext={"groups"={"cart_item:read"}}
* )
* @UniqueEntity(fields={"product","cart"})
*/
class CartItem
{
private $id;
private $product;
private $quantity;
private $cart;
/* ... */
}
假设我有一些数据:
----------------------------------------
| id | product_id | cart_id | quantity |
| 1 | 3 | 2 | 1 |
| 2 | 2 | 2 | 2 |
----------------------------------------
现在,如果我发送此 POST 请求:
{
"product": "/api/products/3",
"quantity": 1,
"cart": "/api/carts/2"
}
我当然会期待此 400
响应,因为插入此条目会破坏 [product_id,cart_id]
的唯一性,因为 ID 1 已使用 [3,2]
:
{
"@context": "/api/contexts/ConstraintViolationList",
"@type": "ConstraintViolationList",
"hydra:title": "An error occurred",
"hydra:description": "product: This value is already used.",
"violations": [
{
"propertyPath": "product",
"message": "This value is already used."
}
]
}
我的问题是:我是否有办法获取本应“重复”的实体的 IRI 或 ID?(在这里,ID 应该是为 1,则 IRI 为 /api/cart_items/1
)。我想用这个实现的是重现 MySQL 的 ON DUPLICATE KEY UPDATE quantity = quantity + :quantity
行为,方法是检测此错误并在发生时发送 PATCH
请求,但发送 PATCH
请求,我需要 IRI,或者至少需要我要修补的项目的 ID。
编辑:
我在 Profiler 中看到它是可见的(请参阅下面的 cause
字段)但我无法进入 API 的响应...
Symfony\Component\Validator\ConstraintViolation {#2332 ▼
-message: "This value is already used."
-messageTemplate: "This value is already used."
-parameters: [▶]
-plural: null
-root: App\Entity\CartItem {#675 ▼
-id: null
-product: App\Entity\Product {#1888 …}
-quantity: 1
-cart: App\Entity\Cart {#2119 …}
}
-propertyPath: "product"
-invalidValue: App\Entity\Product {#1888 …}
-constraint: Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity {#2130 …}
-code: "23bd9dbf-6b9b-41cd-a99e-4844bcf3077f"
-cause: [▼
App\Entity\CartItem {#2330 ▼
-id: 2
-product: App\Entity\Product {#1888 …}
-quantity: 2
-cart: App\Entity\Cart {#2119 …}
}
]
}
在这种情况下,我总是使用 API 过滤器 (https://api-platform.com/docs/core/filters/)。在发送 POST 请求之前,发送 GET 请求以检查实体是否存在。例如,为过滤器添加注释:
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
/**
* @ORM\Entity(repositoryClass=CartItemRepository::class)
* @ApiResource(
* collectionOperations={"get","post"},
* itemOperations={"get","patch"},
* normalizationContext={"groups"={"cart_item:read"}}
* )
* @UniqueEntity(fields={"product","cart"})
*
* @ApiFilter(SearchFilter::class, properties={"product": "exact", "cart": "exact"})
*/
class CartItem
{
private $id;
private $product;
private $quantity;
private $cart;
/* ... */
}
并使用 URL 获取现有实体,如下所示:GET /cart_items?product=3&cart=2
您应该获取一个集合。因此,如果 "hydra:totalItems" > 0
来自响应,您可以从 "hydra:member"[0]
您需要 create your custom @Assert, because it is the only way 才能使用处理该作业的两项服务:
- CartItemRepository,
- IriConverterInterface
首先,创建约束 class MyUniqueCartItem。向 class 声明其用法,以便您可以在验证期间访问所有属性:
public function getTargets()
{
return self::CLASS_CONSTRAINT;
}
然后,创建 MyUniqueCartItemValidator,并将之前的两个服务自动连接到它。使用 CartItemRepository 检查实体是否已经存在,并使用 IriConverterInterface 检索 IRI:
public function validate($value, Constraint $constraint)
{
// i make it short, just take look ath the doc
$criteria = ['cart' => $value->getCart(), 'product' => $value->getProduct()]
$duplicated = $this->cartItemRepository->findOneBy($criteria);
if ($duplicated !== null) {
$iri = $this->iriConverterInterface->getIriFromItem($duplicated);
$this->context->buildViolation("Duplicated entity : $iri" )
->atPath('whatever')
->addViolation();
}
}
请注意,您可以通过向其添加一些属性来使 MyUniqueCartItem 成为通用约束 MyUniqueEntity存储库。在 MyUniqueEntityValidator 中,将 CartItemRepository 替换为 EntityManagerInterface 并获取存储库:
$repository = $this->entityManger->getRepository($constraint->entityClass);