Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

259
app/Models/Post.php Normal file
View File

@@ -0,0 +1,259 @@
<?php
namespace App\Models;
use App\Helpers\StringHelper;
use App\Models\Category;
use App\Models\Image;
use App\Models\Meeting;
use App\Models\PostTranslation;
use Cog\Contracts\Love\Reactable\Models\Reactable as ReactableInterface;
use Cog\Laravel\Love\Reactable\Models\Traits\Reactable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laravel\Scout\Searchable;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Znck\Eloquent\Traits\BelongsToThrough;
class Post extends Model implements HasMedia, ReactableInterface
{
use HasFactory;
use BelongsToThrough;
use InteractsWithMedia;
use SoftDeletes;
use Searchable; // laravel/scout with ElasticSearch
use Reactable; // cybercog/laravel-love
protected $fillable = ['postable_id', 'postable_type', 'category_id', 'author_id', 'author_model'];
/**
* Get the index name for the model.
*
* @return string
*/
public function searchableAs()
{
return 'posts_index';
}
/**
* Convert the this model to a searchable array.
*
* @return array
*/
public function toSearchableArray()
{
return [
'id' => $this->id,
'category_id' => $this->category_id,
'postable' => [
'id' => $this->postable ? $this->postable->id : '',
'name' => $this->postable ? $this->postable->name : '',
],
'post_translations' => $this->translations->mapWithKeys(function ($translation) {
// mapWithKeys() as translations is a collection
return [
'title_' . $translation->locale => $translation->title,
'excerpt_' . $translation->locale => $translation->excerpt,
'content_' . $translation->locale => $translation->content,
// Add publication fields
'from_' . $translation->locale => $translation->from,
'till_' . $translation->locale => $translation->till,
'deleted_at_' . $translation->locale => $translation->deleted_at,
'status_' . $translation->locale => $translation->status,
];
})->toArray(),
'post_category' => $this->category ? [
'id' => $this->category->id,
'names' => $this->category->translations->mapWithKeys(function ($translation) {
// Include the locale in the field name for categories
return ['name_' . $translation->locale => StringHelper::DutchTitleCase($translation->name)];
})->toArray(),
] : [],
];
}
/**
* Get the creator of the post (i.e. user or organization).
*
* @return void
*/
public function postable()
{
return $this->morphTo();
}
/**
* Get the author of the post (polymorphic: User, Organization, or Bank).
*
* @return void
*/
public function author()
{
return $this->morphTo('author', 'author_model', 'author_id');
}
/**
* Get the related translations of the post
* One-to-many relationship
* @return void
*/
public function translations()
{
return $this->hasMany(PostTranslation::class);
}
/**
* Get the related category of the post
*
* @return void
*/
public function category()
{
return $this->belongsTo(Category::class);
}
/**
* Get the related images of the posts
*
* @return void
*/
public function images()
{
return $this->morphToMany(Image::class, 'imageable');
}
public static function last()
{
return static::all()->last();
}
/**
* Spatie Media Library media conversions
* When updated you can use:
* php artisan media-library:regenerate
* to regenerate media disk and database of all media stored (make sure you restart the queue worker first)
*
* @param mixed $media
* @return void
*/
public function registerMediaConversions(Media $media = null): void
{
$this->addMediaConversion('favicon') //1:1
->focalCrop(32, 32, 50, 50)
->optimize()
->format('gif')
->performOnCollections('posts');
$this->addMediaConversion('logo') //1:1
->focalCrop(160, 160, 50, 50)
->optimize()
->format('webp')
->performOnCollections('posts');
$this->addMediaConversion('thumbnail') // 1:1
->focalCrop(150, 150, 50, 50)
->optimize()
->format('webp')
->performOnCollections('posts');
$this->addMediaConversion('blog') //3:2
->focalCrop(1200, 630, 50, 50)
->withResponsiveImages()
->optimize()
->format('webp')
->performOnCollections('posts');
$this->addMediaConversion('hero') //16:9
->focalCrop(3840, 2160, 50, 50)
->withResponsiveImages()
->optimize()
->format('webp')
->performOnCollections('posts');
$this->addMediaConversion('half_hero') //16:4.5 panoramic
->focalCrop(3840, 1080, 50, 50)
->format('webp')
->performOnCollections('posts');
$this->addMediaConversion('4_3') //4:3
->focalCrop(3072, 2304, 50, 50)
->withResponsiveImages()
->optimize()
->format('webp')
->performOnCollections('posts');
$this->addMediaConversion('email') // For email newsletters - resizes without cropping
->width(800)
->optimize()
->format('jpg')
->quality(85)
->performOnCollections('posts');
}
public function registerMediaCollection(): void
{
$this->addMediaCollection('posts')
->useDisk('media')
->singleFile();
}
/**
* Get the related meeting of the post
* One-to-one relation
*
* @return void
*/
public function meeting()
{
return $this->hasOne(Meeting::class);
}
/**
* Get the count of 'like' reactions for this post
*
* @return int
*/
public function getLikeCountAttribute()
{
// Check if post is registered as reactant before getting reactions
if (!$this->isRegisteredAsLoveReactant()) {
return 0;
}
// Get the reactant facade
$reactantFacade = $this->viaLoveReactant();
// Get the reaction counter for 'Like' type
$reactionCounter = $reactantFacade->getReactionCounterOfType('Like');
if (!$reactionCounter) {
return 0;
}
// Return the total count from all users
return $reactionCounter->getCount();
}
}