feat(inco): restrict inco sheets list and search to short projection and remove short query parameter
This commit is contained in:
parent
2b8aae51af
commit
10674f3295
9 changed files with 24 additions and 220 deletions
|
|
@ -41,7 +41,7 @@ final readonly class IncoSheetsIndexController
|
|||
pagination: $request->pagination(),
|
||||
sorter: $request->sorter(),
|
||||
filter: $request->filter(),
|
||||
short: $request->isShort(),
|
||||
short: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ final readonly class IncoSheetsSearchController
|
|||
{
|
||||
return new SearchInput(
|
||||
$request->incoIdSearch(),
|
||||
$request->isShort(),
|
||||
true,
|
||||
$request->pagination(),
|
||||
...$request->brands()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ final class IncoSheetsIndexRequest extends FormRequest
|
|||
'since' => ['sometimes', 'date'],
|
||||
'brands' => ['sometimes', 'array'],
|
||||
'brands.*' => ['sometimes', 'string'],
|
||||
'short' => ['sometimes', Rule::in(['true', 'false', true, false, '1', '0', 1, 0])],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -86,9 +85,4 @@ final class IncoSheetsIndexRequest extends FormRequest
|
|||
default => \SortDirection::Ascending,
|
||||
};
|
||||
}
|
||||
|
||||
public function isShort(): bool
|
||||
{
|
||||
return filter_var($this->input('short', false), FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ namespace Presentation\Api\V1\Http\Requests\IncoSheets;
|
|||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Inco\IncoIdQuery;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
/**
|
||||
* @method \Shared\Pagination pagination(int $defaultPageSize = 25)
|
||||
|
|
@ -22,7 +21,6 @@ final class IncoSheetsSearchRequest extends FormRequest
|
|||
'incoIdLike' => ['required', 'string'],
|
||||
'brands' => ['sometimes', 'array'],
|
||||
'brands.*' => ['sometimes', 'string'],
|
||||
'short' => ['sometimes', Rule::in(['true', 'false', true, false, '1', '0', 1, 0])],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -47,9 +45,4 @@ final class IncoSheetsSearchRequest extends FormRequest
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function isShort(): bool
|
||||
{
|
||||
return filter_var($this->input('short', false), FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,19 +6,9 @@ namespace Presentation\Api\V1\Http\Responses\IncoSheets;
|
|||
|
||||
use Application\Arcadia\Usecase\IncoSheets\FindAll\PaginatedIncoSheet;
|
||||
use Application\Arcadia\Usecase\IncoSheets\FindAll\PaginatedShortIncoSheet;
|
||||
use Domain\Models\ValueObjects\Inco\Additive;
|
||||
use Domain\Models\ValueObjects\Inco\Allergen;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Presentation\Api\V1\Contracts\ApiResponse;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\IncoSheetDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\IncoShortSheetDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\AdditiveDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\AllegationsDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\BrandDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\NutriscoreDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\PortionsDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\StorageConditionDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\WeightDto;
|
||||
use Presentation\Api\V1\Dto\PaginationDto;
|
||||
use Presentation\Api\V1\Presenters\IncoSheets\IncoSheetsIndexView;
|
||||
use Shared\Time\Utc;
|
||||
|
|
@ -51,7 +41,14 @@ final readonly class IncoSheetsIndexResponse implements ApiResponse
|
|||
$items = array_map(
|
||||
fn (PaginatedIncoSheet | PaginatedShortIncoSheet $sheet): array => match (true) {
|
||||
$sheet instanceof PaginatedShortIncoSheet => $this->fromPaginatedShortIncoSheet($sheet)->toArray(),
|
||||
$sheet instanceof PaginatedIncoSheet => $this->fromPaginatedIncoSheet($sheet)->toArray(),
|
||||
$sheet instanceof PaginatedIncoSheet => (new IncoShortSheetDto(
|
||||
incoId: (string) $sheet->id,
|
||||
name: $sheet->name,
|
||||
label: $sheet->label,
|
||||
description: $sheet->description,
|
||||
createdAt: Utc::toNullableRfc3339($sheet->createdAt),
|
||||
updatedAt: Utc::toNullableRfc3339($sheet->updatedAt),
|
||||
))->toArray(),
|
||||
},
|
||||
$this->view->incoSheets
|
||||
);
|
||||
|
|
@ -73,40 +70,4 @@ final readonly class IncoSheetsIndexResponse implements ApiResponse
|
|||
updatedAt: Utc::toNullableRfc3339($sheet->updatedAt),
|
||||
);
|
||||
}
|
||||
|
||||
private function fromPaginatedIncoSheet(PaginatedIncoSheet $sheet): IncoSheetDto
|
||||
{
|
||||
$ingGroups = $sheet->ingredients->groups;
|
||||
$ingObject = empty($ingGroups) ? (object) [] : (object) $ingGroups;
|
||||
|
||||
return new IncoSheetDto(
|
||||
incoId: (string) $sheet->id,
|
||||
name: $sheet->name,
|
||||
label: $sheet->label,
|
||||
description: $sheet->description,
|
||||
allegations: AllegationsDto::fromDomain($sheet->allegations),
|
||||
sellArguments: $sheet->sellArguments,
|
||||
preparationAdvices: $sheet->preparationAdvices,
|
||||
tips: $sheet->tips,
|
||||
sellFamilly: $sheet->sellFamilly,
|
||||
ingredients: $ingObject,
|
||||
portions: $sheet->portions !== null ? PortionsDto::fromDomain($sheet->portions) : null,
|
||||
allergens: array_values(array_map(
|
||||
static fn (Allergen $a): string => $a->label,
|
||||
$sheet->allergens
|
||||
)),
|
||||
brand: BrandDto::fromDomain($sheet->brand),
|
||||
isSeasonal: $sheet->isSeasonal,
|
||||
weight: $sheet->weight !== null ? WeightDto::fromDomain($sheet->weight) : null,
|
||||
nutriscore: $sheet->nutriscore !== null ? NutriscoreDto::fromDomain($sheet->nutriscore) : null,
|
||||
storageCondition: $sheet->storageCondition !== null ? StorageConditionDto::fromDomain($sheet->storageCondition) : null,
|
||||
additives: array_values(array_map(
|
||||
static fn (Additive $a): AdditiveDto => AdditiveDto::fromDomain($a),
|
||||
$sheet->additives
|
||||
)),
|
||||
incoCompoId: $sheet->compo !== null ? (string) $sheet->compo : null,
|
||||
createdAt: Utc::toNullableRfc3339($sheet->createdAt),
|
||||
updatedAt: Utc::toNullableRfc3339($sheet->updatedAt),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,19 +6,9 @@ namespace Presentation\Api\V1\Http\Responses\IncoSheets;
|
|||
|
||||
use Application\Arcadia\Usecase\IncoSheets\Search\PaginatedIncoSheet;
|
||||
use Application\Arcadia\Usecase\IncoSheets\Search\PaginatedShortIncoSheet;
|
||||
use Domain\Models\ValueObjects\Inco\Additive;
|
||||
use Domain\Models\ValueObjects\Inco\Allergen;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Presentation\Api\V1\Contracts\ApiResponse;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\IncoSheetDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\IncoShortSheetDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\AdditiveDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\AllegationsDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\BrandDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\NutriscoreDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\PortionsDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\StorageConditionDto;
|
||||
use Presentation\Api\V1\Dto\IncoSheets\Parts\WeightDto;
|
||||
use Presentation\Api\V1\Dto\PaginationDto;
|
||||
use Presentation\Api\V1\Presenters\IncoSheets\IncoSheetsSearchView;
|
||||
use Shared\Time\Utc;
|
||||
|
|
@ -51,7 +41,14 @@ final readonly class IncoSheetsSearchResponse implements ApiResponse
|
|||
$items = array_map(
|
||||
fn (PaginatedIncoSheet | PaginatedShortIncoSheet $sheet): array => match (true) {
|
||||
$sheet instanceof PaginatedShortIncoSheet => $this->fromPaginatedIncoSheetToShort($sheet)->toArray(),
|
||||
$sheet instanceof PaginatedIncoSheet => $this->fromPaginatedIncoSheetToFull($sheet)->toArray(),
|
||||
$sheet instanceof PaginatedIncoSheet => (new IncoShortSheetDto(
|
||||
incoId: (string) $sheet->id,
|
||||
name: $sheet->name,
|
||||
label: $sheet->label,
|
||||
description: $sheet->description,
|
||||
createdAt: Utc::toNullableRfc3339($sheet->createdAt),
|
||||
updatedAt: Utc::toNullableRfc3339($sheet->updatedAt),
|
||||
))->toArray(),
|
||||
},
|
||||
$this->view->incoSheets
|
||||
);
|
||||
|
|
@ -73,40 +70,4 @@ final readonly class IncoSheetsSearchResponse implements ApiResponse
|
|||
updatedAt: Utc::toNullableRfc3339($sheet->updatedAt),
|
||||
);
|
||||
}
|
||||
|
||||
private function fromPaginatedIncoSheetToFull(PaginatedIncoSheet $sheet): IncoSheetDto
|
||||
{
|
||||
$ingGroups = $sheet->ingredients->groups;
|
||||
$ingObject = empty($ingGroups) ? (object) [] : (object) $ingGroups;
|
||||
|
||||
return new IncoSheetDto(
|
||||
incoId: (string) $sheet->id,
|
||||
name: $sheet->name,
|
||||
label: $sheet->label,
|
||||
description: $sheet->description,
|
||||
allegations: AllegationsDto::fromDomain($sheet->allegations),
|
||||
sellArguments: $sheet->sellArguments,
|
||||
preparationAdvices: $sheet->preparationAdvices,
|
||||
tips: $sheet->tips,
|
||||
sellFamilly: $sheet->sellFamilly,
|
||||
ingredients: $ingObject,
|
||||
portions: $sheet->portions !== null ? PortionsDto::fromDomain($sheet->portions) : null,
|
||||
allergens: array_values(array_map(
|
||||
static fn (Allergen $a): string => $a->label,
|
||||
$sheet->allergens
|
||||
)),
|
||||
brand: BrandDto::fromDomain($sheet->brand),
|
||||
isSeasonal: $sheet->isSeasonal,
|
||||
weight: $sheet->weight !== null ? WeightDto::fromDomain($sheet->weight) : null,
|
||||
nutriscore: $sheet->nutriscore !== null ? NutriscoreDto::fromDomain($sheet->nutriscore) : null,
|
||||
storageCondition: $sheet->storageCondition !== null ? StorageConditionDto::fromDomain($sheet->storageCondition) : null,
|
||||
additives: array_values(array_map(
|
||||
static fn (Additive $a): AdditiveDto => AdditiveDto::fromDomain($a),
|
||||
$sheet->additives
|
||||
)),
|
||||
incoCompoId: $sheet->compo !== null ? (string) $sheet->compo : null,
|
||||
createdAt: Utc::toNullableRfc3339($sheet->createdAt),
|
||||
updatedAt: Utc::toNullableRfc3339($sheet->updatedAt),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,9 +106,7 @@ describe('IncoSheets Index Feature API', function (): void {
|
|||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonPath('incoSheets.0.incoId', '9999001')
|
||||
->assertJsonPath('incoSheets.0.brand.code', $brand->code->value)
|
||||
->assertJsonPath('incoSheets.0.brand.label', 'Le Gaulois Professionnel');
|
||||
$response->assertJsonPath('incoSheets.0.incoId', '9999001');
|
||||
});
|
||||
|
||||
it('returns 422 Unprocessable Entity when brand code format is invalid', function (): void {
|
||||
|
|
@ -123,13 +121,13 @@ describe('IncoSheets Index Feature API', function (): void {
|
|||
$response->assertStatus(422);
|
||||
});
|
||||
|
||||
it('returns 200 OK with short form inco sheets when short parameter is true', function (): void {
|
||||
it('returns 200 OK with short form inco sheets structure', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
$test = $this;
|
||||
|
||||
// WHEN
|
||||
$response = $test->getJson('/api/v1/inco-sheets?short=true');
|
||||
$response = $test->getJson('/api/v1/inco-sheets');
|
||||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
|
|
@ -154,34 +152,4 @@ describe('IncoSheets Index Feature API', function (): void {
|
|||
->and($firstItem)->not->toHaveKey('ingredients')
|
||||
->and($firstItem)->not->toHaveKey('brand');
|
||||
});
|
||||
|
||||
it('returns 200 OK with short form inco sheets when short parameter is numeric 1', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
$test = $this;
|
||||
|
||||
// WHEN
|
||||
$response = $test->getJson('/api/v1/inco-sheets?short=1');
|
||||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'incoSheets' => [
|
||||
'*' => [
|
||||
'incoId',
|
||||
'name',
|
||||
'label',
|
||||
'description',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
],
|
||||
],
|
||||
'pagination',
|
||||
]);
|
||||
|
||||
$firstItem = $response->json('incoSheets.0');
|
||||
expect($firstItem)
|
||||
->toHaveKeys(['incoId', 'name', 'label', 'description', 'createdAt', 'updatedAt'])
|
||||
->and($firstItem)->not->toHaveKey('ingredients');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -84,8 +84,7 @@ describe('IncoSheets Search Feature API', function (): void {
|
|||
// THEN
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonCount(1, 'incoSheets');
|
||||
$response->assertJsonPath('incoSheets.0.incoId', '1000101')
|
||||
->assertJsonPath('incoSheets.0.brand.code', $brand->code->value);
|
||||
$response->assertJsonPath('incoSheets.0.incoId', '1000101');
|
||||
});
|
||||
|
||||
it('returns 422 Unprocessable Entity when brand code format is invalid', function (): void {
|
||||
|
|
@ -101,14 +100,14 @@ describe('IncoSheets Search Feature API', function (): void {
|
|||
$response->assertStatus(422);
|
||||
});
|
||||
|
||||
it('returns 200 OK with short form inco sheets when short parameter is true', function (): void {
|
||||
it('returns 200 OK with short form inco sheets structure on search', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
$test = $this;
|
||||
$query = urlencode('%1000101%');
|
||||
|
||||
// WHEN
|
||||
$response = $test->getJson("/api/v1/inco-sheets/search?incoIdLike={$query}&short=true");
|
||||
$response = $test->getJson("/api/v1/inco-sheets/search?incoIdLike={$query}");
|
||||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
|
|
@ -134,37 +133,6 @@ describe('IncoSheets Search Feature API', function (): void {
|
|||
->and($firstItem)->not->toHaveKey('brand');
|
||||
});
|
||||
|
||||
it('returns 200 OK with short form inco sheets when short parameter is numeric 1', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
$test = $this;
|
||||
$query = urlencode('%10001%');
|
||||
|
||||
// WHEN
|
||||
$response = $test->getJson("/api/v1/inco-sheets/search?incoIdLike={$query}&short=1");
|
||||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
$response->assertJsonStructure([
|
||||
'incoSheets' => [
|
||||
'*' => [
|
||||
'incoId',
|
||||
'name',
|
||||
'label',
|
||||
'description',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
],
|
||||
],
|
||||
'pagination',
|
||||
]);
|
||||
|
||||
$firstItem = $response->json('incoSheets.0');
|
||||
expect($firstItem)
|
||||
->toHaveKeys(['incoId', 'name', 'label', 'description', 'createdAt', 'updatedAt'])
|
||||
->and($firstItem)->not->toHaveKey('ingredients');
|
||||
});
|
||||
|
||||
it('returns 200 OK with empty incoSheets list when no matching inco sheets found', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
|
|
|
|||
|
|
@ -36,26 +36,6 @@ describe('IncoSheet OpenAPI Conformance', function (): void {
|
|||
$response->assertValidResponse(200);
|
||||
});
|
||||
|
||||
it('validates GET /api/v1/inco-sheets list response with short projection against openapi spec', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
$test = $this;
|
||||
|
||||
IncoFactory::new()->create([
|
||||
'NO_ART' => 10002,
|
||||
'DENOM_LEG' => 'Salade Niçoise 300g',
|
||||
]);
|
||||
|
||||
// WHEN
|
||||
/** @var \Illuminate\Testing\TestResponse<\Symfony\Component\HttpFoundation\Response> $response */
|
||||
$response = $test->getJson('/api/v1/inco-sheets?short=true');
|
||||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
$response->assertValidRequest();
|
||||
$response->assertValidResponse(200);
|
||||
});
|
||||
|
||||
it('validates GET /api/v1/inco-sheets list response with brands filter against openapi spec', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
|
|
@ -142,25 +122,4 @@ describe('IncoSheet OpenAPI Conformance', function (): void {
|
|||
$response->assertValidRequest();
|
||||
$response->assertValidResponse(200);
|
||||
});
|
||||
|
||||
it('validates GET /api/v1/inco-sheets/search with short projection against openapi spec', function (): void {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $test */
|
||||
$test = $this;
|
||||
$query = urlencode('%10004%');
|
||||
|
||||
IncoFactory::new()->create([
|
||||
'NO_ART' => 1000402,
|
||||
'DENOM_LEG' => 'Tarte aux Pommes',
|
||||
]);
|
||||
|
||||
// WHEN
|
||||
/** @var \Illuminate\Testing\TestResponse<\Symfony\Component\HttpFoundation\Response> $response */
|
||||
$response = $test->getJson("/api/v1/inco-sheets/search?incoIdLike={$query}&short=true");
|
||||
|
||||
// THEN
|
||||
$response->assertStatus(200);
|
||||
$response->assertValidRequest();
|
||||
$response->assertValidResponse(200);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue