File: /home/xedaptot/ai.naniguide.com/app/Model/PageTemplate.php
<?php
namespace App\Model;
use App\Library\Contracts\TemplateSubjectInterface;
use App\Library\Traits\HasUid;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
/**
* PageTemplate — wrapper row around a Template, for funnel/landing/commerce page
* templates exposed to admins at /rui/admin/page-templates.
*
* Schema only — all business logic (create, copy, rename, delete, save content)
* lives in App\Services\PageTemplateService. The rule (DEV.md): Model stores
* schema + relations + scopes + read-only helpers; Services perform writes.
*
* Wrapper-over-Template invariant: every PageTemplate row owns exactly one
* Template row via 1:1 template_id FK (cascade delete at DB level + cleanup
* orchestrated through App\Services\TemplateService::for($this)).
*/
class PageTemplate extends Model implements TemplateSubjectInterface
{
use HasUid;
/** @var list<string> */
protected $fillable = ['name', 'template_id'];
/**
* Factory for a blank instance.
*/
public static function newDefault(): self
{
return new self();
}
/**
* @return BelongsTo<Template, $this>
*/
public function template(): BelongsTo
{
return $this->belongsTo(Template::class);
}
/**
* Filter by keyword (name substring). Empty keyword = no-op.
*/
public function scopeSearch(Builder $query, ?string $keyword): Builder
{
if (empty($keyword)) {
return $query;
}
return $query->where('name', 'like', '%'.trim($keyword).'%');
}
/**
* Filter by related Template's category UID (Base / Extended).
*/
public function scopeCategoryUid(Builder $query, string $categoryUid): Builder
{
return $query->whereHas('template.categories', function ($q) use ($categoryUid) {
$q->where('uid', $categoryUid);
});
}
}