ldc-groupe/app/Models/News.php
2025-11-12 16:48:20 +01:00

287 lines
7.8 KiB
PHP

<?php
namespace App\Models;
use App\Contracts\TranslatableModel;
use App\Enums\News\NewsStatusEnum;
use App\Helpers\TranslationHelper;
use App\Traits\Models\HasTranslations;
use App\Traits\Models\HasUwilImages;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Uwil\LaravelActivityLogs\Traits\ActivityLog;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
/**
* @property string $title Title of the news.
* @property string $slug Slug of the news.
* @property string $titleSeo Title of the news.
* @property string $descriptionSeo Slug of the news.
* @property string $content Content of the news.
* @property \App\Enums\News\NewsStatusEnum $status Status of the news.
* @property string $picture Main img of the news.
* @property string $picture_alt Alt text for the picture.
* @property string $picture_title Title for the picture.
* @property-read \Illuminate\Support\Carbon $created_at Date on which the news was created.
* @property-read \Illuminate\Support\Carbon $updated_at Date on which the news was updated.
* @property-read \Illuminate\Support\Carbon $deleted_at Date on which the news was updated.
*/
class News extends Model implements TranslatableModel
{
use ActivityLog;
use HasFactory;
use HasTranslations;
use SoftDeletes;
use HasUwilImages {
HasUwilImages::inertiaFill as traitInertiaFill;
}
/**
* Champs contenant des images dynamiques à gérer.
*
* @var array
*/
protected array $imageFields = [
'picture'
];
/**
* Champs contenant des wysiwyg avec images dynamiques à gérer.
*
* @var array
*/
protected array $wysiwygFields = [
'content'
];
/**
* The attributes that are mass assignable.
*
* @var list<string>
*/
protected $fillable = [
'titleSeo',
'descriptionSeo',
'title',
'slug',
'content',
'status',
'picture',
'picture_alt',
'picture_title',
'published_at',
'unpublished_at',
];
/**
* The translatable columns.
*
* @var list<string>
*/
public $translatable = [
'titleSeo',
'descriptionSeo',
'title',
'slug',
'content',
'picture_alt',
'picture_title',
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'status' => NewsStatusEnum::class,
'published_at' => 'datetime',
'unpublished_at' => 'datetime',
];
/**
* Perform any actions required after the model boots.
*
* @return void
*/
protected static function booted(): void
{
static::creating(function (self $model) {
self::manageFields($model);
});
static::created(function (self $model) {
self::resetCache();
});
static::updating(function (self $model) {
self::manageFields($model);
});
static::updated(function (self $model) {
self::resetCache();
});
static::deleted(function () {
self::resetCache();
});
static::restoring(function (self $model) {
self::resetCache();
$model->status = NewsStatusEnum::unpublished;
});
static::forceDeleted(function (self $model) {
self::resetCache();
});
}
/**
* Getter the current status following planification dates planificated_status.
*
* @return boolean
*/
public function getPlanificatedStatusAttribute(): bool
{
/** @var \Carbon\Carbon|null */
$published_at = $this->published_at;
/** @var \Carbon\Carbon|null */
$unpublished_at = $this->unpublished_at;
if ($published_at and $unpublished_at) {
return $unpublished_at->greaterThanOrEqualTo(now()) and $published_at->lessThan(now());
}
if ($published_at) {
return $published_at->lessThan(now());
}
if ($unpublished_at) {
return $unpublished_at->greaterThanOrEqualTo(now());
}
return false;
}
/**
* Reset all cache elements related to this model.
*
* @return void
*/
public static function resetCache(): void
{
Cache::forget('getPublishedNews');
self::getPublishedNews();
}
/**
* Get all published dynamic pages.
*
* @return \Illuminate\Database\Eloquent\Collection<int,self>
*/
public static function getPublishedNews(): \Illuminate\Database\Eloquent\Collection
{
return Cache::remember('getPublishedNews', 86400, function () {
return self::query()
->where('status', NewsStatusEnum::published)
->with('categories')
->get();
});
}
public function publishedAtFormatted()
{
return Carbon::parse($this->published_at)->format('d/m/Y');
}
/**
* The relation with NewsCategory.
*
* @return HasMany
*/
public function categories(): HasMany
{
return $this->hasMany(NewsCategory::class, 'news_id');
}
/**
* Get a comma-separated list of all category labels for this news item.
*
* @return string|null
*/
public function getCategoryLabelsAttribute(): ?string
{
if (empty($this->categories)) {
return null;
}
$labels = collect($this->categories)
->map(fn($cat) => $cat->category->label() ?? null)
->filter()
->values();
return $labels->join(', ');
}
/**
* Get data related to the first category of this news item.
*
* @return array<string, string>|null>
*/
public function getFirstCategoryDataAttribute(): ?array
{
if (empty($this->categories) || empty($this->categories[0])) {
return null;
}
$cat = $this->categories[0]->category;
return [
'category_classes' => $cat->getClasses(),
'date_classes' => $cat->getDateClasses(),
'label' => $cat->label(),
];
}
public function inertiaFill(array $attributes)
{
$attributes = Arr::except($attributes, ['categories']);
$this->traitInertiaFill($attributes);
}
/**
* Manage model fields.
*
* @param self $model
* @return void
*/
private static function manageFields(self $model): void
{
// Check unique fields.
$slug = Str::slug($model->title);
TranslationHelper::assertTranslationFieldIsUnique($model, $model->title, 'title');
TranslationHelper::assertTranslationFieldIsUnique($model, $slug, 'slug', 'title');
$model->setAttribute('slug', $slug);
// Check translations.
self::validateFallbackTranslations($model);
}
/**
* Assert fallback locale translation is present.
*
* @param self $model
* @return void
* @throws \Illuminate\Validation\ValidationException Translations missing.
*/
public static function validateFallbackTranslations(self $model): void
{
if (! $model->status->equals(NewsStatusEnum::published)) {
return;
}
TranslationHelper::validateFallbackTranslations($model);
}
}