refactor(infra): replace Eloquent directory adapters with direct QueryBuilder adapters and mappers
- Replace Eloquent models for replicated Oracle tables with direct QueryBuilder directory adapters - Bind ArcadiaEmployeeDirectory, ArcadiaIncoSheetDirectory, ArcadiaIncoShortSheetDirectory, ArcadiaIncoCompositionDirectory, and ArcadiaMarqueBrandDirectory - Remove obsolete Eloquent directory classes and models
This commit is contained in:
parent
cf918ccd30
commit
cec8d1ea66
20 changed files with 411 additions and 1716 deletions
104
src/Infra/Adapters/Directories/ArcadiaEmployeeDirectory.php
Normal file
104
src/Infra/Adapters/Directories/ArcadiaEmployeeDirectory.php
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Employee;
|
||||
use Domain\Models\ValueObjects\Employees\ArcadiaEmployeeId;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeFilter;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeSortColumn;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeSorter;
|
||||
use Domain\Models\ValueObjects\SiteId;
|
||||
use Domain\Ports\Directories\EmployeeDirectory;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Infra\Adapters\Mappers\EmployeeMapper;
|
||||
use Shared\Paginated;
|
||||
use Shared\Pagination;
|
||||
|
||||
final class ArcadiaEmployeeDirectory implements EmployeeDirectory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Connection $connection,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function findAll(
|
||||
Pagination $pagination,
|
||||
EmployeeSorter $sorter,
|
||||
?EmployeeFilter $filter = null,
|
||||
): Paginated {
|
||||
$query = $this->connection->table('RU_PERSONNE_SIRH');
|
||||
|
||||
if ($filter !== null) {
|
||||
if ($filter->establishment !== null) {
|
||||
$query->where('ETAB_FIC', $filter->establishment->value);
|
||||
}
|
||||
|
||||
if (! empty($filter->sites)) {
|
||||
$siteValues = array_map(static fn (SiteId $s): string => $s->value, $filter->sites);
|
||||
$query->whereIn('SITE_FIC', $siteValues);
|
||||
}
|
||||
|
||||
if ($filter->service !== null) {
|
||||
$query->where('SERVICE_FIC', $filter->service->value);
|
||||
}
|
||||
|
||||
if ($filter->since !== null) {
|
||||
$query->where(static function (Builder $q) use ($filter): void {
|
||||
$q->where('DAT_MAJ', '>=', $filter->since)
|
||||
->orWhere('DAT_CRE', '>=', $filter->since);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$total = (int) (clone $query)->count();
|
||||
|
||||
$rows = (clone $query)
|
||||
->orderBy(
|
||||
$this->toSqlColumn($sorter->sortBy),
|
||||
$sorter->direction
|
||||
)
|
||||
->offset($pagination->from())
|
||||
->limit($pagination->pageSize())
|
||||
->get();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = EmployeeMapper::toDomain($row);
|
||||
}
|
||||
|
||||
/** @var Employee[] $items */
|
||||
return new Paginated($pagination, $items, $total);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function find(ArcadiaEmployeeId $id): ?Employee
|
||||
{
|
||||
$row = $this->connection
|
||||
->table('RU_PERSONNE_SIRH')
|
||||
->where('MATRICULE_FIC', $id->value)
|
||||
->first();
|
||||
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return EmployeeMapper::toDomain($row);
|
||||
}
|
||||
|
||||
private function toSqlColumn(EmployeeSortColumn $sortBy): string
|
||||
{
|
||||
return match ($sortBy) {
|
||||
EmployeeSortColumn::arcadiaId => 'MATRICULE_FIC',
|
||||
EmployeeSortColumn::startDate => 'DATE_DEB_FIC',
|
||||
EmployeeSortColumn::endDate => 'DATE_FIN_FIC',
|
||||
EmployeeSortColumn::plannedEndDate => 'DF_CARRIERE',
|
||||
EmployeeSortColumn::createdAt => 'DAT_CRE',
|
||||
EmployeeSortColumn::updatedAt => 'DAT_MAJ',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Inco\Composition\IncoComposition;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\IncoCompositionId;
|
||||
use Domain\Models\ValueObjects\Inco\IncoId;
|
||||
use Domain\Ports\Directories\IncoCompositionDirectory;
|
||||
use Illuminate\Database\Connection;
|
||||
use Infra\Adapters\Mappers\IncoCompositionMapper;
|
||||
|
||||
final class ArcadiaIncoCompositionDirectory implements IncoCompositionDirectory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Connection $connection,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function find(IncoCompositionId $id): ?IncoComposition
|
||||
{
|
||||
$row = $this->connection
|
||||
->table('INCO_COMPO')
|
||||
->where('ID', $id->value)
|
||||
->first();
|
||||
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return IncoCompositionMapper::toDomain($row);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function findByIncoId(IncoId $incoId): ?IncoComposition
|
||||
{
|
||||
$row = $this->connection
|
||||
->table('INCO_COMPO')
|
||||
->where('ID_INCO', $incoId->value)
|
||||
->first();
|
||||
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return IncoCompositionMapper::toDomain($row);
|
||||
}
|
||||
}
|
||||
166
src/Infra/Adapters/Directories/ArcadiaIncoSheetDirectory.php
Normal file
166
src/Infra/Adapters/Directories/ArcadiaIncoSheetDirectory.php
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Inco\IncoSheet;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Inco\IncoId;
|
||||
use Domain\Models\ValueObjects\Inco\IncoIdQuery;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetFilter;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSortColumn;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSorter;
|
||||
use Domain\Ports\Directories\IncoSheetDirectory;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Infra\Adapters\Mappers\IncoMapper;
|
||||
use Shared\Paginated;
|
||||
use Shared\Pagination;
|
||||
|
||||
final class ArcadiaIncoSheetDirectory implements IncoSheetDirectory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Connection $connection,
|
||||
private readonly BrandRepository $brandRepository,
|
||||
private readonly IncoMapper $mapper,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function findAll(
|
||||
Pagination $pagination,
|
||||
IncoSheetSorter $sorter,
|
||||
?IncoSheetFilter $filter = null
|
||||
): Paginated {
|
||||
$query = $this->connection
|
||||
->table('INCO')
|
||||
->leftJoin('FAM_VENTE', 'INCO.FAMILLE_VTE', '=', 'FAM_VENTE.COD_FAMVTE')
|
||||
->select(['INCO.*', 'FAM_VENTE.LIB_FAMVTE as FAMILLE_VTE_LIBELLE']);
|
||||
|
||||
if ($filter !== null) {
|
||||
if ($filter->since !== null) {
|
||||
$query->where(static function (Builder $q) use ($filter): void {
|
||||
$q->where('INCO.DAT_MAJ', '>=', $filter->since)
|
||||
->orWhere('INCO.DAT_CRE', '>=', $filter->since);
|
||||
});
|
||||
}
|
||||
|
||||
if (! empty($filter->brands)) {
|
||||
$resolvedBrands = $this->resolveBrandFilterCodes(...$filter->brands);
|
||||
$query->whereIn('INCO.MARQUE', $resolvedBrands);
|
||||
}
|
||||
}
|
||||
|
||||
$total = (int) (clone $query)->count();
|
||||
|
||||
$rows = (clone $query)
|
||||
->orderBy(
|
||||
$this->toSqlColumn($sorter->sortBy),
|
||||
$sorter->direction
|
||||
)
|
||||
->offset($pagination->from())
|
||||
->limit($pagination->pageSize())
|
||||
->get();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->mapper->toDomain($row);
|
||||
}
|
||||
|
||||
/** @var IncoSheet[] $items */
|
||||
return new Paginated($pagination, $items, $total);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function search(
|
||||
IncoIdQuery $query,
|
||||
Pagination $pagination,
|
||||
BrandCode ...$brands
|
||||
): Paginated {
|
||||
$dbQuery = $this->connection
|
||||
->table('INCO')
|
||||
->leftJoin('FAM_VENTE', 'INCO.FAMILLE_VTE', '=', 'FAM_VENTE.COD_FAMVTE')
|
||||
->select(['INCO.*', 'FAM_VENTE.LIB_FAMVTE as FAMILLE_VTE_LIBELLE']);
|
||||
|
||||
$dbQuery->where('INCO.NO_ART', 'LIKE', $query->value);
|
||||
|
||||
if (! empty($brands)) {
|
||||
$resolvedBrands = $this->resolveBrandFilterCodes(...$brands);
|
||||
$dbQuery->whereIn('INCO.MARQUE', $resolvedBrands);
|
||||
}
|
||||
|
||||
$total = (int) (clone $dbQuery)->count();
|
||||
|
||||
$rows = $dbQuery
|
||||
->offset($pagination->from())
|
||||
->limit($pagination->pageSize())
|
||||
->get();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->mapper->toDomain($row);
|
||||
}
|
||||
|
||||
/** @var IncoSheet[] $items */
|
||||
return new Paginated($pagination, $items, $total);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function find(IncoId $id): ?IncoSheet
|
||||
{
|
||||
$row = $this->connection
|
||||
->table('INCO')
|
||||
->leftJoin('FAM_VENTE', 'INCO.FAMILLE_VTE', '=', 'FAM_VENTE.COD_FAMVTE')
|
||||
->select(['INCO.*', 'FAM_VENTE.LIB_FAMVTE as FAMILLE_VTE_LIBELLE'])
|
||||
->where('INCO.NO_ART', $id->value)
|
||||
->first();
|
||||
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->mapper->toDomain($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int|string>
|
||||
*/
|
||||
private function resolveBrandFilterCodes(BrandCode ...$brandCodes): array
|
||||
{
|
||||
$resolved = [];
|
||||
|
||||
foreach ($brandCodes as $brandCode) {
|
||||
$brand = $this->brandRepository->findByCode($brandCode);
|
||||
if ($brand !== null) {
|
||||
$resolved[] = (int) $brand->arcadiaId->value;
|
||||
$resolved[] = $brand->arcadiaId->value;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($resolved) && ! empty($brandCodes)) {
|
||||
return [0];
|
||||
}
|
||||
|
||||
$unique = [];
|
||||
foreach ($resolved as $item) {
|
||||
if (! in_array($item, $unique, true)) {
|
||||
$unique[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $unique;
|
||||
}
|
||||
|
||||
private function toSqlColumn(IncoSheetSortColumn $column): string
|
||||
{
|
||||
return match ($column) {
|
||||
IncoSheetSortColumn::incoSheetId => 'NO_ART',
|
||||
IncoSheetSortColumn::createdAt => 'DAT_CRE',
|
||||
IncoSheetSortColumn::updatedAt => 'DAT_MAJ',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -13,18 +13,17 @@ use Domain\Models\ValueObjects\Inco\IncoSheetSortColumn;
|
|||
use Domain\Models\ValueObjects\Inco\IncoSheetSorter;
|
||||
use Domain\Ports\Directories\IncoShortSheetDirectory;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
use Infra\Database\Models\IncoSheet as IncoSheetModel;
|
||||
use Shared\Helpers\DatesHelper;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Infra\Adapters\Mappers\IncoShortMapper;
|
||||
use Shared\Paginated;
|
||||
use Shared\Pagination;
|
||||
|
||||
final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
||||
final class ArcadiaIncoShortSheetDirectory implements IncoShortSheetDirectory
|
||||
{
|
||||
/** @var list<string> */
|
||||
private const array SHORT_FIELDS = ['id', 'name', 'label', 'created_at', 'updated_at'];
|
||||
|
||||
public function __construct(
|
||||
private BrandRepository $brandRepository,
|
||||
private readonly Connection $connection,
|
||||
private readonly BrandRepository $brandRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -34,19 +33,21 @@ final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
|||
IncoSheetSorter $sorter,
|
||||
?IncoSheetFilter $filter = null
|
||||
): Paginated {
|
||||
$query = IncoSheetModel::query()->select(self::SHORT_FIELDS);
|
||||
$query = $this->connection
|
||||
->table('INCO')
|
||||
->select(IncoShortMapper::SELECT_COLUMNS);
|
||||
|
||||
if ($filter !== null) {
|
||||
if ($filter->since !== null) {
|
||||
$query->where(static function ($q) use ($filter): void {
|
||||
$q->where('updated_at', '>=', $filter->since)
|
||||
->orWhere('created_at', '>=', $filter->since);
|
||||
$query->where(static function (Builder $q) use ($filter): void {
|
||||
$q->where('DAT_MAJ', '>=', $filter->since)
|
||||
->orWhere('DAT_CRE', '>=', $filter->since);
|
||||
});
|
||||
}
|
||||
|
||||
if (! empty($filter->brands)) {
|
||||
$resolvedBrands = $this->resolveBrandFilterCodes(...$filter->brands);
|
||||
$query->whereIn('brand->code', $resolvedBrands);
|
||||
$query->whereIn('MARQUE', $resolvedBrands);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +64,7 @@ final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
|||
|
||||
$items = [];
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->toDomain($row);
|
||||
$items[] = IncoShortMapper::toDomain($row);
|
||||
}
|
||||
|
||||
/** @var IncoShortSheet[] $items */
|
||||
|
|
@ -76,13 +77,15 @@ final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
|||
Pagination $pagination,
|
||||
BrandCode ...$brands
|
||||
): Paginated {
|
||||
$dbQuery = IncoSheetModel::query()->select(self::SHORT_FIELDS);
|
||||
$dbQuery = $this->connection
|
||||
->table('INCO')
|
||||
->select(IncoShortMapper::SELECT_COLUMNS);
|
||||
|
||||
$dbQuery->where('id', 'LIKE', $query->value);
|
||||
$dbQuery->where('NO_ART', 'LIKE', $query->value);
|
||||
|
||||
if (! empty($brands)) {
|
||||
$resolvedBrands = $this->resolveBrandFilterCodes(...$brands);
|
||||
$dbQuery->whereIn('brand->code', $resolvedBrands);
|
||||
$dbQuery->whereIn('MARQUE', $resolvedBrands);
|
||||
}
|
||||
|
||||
$total = (int) (clone $dbQuery)->count();
|
||||
|
|
@ -94,7 +97,7 @@ final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
|||
|
||||
$items = [];
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->toDomain($row);
|
||||
$items[] = IncoShortMapper::toDomain($row);
|
||||
}
|
||||
|
||||
/** @var IncoShortSheet[] $items */
|
||||
|
|
@ -104,16 +107,17 @@ final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
|||
#[\Override]
|
||||
public function find(IncoId $id): ?IncoShortSheet
|
||||
{
|
||||
$model = IncoSheetModel::query()
|
||||
->select(self::SHORT_FIELDS)
|
||||
->where('id', $id->value)
|
||||
$row = $this->connection
|
||||
->table('INCO')
|
||||
->select(IncoShortMapper::SELECT_COLUMNS)
|
||||
->where('NO_ART', $id->value)
|
||||
->first();
|
||||
|
||||
if ($model === null) {
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->toDomain($model);
|
||||
return IncoShortMapper::toDomain($row);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -145,35 +149,12 @@ final class EloquentIncoShortSheetDirectory implements IncoShortSheetDirectory
|
|||
return $unique;
|
||||
}
|
||||
|
||||
private function toDomain(IncoSheetModel $model): IncoShortSheet
|
||||
{
|
||||
$rawId = $model->getAttribute('id');
|
||||
$rawName = $model->getAttribute('name');
|
||||
$rawLabel = $model->getAttribute('label');
|
||||
$rawCreatedAt = $model->getAttribute('created_at');
|
||||
$rawUpdatedAt = $model->getAttribute('updated_at');
|
||||
|
||||
$id = is_string($rawId) || is_numeric($rawId) ? (string) $rawId : '';
|
||||
$name = is_string($rawName) ? $rawName : '';
|
||||
$label = is_string($rawLabel) ? $rawLabel : '';
|
||||
$createdAt = is_string($rawCreatedAt) ? DatesHelper::parseDateTime($rawCreatedAt) : null;
|
||||
$updatedAt = is_string($rawUpdatedAt) ? DatesHelper::parseDateTime($rawUpdatedAt) : null;
|
||||
|
||||
return IncoShortSheet::hydrate(
|
||||
id: new IncoId($id),
|
||||
name: $name,
|
||||
label: $label,
|
||||
createdAt: $createdAt,
|
||||
updatedAt: $updatedAt,
|
||||
);
|
||||
}
|
||||
|
||||
private function toSqlColumn(IncoSheetSortColumn $column): string
|
||||
{
|
||||
return match ($column) {
|
||||
IncoSheetSortColumn::incoSheetId => 'id',
|
||||
IncoSheetSortColumn::createdAt => 'created_at',
|
||||
IncoSheetSortColumn::updatedAt => 'updated_at',
|
||||
IncoSheetSortColumn::incoSheetId => 'NO_ART',
|
||||
IncoSheetSortColumn::createdAt => 'DAT_CRE',
|
||||
IncoSheetSortColumn::updatedAt => 'DAT_MAJ',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -6,23 +6,31 @@ namespace Infra\Adapters\Directories;
|
|||
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaBrand;
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
||||
use Domain\Models\ValueObjects\Brand\BrandName;
|
||||
use Domain\Ports\Directories\ArcadiaBrandDirectory;
|
||||
use Infra\Database\Models\ArcadiaBrand as ArcadiaBrandModel;
|
||||
use Domain\Ports\Directories\ArcadiaBrandDirectory as ArcadiaBrandDirectoryPort;
|
||||
use Illuminate\Database\Connection;
|
||||
use Infra\Adapters\Mappers\ArcadiaBrandMapper;
|
||||
|
||||
final class EloquentArcadiaBrandDirectory implements ArcadiaBrandDirectory
|
||||
final class ArcadiaMarqueBrandDirectory implements ArcadiaBrandDirectoryPort
|
||||
{
|
||||
/** @var array<string, ?ArcadiaBrand> */
|
||||
private array $cache = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly Connection $connection,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function findAll(): array
|
||||
{
|
||||
$models = ArcadiaBrandModel::query()->get();
|
||||
$items = [];
|
||||
$rows = $this->connection
|
||||
->table('MARQUE')
|
||||
->get();
|
||||
|
||||
foreach ($models as $model) {
|
||||
$domain = $this->toDomain($model);
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$domain = ArcadiaBrandMapper::toDomain($row);
|
||||
$this->cache[$domain->id->value] = $domain;
|
||||
$items[] = $domain;
|
||||
}
|
||||
|
|
@ -37,25 +45,20 @@ final class EloquentArcadiaBrandDirectory implements ArcadiaBrandDirectory
|
|||
return $this->cache[$id->value];
|
||||
}
|
||||
|
||||
$model = ArcadiaBrandModel::query()->find($id->value);
|
||||
$row = $this->connection
|
||||
->table('MARQUE')
|
||||
->where('COD_MARQ', $id->value)
|
||||
->first();
|
||||
|
||||
if ($model === null) {
|
||||
if ($row === null) {
|
||||
$this->cache[$id->value] = null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$domain = $this->toDomain($model);
|
||||
$domain = ArcadiaBrandMapper::toDomain($row);
|
||||
$this->cache[$id->value] = $domain;
|
||||
|
||||
return $domain;
|
||||
}
|
||||
|
||||
private function toDomain(ArcadiaBrandModel $model): ArcadiaBrand
|
||||
{
|
||||
return new ArcadiaBrand(
|
||||
id: new ArcadiaId((string) $model->code),
|
||||
name: new BrandName((string) $model->libelle),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Employee;
|
||||
use Domain\Models\ValueObjects\Employees\ArcadiaEmployeeId;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeFilter;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeSortColumn;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeSorter;
|
||||
use Domain\Models\ValueObjects\EstablishmentCode;
|
||||
use Domain\Models\ValueObjects\ServiceId;
|
||||
use Domain\Models\ValueObjects\SiteId;
|
||||
use Domain\Ports\Directories\EmployeeDirectory;
|
||||
use Infra\Database\Models\Employee as EmployeeModel;
|
||||
use Shared\Paginated;
|
||||
use Shared\Pagination;
|
||||
|
||||
final class EloquentEmployeeDirectory implements EmployeeDirectory
|
||||
{
|
||||
#[\Override]
|
||||
public function findAll(
|
||||
Pagination $pagination,
|
||||
EmployeeSorter $sorter,
|
||||
?EmployeeFilter $filter = null,
|
||||
): Paginated {
|
||||
$query = EmployeeModel::query();
|
||||
|
||||
if ($filter !== null) {
|
||||
if ($filter->establishment !== null) {
|
||||
$query->where('establishment', $filter->establishment->value);
|
||||
}
|
||||
|
||||
if (! empty($filter->sites)) {
|
||||
$siteValues = array_map(static fn (SiteId $s): string => $s->value, $filter->sites);
|
||||
$query->whereIn('site', $siteValues);
|
||||
}
|
||||
|
||||
if ($filter->service !== null) {
|
||||
$query->where('service', $filter->service->value);
|
||||
}
|
||||
|
||||
if ($filter->since !== null) {
|
||||
$query->where(static function ($q) use ($filter): void {
|
||||
$q->where('updated_at', '>=', $filter->since)
|
||||
->orWhere('created_at', '>=', $filter->since);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$total = (int) (clone $query)->count();
|
||||
|
||||
/** @var \Illuminate\Support\Collection<int, EmployeeModel> $rows */
|
||||
$rows = (clone $query)
|
||||
->orderBy(
|
||||
$this->toSqlColumn($sorter->sortBy),
|
||||
$sorter->direction
|
||||
)
|
||||
->offset($pagination->from())
|
||||
->limit($pagination->pageSize())
|
||||
->get();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->toDomain($row);
|
||||
}
|
||||
|
||||
/** @var Employee[] $items */
|
||||
return new Paginated($pagination, $items, $total);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function find(ArcadiaEmployeeId $id): ?Employee
|
||||
{
|
||||
$model = EmployeeModel::query()
|
||||
->where('public_employee_number', $id->value)
|
||||
->first();
|
||||
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->toDomain($model);
|
||||
}
|
||||
|
||||
private function toDomain(EmployeeModel $employee): Employee
|
||||
{
|
||||
if ($employee->created_at === null) {
|
||||
throw new \UnexpectedValueException('Employee created_at cannot be null.');
|
||||
}
|
||||
|
||||
return Employee::hydrate(
|
||||
publicEmployeeNumber: new ArcadiaEmployeeId((string) $employee->public_employee_number),
|
||||
lastName: (string) $employee->last_name,
|
||||
firstName: (string) $employee->first_name,
|
||||
startDate: $employee->start_date,
|
||||
endDate: $employee->end_date,
|
||||
plannedEndDate: $employee->planned_end_date,
|
||||
establishment: new EstablishmentCode((string) $employee->establishment),
|
||||
site: new SiteId((string) $employee->site),
|
||||
service: new ServiceId((string) $employee->service),
|
||||
createdAt: $employee->created_at,
|
||||
updatedAt: $employee->updated_at,
|
||||
);
|
||||
}
|
||||
|
||||
private function toSqlColumn(EmployeeSortColumn $sortBy): string
|
||||
{
|
||||
return match ($sortBy) {
|
||||
EmployeeSortColumn::arcadiaId => 'public_employee_number',
|
||||
EmployeeSortColumn::startDate => 'start_date',
|
||||
EmployeeSortColumn::endDate => 'end_date',
|
||||
EmployeeSortColumn::plannedEndDate => 'planned_end_date',
|
||||
EmployeeSortColumn::createdAt => 'created_at',
|
||||
EmployeeSortColumn::updatedAt => 'updated_at',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,392 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Inco\Composition\IncoComposition;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\AminoAcids;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\CarbohydratesDetail;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\Energy;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\EnergyValues;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\FattyAcids;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\FreshProduceAndNuts;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\FruitAndNutAmount;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\Identification;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\IncoCompositionId;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\Minerals;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\NutrientValue;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\NutriScore;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\NutriScorePoints;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\PercentageValue;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\PortionMacronutrients;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\ReferenceIntakes;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\ReferenceMacronutrients;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\SpecialCompounds;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\Vitamins;
|
||||
use Domain\Models\ValueObjects\Inco\IncoId;
|
||||
use Domain\Ports\Directories\IncoCompositionDirectory;
|
||||
use Infra\Database\Models\IncoCompo as IncoCompoModel;
|
||||
|
||||
final class EloquentIncoCompositionDirectory implements IncoCompositionDirectory
|
||||
{
|
||||
#[\Override]
|
||||
public function find(IncoCompositionId $id): ?IncoComposition
|
||||
{
|
||||
$model = IncoCompoModel::query()
|
||||
->where('id', $id->value)
|
||||
->first();
|
||||
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->toDomain($model);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function findByIncoId(IncoId $incoId): ?IncoComposition
|
||||
{
|
||||
$model = IncoCompoModel::query()
|
||||
->where('id_inco', $incoId->value)
|
||||
->first();
|
||||
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->toDomain($model);
|
||||
}
|
||||
|
||||
private function toDomain(IncoCompoModel $model): IncoComposition
|
||||
{
|
||||
return IncoComposition::builder()
|
||||
->withId(new IncoCompositionId((string) $model->id))
|
||||
->withIdInco(new IncoId((string) $model->id_inco))
|
||||
->withIdentification($this->identificationFrom($model))
|
||||
->withEnergy($this->energyFrom($model))
|
||||
->withReferenceMacronutrients($this->refMacronutrientsFrom($model))
|
||||
->withPortionMacronutrients($this->portionMacronutrientsFrom($model))
|
||||
->withFreshProduceAndNuts($this->freshProduceAndNutsFrom($model))
|
||||
->withReferenceIntakes($this->refIntakesFrom($model))
|
||||
->withNutriScore($this->nutriScoreFrom($model))
|
||||
->withNutriScorePoints($this->nutriScorePointsFrom($model))
|
||||
->withMinerals($this->mineralsFrom($model))
|
||||
->withVitamins($this->vitaminsFrom($model))
|
||||
->withCarbohydratesDetail($this->carbohydratesDetailFrom($model))
|
||||
->withFattyAcids($this->fattyAcidsFrom($model))
|
||||
->withAminoAcids($this->aminoAcidsFrom($model))
|
||||
->withSpecialCompounds($this->specialCompoundsFrom($model))
|
||||
->build();
|
||||
}
|
||||
|
||||
private function identificationFrom(IncoCompoModel $model): Identification
|
||||
{
|
||||
$raw = is_array($model->identification) ? $model->identification : [];
|
||||
|
||||
return new Identification(
|
||||
name: $this->getString($raw, 'name', 'Inconnu'),
|
||||
number: $this->getString($raw, 'number', (string) $model->id_inco),
|
||||
source: $this->getString($raw, 'source', 'System'),
|
||||
);
|
||||
}
|
||||
|
||||
private function energyFrom(IncoCompoModel $model): Energy
|
||||
{
|
||||
$energyRaw = is_array($model->energy) ? $model->energy : [];
|
||||
$refArr = is_array($energyRaw['reference'] ?? null) ? $energyRaw['reference'] : [];
|
||||
$porArr = is_array($energyRaw['portion'] ?? null) ? $energyRaw['portion'] : [];
|
||||
|
||||
$refEnergy = new EnergyValues(
|
||||
size: $this->getStringWithFallback($refArr, 'size', 'portionAmount', '100g'),
|
||||
energyKj: $this->getStringWithFallback($refArr, 'energyKj', 'kilojoules'),
|
||||
energyKcal: $this->getStringWithFallback($refArr, 'energyKcal', 'kilocalories'),
|
||||
);
|
||||
$porEnergy = new EnergyValues(
|
||||
size: $this->getStringWithFallback($porArr, 'size', 'portionAmount', '100g'),
|
||||
energyKj: $this->getStringWithFallback($porArr, 'energyKj', 'kilojoules'),
|
||||
energyKcal: $this->getStringWithFallback($porArr, 'energyKcal', 'kilocalories'),
|
||||
);
|
||||
|
||||
return new Energy($refEnergy, $porEnergy);
|
||||
}
|
||||
|
||||
private function refMacronutrientsFrom(IncoCompoModel $model): ReferenceMacronutrients
|
||||
{
|
||||
$raw = is_array($model->reference_macronutrients) ? $model->reference_macronutrients : [];
|
||||
|
||||
return new ReferenceMacronutrients(
|
||||
fat: $this->getNutrient($raw, 'fat'),
|
||||
saturatedFat: $this->getNutrient($raw, 'saturatedFat'),
|
||||
carbohydrates: $this->getNutrient($raw, 'carbohydrates'),
|
||||
sugars: $this->getNutrient($raw, 'sugars'),
|
||||
fiber: $this->getNutrient($raw, 'fiber'),
|
||||
protein: $this->getNutrient($raw, 'protein'),
|
||||
salt: $this->getNutrient($raw, 'salt'),
|
||||
);
|
||||
}
|
||||
|
||||
private function portionMacronutrientsFrom(IncoCompoModel $model): PortionMacronutrients
|
||||
{
|
||||
$raw = is_array($model->portion_macronutrients) ? $model->portion_macronutrients : [];
|
||||
|
||||
return new PortionMacronutrients(
|
||||
fat: $this->getNutrient($raw, 'fat'),
|
||||
saturatedFat: $this->getNutrient($raw, 'saturatedFat'),
|
||||
carbohydrates: $this->getNutrient($raw, 'carbohydrates'),
|
||||
sugars: $this->getNutrient($raw, 'sugars'),
|
||||
fiber: $this->getNutrient($raw, 'fiber'),
|
||||
protein: $this->getNutrient($raw, 'protein'),
|
||||
salt: $this->getNutrient($raw, 'salt'),
|
||||
);
|
||||
}
|
||||
|
||||
private function freshProduceAndNutsFrom(IncoCompoModel $model): FreshProduceAndNuts
|
||||
{
|
||||
$raw = is_array($model->fresh_produce_and_nuts) ? $model->fresh_produce_and_nuts : [];
|
||||
$fruitAmount = new FruitAndNutAmount();
|
||||
|
||||
return new FreshProduceAndNuts(
|
||||
reference: $fruitAmount,
|
||||
portion: $fruitAmount,
|
||||
freshFnlPercentage: $this->getPercentage($raw, 'freshFnlPercentage'),
|
||||
fruitsPercentage: $this->getPercentage($raw, 'fruitsPercentage'),
|
||||
);
|
||||
}
|
||||
|
||||
private function refIntakesFrom(IncoCompoModel $model): ReferenceIntakes
|
||||
{
|
||||
$raw = is_array($model->reference_intakes) ? $model->reference_intakes : [];
|
||||
|
||||
return new ReferenceIntakes(
|
||||
energyE14: $this->getPercentage($raw, 'energyE14'),
|
||||
energyKj: $this->getPercentage($raw, 'energyKj'),
|
||||
fat: $this->getPercentage($raw, 'fat'),
|
||||
saturatedFat: $this->getPercentage($raw, 'saturatedFat'),
|
||||
carbohydrates: $this->getPercentage($raw, 'carbohydrates'),
|
||||
sugars: $this->getPercentage($raw, 'sugars'),
|
||||
protein: $this->getPercentage($raw, 'protein'),
|
||||
salt: $this->getPercentage($raw, 'salt'),
|
||||
portionAmount: $this->getString($raw, 'portionAmount', '100g'),
|
||||
);
|
||||
}
|
||||
|
||||
private function nutriScoreFrom(IncoCompoModel $model): NutriScore
|
||||
{
|
||||
$raw = is_array($model->nutri_score) ? $model->nutri_score : [];
|
||||
|
||||
return new NutriScore(
|
||||
negativeComponent: $this->getString($raw, 'negativeComponent'),
|
||||
score: $this->getString($raw, 'score'),
|
||||
grade: $this->getString($raw, 'grade', 'A'),
|
||||
);
|
||||
}
|
||||
|
||||
private function nutriScorePointsFrom(IncoCompoModel $model): NutriScorePoints
|
||||
{
|
||||
$raw = is_array($model->nutri_score_points) ? $model->nutri_score_points : [];
|
||||
|
||||
return new NutriScorePoints(
|
||||
energyPoints: $this->getStringWithFallback($raw, 'energyPoints', 'energy'),
|
||||
saturatedFatPoints: $this->getStringWithFallback($raw, 'saturatedFatPoints', 'saturatedFat'),
|
||||
sugarsPoints: $this->getStringWithFallback($raw, 'sugarsPoints', 'sugars'),
|
||||
saltPoints: $this->getStringWithFallback($raw, 'saltPoints', 'sodium'),
|
||||
fiberPoints: $this->getStringWithFallback($raw, 'fiberPoints', 'fiber'),
|
||||
proteinPoints: $this->getStringWithFallback($raw, 'proteinPoints', 'proteins'),
|
||||
freshFnlPoints: $this->getStringWithFallback($raw, 'freshFnlPoints', 'fruitsNuts'),
|
||||
);
|
||||
}
|
||||
|
||||
private function mineralsFrom(IncoCompoModel $model): Minerals
|
||||
{
|
||||
$raw = is_array($model->minerals) ? $model->minerals : [];
|
||||
|
||||
return new Minerals(
|
||||
calcium: $this->getString($raw, 'calcium'),
|
||||
magnesium: $this->getString($raw, 'magnesium'),
|
||||
potassium: $this->getString($raw, 'potassium'),
|
||||
phosphorus: $this->getString($raw, 'phosphorus'),
|
||||
chloride: $this->getString($raw, 'chloride'),
|
||||
iron: $this->getString($raw, 'iron'),
|
||||
zinc: $this->getString($raw, 'zinc'),
|
||||
copper: $this->getString($raw, 'copper'),
|
||||
manganese: $this->getString($raw, 'manganese'),
|
||||
selenium: $this->getString($raw, 'selenium'),
|
||||
iodine: $this->getString($raw, 'iodine'),
|
||||
chromium: $this->getString($raw, 'chromium'),
|
||||
molybdenum: $this->getString($raw, 'molybdenum'),
|
||||
sulfur: $this->getString($raw, 'sulfur'),
|
||||
nitrates: $this->getString($raw, 'nitrates'),
|
||||
);
|
||||
}
|
||||
|
||||
private function vitaminsFrom(IncoCompoModel $model): Vitamins
|
||||
{
|
||||
$raw = is_array($model->vitamins) ? $model->vitamins : [];
|
||||
|
||||
return new Vitamins(
|
||||
vitaminA: $this->getString($raw, 'vitaminA'),
|
||||
vitaminB6: $this->getString($raw, 'vitaminB6'),
|
||||
vitaminB12: $this->getString($raw, 'vitaminB12'),
|
||||
vitaminC: $this->getString($raw, 'vitaminC'),
|
||||
vitaminD: $this->getString($raw, 'vitaminD'),
|
||||
vitaminE: $this->getString($raw, 'vitaminE'),
|
||||
vitaminK: $this->getString($raw, 'vitaminK'),
|
||||
cholecalciferol: $this->getString($raw, 'cholecalciferol'),
|
||||
niacin: $this->getString($raw, 'niacin'),
|
||||
riboflavin: $this->getString($raw, 'riboflavin'),
|
||||
thiamine: $this->getString($raw, 'thiamine'),
|
||||
pantothenicAcid: $this->getString($raw, 'pantothenicAcid'),
|
||||
biotin: $this->getString($raw, 'biotin'),
|
||||
folates: $this->getString($raw, 'folates'),
|
||||
);
|
||||
}
|
||||
|
||||
private function carbohydratesDetailFrom(IncoCompoModel $model): CarbohydratesDetail
|
||||
{
|
||||
$raw = is_array($model->carbohydrates_detail) ? $model->carbohydrates_detail : [];
|
||||
|
||||
return new CarbohydratesDetail(
|
||||
starch: $this->getString($raw, 'starch'),
|
||||
maltodextrin: $this->getString($raw, 'maltodextrin'),
|
||||
sucrose: $this->getString($raw, 'sucrose'),
|
||||
glucose: $this->getString($raw, 'glucose'),
|
||||
lactose: $this->getString($raw, 'lactose'),
|
||||
maltose: $this->getString($raw, 'maltose'),
|
||||
galactose: $this->getString($raw, 'galactose'),
|
||||
carbohydrateHydrates: $this->getString($raw, 'carbohydrateHydrates'),
|
||||
boundFructose: $this->getString($raw, 'boundFructose'),
|
||||
freeFructose: $this->getString($raw, 'freeFructose'),
|
||||
oligosaccharides: $this->getString($raw, 'oligosaccharides'),
|
||||
polyols: $this->getString($raw, 'polyols'),
|
||||
solubleFiber: $this->getString($raw, 'solubleFiber'),
|
||||
inositol: $this->getString($raw, 'inositol'),
|
||||
);
|
||||
}
|
||||
|
||||
private function fattyAcidsFrom(IncoCompoModel $model): FattyAcids
|
||||
{
|
||||
$raw = is_array($model->fatty_acids) ? $model->fatty_acids : [];
|
||||
|
||||
return new FattyAcids(
|
||||
fd: $this->getString($raw, 'fd'),
|
||||
cholesterol: $this->getString($raw, 'cholesterol'),
|
||||
transFat: $this->getString($raw, 'transFat'),
|
||||
formic: $this->getString($raw, 'formic'),
|
||||
acetic: $this->getString($raw, 'acetic'),
|
||||
propionic: $this->getString($raw, 'propionic'),
|
||||
butyric: $this->getString($raw, 'butyric'),
|
||||
valeric: $this->getString($raw, 'valeric'),
|
||||
caproic: $this->getString($raw, 'caproic'),
|
||||
enanthic: $this->getString($raw, 'enanthic'),
|
||||
caprylic: $this->getString($raw, 'caprylic'),
|
||||
pelargonic: $this->getString($raw, 'pelargonic'),
|
||||
capric: $this->getString($raw, 'capric'),
|
||||
undecylic: $this->getString($raw, 'undecylic'),
|
||||
lauric: $this->getString($raw, 'lauric'),
|
||||
tridecylic: $this->getString($raw, 'tridecylic'),
|
||||
myristic: $this->getString($raw, 'myristic'),
|
||||
pentadecylic: $this->getString($raw, 'pentadecylic'),
|
||||
f16d0: $this->getString($raw, 'f16d0'),
|
||||
margaric: $this->getString($raw, 'margaric'),
|
||||
stearic: $this->getString($raw, 'stearic'),
|
||||
arachidic: $this->getString($raw, 'arachidic'),
|
||||
heneicosylic: $this->getString($raw, 'heneicosylic'),
|
||||
behenic: $this->getString($raw, 'behenic'),
|
||||
tricosylic: $this->getString($raw, 'tricosylic'),
|
||||
lignoceric: $this->getString($raw, 'lignoceric'),
|
||||
carboceric: $this->getString($raw, 'carboceric'),
|
||||
cerotic: $this->getString($raw, 'cerotic'),
|
||||
ceroplastic: $this->getString($raw, 'ceroplastic'),
|
||||
montanic: $this->getString($raw, 'montanic'),
|
||||
nonacosylic: $this->getString($raw, 'nonacosylic'),
|
||||
melissic: $this->getString($raw, 'melissic'),
|
||||
laceric: $this->getString($raw, 'laceric'),
|
||||
hentriacontylic: $this->getString($raw, 'hentriacontylic'),
|
||||
hextriacontylic: $this->getString($raw, 'hextriacontylic'),
|
||||
heptatriacontylic: $this->getString($raw, 'heptatriacontylic'),
|
||||
octatriacontylic: $this->getString($raw, 'octatriacontylic'),
|
||||
nonadylie: $this->getString($raw, 'nonadylie'),
|
||||
psyllic: $this->getString($raw, 'psyllic'),
|
||||
palmitic: $this->getString($raw, 'palmitic'),
|
||||
oleic: $this->getString($raw, 'oleic'),
|
||||
f18d: $this->getString($raw, 'f18d'),
|
||||
f19d: $this->getString($raw, 'f19d'),
|
||||
f11eico: $this->getString($raw, 'f11eico'),
|
||||
geddic: $this->getString($raw, 'geddic'),
|
||||
erucic: $this->getString($raw, 'erucic'),
|
||||
nervonic: $this->getString($raw, 'nervonic'),
|
||||
hyenic: $this->getString($raw, 'hyenic'),
|
||||
amscis: $this->getString($raw, 'amscis'),
|
||||
f18d2cn6: $this->getString($raw, 'f18d2cn6'),
|
||||
f18d3n3: $this->getString($raw, 'f18d3n3'),
|
||||
f20d4: $this->getString($raw, 'f20d4'),
|
||||
f20d5n3: $this->getString($raw, 'f20d5n3'),
|
||||
f22d6n3: $this->getString($raw, 'f22d6n3'),
|
||||
fapun3: $this->getString($raw, 'fapun3'),
|
||||
fapun6: $this->getString($raw, 'fapun6'),
|
||||
fapun9: $this->getString($raw, 'fapun9'),
|
||||
fapucis: $this->getString($raw, 'fapucis'),
|
||||
fapulc: $this->getString($raw, 'fapulc'),
|
||||
);
|
||||
}
|
||||
|
||||
private function aminoAcidsFrom(IncoCompoModel $model): AminoAcids
|
||||
{
|
||||
$raw = is_array($model->amino_acids) ? $model->amino_acids : [];
|
||||
|
||||
return new AminoAcids(
|
||||
essentialAminoAcids: $this->getString($raw, 'essentialAminoAcids'),
|
||||
caseins: $this->getString($raw, 'caseins'),
|
||||
wheyProtein: $this->getString($raw, 'wheyProtein'),
|
||||
);
|
||||
}
|
||||
|
||||
private function specialCompoundsFrom(IncoCompoModel $model): SpecialCompounds
|
||||
{
|
||||
$raw = is_array($model->special_compounds) ? $model->special_compounds : [];
|
||||
|
||||
return new SpecialCompounds(
|
||||
choline: $this->getString($raw, 'choline'),
|
||||
carnitine: $this->getString($raw, 'carnitine'),
|
||||
taurine: $this->getString($raw, 'taurine'),
|
||||
nucleotides: $this->getString($raw, 'nucleotides'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
private function getString(array $data, string $key, string $default = '0'): string
|
||||
{
|
||||
$val = $data[$key] ?? null;
|
||||
|
||||
return is_scalar($val) ? (string) $val : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
private function getStringWithFallback(array $data, string $key, string $fallbackKey, string $default = '0'): string
|
||||
{
|
||||
$val = $data[$key] ?? $data[$fallbackKey] ?? null;
|
||||
|
||||
return is_scalar($val) ? (string) $val : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
private function getNutrient(array $data, string $key, string $default = '0'): NutrientValue
|
||||
{
|
||||
return new NutrientValue($this->getString($data, $key, $default));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
private function getPercentage(array $data, string $key, string $default = '0'): PercentageValue
|
||||
{
|
||||
return new PercentageValue($this->getString($data, $key, $default));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,410 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Inco\IncoSheet;
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Inco\Additive;
|
||||
use Domain\Models\ValueObjects\Inco\Allegations;
|
||||
use Domain\Models\ValueObjects\Inco\Allergen;
|
||||
use Domain\Models\ValueObjects\Inco\Composition\IncoCompositionId;
|
||||
use Domain\Models\ValueObjects\Inco\IncoBrand;
|
||||
use Domain\Models\ValueObjects\Inco\IncoId;
|
||||
use Domain\Models\ValueObjects\Inco\IncoIdQuery;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetFilter;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSortColumn;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSorter;
|
||||
use Domain\Models\ValueObjects\Inco\IncoWeight;
|
||||
use Domain\Models\ValueObjects\Inco\Ingredients;
|
||||
use Domain\Models\ValueObjects\Inco\Nutriscore;
|
||||
use Domain\Models\ValueObjects\Inco\PortionAmount;
|
||||
use Domain\Models\ValueObjects\Inco\StorageCondition;
|
||||
use Domain\Ports\Directories\IncoSheetDirectory;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
use Domain\Services\BrandResolver;
|
||||
use Infra\Database\Models\IncoSheet as IncoSheetModel;
|
||||
use Shared\Helpers\DatesHelper;
|
||||
use Shared\Paginated;
|
||||
use Shared\Pagination;
|
||||
|
||||
final class EloquentIncoSheetDirectory implements IncoSheetDirectory
|
||||
{
|
||||
public function __construct(
|
||||
private BrandResolver $brandResolver,
|
||||
private BrandRepository $brandRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function findAll(
|
||||
Pagination $pagination,
|
||||
IncoSheetSorter $sorter,
|
||||
?IncoSheetFilter $filter = null
|
||||
): Paginated {
|
||||
$query = IncoSheetModel::query();
|
||||
|
||||
if ($filter !== null) {
|
||||
if ($filter->since !== null) {
|
||||
$query->where(static function ($q) use ($filter): void {
|
||||
$q->where('updated_at', '>=', $filter->since)
|
||||
->orWhere('created_at', '>=', $filter->since);
|
||||
});
|
||||
}
|
||||
|
||||
if (! empty($filter->brands)) {
|
||||
$resolvedBrands = $this->resolveBrandFilterCodes(...$filter->brands);
|
||||
$query->whereIn('brand->code', $resolvedBrands);
|
||||
}
|
||||
}
|
||||
|
||||
$total = (int) (clone $query)->count();
|
||||
|
||||
$rows = (clone $query)
|
||||
->orderBy(
|
||||
$this->toSqlColumn($sorter->sortBy),
|
||||
$sorter->direction
|
||||
)
|
||||
->offset($pagination->from())
|
||||
->limit($pagination->pageSize())
|
||||
->get();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->toDomain($row);
|
||||
}
|
||||
|
||||
/** @var IncoSheet[] $items */
|
||||
return new Paginated($pagination, $items, $total);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function search(
|
||||
IncoIdQuery $query,
|
||||
Pagination $pagination,
|
||||
BrandCode ...$brands
|
||||
): Paginated {
|
||||
$dbQuery = IncoSheetModel::query();
|
||||
|
||||
$dbQuery->where('id', 'LIKE', $query->value);
|
||||
|
||||
if (! empty($brands)) {
|
||||
$resolvedBrands = $this->resolveBrandFilterCodes(...$brands);
|
||||
$dbQuery->whereIn('brand->code', $resolvedBrands);
|
||||
}
|
||||
|
||||
$total = (int) (clone $dbQuery)->count();
|
||||
|
||||
$rows = $dbQuery
|
||||
->offset($pagination->from())
|
||||
->limit($pagination->pageSize())
|
||||
->get();
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$items[] = $this->toDomain($row);
|
||||
}
|
||||
|
||||
/** @var IncoSheet[] $items */
|
||||
return new Paginated($pagination, $items, $total);
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function find(IncoId $id): ?IncoSheet
|
||||
{
|
||||
$model = IncoSheetModel::query()
|
||||
->where('id', $id->value)
|
||||
->first();
|
||||
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->toDomain($model);
|
||||
}
|
||||
|
||||
private function toDomain(IncoSheetModel $model): IncoSheet
|
||||
{
|
||||
$allegations = $this->allegationsFrom($model);
|
||||
$ingredients = $this->ingredientsFrom($model);
|
||||
$portions = $this->portionsFrom($model);
|
||||
$allergens = $this->allergensFrom($model);
|
||||
$brand = $this->brandFrom($model);
|
||||
$weight = $this->weightFrom($model);
|
||||
$nutriscore = $this->nutriscoreFrom($model);
|
||||
$storageCondition = $this->storageConditionFrom($model);
|
||||
$additives = $this->additivesFrom($model);
|
||||
|
||||
$compo = $model->compo_id !== null ? new IncoCompositionId((string) $model->compo_id) : null;
|
||||
|
||||
return IncoSheet::builder()
|
||||
->withId(new IncoId((string) $model->id))
|
||||
->withName((string) $model->name)
|
||||
->withLabel((string) $model->label)
|
||||
->withDescription((string) $model->description)
|
||||
->withAllegations($allegations)
|
||||
->withSellArguments((string) $model->sell_arguments)
|
||||
->withPreparationAdvices((string) $model->preparation_advices)
|
||||
->withTips($this->toNullableString($model->tips))
|
||||
->withSellFamilly($this->toNullableString($model->sell_familly))
|
||||
->withIngredients($ingredients)
|
||||
->withPortions($portions)
|
||||
->withAllergens(...$allergens)
|
||||
->withBrand($brand)
|
||||
->withIsSeasonal((bool) $model->is_seasonal)
|
||||
->withWeight($weight)
|
||||
->withNutriscore($nutriscore)
|
||||
->withStorageCondition($storageCondition)
|
||||
->withAdditives(...$additives)
|
||||
->withCompo($compo)
|
||||
->withCreatedAt($this->toNullableDateTime($model->created_at))
|
||||
->withUpdatedAt($this->toNullableDateTime($model->updated_at))
|
||||
->build();
|
||||
}
|
||||
|
||||
private function allegationsFrom(IncoSheetModel $model): Allegations
|
||||
{
|
||||
$raw = is_array($model->allegations) ? $model->allegations : [];
|
||||
|
||||
return new Allegations(
|
||||
allegations: $this->getArrayOfStrings($raw, 'allegations'),
|
||||
health: $this->getArrayOfStrings($raw, 'health'),
|
||||
nutrition: $this->getArrayOfStrings($raw, 'nutrition'),
|
||||
other: $this->getArrayOfStrings($raw, 'other'),
|
||||
);
|
||||
}
|
||||
|
||||
private function ingredientsFrom(IncoSheetModel $model): Ingredients
|
||||
{
|
||||
$raw = is_array($model->ingredients) ? $model->ingredients : [];
|
||||
|
||||
/** @var array<string, list<string>> $cleanIngredients */
|
||||
$cleanIngredients = [];
|
||||
|
||||
foreach ($raw as $key => $values) {
|
||||
if (is_string($key) && is_array($values)) {
|
||||
$cleanIngredients[$key] = array_values(
|
||||
array_filter($values, static fn ($item): bool => is_string($item))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new Ingredients($cleanIngredients);
|
||||
}
|
||||
|
||||
private function portionsFrom(IncoSheetModel $model): ?PortionAmount
|
||||
{
|
||||
$raw = is_array($model->portions) ? $model->portions : null;
|
||||
|
||||
if ($raw === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PortionAmount(
|
||||
lowPart: $this->getInt($raw, 'lowPart'),
|
||||
highPart: $this->getInt($raw, 'highPart'),
|
||||
approximative: $this->getBool($raw, 'approximative'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Allergen>
|
||||
*/
|
||||
private function allergensFrom(IncoSheetModel $model): array
|
||||
{
|
||||
$raw = is_array($model->allergens) ? $model->allergens : [];
|
||||
|
||||
$allergens = [];
|
||||
|
||||
foreach ($raw as $a) {
|
||||
if (is_array($a) && isset($a['code'], $a['label']) && is_numeric($a['code']) && is_string($a['label'])) {
|
||||
$allergens[] = new Allergen((int) $a['code'], $a['label']);
|
||||
}
|
||||
}
|
||||
|
||||
return $allergens;
|
||||
}
|
||||
|
||||
private function brandFrom(IncoSheetModel $model): IncoBrand
|
||||
{
|
||||
$raw = is_array($model->brand) ? $model->brand : [];
|
||||
$rawCode = isset($raw['code']) && (is_string($raw['code']) || is_numeric($raw['code']))
|
||||
? (string) $raw['code']
|
||||
: '1';
|
||||
|
||||
$arcadiaId = new ArcadiaId($rawCode);
|
||||
$brand = $this->brandResolver->resolve($arcadiaId);
|
||||
|
||||
return new IncoBrand(
|
||||
name: $brand->name,
|
||||
code: $brand->code,
|
||||
arcadiaBrandCode: $brand->arcadiaId,
|
||||
);
|
||||
}
|
||||
|
||||
private function weightFrom(IncoSheetModel $model): ?IncoWeight
|
||||
{
|
||||
$raw = is_array($model->weight) ? $model->weight : null;
|
||||
|
||||
if ($raw === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IncoWeight(
|
||||
netWeight: $this->getInt($raw, 'netWeight'),
|
||||
grossWeight: $this->getInt($raw, 'grossWeight'),
|
||||
theoreticalAverage: $this->getInt($raw, 'theoreticalAverage'),
|
||||
);
|
||||
}
|
||||
|
||||
private function nutriscoreFrom(IncoSheetModel $model): ?Nutriscore
|
||||
{
|
||||
$raw = is_array($model->nutriscore) ? $model->nutriscore : null;
|
||||
|
||||
if ($raw === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$grade = $this->getString($raw, 'grade');
|
||||
|
||||
if ($grade === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Nutriscore($grade);
|
||||
}
|
||||
|
||||
private function storageConditionFrom(IncoSheetModel $model): ?StorageCondition
|
||||
{
|
||||
$raw = is_array($model->storage_condition) ? $model->storage_condition : null;
|
||||
|
||||
if ($raw === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$instructions = $this->getString($raw, 'instructions');
|
||||
|
||||
if ($instructions === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new StorageCondition($instructions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Additive>
|
||||
*/
|
||||
private function additivesFrom(IncoSheetModel $model): array
|
||||
{
|
||||
$raw = is_array($model->additives) ? $model->additives : [];
|
||||
|
||||
$additives = [];
|
||||
|
||||
foreach ($raw as $a) {
|
||||
if (is_array($a) && isset($a['code'], $a['label']) && is_string($a['code']) && is_string($a['label'])) {
|
||||
$additives[] = new Additive($a['code'], $a['label']);
|
||||
}
|
||||
}
|
||||
|
||||
return $additives;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int|string>
|
||||
*/
|
||||
private function resolveBrandFilterCodes(BrandCode ...$brandCodes): array
|
||||
{
|
||||
$resolved = [];
|
||||
|
||||
foreach ($brandCodes as $brandCode) {
|
||||
$brand = $this->brandRepository->findByCode($brandCode);
|
||||
if ($brand !== null) {
|
||||
$resolved[] = (int) $brand->arcadiaId->value;
|
||||
$resolved[] = $brand->arcadiaId->value;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($resolved) && ! empty($brandCodes)) {
|
||||
return [0];
|
||||
}
|
||||
|
||||
$unique = [];
|
||||
foreach ($resolved as $item) {
|
||||
if (! in_array($item, $unique, true)) {
|
||||
$unique[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $unique;
|
||||
}
|
||||
|
||||
private function toSqlColumn(IncoSheetSortColumn $column): string
|
||||
{
|
||||
return match ($column) {
|
||||
IncoSheetSortColumn::incoSheetId => 'id',
|
||||
IncoSheetSortColumn::createdAt => 'created_at',
|
||||
IncoSheetSortColumn::updatedAt => 'updated_at',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed> $data
|
||||
* @return array<string>
|
||||
*/
|
||||
private function getArrayOfStrings(array $data, string $key): array
|
||||
{
|
||||
if (! isset($data[$key]) || ! is_array($data[$key])) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_values(
|
||||
array_filter($data[$key], static fn ($item): bool => is_string($item))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed> $data
|
||||
*/
|
||||
private function getString(array $data, string $key, string $default = ''): string
|
||||
{
|
||||
return isset($data[$key]) && is_string($data[$key]) ? $data[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed> $data
|
||||
*/
|
||||
private function getInt(array $data, string $key, int $default = 0): int
|
||||
{
|
||||
return isset($data[$key]) && is_numeric($data[$key]) ? (int) $data[$key] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<array-key, mixed> $data
|
||||
*/
|
||||
private function getBool(array $data, string $key, bool $default = false): bool
|
||||
{
|
||||
return isset($data[$key]) ? (bool) $data[$key] : $default;
|
||||
}
|
||||
|
||||
private function toNullableString(mixed $value): ?string
|
||||
{
|
||||
return is_string($value) && trim($value) !== '' ? $value : null;
|
||||
}
|
||||
|
||||
private function toNullableDateTime(mixed $value): ?\DateTimeInterface
|
||||
{
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
return DatesHelper::parseDateTime($value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,10 +9,9 @@ use Application\Arcadia\Config\ThrottlingConfig;
|
|||
use Application\Health\Contracts\HealthChecker;
|
||||
use Illuminate\Cache\RateLimiting\Limit;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request as IlluminateRequest;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Date;
|
||||
use Illuminate\Support\Facades\RateLimiter;
|
||||
use Illuminate\Support\Facades\Request;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Infra\Http\Helpers\RequestHelper;
|
||||
|
|
@ -77,11 +76,11 @@ class AppServiceProvider extends ServiceProvider
|
|||
|
||||
protected function configureRateLimiting(ThrottlingConfig $throttlingConfig): void
|
||||
{
|
||||
RateLimiter::for('web', function (IlluminateRequest $request) use ($throttlingConfig) {
|
||||
RateLimiter::for('web', function (Request $request) use ($throttlingConfig) {
|
||||
return Limit::perMinute($throttlingConfig->webLimit->toInt())->by($request->ip() ?? '127.0.0.1');
|
||||
});
|
||||
|
||||
RateLimiter::for('api.v1', function (IlluminateRequest $request) use ($throttlingConfig) {
|
||||
RateLimiter::for('api.v1', function (Request $request) use ($throttlingConfig) {
|
||||
return Limit::perMinute($throttlingConfig->apiV1Limit->toInt())->by($request->ip() ?? '127.0.0.1');
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,18 @@ use Domain\Ports\Directories\IncoSheetDirectory;
|
|||
use Domain\Ports\Directories\IncoShortSheetDirectory;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Database\Connection;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Infra\Adapters\Directories\EloquentArcadiaBrandDirectory;
|
||||
use Infra\Adapters\Directories\ArcadiaEmployeeDirectory;
|
||||
use Infra\Adapters\Directories\ArcadiaIncoCompositionDirectory;
|
||||
use Infra\Adapters\Directories\ArcadiaIncoSheetDirectory;
|
||||
use Infra\Adapters\Directories\ArcadiaIncoShortSheetDirectory;
|
||||
use Infra\Adapters\Directories\ArcadiaMarqueBrandDirectory;
|
||||
use Infra\Adapters\Directories\EloquentClientAuditLogDirectory;
|
||||
use Infra\Adapters\Directories\EloquentEmployeeDirectory;
|
||||
use Infra\Adapters\Directories\EloquentIncoCompositionDirectory;
|
||||
use Infra\Adapters\Directories\EloquentIncoSheetDirectory;
|
||||
use Infra\Adapters\Directories\EloquentIncoShortSheetDirectory;
|
||||
use Infra\Adapters\Events\LaravelTransactionalDomainEventDispatcher;
|
||||
use Infra\Adapters\Mappers\IncoMapper;
|
||||
use Infra\Adapters\Repositories\EloquentBrandRepository;
|
||||
use Infra\Cache\BrandCache;
|
||||
use Infra\Config\ArcadiaStorageConfig;
|
||||
|
|
@ -35,11 +38,35 @@ class DomainServiceProvider extends ServiceProvider
|
|||
#[\Override]
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind(EmployeeDirectory::class, EloquentEmployeeDirectory::class);
|
||||
$this->app->bind(IncoSheetDirectory::class, EloquentIncoSheetDirectory::class);
|
||||
$this->app->bind(IncoShortSheetDirectory::class, EloquentIncoShortSheetDirectory::class);
|
||||
$this->app->bind(IncoCompositionDirectory::class, EloquentIncoCompositionDirectory::class);
|
||||
$this->app->scoped(ArcadiaBrandDirectory::class, EloquentArcadiaBrandDirectory::class);
|
||||
$this->app->bind('arcadiaConnection', static function (Application $app): Connection {
|
||||
$storageConfig = $app->make(ArcadiaStorageConfig::class);
|
||||
|
||||
return DB::connection($storageConfig->databaseConnection);
|
||||
});
|
||||
$this->app->bind(
|
||||
EmployeeDirectory::class,
|
||||
fn (Application $app) => new ArcadiaEmployeeDirectory($app->make('arcadiaConnection'))
|
||||
);
|
||||
$this->app->bind(
|
||||
IncoSheetDirectory::class,
|
||||
fn (Application $app) => new ArcadiaIncoSheetDirectory(
|
||||
$app->make('arcadiaConnection'),
|
||||
$app->make(BrandRepository::class),
|
||||
$app->make(IncoMapper::class)
|
||||
)
|
||||
);
|
||||
$this->app->bind(
|
||||
IncoShortSheetDirectory::class,
|
||||
fn (Application $app) => new ArcadiaIncoShortSheetDirectory($app->make('arcadiaConnection'), $app->make(BrandRepository::class))
|
||||
);
|
||||
$this->app->bind(
|
||||
IncoCompositionDirectory::class,
|
||||
fn (Application $app) => new ArcadiaIncoCompositionDirectory($app->make('arcadiaConnection'))
|
||||
);
|
||||
$this->app->bind(
|
||||
ArcadiaBrandDirectory::class,
|
||||
fn (Application $app) => new ArcadiaMarqueBrandDirectory($app->make('arcadiaConnection'))
|
||||
);
|
||||
$this->app->bind(BrandRepository::class, EloquentBrandRepository::class);
|
||||
$this->app->bind(ClientAuditLogDirectory::class, EloquentClientAuditLogDirectory::class);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,6 @@ describe('Infra Architecture Rules', function (): void {
|
|||
->expect('Infra\Database\Models')
|
||||
->toBeFinal();
|
||||
|
||||
arch('Infra adapters implement Domain Ports')
|
||||
->expect('Infra\Adapters\Directories\EloquentEmployeeDirectory')
|
||||
->toImplement('Domain\Ports\Directories\EmployeeDirectory');
|
||||
|
||||
arch('Infra EloquentEmployeeRepository implements Domain EmployeeRepository port')
|
||||
->expect('Infra\Adapters\Repositories\EloquentEmployeeRepository')
|
||||
->toImplement('Domain\Ports\Repositories\EmployeeRepository');
|
||||
|
||||
arch('Infra layer uses strict types')
|
||||
->expect('Infra')
|
||||
->toUseStrictTypes();
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Database\Seeders;
|
||||
|
||||
use Database\Seeders\EmployeeSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Database\Models\Employee;
|
||||
use Tests\TestCase;
|
||||
|
||||
covers(Employee::class);
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
|
||||
describe('EmployeeSeeder Integration Test', function (): void {
|
||||
it('seeds default employee records into the database', function (): void {
|
||||
// GIVEN
|
||||
$seeder = new EmployeeSeeder();
|
||||
|
||||
// WHEN
|
||||
$seeder->run();
|
||||
|
||||
// THEN
|
||||
expect(Employee::count())->toBe(4);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaBrand as ArcadiaBrandDomain;
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Infra\Adapters\Directories\EloquentArcadiaBrandDirectory;
|
||||
use Infra\Database\Models\ArcadiaBrand;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
covers(EloquentArcadiaBrandDirectory::class);
|
||||
|
||||
describe('EloquentArcadiaBrandDirectory Integration Tests', function (): void {
|
||||
beforeEach(function (): void {
|
||||
ArcadiaBrand::query()->delete();
|
||||
ArcadiaBrand::query()->create(['code' => 1, 'libelle' => 'Le Gaulois']);
|
||||
ArcadiaBrand::query()->create(['code' => 2, 'libelle' => 'Maître CoQ']);
|
||||
});
|
||||
|
||||
it('finds an arcadia brand by ArcadiaId and memoizes the result in memory', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentArcadiaBrandDirectory();
|
||||
$arcadiaId = new ArcadiaId('1');
|
||||
|
||||
// WHEN: First lookup (hits database)
|
||||
$first = $directory->find($arcadiaId);
|
||||
|
||||
// THEN
|
||||
expect($first)->toBeInstanceOf(ArcadiaBrandDomain::class)
|
||||
->and($first?->id->value)->toBe('1')
|
||||
->and($first?->name->value)->toBe('Le Gaulois');
|
||||
|
||||
// WHEN: Second lookup - DB query count should not increase because of in-memory caching
|
||||
$queryCount = 0;
|
||||
DB::listen(function () use (&$queryCount): void {
|
||||
$queryCount++;
|
||||
});
|
||||
|
||||
$second = $directory->find($arcadiaId);
|
||||
|
||||
// THEN: Second call returns the exact memoized entity with 0 extra queries
|
||||
expect($second)->toBe($first)
|
||||
->and($queryCount)->toBe(0);
|
||||
});
|
||||
|
||||
it('returns null when arcadia brand is not found and caches the null result', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentArcadiaBrandDirectory();
|
||||
$unknownId = new ArcadiaId('999');
|
||||
|
||||
// WHEN: First lookup for non-existent brand
|
||||
$first = $directory->find($unknownId);
|
||||
|
||||
// THEN
|
||||
expect($first)->toBeNull();
|
||||
|
||||
// WHEN: Second lookup
|
||||
$queryCount = 0;
|
||||
DB::listen(function () use (&$queryCount): void {
|
||||
$queryCount++;
|
||||
});
|
||||
|
||||
$second = $directory->find($unknownId);
|
||||
|
||||
// THEN
|
||||
expect($second)->toBeNull()
|
||||
->and($queryCount)->toBe(0);
|
||||
});
|
||||
|
||||
it('finds all arcadia brands and populates the cache', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentArcadiaBrandDirectory();
|
||||
|
||||
// WHEN
|
||||
$all = $directory->findAll();
|
||||
|
||||
// THEN
|
||||
expect($all)->toHaveCount(2);
|
||||
|
||||
// WHEN: Calling find() on cached items
|
||||
$queryCount = 0;
|
||||
DB::listen(function () use (&$queryCount): void {
|
||||
$queryCount++;
|
||||
});
|
||||
|
||||
$brand1 = $directory->find(new ArcadiaId('1'));
|
||||
|
||||
// THEN
|
||||
expect($brand1)->not->toBeNull()
|
||||
->and($brand1?->name->value)->toBe('Le Gaulois')
|
||||
->and($queryCount)->toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,186 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Employee;
|
||||
use Domain\Models\ValueObjects\Employees\ArcadiaEmployeeId;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeFilter;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeSortColumn;
|
||||
use Domain\Models\ValueObjects\Employees\EmployeeSorter;
|
||||
use Domain\Models\ValueObjects\EstablishmentCode;
|
||||
use Domain\Models\ValueObjects\ServiceId;
|
||||
use Domain\Models\ValueObjects\SiteId;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Adapters\Directories\EloquentEmployeeDirectory;
|
||||
use Infra\Database\Models\Employee as EmployeeModel;
|
||||
use Shared\Paginated;
|
||||
use Shared\Pagination;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
covers(EloquentEmployeeDirectory::class);
|
||||
|
||||
beforeEach(function (): void {
|
||||
EmployeeModel::query()->delete();
|
||||
});
|
||||
|
||||
describe('EloquentEmployeeDirectory Integration Tests', function (): void {
|
||||
it('finds an employee by public employee number and maps to domain entity', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentEmployeeDirectory();
|
||||
|
||||
EmployeeModel::factory()->create([
|
||||
'public_employee_number' => '1234567',
|
||||
'last_name' => 'DUPONT',
|
||||
'first_name' => 'Jean',
|
||||
'start_date' => '2024-01-01',
|
||||
'end_date' => '2025-01-01',
|
||||
'planned_end_date' => '2025-06-01',
|
||||
'establishment' => '01',
|
||||
'site' => 'LDCSER',
|
||||
'service' => '097',
|
||||
'created_at' => '2024-01-01 10:00:00',
|
||||
'updated_at' => '2024-01-02 12:00:00',
|
||||
]);
|
||||
|
||||
$employeeId = new ArcadiaEmployeeId('1234567');
|
||||
|
||||
// WHEN
|
||||
$result = $directory->find($employeeId);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(Employee::class)
|
||||
->and($result?->id()->value)->toBe('1234567')
|
||||
->and($result?->lastName)->toBe('DUPONT')
|
||||
->and($result?->firstName)->toBe('Jean')
|
||||
->and($result?->startDate->format('Y-m-d'))->toBe('2024-01-01')
|
||||
->and($result?->endDate?->format('Y-m-d'))->toBe('2025-01-01')
|
||||
->and($result?->plannedEndDate?->format('Y-m-d'))->toBe('2025-06-01')
|
||||
->and($result?->establishment->value)->toBe('01')
|
||||
->and($result?->site->value)->toBe('LDCSER')
|
||||
->and($result?->service->value)->toBe('097')
|
||||
->and($result?->createdAt->format('Y-m-d H:i:s'))->toBe('2024-01-01 10:00:00')
|
||||
->and($result?->updatedAt?->format('Y-m-d H:i:s'))->toBe('2024-01-02 12:00:00');
|
||||
});
|
||||
|
||||
it('returns null when employee is not found', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentEmployeeDirectory();
|
||||
$employeeId = new ArcadiaEmployeeId('9999999');
|
||||
|
||||
// WHEN
|
||||
$result = $directory->find($employeeId);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeNull();
|
||||
});
|
||||
|
||||
it('throws UnexpectedValueException when created_at is null', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentEmployeeDirectory();
|
||||
|
||||
EmployeeModel::query()->insert([
|
||||
'public_employee_number' => '7654321',
|
||||
'last_name' => 'MARTIN',
|
||||
'first_name' => 'Alice',
|
||||
'start_date' => '2024-01-01',
|
||||
'establishment' => '01',
|
||||
'site' => 'LDCSER',
|
||||
'service' => '097',
|
||||
'created_at' => null,
|
||||
'updated_at' => null,
|
||||
]);
|
||||
|
||||
$employeeId = new ArcadiaEmployeeId('7654321');
|
||||
|
||||
// WHEN & THEN
|
||||
expect(fn () => $directory->find($employeeId))
|
||||
->toThrow(\UnexpectedValueException::class, 'Employee created_at cannot be null.');
|
||||
});
|
||||
|
||||
it('filters employees when EmployeeFilter parameters are provided', function (): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentEmployeeDirectory();
|
||||
|
||||
EmployeeModel::factory()->create([
|
||||
'public_employee_number' => '1000001',
|
||||
'establishment' => '01',
|
||||
'site' => 'LDCSER',
|
||||
'service' => '097',
|
||||
'created_at' => '2024-01-01 08:00:00',
|
||||
'updated_at' => '2024-01-01 09:00:00',
|
||||
]);
|
||||
|
||||
EmployeeModel::factory()->create([
|
||||
'public_employee_number' => '1000002',
|
||||
'establishment' => 'LY',
|
||||
'site' => 'LDCSER',
|
||||
'service' => '101',
|
||||
'created_at' => '2024-01-01 08:00:00',
|
||||
'updated_at' => '2024-01-01 09:00:00',
|
||||
]);
|
||||
|
||||
$filter = new EmployeeFilter(
|
||||
establishment: new EstablishmentCode('01'),
|
||||
sites: [new SiteId('LDCSER')],
|
||||
service: new ServiceId('097'),
|
||||
since: new \DateTimeImmutable('2024-01-01 00:00:00')
|
||||
);
|
||||
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
$sorter = new EmployeeSorter(EmployeeSortColumn::arcadiaId, \SortDirection::Ascending);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->findAll($pagination, $sorter, $filter);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(Paginated::class)
|
||||
->and($result->getTotal())->toBe(1)
|
||||
->and(count($result->getItems()))->toBe(1)
|
||||
->and($result->getItems()[0]->id()->value)->toBe('1000001');
|
||||
});
|
||||
|
||||
it('returns paginated employees sorted by specified columns', function (EmployeeSortColumn $sortColumn, \SortDirection $direction): void {
|
||||
// GIVEN
|
||||
$directory = new EloquentEmployeeDirectory();
|
||||
|
||||
EmployeeModel::factory()->create([
|
||||
'public_employee_number' => '1000001',
|
||||
'start_date' => '2024-01-01',
|
||||
'end_date' => '2024-06-01',
|
||||
'planned_end_date' => '2024-12-01',
|
||||
'created_at' => '2024-01-01 08:00:00',
|
||||
'updated_at' => '2024-01-01 09:00:00',
|
||||
]);
|
||||
|
||||
EmployeeModel::factory()->create([
|
||||
'public_employee_number' => '1000002',
|
||||
'start_date' => '2024-02-01',
|
||||
'end_date' => '2024-07-01',
|
||||
'planned_end_date' => '2024-12-15',
|
||||
'created_at' => '2024-02-01 08:00:00',
|
||||
'updated_at' => '2024-02-01 09:00:00',
|
||||
]);
|
||||
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
$sorter = new EmployeeSorter($sortColumn, $direction);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->findAll($pagination, $sorter);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(Paginated::class)
|
||||
->and($result->getTotal())->toBe(2)
|
||||
->and(count($result->getItems()))->toBe(2);
|
||||
})->with([
|
||||
'arcadiaId asc' => [EmployeeSortColumn::arcadiaId, \SortDirection::Ascending],
|
||||
'arcadiaId desc' => [EmployeeSortColumn::arcadiaId, \SortDirection::Descending],
|
||||
'startDate asc' => [EmployeeSortColumn::startDate, \SortDirection::Ascending],
|
||||
'endDate desc' => [EmployeeSortColumn::endDate, \SortDirection::Descending],
|
||||
'plannedEndDate asc' => [EmployeeSortColumn::plannedEndDate, \SortDirection::Ascending],
|
||||
'createdAt desc' => [EmployeeSortColumn::createdAt, \SortDirection::Descending],
|
||||
'updatedAt asc' => [EmployeeSortColumn::updatedAt, \SortDirection::Ascending],
|
||||
]);
|
||||
});
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Inco\IncoSheet;
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Inco\IncoId;
|
||||
use Domain\Models\ValueObjects\Inco\IncoIdQuery;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetFilter;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSortColumn;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSorter;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
use Domain\Services\BrandResolver;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Adapters\Directories\EloquentIncoSheetDirectory;
|
||||
use Infra\Database\Models\ArcadiaBrand;
|
||||
use Infra\Database\Models\IncoSheet as IncoSheetModel;
|
||||
use Shared\Pagination;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
covers(EloquentIncoSheetDirectory::class);
|
||||
|
||||
describe('EloquentIncoSheetDirectory Integration Tests', function (): void {
|
||||
beforeEach(function (): void {
|
||||
IncoSheetModel::query()->delete();
|
||||
ArcadiaBrand::query()->firstOrCreate(['code' => 1], ['libelle' => 'Le Gaulois']);
|
||||
ArcadiaBrand::query()->firstOrCreate(['code' => 2], ['libelle' => 'Maître CoQ']);
|
||||
});
|
||||
|
||||
it('finds an inco sheet by IncoId and resolves its IncoBrand', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoSheetDirectory($resolver, $repository);
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000101',
|
||||
'name' => 'Poulet Rôti',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
|
||||
$incoId = new IncoId('1000101');
|
||||
|
||||
// WHEN
|
||||
$result = $directory->find($incoId);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(IncoSheet::class)
|
||||
->and((string) $result?->id->value)->toBe('1000101')
|
||||
->and($result?->name)->toBe('Poulet Rôti')
|
||||
->and($result?->brand->name->value)->toBe('Le Gaulois')
|
||||
->and($result?->brand->arcadiaBrandCode->value)->toBe('1')
|
||||
->and($result?->brand->code->value)->toMatch('/^[A-Z]{3}\d{2}$/');
|
||||
});
|
||||
|
||||
it('returns null when inco sheet is not found', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoSheetDirectory($resolver, $repository);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->find(new IncoId('9999999'));
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeNull();
|
||||
});
|
||||
|
||||
it('finds all inco sheets filtered by BrandCode', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoSheetDirectory($resolver, $repository);
|
||||
|
||||
$brand1 = $resolver->resolve(new ArcadiaId('1'));
|
||||
$brand2 = $resolver->resolve(new ArcadiaId('2'));
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000101',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000102',
|
||||
'brand' => ['code' => 2, 'label' => 'Maître CoQ'],
|
||||
]);
|
||||
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
$sorter = new IncoSheetSorter(IncoSheetSortColumn::incoSheetId, \SortDirection::Ascending);
|
||||
$filter = new IncoSheetFilter(null, $brand1->code);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->findAll($pagination, $sorter, $filter);
|
||||
|
||||
// THEN
|
||||
expect($result->getTotal())->toBe(1)
|
||||
->and($result->getItems())->toHaveCount(1)
|
||||
->and((string) $result->getItems()[0]->id->value)->toBe('1000101');
|
||||
});
|
||||
|
||||
it('searches inco sheets by id query and BrandCode', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoSheetDirectory($resolver, $repository);
|
||||
|
||||
$brand1 = $resolver->resolve(new ArcadiaId('1'));
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1234501',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1234502',
|
||||
'brand' => ['code' => 2, 'label' => 'Maître CoQ'],
|
||||
]);
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '9999901',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
|
||||
$query = new IncoIdQuery('1234%');
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->search($query, $pagination, $brand1->code);
|
||||
|
||||
// THEN
|
||||
expect($result->getTotal())->toBe(1)
|
||||
->and($result->getItems())->toHaveCount(1)
|
||||
->and((string) $result->getItems()[0]->id->value)->toBe('1234501');
|
||||
});
|
||||
|
||||
it('returns empty paginated result when filtering by non-existent BrandCode', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoSheetDirectory($resolver, $repository);
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000101',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
|
||||
$unknownCode = new BrandCode('ZZZ01');
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
$sorter = new IncoSheetSorter(IncoSheetSortColumn::incoSheetId, \SortDirection::Ascending);
|
||||
$filter = new IncoSheetFilter(null, $unknownCode);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->findAll($pagination, $sorter, $filter);
|
||||
|
||||
// THEN
|
||||
expect($result->getTotal())->toBe(0)
|
||||
->and($result->getItems())->toBeEmpty();
|
||||
});
|
||||
});
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Adapters\Directories;
|
||||
|
||||
use Domain\Models\Entities\Inco\IncoShortSheet;
|
||||
use Domain\Models\ValueObjects\Brand\ArcadiaId;
|
||||
use Domain\Models\ValueObjects\Brand\BrandCode;
|
||||
use Domain\Models\ValueObjects\Inco\IncoId;
|
||||
use Domain\Models\ValueObjects\Inco\IncoIdQuery;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetFilter;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSortColumn;
|
||||
use Domain\Models\ValueObjects\Inco\IncoSheetSorter;
|
||||
use Domain\Ports\Repositories\BrandRepository;
|
||||
use Domain\Services\BrandResolver;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Adapters\Directories\EloquentIncoShortSheetDirectory;
|
||||
use Infra\Database\Models\ArcadiaBrand;
|
||||
use Infra\Database\Models\IncoSheet as IncoSheetModel;
|
||||
use Shared\Pagination;
|
||||
use Tests\TestCase;
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
covers(EloquentIncoShortSheetDirectory::class);
|
||||
|
||||
describe('EloquentIncoShortSheetDirectory Integration Tests', function (): void {
|
||||
beforeEach(function (): void {
|
||||
IncoSheetModel::query()->delete();
|
||||
ArcadiaBrand::query()->firstOrCreate(['code' => 1], ['libelle' => 'Le Gaulois']);
|
||||
ArcadiaBrand::query()->firstOrCreate(['code' => 2], ['libelle' => 'Maître CoQ']);
|
||||
});
|
||||
|
||||
it('finds an inco short sheet by IncoId', function (): void {
|
||||
// GIVEN
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoShortSheetDirectory($repository);
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000101',
|
||||
'name' => 'Poulet Rôti Court',
|
||||
]);
|
||||
|
||||
$incoId = new IncoId('1000101');
|
||||
|
||||
// WHEN
|
||||
$result = $directory->find($incoId);
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeInstanceOf(IncoShortSheet::class)
|
||||
->and((string) $result?->id->value)->toBe('1000101')
|
||||
->and($result?->name)->toBe('Poulet Rôti Court');
|
||||
});
|
||||
|
||||
it('returns null when inco short sheet is not found', function (): void {
|
||||
// GIVEN
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoShortSheetDirectory($repository);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->find(new IncoId('9999999'));
|
||||
|
||||
// THEN
|
||||
expect($result)->toBeNull();
|
||||
});
|
||||
|
||||
it('finds all inco short sheets filtered by BrandCode', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoShortSheetDirectory($repository);
|
||||
|
||||
$brand1 = $resolver->resolve(new ArcadiaId('1'));
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000101',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000102',
|
||||
'brand' => ['code' => 2, 'label' => 'Maître CoQ'],
|
||||
]);
|
||||
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
$sorter = new IncoSheetSorter(IncoSheetSortColumn::incoSheetId, \SortDirection::Ascending);
|
||||
$filter = new IncoSheetFilter(null, $brand1->code);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->findAll($pagination, $sorter, $filter);
|
||||
|
||||
// THEN
|
||||
expect($result->getTotal())->toBe(1)
|
||||
->and($result->getItems())->toHaveCount(1)
|
||||
->and((string) $result->getItems()[0]->id->value)->toBe('1000101');
|
||||
});
|
||||
|
||||
it('searches inco short sheets by id query and BrandCode', function (): void {
|
||||
// GIVEN
|
||||
$resolver = app(BrandResolver::class);
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoShortSheetDirectory($repository);
|
||||
|
||||
$brand1 = $resolver->resolve(new ArcadiaId('1'));
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1234501',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1234502',
|
||||
'brand' => ['code' => 2, 'label' => 'Maître CoQ'],
|
||||
]);
|
||||
|
||||
$query = new IncoIdQuery('1234%');
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->search($query, $pagination, $brand1->code);
|
||||
|
||||
// THEN
|
||||
expect($result->getTotal())->toBe(1)
|
||||
->and($result->getItems())->toHaveCount(1)
|
||||
->and((string) $result->getItems()[0]->id->value)->toBe('1234501');
|
||||
});
|
||||
|
||||
it('returns empty paginated short sheets when filtering by non-existent BrandCode', function (): void {
|
||||
// GIVEN
|
||||
$repository = app(BrandRepository::class);
|
||||
$directory = new EloquentIncoShortSheetDirectory($repository);
|
||||
|
||||
IncoSheetModel::factory()->create([
|
||||
'id' => '1000101',
|
||||
'brand' => ['code' => 1, 'label' => 'Le Gaulois'],
|
||||
]);
|
||||
|
||||
$unknownCode = new BrandCode('ZZZ01');
|
||||
$pagination = Pagination::ofPage(1, 10);
|
||||
$sorter = new IncoSheetSorter(IncoSheetSortColumn::incoSheetId, \SortDirection::Ascending);
|
||||
$filter = new IncoSheetFilter(null, $unknownCode);
|
||||
|
||||
// WHEN
|
||||
$result = $directory->findAll($pagination, $sorter, $filter);
|
||||
|
||||
// THEN
|
||||
expect($result->getTotal())->toBe(0)
|
||||
->and($result->getItems())->toBeEmpty();
|
||||
});
|
||||
});
|
||||
|
|
@ -13,7 +13,6 @@ use Illuminate\Foundation\Testing\RefreshDatabase;
|
|||
use Illuminate\Support\Facades\Cache;
|
||||
use Infra\Adapters\Repositories\EloquentBrandRepository;
|
||||
use Infra\Cache\BrandCache;
|
||||
use Infra\Database\Models\ArcadiaBrand;
|
||||
use Infra\Database\Models\Brand as BrandModel;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Tests\TestCase;
|
||||
|
|
@ -24,7 +23,6 @@ covers(EloquentBrandRepository::class);
|
|||
beforeEach(function (): void {
|
||||
Cache::flush();
|
||||
BrandModel::query()->delete();
|
||||
ArcadiaBrand::query()->delete();
|
||||
});
|
||||
|
||||
describe('EloquentBrandRepository Integration Tests', function (): void {
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Database\Models;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Database\Models\Employee;
|
||||
use Tests\TestCase;
|
||||
|
||||
covers(Employee::class);
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
|
||||
describe('Employee Eloquent Model & Factory', function (): void {
|
||||
it('creates and persists an Employee record via factory', function (): void {
|
||||
// GIVEN
|
||||
$employee = Employee::factory()->create();
|
||||
|
||||
// WHEN
|
||||
$retrieved = Employee::find($employee->public_employee_number);
|
||||
|
||||
// THEN
|
||||
expect($retrieved)->not->toBeNull()
|
||||
->and($retrieved->public_employee_number)->toBe($employee->public_employee_number);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Database\Models;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Database\Models\IncoCompo;
|
||||
use Tests\TestCase;
|
||||
|
||||
covers(IncoCompo::class);
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
|
||||
describe('IncoCompo Eloquent Model & Factory', function (): void {
|
||||
it('creates and persists an IncoCompo record via factory', function (): void {
|
||||
// GIVEN
|
||||
$compo = IncoCompo::factory()->create();
|
||||
|
||||
// WHEN
|
||||
$retrieved = IncoCompo::find($compo->id);
|
||||
|
||||
// THEN
|
||||
expect($retrieved)->not->toBeNull()
|
||||
->and($retrieved->id)->toBe($compo->id);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Integration\Infra\Database\Models;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Infra\Database\Models\IncoSheet;
|
||||
use Tests\TestCase;
|
||||
|
||||
covers(IncoSheet::class);
|
||||
|
||||
uses(TestCase::class, RefreshDatabase::class);
|
||||
|
||||
describe('IncoSheet Eloquent Model & Factory', function (): void {
|
||||
it('creates and persists an IncoSheet record via factory', function (): void {
|
||||
// GIVEN
|
||||
$sheet = IncoSheet::factory()->create([
|
||||
'name' => 'Poulet Rôti 1kg Test',
|
||||
]);
|
||||
|
||||
// WHEN
|
||||
$retrieved = IncoSheet::find($sheet->id);
|
||||
|
||||
// THEN
|
||||
expect($retrieved)->not->toBeNull()
|
||||
->and($retrieved->id)->toBe($sheet->id)
|
||||
->and($retrieved->name)->toBe('Poulet Rôti 1kg Test');
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue