Trong một dự án drupal 9 được tách rời hoàn toàn, tôi có một loại thực thể tùy chỉnh và đã thêm một ràng buộc duy nhất cho một số trường như được mô tả đây. Điều này hoạt động tốt và không thể thêm một thực thể thứ hai có cùng giá trị trường. Tuy nhiên, tôi đang sử dụng các yêu cầu POST JSONAPI để tạo các thực thể. Tôi nhận thấy rằng khi đưa ra nhiều yêu cầu POST với các giá trị trường giống hệt nhau ngay sau một yêu cầu khác, phương thức trình xác thực (sử dụng entityTypeManager->getStorage(...)->getQuery(...)->condition(...)->execute()
để kiểm tra DB) không trả về các thực thể khác, vì chưa có thực thể trùng lặp nào tồn tại. I E. nó xảy ra nhanh đến mức nhiều thực thể có giá trị giống hệt nhau được tạo ở cùng một dấu thời gian (The tạo
giá trị của các thực thể giống hệt nhau)!
Bỏ qua các ràng buộc là nguy hiểm và phải được ngăn chặn.
Tôi có thể làm gì để giải quyết vấn đề này?
Cập nhật
Đây là chức năng được gọi bên trong Hạn chếValidator
xác thực hàm công khai($entity, Constraint $constraint)
{
...
nếu (!$this->isUnique($entity))
$this->context->addViolation($constraint->notUnique);
...
}
chức năng riêng làUnique(CustomType $entity) {
$date = $entity->get('date')->value;
$type = $entity->bundle();
$employee = $entity->get('employee')->target_id;
$query = $this->entityTypeManager->getStorage('custom_type')->getQuery()
->điều kiện('trạng thái', 1)
->điều kiện('loại', $loại)
->điều kiện('nhân viên', $nhân viên)
->điều kiện('ngày', $ngày);
nếu (!is_null($entity->id()))
$query->condition('id', $entity->id(), '<>');
$workIds = $query->execute();
trả về trống($workIds);
}
Tôi rất vui khi tìm thấy bất kỳ sai sót. Cho đến nay mã này hoạt động tốt trong tất cả các trường hợp khác.
Cập nhật Drupal::lock()
Tôi đã triển khai 2 người đăng ký sự kiện để thêm và phát hành \Drupal::lock()
như đã đề cập trong các ý kiến. Sử dụng xdebug, tôi có thể xác nhận rằng mã đang chạy, tuy nhiên, khóa dường như không có bất kỳ tác dụng nào. Các tài liệu cho Khóa()
là khá hạn chế. Không chắc có gì sai ở đây.
<?php
không gian tên Drupal\custom_entities\EventSubscriber;
sử dụng Symfony\Component\EventDispatcher\EventSubscriberInterface;
sử dụng Symfony\Thành phần\HttpKernel\Sự kiện\RequestEvent;
sử dụng Symfony\Thành phần\HttpKernel\KernelEvents;
lớp JsonApiRequestDBLock triển khai EventSubscriberInterface {
/**
* Thêm khóa cho các yêu cầu JSON:API.
*
* @param \Symfony\Component\HttpKernel\Event\RequestEvent $event
* Sự kiện cần xử lý.
*/
hàm công khai onRequest(RequestEvent $event) {
$request = $event->getRequest();
if ($request->getRequestFormat() !== 'api_json') {
trở lại;
}
if ($request->attributes->get('_route') === 'jsonapi.custom_type--work.collection.post' &&
$request->attributes->get('_controller') === 'jsonapi.entity_resource:createIndividual'
) {
$lock = \Drupal::lock();
$lock->acre('custom_create_lock');
}
}
/**
* {@inheritdoc}
*/
hàm tĩnh công khai getSubscribeEvents() {
$events[KernelEvents::REQUEST][] = ['onRequest'];
trả lại sự kiện $;
}
}
và nhả khóa sau khi phản hồi
<?php
không gian tên Drupal\custom_entities\EventSubscriber;
sử dụng Symfony\Component\EventDispatcher\EventSubscriberInterface;
sử dụng Symfony\Component\HttpKernel\Event\ResponseEvent;
sử dụng Symfony\Thành phần\HttpKernel\KernelEvents;
lớp JsonApiResponseDBRelease triển khai EventSubscriberInterface {
/**
* {@inheritdoc}
*/
hàm tĩnh công khai getSubscribeEvents() {
$events[KernelEvents::RESPONSE][] = ['onResponse'];
trả lại sự kiện $;
}
/**
* Phát hành các phản hồi JSON:API.
*
* @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
* Sự kiện cần xử lý.
*/
hàm công khai onResponse(ResponseEvent $event) {
$response = $event->getResponse();
if (strpos($response->headers->get('Content-Type'), 'application/vnd.api+json') === FALSE) {
trở lại;
}
$request = $event->getRequest();
if ($request->attributes->get('_route') === 'jsonapi.custom_type--work.collection.post' &&
$request->attributes->get('_controller') === 'jsonapi.entity_resource:createIndividual'
) {
// Thả khóa.
$lock = \Drupal::lock();
nếu (!$lock->lockMayBeAvailable('custom_create_lock'))
$lock->release('custom_create_lock');
}
}
}
Điều này đã được thêm vào dịch vụ.yml
# Người đăng ký sự kiện.
custom_entities.jsonapi_db_lock.subscriber:
lớp: Drupal\custom_entities\EventSubscriber\JsonApiRequestDBLock
thẻ:
- { tên: event_subscriber }
custom_entities.jsonapi_response_db_release.subscriber:
lớp: Drupal\custom_entities\EventSubscriber\JsonApiResponseDBRelease
thẻ:
- { tên: event_subscriber }