ldc-ovoteam/app/Directories/EloquentRecipeDirectory.php

141 lines
4.6 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Directories;
use App\Contracts\Directories\RecipeDirectory;
use App\Models\Product;
use App\Models\Recipe;
use Domain\Models\Entities\Recipe as DomainRecipe;
use Domain\Models\ValueObjects\Entities\ProductId;
use Domain\Models\ValueObjects\Entities\RecipeId;
use Domain\Models\ValueObjects\Pagination;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Ramsey\Uuid\Uuid;
class EloquentRecipeDirectory implements RecipeDirectory
{
public function find(RecipeId $id): ?DomainRecipe
{
return Recipe::query()
->with(['products'])
->where('id', (string) $id->value)
->limit(1)
->get()
->map(fn (Recipe $recipe) => $this->mapToEntity($recipe))
->first();
}
public function findBySlug(string $slug): ?DomainRecipe
{
return Recipe::query()
->with(['products'])
->where('slug', $slug)
->limit(1)
->get()
->map(fn (Recipe $recipe) => $this->mapToEntity($recipe))
->first();
}
public function getPaginatedRecipes(
Pagination $pagination,
array $productRanges = [],
array $consumptionTimes = [],
array $inspirations = [],
array $seasons = [],
string $search = ''
): LengthAwarePaginator {
$dbQueryCallback = function (Builder $query) use ($productRanges, $consumptionTimes, $inspirations, $seasons) {
/** @var \Illuminate\Database\Eloquent\Builder<Recipe> $query */
$query->with(['products']);
if (! empty($productRanges)) {
$rangesValues = array_map(fn ($r) => $r->value, $productRanges);
$query->whereIn('product_category', $rangesValues);
}
if (! empty($consumptionTimes)) {
$timesValues = array_map(fn ($t) => $t->value, $consumptionTimes);
$query->whereIn('consomption_time', $timesValues);
}
if (! empty($inspirations)) {
$inspValues = array_map(fn ($i) => $i->value, $inspirations);
$query->whereIn('inspiration', $inspValues);
}
if (! empty($seasons)) {
$seasonValues = array_map(fn ($s) => $s->value, $seasons);
$query->whereIn('season', $seasonValues);
}
};
$query = Recipe::query();
if (! empty($search)) {
$scout = Recipe::search($search);
$matchingIds = $scout->keys();
if ($matchingIds->isEmpty()) {
/** @var \Illuminate\Pagination\LengthAwarePaginator<array-key,DomainRecipe> */
return $query->whereIn('id', [])->paginate(
perPage: $pagination->pageSize(),
page: $pagination->pageNumber()
);
}
$query->whereIn('id', $matchingIds);
}
$dbQueryCallback($query);
return $query->paginate(
perPage: $pagination->pageSize(),
page: $pagination->pageNumber()
)->through(fn (Recipe $recipe) => $this->mapToEntity($recipe));
}
private function mapToEntity(Recipe $recipe): DomainRecipe
{
return new DomainRecipe(
id: new RecipeId(Uuid::fromString($recipe->id)),
name: $recipe->name,
slug: $recipe->slug,
picture: $recipe->picture,
seoTitle: $recipe->seo_title,
seoDescription: $recipe->seo_description,
productRange: $recipe->product_category,
consomptionTime: $recipe->consomption_time,
inspiration: $recipe->inspiration,
season: $recipe->season,
description: $recipe->description,
details: $recipe->details,
preparationTime: '15 min de préparation',
guestsCount: 4,
ingredientsList: $recipe->ingredients_list,
preparationSteps: $recipe->preparation_steps,
tipsAndAdvices: $recipe->tips_and_advices,
associatedProducts: []
);
}
public function getRelatedRecipes(ProductId $productId, int $limit = 4): array
{
$product = Product::query()
->where('id', (string) $productId->value)
->first();
if (! $product) {
return [];
}
return $product->recipes()
->with(['products'])
->limit($limit)
->get()
->map(fn (Recipe $recipe) => $this->mapToEntity($recipe))
->all();
}
}