From 76044381fdb67502b42dc53f2faf51950e496078 Mon Sep 17 00:00:00 2001 From: Valery Petrov Date: Fri, 15 May 2026 15:35:50 +0300 Subject: [PATCH] issues/27: filter DTO, strip id from payloads, lifecycle updateAt --- src/Controller/ArticleController.php | 3 +- src/Controller/DiseaseController.php | 3 +- src/Controller/MedicalCenterController.php | 3 +- src/Controller/NewsController.php | 3 +- src/Controller/PromoController.php | 3 +- src/Controller/SiteServiceController.php | 3 +- src/Dto/Content/ContentFilterDto.php | 63 +++++++++++++ src/Entity/Article.php | 6 +- src/Entity/Behavior/UpdateTimestampTrait.php | 24 +++++ src/Entity/Disease.php | 6 +- src/Entity/MedicalCenter.php | 6 +- src/Entity/News.php | 6 +- src/Entity/Promo.php | 6 +- src/Entity/SiteService.php | 6 +- src/Repository/ArticleRepository.php | 4 +- src/Repository/ContentFilterTrait.php | 99 ++------------------ src/Repository/DiseaseRepository.php | 4 +- src/Repository/MedicalCenterRepository.php | 4 +- src/Repository/NewsRepository.php | 4 +- src/Repository/PromoRepository.php | 4 +- src/Repository/SiteServiceRepository.php | 4 +- src/Service/Crud/CrudResponder.php | 18 +--- 22 files changed, 153 insertions(+), 129 deletions(-) create mode 100644 src/Dto/Content/ContentFilterDto.php create mode 100644 src/Entity/Behavior/UpdateTimestampTrait.php diff --git a/src/Controller/ArticleController.php b/src/Controller/ArticleController.php index 798b0d4..5ab7989 100644 --- a/src/Controller/ArticleController.php +++ b/src/Controller/ArticleController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Dto\Content\ContentFilterDto; use App\Entity\Article; use App\Repository\ArticleRepository; use App\Service\Crud\CrudResponder; @@ -37,7 +38,7 @@ final class ArticleController extends AbstractController #[Route('/list', name: 'article_list', methods: ['GET'])] public function list(Request $request, ArticleRepository $repository): JsonResponse { - $qb = $repository->createFilteredQueryBuilder($request->query->all()); + $qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request)); return $this->json($this->paginator->paginateWithLegacyMeta($qb, $request), Response::HTTP_OK, [], [ 'groups' => self::READ_GROUPS, diff --git a/src/Controller/DiseaseController.php b/src/Controller/DiseaseController.php index 1c18794..34ccc34 100644 --- a/src/Controller/DiseaseController.php +++ b/src/Controller/DiseaseController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Dto\Content\ContentFilterDto; use App\Entity\Disease; use App\Repository\DiseaseRepository; use App\Service\Crud\CrudResponder; @@ -36,7 +37,7 @@ final class DiseaseController extends AbstractController #[Route('/list', name: 'disease_list', methods: ['GET'])] public function list(Request $request, DiseaseRepository $repository): JsonResponse { - $qb = $repository->createFilteredQueryBuilder($request->query->all()); + $qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request)); return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [ 'groups' => self::READ_GROUPS, diff --git a/src/Controller/MedicalCenterController.php b/src/Controller/MedicalCenterController.php index 8125326..474a765 100644 --- a/src/Controller/MedicalCenterController.php +++ b/src/Controller/MedicalCenterController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Dto\Content\ContentFilterDto; use App\Entity\MedicalCenter; use App\Repository\MedicalCenterRepository; use App\Service\Crud\CrudResponder; @@ -36,7 +37,7 @@ final class MedicalCenterController extends AbstractController #[Route('/list', name: 'medical_center_list', methods: ['GET'])] public function list(Request $request, MedicalCenterRepository $repository): JsonResponse { - $qb = $repository->createFilteredQueryBuilder($request->query->all()); + $qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request)); return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [ 'groups' => self::READ_GROUPS, diff --git a/src/Controller/NewsController.php b/src/Controller/NewsController.php index dd57dda..08b29ac 100644 --- a/src/Controller/NewsController.php +++ b/src/Controller/NewsController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Dto\Content\ContentFilterDto; use App\Entity\News; use App\Repository\NewsRepository; use App\Service\Crud\CrudResponder; @@ -36,7 +37,7 @@ final class NewsController extends AbstractController #[Route('/list', name: 'news_list', methods: ['GET'])] public function list(Request $request, NewsRepository $repository): JsonResponse { - $qb = $repository->createFilteredQueryBuilder($request->query->all()); + $qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request)); return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [ 'groups' => self::READ_GROUPS, diff --git a/src/Controller/PromoController.php b/src/Controller/PromoController.php index dff9926..ba95aad 100644 --- a/src/Controller/PromoController.php +++ b/src/Controller/PromoController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Dto\Content\ContentFilterDto; use App\Entity\Promo; use App\Repository\PromoRepository; use App\Service\Crud\CrudResponder; @@ -36,7 +37,7 @@ final class PromoController extends AbstractController #[Route('/list', name: 'promo_list', methods: ['GET'])] public function list(Request $request, PromoRepository $repository): JsonResponse { - $qb = $repository->createFilteredQueryBuilder($request->query->all()); + $qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request)); return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [ 'groups' => self::READ_GROUPS, diff --git a/src/Controller/SiteServiceController.php b/src/Controller/SiteServiceController.php index 50893a7..32a232f 100644 --- a/src/Controller/SiteServiceController.php +++ b/src/Controller/SiteServiceController.php @@ -2,6 +2,7 @@ namespace App\Controller; +use App\Dto\Content\ContentFilterDto; use App\Entity\SiteService; use App\Repository\SiteServiceRepository; use App\Service\Crud\CrudResponder; @@ -36,7 +37,7 @@ final class SiteServiceController extends AbstractController #[Route('/list', name: 'site_service_list', methods: ['GET'])] public function list(Request $request, SiteServiceRepository $repository): JsonResponse { - $qb = $repository->createFilteredQueryBuilder($request->query->all()); + $qb = $repository->createFilteredQueryBuilder(ContentFilterDto::fromRequest($request)); return $this->json($this->paginator->paginate($qb, $request), Response::HTTP_OK, [], [ 'groups' => self::READ_GROUPS, diff --git a/src/Dto/Content/ContentFilterDto.php b/src/Dto/Content/ContentFilterDto.php new file mode 100644 index 0000000..8cb53cb --- /dev/null +++ b/src/Dto/Content/ContentFilterDto.php @@ -0,0 +1,63 @@ +query->get('regionId', $request->query->get('region_id'))), + active: self::nullableBool($request->query->get('active')), + alias: self::nonEmptyString($request->query->get('alias')), + search: self::nonEmptyString($request->query->get('search', $request->query->get('q'))), + ); + } + + private static function positiveInt(mixed $value): ?int + { + if ($value === null || $value === '' || !is_numeric($value)) { + return null; + } + + $value = (int) $value; + + return $value > 0 ? $value : null; + } + + private static function nullableBool(mixed $value): ?bool + { + if ($value === null || $value === '') { + return null; + } + + if (is_bool($value)) { + return $value; + } + + return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + } + + private static function nonEmptyString(mixed $value): ?string + { + if (!is_string($value)) { + return null; + } + + $value = trim($value); + + return $value !== '' ? $value : null; + } +} diff --git a/src/Entity/Article.php b/src/Entity/Article.php index dffa469..675d15f 100644 --- a/src/Entity/Article.php +++ b/src/Entity/Article.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Entity\Behavior\UpdateTimestampTrait; use App\Repository\ArticleRepository; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -12,8 +13,11 @@ use Symfony\Component\Validator\Constraints as Assert; #[ORM\Table(name: 'article')] #[ORM\Index(name: 'idx_article_region_id', columns: ['region_id'])] #[ORM\Index(name: 'idx_article_active', columns: ['active'])] +#[ORM\HasLifecycleCallbacks] class Article { + use UpdateTimestampTrait; + #[Groups(['article:read'])] #[ORM\Id] #[ORM\GeneratedValue(strategy: "IDENTITY")] @@ -56,7 +60,7 @@ class Article #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $content = null; - #[Groups(['article:read', 'article:write'])] + #[Groups(['article:read'])] #[ORM\Column(name: 'update_at', type: Types::DATETIME_MUTABLE, nullable: true)] private ?\DateTimeInterface $updateAt = null; diff --git a/src/Entity/Behavior/UpdateTimestampTrait.php b/src/Entity/Behavior/UpdateTimestampTrait.php new file mode 100644 index 0000000..7d851d3 --- /dev/null +++ b/src/Entity/Behavior/UpdateTimestampTrait.php @@ -0,0 +1,24 @@ +updateAt === null) { + $this->updateAt = new \DateTime(); + } + } + + #[ORM\PreUpdate] + public function refreshUpdateAt(): void + { + $this->updateAt = new \DateTime(); + } +} diff --git a/src/Entity/Disease.php b/src/Entity/Disease.php index 9bbd65c..1851e00 100644 --- a/src/Entity/Disease.php +++ b/src/Entity/Disease.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Entity\Behavior\UpdateTimestampTrait; use App\Repository\DiseaseRepository; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -11,8 +12,11 @@ use Symfony\Component\Serializer\Annotation\Groups; #[ORM\Table(name: 'disease')] #[ORM\Index(name: 'idx_disease_region_id', columns: ['region_id'])] #[ORM\Index(name: 'idx_disease_active', columns: ['active'])] +#[ORM\HasLifecycleCallbacks] class Disease { + use UpdateTimestampTrait; + #[Groups(['disease:read'])] #[ORM\Id] #[ORM\GeneratedValue(strategy: "IDENTITY")] @@ -43,7 +47,7 @@ class Disease #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $anons = null; - #[Groups(['disease:read', 'disease:write'])] + #[Groups(['disease:read'])] #[ORM\Column(name: 'update_at', type: Types::DATETIME_MUTABLE, nullable: true)] private ?\DateTimeInterface $updateAt = null; diff --git a/src/Entity/MedicalCenter.php b/src/Entity/MedicalCenter.php index 028cee6..6e01ced 100644 --- a/src/Entity/MedicalCenter.php +++ b/src/Entity/MedicalCenter.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Entity\Behavior\UpdateTimestampTrait; use App\Repository\MedicalCenterRepository; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -9,8 +10,11 @@ use Symfony\Component\Serializer\Annotation\Groups; #[ORM\Entity(repositoryClass: MedicalCenterRepository::class)] #[ORM\Table(name: 'medical_center')] +#[ORM\HasLifecycleCallbacks] class MedicalCenter { + use UpdateTimestampTrait; + #[ORM\Id] #[ORM\GeneratedValue(strategy: "IDENTITY")] #[ORM\Column(type: Types::INTEGER)] @@ -42,7 +46,7 @@ class MedicalCenter private ?string $content = null; #[ORM\Column(name: 'update_at', type: Types::DATETIME_MUTABLE, nullable: true)] - #[Groups(['medical_center:read', 'medical_center:write'])] + #[Groups(['medical_center:read'])] private ?\DateTimeInterface $updateAt = null; #[ORM\Column(name: 'kod_uslug', type: 'jsonb', nullable: true)] diff --git a/src/Entity/News.php b/src/Entity/News.php index 552af9f..f91922a 100644 --- a/src/Entity/News.php +++ b/src/Entity/News.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Entity\Behavior\UpdateTimestampTrait; use App\Repository\NewsRepository; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -11,8 +12,11 @@ use Symfony\Component\Serializer\Annotation\Groups; #[ORM\Table(name: 'news')] #[ORM\Index(name: 'idx_news_region_id', columns: ['region_id'])] #[ORM\Index(name: 'idx_news_active', columns: ['active'])] +#[ORM\HasLifecycleCallbacks] class News { + use UpdateTimestampTrait; + #[ORM\Id] #[ORM\GeneratedValue(strategy: "IDENTITY")] #[ORM\Column(type: Types::INTEGER)] @@ -44,7 +48,7 @@ class News private ?string $content = null; #[ORM\Column(name: 'update_at', type: Types::DATETIME_MUTABLE, nullable: true)] - #[Groups(['news:read', 'news:write'])] + #[Groups(['news:read'])] private ?\DateTimeInterface $updateAt = null; #[ORM\Column(name: 'link_el_price', type: Types::TEXT, nullable: true)] diff --git a/src/Entity/Promo.php b/src/Entity/Promo.php index 4f1e983..63076f0 100644 --- a/src/Entity/Promo.php +++ b/src/Entity/Promo.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Entity\Behavior\UpdateTimestampTrait; use App\Repository\PromoRepository; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -11,8 +12,11 @@ use Symfony\Component\Serializer\Annotation\Groups; #[ORM\Table(name: 'promo')] #[ORM\Index(name: 'idx_promo_region_id', columns: ['region_id'])] #[ORM\Index(name: 'idx_promo_active', columns: ['active'])] +#[ORM\HasLifecycleCallbacks] class Promo { + use UpdateTimestampTrait; + #[ORM\Id] #[ORM\GeneratedValue(strategy: "IDENTITY")] #[ORM\Column(type: Types::INTEGER)] @@ -44,7 +48,7 @@ class Promo private ?string $content = null; #[ORM\Column(name: 'update_at', type: Types::DATETIME_MUTABLE, nullable: true)] - #[Groups(['promo:read', 'promo:write'])] + #[Groups(['promo:read'])] private ?\DateTimeInterface $updateAt = null; #[ORM\Column(type: 'jsonb', nullable: true)] diff --git a/src/Entity/SiteService.php b/src/Entity/SiteService.php index ac29328..9691651 100644 --- a/src/Entity/SiteService.php +++ b/src/Entity/SiteService.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Entity\Behavior\UpdateTimestampTrait; use App\Repository\SiteServiceRepository; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping as ORM; @@ -11,8 +12,11 @@ use Symfony\Component\Serializer\Annotation\Groups; #[ORM\Table(name: 'site_services')] #[ORM\Index(name: 'idx_site_services_region_id', columns: ['region_id'])] #[ORM\Index(name: 'idx_site_services_active', columns: ['active'])] +#[ORM\HasLifecycleCallbacks] class SiteService { + use UpdateTimestampTrait; + #[ORM\Id] #[ORM\GeneratedValue(strategy: "IDENTITY")] #[ORM\Column(type: Types::INTEGER)] @@ -44,7 +48,7 @@ class SiteService private ?string $content = null; #[ORM\Column(name: 'update_at', type: Types::DATETIME_MUTABLE, nullable: true)] - #[Groups(['site_service:read', 'site_service:write'])] + #[Groups(['site_service:read'])] private ?\DateTimeInterface $updateAt = null; #[ORM\Column(name: 'link_videoreviews', type: 'jsonb', nullable: true)] diff --git a/src/Repository/ArticleRepository.php b/src/Repository/ArticleRepository.php index 7b70263..e194953 100644 --- a/src/Repository/ArticleRepository.php +++ b/src/Repository/ArticleRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use App\Entity\Article; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; @@ -20,9 +21,8 @@ class ArticleRepository extends ServiceEntityRepository } /** - * @param array $filters */ - public function createFilteredQueryBuilder(array $filters): QueryBuilder + public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder { $qb = $this->createQueryBuilder('a')->orderBy('a.id', 'DESC'); diff --git a/src/Repository/ContentFilterTrait.php b/src/Repository/ContentFilterTrait.php index c95453b..6a47ec2 100644 --- a/src/Repository/ContentFilterTrait.php +++ b/src/Repository/ContentFilterTrait.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use Doctrine\ORM\QueryBuilder; /** @@ -24,107 +25,27 @@ use Doctrine\ORM\QueryBuilder; trait ContentFilterTrait { /** - * @param array $filters */ - private function applyCommonFilters(QueryBuilder $qb, string $alias, array $filters): void + private function applyCommonFilters(QueryBuilder $qb, string $alias, ContentFilterDto $filters): void { - $regionId = $this->extractIntFilter($filters, ['regionId', 'region_id']); - if ($regionId !== null && $regionId > 0) { + if ($filters->regionId !== null) { $qb->andWhere("$alias.regionId = :regionId") - ->setParameter('regionId', $regionId); + ->setParameter('regionId', $filters->regionId); } - $active = $this->extractBoolFilter($filters, ['active']); - if ($active !== null) { + if ($filters->active !== null) { $qb->andWhere("$alias.active = :active") - ->setParameter('active', $active); + ->setParameter('active', $filters->active); } - $aliasFilter = $this->extractNonEmptyStringFilter($filters, ['alias']); - if ($aliasFilter !== null) { + if ($filters->alias !== null) { $qb->andWhere("$alias.alias = :aliasValue") - ->setParameter('aliasValue', $aliasFilter); + ->setParameter('aliasValue', $filters->alias); } - $search = $this->extractNonEmptyStringFilter($filters, ['search', 'q']); - if ($search !== null) { + if ($filters->search !== null) { $qb->andWhere("LOWER($alias.name) LIKE :search") - ->setParameter('search', '%' . mb_strtolower($search) . '%'); + ->setParameter('search', '%' . mb_strtolower($filters->search) . '%'); } } - - /** - * @param array $filters - * @param list $keys - */ - private function extractIntFilter(array $filters, array $keys): ?int - { - foreach ($keys as $key) { - if (!array_key_exists($key, $filters)) { - continue; - } - - $value = $filters[$key]; - if ($value === null || $value === '') { - continue; - } - - if (is_numeric($value)) { - return (int) $value; - } - } - - return null; - } - - /** - * @param array $filters - * @param list $keys - */ - private function extractBoolFilter(array $filters, array $keys): ?bool - { - foreach ($keys as $key) { - if (!array_key_exists($key, $filters)) { - continue; - } - - $value = $filters[$key]; - if ($value === null || $value === '') { - continue; - } - - if (is_bool($value)) { - return $value; - } - - return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); - } - - return null; - } - - /** - * @param array $filters - * @param list $keys - */ - private function extractNonEmptyStringFilter(array $filters, array $keys): ?string - { - foreach ($keys as $key) { - if (!array_key_exists($key, $filters)) { - continue; - } - - $value = $filters[$key]; - if (!is_string($value)) { - continue; - } - - $trimmed = trim($value); - if ($trimmed !== '') { - return $trimmed; - } - } - - return null; - } } diff --git a/src/Repository/DiseaseRepository.php b/src/Repository/DiseaseRepository.php index 77faff4..33dd6b1 100644 --- a/src/Repository/DiseaseRepository.php +++ b/src/Repository/DiseaseRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use App\Entity\Disease; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; @@ -23,9 +24,8 @@ class DiseaseRepository extends ServiceEntityRepository } /** - * @param array $filters */ - public function createFilteredQueryBuilder(array $filters): QueryBuilder + public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder { $qb = $this->createQueryBuilder('d')->orderBy('d.id', 'ASC'); diff --git a/src/Repository/MedicalCenterRepository.php b/src/Repository/MedicalCenterRepository.php index 9c00e8e..021af74 100644 --- a/src/Repository/MedicalCenterRepository.php +++ b/src/Repository/MedicalCenterRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use App\Entity\MedicalCenter; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; @@ -23,9 +24,8 @@ class MedicalCenterRepository extends ServiceEntityRepository } /** - * @param array $filters */ - public function createFilteredQueryBuilder(array $filters): QueryBuilder + public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder { $qb = $this->createQueryBuilder('m')->orderBy('m.id', 'DESC'); diff --git a/src/Repository/NewsRepository.php b/src/Repository/NewsRepository.php index c2d3c41..4520283 100644 --- a/src/Repository/NewsRepository.php +++ b/src/Repository/NewsRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use App\Entity\News; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; @@ -27,9 +28,8 @@ class NewsRepository extends ServiceEntityRepository * * Поддерживаемые фильтры: regionId, active (по умолчанию true), alias, search. * - * @param array $filters */ - public function createFilteredQueryBuilder(array $filters): QueryBuilder + public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder { $qb = $this->createQueryBuilder('n')->orderBy('n.id', 'DESC'); diff --git a/src/Repository/PromoRepository.php b/src/Repository/PromoRepository.php index 0f89df0..3d73d2b 100644 --- a/src/Repository/PromoRepository.php +++ b/src/Repository/PromoRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use App\Entity\Promo; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; @@ -23,9 +24,8 @@ class PromoRepository extends ServiceEntityRepository } /** - * @param array $filters */ - public function createFilteredQueryBuilder(array $filters): QueryBuilder + public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder { $qb = $this->createQueryBuilder('p')->orderBy('p.id', 'DESC'); diff --git a/src/Repository/SiteServiceRepository.php b/src/Repository/SiteServiceRepository.php index 7964a99..73d834a 100644 --- a/src/Repository/SiteServiceRepository.php +++ b/src/Repository/SiteServiceRepository.php @@ -2,6 +2,7 @@ namespace App\Repository; +use App\Dto\Content\ContentFilterDto; use App\Entity\SiteService; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; @@ -23,9 +24,8 @@ class SiteServiceRepository extends ServiceEntityRepository } /** - * @param array $filters */ - public function createFilteredQueryBuilder(array $filters): QueryBuilder + public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder { $qb = $this->createQueryBuilder('s')->orderBy('s.id', 'ASC'); diff --git a/src/Service/Crud/CrudResponder.php b/src/Service/Crud/CrudResponder.php index 138511c..e8dd60a 100644 --- a/src/Service/Crud/CrudResponder.php +++ b/src/Service/Crud/CrudResponder.php @@ -52,22 +52,17 @@ final class CrudResponder string $entityClass, array $writeGroups, array $readGroups, - bool $allowIdFromPayload = false, ): JsonResponse { $payload = $this->decodePayload($request); if ($payload === null) { return $this->jsonError('Ожидается JSON-объект в теле запроса', Response::HTTP_BAD_REQUEST); } - - $deserializationPayload = $payload; - if (!$allowIdFromPayload) { - unset($deserializationPayload['id']); - } + unset($payload['id']); try { /** @var T $entity */ $entity = $this->serializer->deserialize( - $this->encodePayload($deserializationPayload), + $this->encodePayload($payload), $entityClass, 'json', [ @@ -78,15 +73,6 @@ final class CrudResponder return $this->jsonError('Ошибка десериализации: ' . $e->getMessage(), Response::HTTP_BAD_REQUEST); } - // По умолчанию публичный CRUD не принимает id от клиента. Если системной - // интеграции понадобится внешний id, конкретный вызов должен явно передать true. - if ($allowIdFromPayload && isset($payload['id']) && method_exists($entity, 'setId')) { - $id = (int) $payload['id']; - if ($id > 0) { - $entity->setId($id); - } - } - if (($validationResponse = $this->validate($entity)) !== null) { return $validationResponse; }