diff --git a/src/Domain/Builders/Inco/IncoCompositionBuilder.php b/src/Domain/Builders/Inco/IncoCompositionBuilder.php new file mode 100644 index 0000000..00ede07 --- /dev/null +++ b/src/Domain/Builders/Inco/IncoCompositionBuilder.php @@ -0,0 +1,213 @@ +id = $id; + + return $this; + } + + public function withIdInco(IncoId $idInco): self + { + $this->idInco = $idInco; + + return $this; + } + + public function withIdentification(Identification $identification): self + { + $this->identification = $identification; + + return $this; + } + + public function withEnergy(Energy $energy): self + { + $this->energy = $energy; + + return $this; + } + + public function withReferenceMacronutrients(ReferenceMacronutrients $referenceMacronutrients): self + { + $this->referenceMacronutrients = $referenceMacronutrients; + + return $this; + } + + public function withPortionMacronutrients(PortionMacronutrients $portionMacronutrients): self + { + $this->portionMacronutrients = $portionMacronutrients; + + return $this; + } + + public function withFreshProduceAndNuts(FreshProduceAndNuts $freshProduceAndNuts): self + { + $this->freshProduceAndNuts = $freshProduceAndNuts; + + return $this; + } + + public function withReferenceIntakes(ReferenceIntakes $referenceIntakes): self + { + $this->referenceIntakes = $referenceIntakes; + + return $this; + } + + public function withNutriScore(NutriScore $nutriScore): self + { + $this->nutriScore = $nutriScore; + + return $this; + } + + public function withNutriScorePoints(NutriScorePoints $nutriScorePoints): self + { + $this->nutriScorePoints = $nutriScorePoints; + + return $this; + } + + public function withMinerals(Minerals $minerals): self + { + $this->minerals = $minerals; + + return $this; + } + + public function withVitamins(Vitamins $vitamins): self + { + $this->vitamins = $vitamins; + + return $this; + } + + public function withCarbohydratesDetail(CarbohydratesDetail $carbohydratesDetail): self + { + $this->carbohydratesDetail = $carbohydratesDetail; + + return $this; + } + + public function withFattyAcids(FattyAcids $fattyAcids): self + { + $this->fattyAcids = $fattyAcids; + + return $this; + } + + public function withAminoAcids(AminoAcids $aminoAcids): self + { + $this->aminoAcids = $aminoAcids; + + return $this; + } + + public function withSpecialCompounds(SpecialCompounds $specialCompounds): self + { + $this->specialCompounds = $specialCompounds; + + return $this; + } + + public function build(): IncoComposition + { + if ( + $this->id === null + || $this->idInco === null + || $this->identification === null + || $this->energy === null + || $this->referenceMacronutrients === null + || $this->portionMacronutrients === null + || $this->freshProduceAndNuts === null + || $this->referenceIntakes === null + || $this->nutriScore === null + || $this->nutriScorePoints === null + || $this->minerals === null + || $this->vitamins === null + || $this->carbohydratesDetail === null + || $this->fattyAcids === null + || $this->aminoAcids === null + || $this->specialCompounds === null + ) { + throw new \DomainException('Cannot build IncoComposition: missing required components.'); + } + + return IncoComposition::hydrate( + id: $this->id, + idInco: $this->idInco, + identification: $this->identification, + energy: $this->energy, + referenceMacronutrients: $this->referenceMacronutrients, + portionMacronutrients: $this->portionMacronutrients, + freshProduceAndNuts: $this->freshProduceAndNuts, + referenceIntakes: $this->referenceIntakes, + nutriScore: $this->nutriScore, + nutriScorePoints: $this->nutriScorePoints, + minerals: $this->minerals, + vitamins: $this->vitamins, + carbohydratesDetail: $this->carbohydratesDetail, + fattyAcids: $this->fattyAcids, + aminoAcids: $this->aminoAcids, + specialCompounds: $this->specialCompounds, + ); + } +} diff --git a/src/Domain/Builders/Inco/IncoSheetBuilder.php b/src/Domain/Builders/Inco/IncoSheetBuilder.php new file mode 100644 index 0000000..0a0a380 --- /dev/null +++ b/src/Domain/Builders/Inco/IncoSheetBuilder.php @@ -0,0 +1,248 @@ + */ + private array $allergens = []; + + private ?IncoBrand $brand = null; + + private bool $isSeasonal = false; + + private ?IncoWeight $weight = null; + + private ?Nutriscore $nutriscore = null; + + private ?StorageCondition $storageCondition = null; + + /** @var array<\Domain\Models\ValueObjects\Inco\Additive> */ + private array $additives = []; + + private ?IncoCompositionId $compo = null; + + private ?\DateTimeInterface $createdAt = null; + + private ?\DateTimeInterface $updatedAt = null; + + public function withId(IncoId $id): self + { + $this->id = $id; + + return $this; + } + + public function withName(string $name): self + { + $this->name = $name; + + return $this; + } + + public function withLabel(string $label): self + { + $this->label = $label; + + return $this; + } + + public function withDescription(string $description): self + { + $this->description = $description; + + return $this; + } + + public function withAllegations(Allegations $allegations): self + { + $this->allegations = $allegations; + + return $this; + } + + public function withSellArguments(string $sellArguments): self + { + $this->sellArguments = $sellArguments; + + return $this; + } + + public function withPreparationAdvices(string $preparationAdvices): self + { + $this->preparationAdvices = $preparationAdvices; + + return $this; + } + + public function withTips(?string $tips): self + { + $this->tips = $tips; + + return $this; + } + + public function withSellFamilly(?string $sellFamilly): self + { + $this->sellFamilly = $sellFamilly; + + return $this; + } + + public function withIngredients(Ingredients $ingredients): self + { + $this->ingredients = $ingredients; + + return $this; + } + + public function withPortions(?PortionAmount $portions): self + { + $this->portions = $portions; + + return $this; + } + + public function withAllergens(Allergen ...$allergens): self + { + $this->allergens = $allergens; + + return $this; + } + + public function withBrand(IncoBrand $brand): self + { + $this->brand = $brand; + + return $this; + } + + public function withIsSeasonal(bool $isSeasonal): self + { + $this->isSeasonal = $isSeasonal; + + return $this; + } + + public function withWeight(?IncoWeight $weight): self + { + $this->weight = $weight; + + return $this; + } + + public function withNutriscore(?Nutriscore $nutriscore): self + { + $this->nutriscore = $nutriscore; + + return $this; + } + + public function withStorageCondition(?StorageCondition $storageCondition): self + { + $this->storageCondition = $storageCondition; + + return $this; + } + + public function withAdditives(Additive ...$additives): self + { + $this->additives = $additives; + + return $this; + } + + public function withCompo(?IncoCompositionId $compo): self + { + $this->compo = $compo; + + return $this; + } + + public function withCreatedAt(?\DateTimeInterface $createdAt): self + { + $this->createdAt = $createdAt; + + return $this; + } + + public function withUpdatedAt(?\DateTimeInterface $updatedAt): self + { + $this->updatedAt = $updatedAt; + + return $this; + } + + public function build(): IncoSheet + { + if ( + $this->id === null + || $this->allegations === null + || $this->ingredients === null + || $this->brand === null + ) { + throw new \DomainException('Cannot build IncoSheet: missing required components.'); + } + + return IncoSheet::hydrate( + id: $this->id, + name: $this->name, + label: $this->label, + description: $this->description, + allegations: $this->allegations, + sellArguments: $this->sellArguments, + preparationAdvices: $this->preparationAdvices, + tips: $this->tips, + sellFamilly: $this->sellFamilly, + ingredients: $this->ingredients, + portions: $this->portions, + allergens: $this->allergens, + brand: $this->brand, + isSeasonal: $this->isSeasonal, + weight: $this->weight, + nutriscore: $this->nutriscore, + storageCondition: $this->storageCondition, + additives: $this->additives, + compo: $this->compo, + createdAt: $this->createdAt, + updatedAt: $this->updatedAt, + ); + } +} diff --git a/src/Domain/Models/Entities/Inco/Composition/IncoComposition.php b/src/Domain/Models/Entities/Inco/Composition/IncoComposition.php index 112a743..5dd31c4 100644 --- a/src/Domain/Models/Entities/Inco/Composition/IncoComposition.php +++ b/src/Domain/Models/Entities/Inco/Composition/IncoComposition.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Domain\Models\Entities\Inco\Composition; +use Domain\Builders\Inco\IncoCompositionBuilder; use Domain\Models\ValueObjects\Inco\Composition\AminoAcids; use Domain\Models\ValueObjects\Inco\Composition\CarbohydratesDetail; use Domain\Models\ValueObjects\Inco\Composition\Energy; @@ -51,6 +52,11 @@ final readonly class IncoComposition implements Entity return $this->id; } + public static function builder(): IncoCompositionBuilder + { + return new IncoCompositionBuilder(); + } + public static function hydrate( IncoCompositionId $id, IncoId $idInco, diff --git a/src/Domain/Models/Entities/Inco/IncoSheet.php b/src/Domain/Models/Entities/Inco/IncoSheet.php index 8ca091c..4908418 100644 --- a/src/Domain/Models/Entities/Inco/IncoSheet.php +++ b/src/Domain/Models/Entities/Inco/IncoSheet.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Domain\Models\Entities\Inco; +use Domain\Builders\Inco\IncoSheetBuilder; use Domain\Models\ValueObjects\Inco\Allegations; use Domain\Models\ValueObjects\Inco\Composition\IncoCompositionId; use Domain\Models\ValueObjects\Inco\IncoBrand; @@ -53,6 +54,11 @@ final readonly class IncoSheet implements Entity return $this->id; } + public static function builder(): IncoSheetBuilder + { + return new IncoSheetBuilder(); + } + /** * @param array<\Domain\Models\ValueObjects\Inco\Allergen> $allergens * @param array<\Domain\Models\ValueObjects\Inco\Additive> $additives diff --git a/src/Infra/Adapters/Directories/EloquentIncoCompositionDirectory.php b/src/Infra/Adapters/Directories/EloquentIncoCompositionDirectory.php index bb165af..0da6a28 100644 --- a/src/Infra/Adapters/Directories/EloquentIncoCompositionDirectory.php +++ b/src/Infra/Adapters/Directories/EloquentIncoCompositionDirectory.php @@ -60,24 +60,24 @@ final class EloquentIncoCompositionDirectory implements IncoCompositionDirectory private function toDomain(IncoCompoModel $model): IncoComposition { - return IncoComposition::hydrate( - id: new IncoCompositionId((string) $model->id), - idInco: new IncoId((string) $model->id_inco), - identification: $this->identificationFrom($model), - energy: $this->energyFrom($model), - referenceMacronutrients: $this->refMacronutrientsFrom($model), - portionMacronutrients: $this->portionMacronutrientsFrom($model), - freshProduceAndNuts: $this->freshProduceAndNutsFrom($model), - referenceIntakes: $this->refIntakesFrom($model), - nutriScore: $this->nutriScoreFrom($model), - nutriScorePoints: $this->nutriScorePointsFrom($model), - minerals: $this->mineralsFrom($model), - vitamins: $this->vitaminsFrom($model), - carbohydratesDetail: $this->carbohydratesDetailFrom($model), - fattyAcids: $this->fattyAcidsFrom($model), - aminoAcids: $this->aminoAcidsFrom($model), - specialCompounds: $this->specialCompoundsFrom($model), - ); + 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 diff --git a/src/Infra/Adapters/Directories/EloquentIncoSheetDirectory.php b/src/Infra/Adapters/Directories/EloquentIncoSheetDirectory.php index 6a5721e..e911015 100644 --- a/src/Infra/Adapters/Directories/EloquentIncoSheetDirectory.php +++ b/src/Infra/Adapters/Directories/EloquentIncoSheetDirectory.php @@ -141,29 +141,29 @@ final class EloquentIncoSheetDirectory implements IncoSheetDirectory $compo = $model->compo_id !== null ? new IncoCompositionId((string) $model->compo_id) : null; - return IncoSheet::hydrate( - id: new IncoId((string) $model->id), - name: (string) $model->name, - label: (string) $model->label, - description: (string) $model->description, - allegations: $allegations, - sellArguments: (string) $model->sell_arguments, - preparationAdvices: (string) $model->preparation_advices, - tips: $this->toNullableString($model->tips), - sellFamilly: $this->toNullableString($model->sell_familly), - ingredients: $ingredients, - portions: $portions, - allergens: $allergens, - brand: $brand, - isSeasonal: (bool) $model->is_seasonal, - weight: $weight, - nutriscore: $nutriscore, - storageCondition: $storageCondition, - additives: $additives, - compo: $compo, - createdAt: $this->toNullableDateTime($model->created_at), - updatedAt: $this->toNullableDateTime($model->updated_at), - ); + 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 diff --git a/src/Presentation/Api/V1/Presenters/Brands/BrandsIndexView.php b/src/Presentation/Api/V1/Presenters/Brands/BrandsIndexView.php index 56dfb30..7c08eda 100644 --- a/src/Presentation/Api/V1/Presenters/Brands/BrandsIndexView.php +++ b/src/Presentation/Api/V1/Presenters/Brands/BrandsIndexView.php @@ -7,7 +7,7 @@ namespace Presentation\Api\V1\Presenters\Brands; final readonly class BrandsIndexView { /** - * @param list $brands + * @param list<\Application\Arcadia\Usecase\Brands\FindAll\BrandItem> $brands */ public function __construct( public array $brands, diff --git a/src/Shared/DDD/Usecase/Builder/BuilderStepPresenter.php b/src/Shared/DDD/Usecase/Builder/BuilderStepPresenter.php index 404859d..8e1e76e 100644 --- a/src/Shared/DDD/Usecase/Builder/BuilderStepPresenter.php +++ b/src/Shared/DDD/Usecase/Builder/BuilderStepPresenter.php @@ -7,7 +7,7 @@ namespace Shared\DDD\Usecase\Builder; use Shared\DDD\Usecase\Presenter; /** - * @template TOutput of Output + * @template TOutput of \Shared\DDD\Usecase\Output * * @extends BuilderStepBuild */ diff --git a/tests/Support/Builders/IncoCompositionTestBuilder.php b/tests/Support/Builders/IncoCompositionTestBuilder.php new file mode 100644 index 0000000..ebf4ba2 --- /dev/null +++ b/tests/Support/Builders/IncoCompositionTestBuilder.php @@ -0,0 +1,175 @@ +id = new IncoCompositionId('67890'); + $this->idInco = new IncoId('12345'); + $this->identification = new Identification('Poulet Rôti Test', '12345', 'LDC'); + + $energyValues = new EnergyValues('100g', '750', '180'); + $this->energy = new Energy($energyValues, $energyValues); + + $zeroNutrient = new NutrientValue('0'); + $this->referenceMacronutrients = new ReferenceMacronutrients($zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient); + $this->portionMacronutrients = new PortionMacronutrients($zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient, $zeroNutrient); + + $fnAmount = new FruitAndNutAmount(); + $zeroPercent = new PercentageValue('0'); + $this->freshProduceAndNuts = new FreshProduceAndNuts($fnAmount, $fnAmount, $zeroPercent, $zeroPercent); + + $this->referenceIntakes = new ReferenceIntakes($zeroPercent, $zeroPercent, $zeroPercent, $zeroPercent, $zeroPercent, $zeroPercent, $zeroPercent, $zeroPercent, '100g'); + $this->nutriScore = new NutriScore('0', '0', 'A'); + $this->nutriScorePoints = new NutriScorePoints('0', '0', '0', '0', '0', '0', '0'); + + $this->minerals = new Minerals('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); + $this->vitamins = new Vitamins('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); + $this->carbohydratesDetail = new CarbohydratesDetail('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); + $this->fattyAcids = new FattyAcids('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); + $this->aminoAcids = new AminoAcids('0', '0', '0'); + $this->specialCompounds = new SpecialCompounds('0', '0', '0', '0'); + } + + public static function create(): self + { + return new self(); + } + + public function withId(string | IncoCompositionId $id): self + { + $this->id = is_string($id) ? new IncoCompositionId($id) : $id; + + return $this; + } + + public function withIdInco(string | IncoId $idInco): self + { + $this->idInco = is_string($idInco) ? new IncoId($idInco) : $idInco; + + return $this; + } + + public function withIdentification(string $name, ?string $number = null, ?string $source = null): self + { + $this->identification = new Identification( + name: $name, + number: $number ?? $this->idInco->value, + source: $source ?? 'Arcadia', + ); + + return $this; + } + + public function withNutriScore(string $grade, string $score = '0', string $negativeComponent = '0'): self + { + $this->nutriScore = new NutriScore($negativeComponent, $score, $grade); + + return $this; + } + + public function build(): IncoComposition + { + return IncoComposition::hydrate( + id: $this->id, + idInco: $this->idInco, + identification: $this->identification, + energy: $this->energy, + referenceMacronutrients: $this->referenceMacronutrients, + portionMacronutrients: $this->portionMacronutrients, + freshProduceAndNuts: $this->freshProduceAndNuts, + referenceIntakes: $this->referenceIntakes, + nutriScore: $this->nutriScore, + nutriScorePoints: $this->nutriScorePoints, + minerals: $this->minerals, + vitamins: $this->vitamins, + carbohydratesDetail: $this->carbohydratesDetail, + fattyAcids: $this->fattyAcids, + aminoAcids: $this->aminoAcids, + specialCompounds: $this->specialCompounds, + ); + } + + public function buildOutput(): IncoCompositionOutput + { + $entity = $this->build(); + + return new IncoCompositionOutput( + id: $entity->id(), + idInco: $entity->idInco, + identification: $entity->identification, + energy: $entity->energy, + referenceMacronutrients: $entity->referenceMacronutrients, + portionMacronutrients: $entity->portionMacronutrients, + freshProduceAndNuts: $entity->freshProduceAndNuts, + referenceIntakes: $entity->referenceIntakes, + nutriScore: $entity->nutriScore, + nutriScorePoints: $entity->nutriScorePoints, + minerals: $entity->minerals, + vitamins: $entity->vitamins, + carbohydratesDetail: $entity->carbohydratesDetail, + fattyAcids: $entity->fattyAcids, + aminoAcids: $entity->aminoAcids, + specialCompounds: $entity->specialCompounds, + ); + } +} diff --git a/tests/Support/Builders/IncoSheetTestBuilder.php b/tests/Support/Builders/IncoSheetTestBuilder.php new file mode 100644 index 0000000..59c8d1a --- /dev/null +++ b/tests/Support/Builders/IncoSheetTestBuilder.php @@ -0,0 +1,215 @@ + */ + private array $allergens = []; + + private IncoBrand $brand; + + private bool $isSeasonal = false; + + private ?IncoWeight $weight = null; + + private ?Nutriscore $nutriscore = null; + + private ?StorageCondition $storageCondition = null; + + /** @var array */ + private array $additives = []; + + private ?IncoCompositionId $compo = null; + + private ?\DateTimeInterface $createdAt = null; + + private ?\DateTimeInterface $updatedAt = null; + + public function __construct() + { + $this->id = new IncoId('12345'); + $this->name = 'Poulet Rôti 1kg'; + $this->label = 'Poulet Rôti Classe A'; + $this->description = 'Poulet prêt à cuire'; + $this->allegations = new Allegations(['Volaille française']); + $this->sellArguments = 'Délicieux et tendre'; + $this->preparationAdvices = 'Cuire 45min à 180°C'; + $this->ingredients = new Ingredients(['Ingrédients' => ['Viande de dinde (66%)']]); + $this->brand = new IncoBrand(new BrandName('Le Gaulois'), new BrandCode('LGL01'), new ArcadiaId(504)); + } + + public static function create(): self + { + return new self(); + } + + public function withId(string | IncoId $id): self + { + $this->id = is_string($id) ? new IncoId($id) : $id; + + return $this; + } + + public function withName(string $name): self + { + $this->name = $name; + + return $this; + } + + public function withLabel(string $label): self + { + $this->label = $label; + + return $this; + } + + public function withDescription(string $description): self + { + $this->description = $description; + + return $this; + } + + public function withBrand(IncoBrand | string $brand, ?string $code = null, ?int $arcadiaId = null): self + { + if (is_string($brand)) { + $this->brand = new IncoBrand( + name: new BrandName($brand), + code: new BrandCode($code ?? 'LGL01'), + arcadiaBrandCode: new ArcadiaId($arcadiaId ?? 1), + ); + } else { + $this->brand = $brand; + } + + return $this; + } + + public function withNutriscore(?string $grade): self + { + $this->nutriscore = $grade !== null ? new Nutriscore($grade) : null; + + return $this; + } + + public function withCompo(?string $compoId): self + { + $this->compo = $compoId !== null ? new IncoCompositionId($compoId) : null; + + return $this; + } + + public function withSeasonal(bool $isSeasonal): self + { + $this->isSeasonal = $isSeasonal; + + return $this; + } + + public function withDates(?\DateTimeInterface $createdAt, ?\DateTimeInterface $updatedAt = null): self + { + $this->createdAt = $createdAt; + $this->updatedAt = $updatedAt ?? $createdAt; + + return $this; + } + + public function build(): IncoSheet + { + return IncoSheet::hydrate( + id: $this->id, + name: $this->name, + label: $this->label, + description: $this->description, + allegations: $this->allegations, + sellArguments: $this->sellArguments, + preparationAdvices: $this->preparationAdvices, + tips: $this->tips, + sellFamilly: $this->sellFamilly, + ingredients: $this->ingredients, + portions: $this->portions, + allergens: $this->allergens, + brand: $this->brand, + isSeasonal: $this->isSeasonal, + weight: $this->weight, + nutriscore: $this->nutriscore, + storageCondition: $this->storageCondition, + additives: $this->additives, + compo: $this->compo, + createdAt: $this->createdAt, + updatedAt: $this->updatedAt, + ); + } + + public function buildOutput(): IncoSheetOutput + { + $entity = $this->build(); + + return new IncoSheetOutput( + id: $entity->id, + name: $entity->name, + label: $entity->label, + description: $entity->description, + allegations: $entity->allegations, + sellArguments: $entity->sellArguments, + preparationAdvices: $entity->preparationAdvices, + tips: $entity->tips, + sellFamilly: $entity->sellFamilly, + ingredients: $entity->ingredients, + portions: $entity->portions, + allergens: $entity->allergens, + brand: $entity->brand, + isSeasonal: $entity->isSeasonal, + weight: $entity->weight, + nutriscore: $entity->nutriscore, + storageCondition: $entity->storageCondition, + additives: $entity->additives, + compo: $entity->compo, + createdAt: $entity->createdAt, + updatedAt: $entity->updatedAt, + ); + } +} diff --git a/tests/Support/Mothers/BrandMother.php b/tests/Support/Mothers/BrandMother.php new file mode 100644 index 0000000..87e36d3 --- /dev/null +++ b/tests/Support/Mothers/BrandMother.php @@ -0,0 +1,28 @@ +withId($compoId); + } + + if ($incoId !== null) { + $builder->withIdInco($incoId); + } + + if ($name !== null) { + $builder->withIdentification($name); + } + + return $builder->build(); + } + + public static function createOutput(?string $compoId = null, ?string $incoId = null, ?string $name = null): Output + { + $builder = IncoCompositionTestBuilder::create(); + + if ($compoId !== null) { + $builder->withId($compoId); + } + + if ($incoId !== null) { + $builder->withIdInco($incoId); + } + + if ($name !== null) { + $builder->withIdentification($name); + } + + return $builder->buildOutput(); + } + + public static function pouletRoti(): IncoComposition + { + return IncoCompositionTestBuilder::create() + ->withId('67890') + ->withIdInco('12345') + ->withIdentification('Poulet Rôti 1kg', '12345', 'LDC') + ->withNutriScore('B', '2') + ->build(); + } +} diff --git a/tests/Support/Mothers/IncoSheetMother.php b/tests/Support/Mothers/IncoSheetMother.php new file mode 100644 index 0000000..9c9762c --- /dev/null +++ b/tests/Support/Mothers/IncoSheetMother.php @@ -0,0 +1,58 @@ +withId($id); + } + + if ($name !== null) { + $builder->withName($name); + } + + if ($brand !== null) { + $builder->withBrand($brand); + } + + return $builder->build(); + } + + public static function createOutput(?string $id = null, ?string $name = null): Output + { + $builder = IncoSheetTestBuilder::create(); + + if ($id !== null) { + $builder->withId($id); + } + + if ($name !== null) { + $builder->withName($name); + } + + return $builder->buildOutput(); + } + + public static function pouletRoti(): IncoSheet + { + return IncoSheetTestBuilder::create() + ->withId('12345') + ->withName('Poulet Rôti 1kg') + ->withLabel('Poulet Rôti Classe A') + ->withDescription('Poulet prêt à cuire') + ->withBrand('Le Gaulois', 'LGL01', 504) + ->withNutriscore('A') + ->build(); + } +} diff --git a/tests/Unit/Application/Arcadia/Usecase/IncoCompositions/FindIncoCompositionTest.php b/tests/Unit/Application/Arcadia/Usecase/IncoCompositions/FindIncoCompositionTest.php index 0dad43b..8805e68 100644 --- a/tests/Unit/Application/Arcadia/Usecase/IncoCompositions/FindIncoCompositionTest.php +++ b/tests/Unit/Application/Arcadia/Usecase/IncoCompositions/FindIncoCompositionTest.php @@ -8,28 +8,9 @@ use Application\Arcadia\Exceptions\IncoCompositionNotFoundException; use Application\Arcadia\Usecase\IncoCompositions\Find\FindIncoComposition; use Application\Arcadia\Usecase\IncoCompositions\Find\Input; use Application\Arcadia\Usecase\IncoCompositions\Find\Output; -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 Infra\Adapters\Directories\InMemoryIncoCompositionDirectory; +use Tests\Support\Mothers\IncoCompositionMother; covers( FindIncoComposition::class, @@ -44,58 +25,10 @@ describe('FindIncoComposition Usecase Unit Tests', function (): void { $directory->clear(); }); - function createComposition(string $compoIdStr, string $incoIdStr): IncoComposition - { - $compoId = new IncoCompositionId($compoIdStr); - $incoId = new IncoId($incoIdStr); - $identification = new Identification('Poulet Rôti 1kg Test', $incoIdStr, 'LDC'); - - $energyValues = new EnergyValues('100g', '0', '0'); - $energy = new Energy($energyValues, $energyValues); - - $nutrient = new NutrientValue('0'); - $refMacro = new ReferenceMacronutrients($nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient); - $porMacro = new PortionMacronutrients($nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient); - - $fnAmount = new FruitAndNutAmount(); - $pct = new PercentageValue('0'); - $fresh = new FreshProduceAndNuts($fnAmount, $fnAmount, $pct, $pct); - - $refIntakes = new ReferenceIntakes($pct, $pct, $pct, $pct, $pct, $pct, $pct, $pct, '100g'); - $nutriScore = new NutriScore('0', '0', 'A'); - $nutriScorePoints = new NutriScorePoints('0', '0', '0', '0', '0', '0', '0'); - - $minerals = new Minerals('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $vitamins = new Vitamins('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $carbs = new CarbohydratesDetail('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $fatty = new FattyAcids('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $amino = new AminoAcids('0', '0', '0'); - $special = new SpecialCompounds('0', '0', '0', '0'); - - return IncoComposition::hydrate( - id: $compoId, - idInco: $incoId, - identification: $identification, - energy: $energy, - referenceMacronutrients: $refMacro, - portionMacronutrients: $porMacro, - freshProduceAndNuts: $fresh, - referenceIntakes: $refIntakes, - nutriScore: $nutriScore, - nutriScorePoints: $nutriScorePoints, - minerals: $minerals, - vitamins: $vitamins, - carbohydratesDetail: $carbs, - fattyAcids: $fatty, - aminoAcids: $amino, - specialCompounds: $special, - ); - } - it('executes successfully and returns Output when composition exists', function () use ($directory): void { // GIVEN $incoId = new IncoId('12345'); - $composition = createComposition('67890', '12345'); + $composition = IncoCompositionMother::create(compoId: '67890', incoId: '12345'); $directory->add($composition); $usecase = new FindIncoComposition($directory); diff --git a/tests/Unit/Application/Arcadia/Usecase/Incosheets/FindIncoSheetTest.php b/tests/Unit/Application/Arcadia/Usecase/Incosheets/FindIncoSheetTest.php index 6c5ed9b..c537e39 100644 --- a/tests/Unit/Application/Arcadia/Usecase/Incosheets/FindIncoSheetTest.php +++ b/tests/Unit/Application/Arcadia/Usecase/Incosheets/FindIncoSheetTest.php @@ -8,15 +8,9 @@ use Application\Arcadia\Exceptions\IncoSheetNotFoundException; use Application\Arcadia\Usecase\IncoSheets\Find\FindIncoSheet; use Application\Arcadia\Usecase\IncoSheets\Find\Input; use Application\Arcadia\Usecase\IncoSheets\Find\Output; -use Domain\Models\Entities\Inco\IncoSheet; -use Domain\Models\ValueObjects\Brand\ArcadiaId; -use Domain\Models\ValueObjects\Brand\BrandCode; -use Domain\Models\ValueObjects\Brand\BrandName; -use Domain\Models\ValueObjects\Inco\Allegations; -use Domain\Models\ValueObjects\Inco\IncoBrand; use Domain\Models\ValueObjects\Inco\IncoId; -use Domain\Models\ValueObjects\Inco\Ingredients; use Infra\Adapters\Directories\InMemoryIncoSheetDirectory; +use Tests\Support\Mothers\IncoSheetMother; covers( FindIncoSheet::class, @@ -34,29 +28,7 @@ describe('FindIncoSheet Usecase Unit Tests', function (): void { it('executes successfully and returns Output when inco sheet exists', function () use ($directory): void { // GIVEN $incoId = new IncoId('12345'); - $incoSheet = IncoSheet::hydrate( - id: $incoId, - name: 'Poulet Rôti 1kg', - label: 'Poulet Rôti Classe A', - description: 'Poulet prêt à cuire', - allegations: new Allegations(['Volaille française']), - sellArguments: 'Délicieux', - preparationAdvices: 'Cuire 45min à 180°C', - tips: null, - sellFamilly: 'Boucherie', - ingredients: new Ingredients(['Ingrédients' => ['Viande de dinde (66%)']]), - portions: null, - allergens: [], - brand: new IncoBrand(new BrandName('Le Gaulois'), new BrandCode('LGL01'), new ArcadiaId(1)), - isSeasonal: true, - weight: null, - nutriscore: null, - storageCondition: null, - additives: [], - compo: null, - createdAt: null, - updatedAt: null, - ); + $incoSheet = IncoSheetMother::create(id: '12345', name: 'Poulet Rôti 1kg'); $directory->add($incoSheet); $usecase = new FindIncoSheet($directory); @@ -67,12 +39,10 @@ describe('FindIncoSheet Usecase Unit Tests', function (): void { // THEN expect($result)->toBeInstanceOf(Output::class) - ->and($result->id)->toBe($incoId) + ->and($result->id->value)->toBe('12345') ->and($result->name)->toBe('Poulet Rôti 1kg') - ->and($result->label)->toBe('Poulet Rôti Classe A') ->and($result->brand->name->value)->toBe('Le Gaulois') - ->and($result->brand->code->value)->toBe('LGL01') - ->and($result->isSeasonal)->toBeTrue(); + ->and($result->brand->code->value)->toBe('LGL01'); }); it('throws NotFoundException when inco sheet does not exist', function () use ($directory): void { diff --git a/tests/Unit/Domain/Entities/Inco/IncoCompositionBuilderTest.php b/tests/Unit/Domain/Entities/Inco/IncoCompositionBuilderTest.php new file mode 100644 index 0000000..fb0ddc0 --- /dev/null +++ b/tests/Unit/Domain/Entities/Inco/IncoCompositionBuilderTest.php @@ -0,0 +1,132 @@ +withId($id) + ->withIdInco($idInco) + ->withIdentification($identification) + ->withEnergy($energy) + ->withReferenceMacronutrients($refMacronutrients) + ->withPortionMacronutrients($portionMacronutrients) + ->withFreshProduceAndNuts($freshProduce) + ->withReferenceIntakes($referenceIntakes) + ->withNutriScore($nutriScore) + ->withNutriScorePoints($nutriScorePoints) + ->withMinerals($minerals) + ->withVitamins($vitamins) + ->withCarbohydratesDetail($carbohydratesDetail) + ->withFattyAcids($fattyAcids) + ->withAminoAcids($aminoAcids) + ->withSpecialCompounds($specialCompounds) + ->build(); + + // THEN + expect($compo)->toBeInstanceOf(IncoComposition::class) + ->and($compo->id())->toBe($id) + ->and($compo->idInco)->toBe($idInco) + ->and($compo->identification->name)->toBe('Poulet Rôti') + ->and($compo->nutriScore->grade)->toBe('D'); + }); + + it('throws DomainException when required fields are missing', function (): void { + // GIVEN + $builder = new IncoCompositionBuilder(); + + // WHEN + expect(fn () => $builder->build()) + + // THEN + ->toThrow(\DomainException::class, 'Cannot build IncoComposition: missing required components.'); + }); +}); diff --git a/tests/Unit/Domain/Entities/Inco/IncoSheetBuilderTest.php b/tests/Unit/Domain/Entities/Inco/IncoSheetBuilderTest.php new file mode 100644 index 0000000..babfd44 --- /dev/null +++ b/tests/Unit/Domain/Entities/Inco/IncoSheetBuilderTest.php @@ -0,0 +1,65 @@ + ['Viande de dinde (66%)']]); + $brand = new IncoBrand(new BrandName('Le Gaulois'), new BrandCode('LGL01'), new ArcadiaId(504)); + + // WHEN + $sheet = IncoSheet::builder() + ->withId($id) + ->withName('Poulet Rôti 1kg') + ->withLabel('Poulet Rôti Classe A') + ->withDescription('Poulet prêt à cuire') + ->withAllegations($allegations) + ->withSellArguments('Délicieux') + ->withPreparationAdvices('Cuire 45min à 180°C') + ->withSellFamilly('Boucherie') + ->withIngredients($ingredients) + ->withBrand($brand) + ->withIsSeasonal(true) + ->build(); + + // THEN + expect($sheet)->toBeInstanceOf(IncoSheet::class) + ->and($sheet->id())->toBe($id) + ->and($sheet->name)->toBe('Poulet Rôti 1kg') + ->and($sheet->label)->toBe('Poulet Rôti Classe A') + ->and($sheet->description)->toBe('Poulet prêt à cuire') + ->and($sheet->sellFamilly)->toBe('Boucherie') + ->and($sheet->brand->name->value)->toBe('Le Gaulois') + ->and($sheet->brand->code->value)->toBe('LGL01') + ->and($sheet->brand->arcadiaBrandCode->value)->toBe(504) + ->and($sheet->isSeasonal)->toBeTrue(); + }); + + it('throws DomainException when required fields are missing', function (): void { + // GIVEN + $builder = new IncoSheetBuilder(); + + // WHEN + expect(fn () => $builder->build()) + + // THEN + ->toThrow(\DomainException::class, 'Cannot build IncoSheet: missing required components.'); + }); +}); diff --git a/tests/Unit/Presentation/Api/V1/Presenters/IncoCompositions/IncoCompositionShowPresenterTest.php b/tests/Unit/Presentation/Api/V1/Presenters/IncoCompositions/IncoCompositionShowPresenterTest.php index 72ac134..70f8e2d 100644 --- a/tests/Unit/Presentation/Api/V1/Presenters/IncoCompositions/IncoCompositionShowPresenterTest.php +++ b/tests/Unit/Presentation/Api/V1/Presenters/IncoCompositions/IncoCompositionShowPresenterTest.php @@ -4,29 +4,9 @@ declare(strict_types=1); namespace Tests\Unit\Presentation\Api\V1\Presenters\IncoCompositions; -use Application\Arcadia\Usecase\IncoCompositions\Find\Output; -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 Presentation\Api\V1\Presenters\IncoCompositions\IncoCompositionShowPresenter; use Presentation\Api\V1\Presenters\IncoCompositions\IncoCompositionShowView; +use Tests\Support\Mothers\IncoCompositionMother; covers( IncoCompositionShowPresenter::class, @@ -36,47 +16,7 @@ covers( describe('IncoCompositionShowPresenter Unit Tests', function (): void { it('transforms Output into IncoCompositionShowView', function (): void { // GIVEN - $energyValues = new EnergyValues('100g', '0', '0'); - $energy = new Energy($energyValues, $energyValues); - - $nutrient = new NutrientValue('0'); - $refMacro = new ReferenceMacronutrients($nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient); - $porMacro = new PortionMacronutrients($nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient, $nutrient); - - $fnAmount = new FruitAndNutAmount(); - $pct = new PercentageValue('0'); - $fresh = new FreshProduceAndNuts($fnAmount, $fnAmount, $pct, $pct); - - $refIntakes = new ReferenceIntakes($pct, $pct, $pct, $pct, $pct, $pct, $pct, $pct, '100g'); - $nutriScore = new NutriScore('0', '0', 'A'); - $nutriScorePoints = new NutriScorePoints('0', '0', '0', '0', '0', '0', '0'); - - $minerals = new Minerals('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $vitamins = new Vitamins('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $carbs = new CarbohydratesDetail('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $fatty = new FattyAcids('0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'); - $amino = new AminoAcids('0', '0', '0'); - $special = new SpecialCompounds('0', '0', '0', '0'); - - $output = new Output( - id: new IncoCompositionId('1000101'), - idInco: new IncoId('1000101'), - identification: new Identification(name: 'Composition Test', number: '10001', source: 'Arcadia'), - energy: $energy, - referenceMacronutrients: $refMacro, - portionMacronutrients: $porMacro, - freshProduceAndNuts: $fresh, - referenceIntakes: $refIntakes, - nutriScore: $nutriScore, - nutriScorePoints: $nutriScorePoints, - minerals: $minerals, - vitamins: $vitamins, - carbohydratesDetail: $carbs, - fattyAcids: $fatty, - aminoAcids: $amino, - specialCompounds: $special, - ); - + $output = IncoCompositionMother::createOutput(); $presenter = new IncoCompositionShowPresenter(); // WHEN diff --git a/tests/Unit/Presentation/Api/V1/Presenters/IncoSheets/IncoSheetsShowPresenterTest.php b/tests/Unit/Presentation/Api/V1/Presenters/IncoSheets/IncoSheetsShowPresenterTest.php index f0af8a4..b65645f 100644 --- a/tests/Unit/Presentation/Api/V1/Presenters/IncoSheets/IncoSheetsShowPresenterTest.php +++ b/tests/Unit/Presentation/Api/V1/Presenters/IncoSheets/IncoSheetsShowPresenterTest.php @@ -4,16 +4,9 @@ declare(strict_types=1); namespace Tests\Unit\Presentation\Api\V1\Presenters\IncoSheets; -use Application\Arcadia\Usecase\IncoSheets\Find\Output; -use Domain\Models\ValueObjects\Brand\ArcadiaId; -use Domain\Models\ValueObjects\Brand\BrandCode; -use Domain\Models\ValueObjects\Brand\BrandName; -use Domain\Models\ValueObjects\Inco\Allegations; -use Domain\Models\ValueObjects\Inco\IncoBrand; -use Domain\Models\ValueObjects\Inco\IncoId; -use Domain\Models\ValueObjects\Inco\Ingredients; use Presentation\Api\V1\Presenters\IncoSheets\IncoSheetsShowPresenter; use Presentation\Api\V1\Presenters\IncoSheets\IncoSheetsShowView; +use Tests\Support\Mothers\IncoSheetMother; covers( IncoSheetsShowPresenter::class, @@ -23,30 +16,7 @@ covers( describe('IncoSheetsShowPresenter Unit Tests', function (): void { it('transforms Output into IncoSheetsShowView', function (): void { // GIVEN - $output = new Output( - id: new IncoId('1000101'), - name: 'Poulet Rôti', - label: 'Le Gaulois', - description: 'Poulet rôti de qualité', - allegations: new Allegations([]), - sellArguments: 'Délicieux', - preparationAdvices: 'Réchauffer 10min', - tips: null, - sellFamilly: null, - ingredients: new Ingredients([]), - portions: null, - allergens: [], - brand: new IncoBrand(new BrandName('Le Gaulois'), new BrandCode('LGL01'), new ArcadiaId(1)), - isSeasonal: false, - weight: null, - nutriscore: null, - storageCondition: null, - additives: [], - compo: null, - createdAt: new \DateTimeImmutable('2024-01-01'), - updatedAt: new \DateTimeImmutable('2024-01-02'), - ); - + $output = IncoSheetMother::createOutput(id: '1000101', name: 'Poulet Rôti'); $presenter = new IncoSheetsShowPresenter(); // WHEN