*/ protected $fillable = [ 'title', 'slug', 'content', 'config_id', 'status', 'isLocked', ]; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'content' => 'array', 'status' => PageStatusEnum::class, 'isLocked' => 'boolean', ]; /** * The translatable columns. * * @var list */ public $translatable = [ 'title', 'content', ]; /** * Perform any actions required after the model boots. * * @return void */ protected static function booted(): void { static::creating(function (self $model) { self::manageFields($model); self::validateTranslations($model); }); static::created(function () { self::resetCache(); }); static::updating(function (self $model) { self::manageFields($model); self::validateTranslations($model); }); static::updated(function (self $model) { self::resetCache(); self::removeImgs($model); }); static::deleted(function (self $model) { self::resetCache(); self::removeImgs($model); }); } // * METHODS /** * Manage model fields. * * @param self $model * @return void */ private static function manageFields(self $model): void { $table = (new self())->getTable(); ToolboxHelper::assertFieldIsUnique($table, 'title', $model->title); ToolboxHelper::assertFieldIsUnique($table, 'slug', Str::slug($model->title), $model->getKey()); $model->slug = Str::slug($model->title); } /** * Validate all translations required are defined. * * @param self $model * @return void * @throws \Illuminate\Validation\ValidationException Translations missing. */ public static function validateTranslations(self $model): void { if (! $model->status->equals(PageStatusEnum::published)) { return; } $locales = collect(config('app.locales')); $modelLocales = collect(array_keys($model->config->getTranslations('config'))); $allowedLocales = $modelLocales->intersect($locales); $missingLocales = $allowedLocales->reject( fn($locale) => $model->hasTranslation('content', $locale) ); if ($missingLocales->isNotEmpty()) { throw ValidationException::withMessages([ 'content' => trans_choice( 'back.missing_translations', $missingLocales->count() > 2 ? \INF : 1, ['locales' => Str::upper($missingLocales->implode(', '))] ), ]); } } /** * Remove imgs from wysiwyg OR dynamic wysiwyg. * * @param self $model * @return void */ public static function removeImgs(self $model): void { $model = $model->load('config'); if (!is_null($model->config)) { collect($model->config->config) ->filter(fn(array $field) => $field['type'] === DynamicFieldTypes::text->value()) ->map(function (array $field) use ($model) { collect($model->getOriginal("content")) ->map(function (string|array $content, string $locale) use ($model, $field) { // Need json decoding because $model->getAttributes() is an array. $modelContent = json_decode($model->getAttributes()['content'], true); if (isset($modelContent[$locale])) { $modelContent = $modelContent[$locale]; $modelContent = $modelContent[$field["key"]] ?? ""; } if (is_array($content)) { $content = $content[$field["key"]] ?? ""; } FileHelper::removeOldModelFilesFromHtml($modelContent, $content); }); }); } else { FileHelper::removeOldModelFilesFromHtml( $model->content, $model->getOriginal("content")[config('app.locale')] ); } //end if } /** * Reset all cache elements related to this model. * * @return void */ public static function resetCache(): void { Cache::forget('publishedDynamicPages'); self::getPublishedDynamicPages(); } /** * Get all published dynamic pages. * * @return \Illuminate\Database\Eloquent\Collection */ public static function getPublishedDynamicPages(): \Illuminate\Database\Eloquent\Collection { return Cache::remember('publishedDynamicPages', 86400, function () { return self::query() ->where('status', PageStatusEnum::published) ->with('config') ->get(); }); } // * RELATIONSHIPS /** * Get the config for the page. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo<\App\Models\PageConfig,$this> */ public function config(): \Illuminate\Database\Eloquent\Relations\BelongsTo { return $this->belongsTo(PageConfig::class); } }