issues/27: filter DTO, strip id from payloads, lifecycle updateAt
This commit is contained in:
committed by
Valeriy Petrov
parent
da5f7bb242
commit
76044381fd
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Dto\Content;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
final readonly class ContentFilterDto
|
||||
{
|
||||
public function __construct(
|
||||
public ?int $regionId = null,
|
||||
public ?bool $active = null,
|
||||
public ?string $alias = null,
|
||||
public ?string $search = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function fromRequest(Request $request): self
|
||||
{
|
||||
return new self(
|
||||
regionId: self::positiveInt($request->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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity\Behavior;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
trait UpdateTimestampTrait
|
||||
{
|
||||
#[ORM\PrePersist]
|
||||
public function setInitialUpdateAt(): void
|
||||
{
|
||||
if ($this->updateAt === null) {
|
||||
$this->updateAt = new \DateTime();
|
||||
}
|
||||
}
|
||||
|
||||
#[ORM\PreUpdate]
|
||||
public function refreshUpdateAt(): void
|
||||
{
|
||||
$this->updateAt = new \DateTime();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)]
|
||||
|
||||
+5
-1
@@ -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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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<string, mixed> $filters
|
||||
*/
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('a')->orderBy('a.id', 'DESC');
|
||||
|
||||
|
||||
@@ -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<string, mixed> $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<string, mixed> $filters
|
||||
* @param list<string> $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<string, mixed> $filters
|
||||
* @param list<string> $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<string, mixed> $filters
|
||||
* @param list<string> $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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string, mixed> $filters
|
||||
*/
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('d')->orderBy('d.id', 'ASC');
|
||||
|
||||
|
||||
@@ -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<string, mixed> $filters
|
||||
*/
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('m')->orderBy('m.id', 'DESC');
|
||||
|
||||
|
||||
@@ -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<string, mixed> $filters
|
||||
*/
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('n')->orderBy('n.id', 'DESC');
|
||||
|
||||
|
||||
@@ -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<string, mixed> $filters
|
||||
*/
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('p')->orderBy('p.id', 'DESC');
|
||||
|
||||
|
||||
@@ -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<string, mixed> $filters
|
||||
*/
|
||||
public function createFilteredQueryBuilder(array $filters): QueryBuilder
|
||||
public function createFilteredQueryBuilder(ContentFilterDto $filters): QueryBuilder
|
||||
{
|
||||
$qb = $this->createQueryBuilder('s')->orderBy('s.id', 'ASC');
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user