$slider_pictures Array of paths of pictures. * @property array> $packaging Packaging. * @property array> $caliber Caliber. * @property array> $nutritionnal_values Nutritionnal values. * @property string $ingredients Ingredients. * @property string $advantage Advantage. * @property string $preparation Preparation. * @property boolean $is_frenchpoultry Is frenchpoultry or not. * @property boolean $is_vip Is vip or not. * @property boolean $is_egalim Is egalim or not. * @property boolean $published Status. * @property integer $order Order. * @property-read \Illuminate\Support\Carbon $created_at Created date. * @property-read \Illuminate\Support\Carbon $updated_at Updated date. * * @property-read \App\Models\Subrange $subrange Subrange Has-One relation. * @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\Advice> $advices * Advices Belongs-To-Many relation. * @property-read \Illuminate\Database\Eloquent\Collection<\App\Models\News> $news * News Belongs-To-Many relation. */ class Product extends Model implements SeoInterface, Sitemapable { use HasFactory; use SeoTrait; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'label', 'slug', 'seo_title', 'seo_description', 'subrange_id', 'species', 'nutriscore', 'ingredients', 'advantage', 'preparation', 'sticker_sm', 'sticker_sm_alt', 'sticker_sm_title', 'slider_pictures', 'packaging', 'caliber', 'nutritionnal_values', 'is_frenchpoultry', 'is_vip', 'is_egalim', 'published' ]; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'slider_pictures' => 'array', 'packaging' => 'array', 'caliber' => 'array', 'nutritionnal_values' => 'array', 'is_frenchpoultry' => 'bool', 'is_vip' => 'bool', 'is_egalim' => 'bool', 'published' => 'bool', 'species' => ProductSpeciesEnum::class, 'nutriscore' => NutriscoreEnum::class ]; /** * Perform any actions required after the model boots. * * @return void */ protected static function booted(): void { // * EVENT CLOSURES. static::creating(function (self $model) { self::manageFields($model); $model->order = \intval(self::query()->max('order')) + 1; }); static::updating(function (self $model) { self::manageFields($model); }); static::updated(function (self $model) { FileStorageHelper::removeOldFile($model, 'sticker_sm'); FileStorageHelper::removeOldFiles( !is_array($model->getOriginal('slider_pictures')) ? [] : $model->getOriginal('slider_pictures'), $model->slider_pictures ); }); static::deleted(function (self $model) { FileStorageHelper::removeFile($model, 'sticker_sm'); FileStorageHelper::removeFiles( $model, !is_array($model->getOriginal('slider_pictures')) ? [] : $model->getOriginal('slider_pictures'), ); }); } // * METHODS /** * Common methods function. * * @param self $model * @return void */ private static function manageFields(self $model): void { // * ASSERTIONS self::assertLabelIsUnique($model->label, $model->id); ToolboxHelper::assertNoInternalBoUrls('ingredients', $model->ingredients); ToolboxHelper::assertNoInternalBoUrls('advantage', $model->advantage); ToolboxHelper::assertNoInternalBoUrls('preparation', $model->preparation); foreach ($model->packaging as $pack) { ToolboxHelper::assertNoInternalBoUrls('packaging', $pack['value']); } foreach ($model->caliber as $calib) { ToolboxHelper::assertNoInternalBoUrls('caliber', $calib['value']); } foreach ($model->nutritionnal_values as $nutritionnal_value) { if (!empty($nutritionnal_value['value'])) { ToolboxHelper::assertNoInternalBoUrls('nutritionnal_values', $nutritionnal_value['value']); } } // * TRANSFORMATIONS $model->slug = Str::slug($model->label); $model->sticker_sm = FileStorageHelper::storeFile($model, $model->sticker_sm, true); $model->ingredients = clean($model->ingredients); $model->advantage = clean($model->advantage); $model->preparation = clean($model->preparation); $model->slider_pictures = clean($model->slider_pictures); $model->packaging = clean($model->packaging); $model->caliber = clean($model->caliber); $model->nutritionnal_values = clean($model->nutritionnal_values); } /** * Asserts using validation that the label is unique. * * @param string $label * @param integer|null $id * @return void */ private static function assertLabelIsUnique(string $label, ?int $id = null): void { $table = (new self())->getTable(); ToolboxHelper::assertFieldIsUnique($table, 'label', $label, $id); ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($label), $id); } /** * Get associated tips. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function tipsQuery(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->advices()->where('type', AdviceTypeEnum::tips); } /** * Get associated recipes. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function recipesQuery(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->advices()->where('type', AdviceTypeEnum::recipes); } /** * Get associated tips. * * @return \Illuminate\Database\Eloquent\Collection */ public function tips(): \Illuminate\Database\Eloquent\Collection { // @phpstan-ignore-next-line return $this->tipsQuery()->get(); } /** * Get associated recipes. * * @return \Illuminate\Database\Eloquent\Collection */ public function recipes(): \Illuminate\Database\Eloquent\Collection { // @phpstan-ignore-next-line return $this->recipesQuery()->get(); } // * RELATIONSHIPS /** * Subrange Has-One relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function subrange(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(Subrange::class); } /** * Advices Belongs-To-Many relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function advices(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->belongsToMany(Advice::class, 'advice_product'); } /** * News Belongs-To-Many relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ public function news(): \Illuminate\Database\Eloquent\Relations\BelongsToMany { return $this->belongsToMany(News::class); } /** * toSitemapTag method * * @return Url|string|array */ public function toSitemapTag(): Url | string | array { $model = $this; $route = 'fo.product.show'; $params = ['publishedProduct' => $model]; return SitemapHelper::generateUrl($route, $params, $model); } /** * Transform to seoModel * * @return \Uwil\Seo\Laravel\Objects\SeoItem */ public function toSeoItem(): SeoItem { return new SeoItem( \trans($this->getTable()), $this->seo_title, $this->seo_description, $this->published ?? false, \route(\config('seo.bo_route_prefix') . $this->getTable() . '.edit', $this), route('fo.product.show', $this) ); } }