File: /home/xedaptot/ai.naniguide.com/app/Model/AdTemplate.php
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use App\Library\Traits\HasUid;
class AdTemplate extends Model
{
use HasFactory;
use HasUid;
const STATUS_ACTIVE = 'active'; // for HasUid trait compatibility
const FORMAT_IMAGE = 'image';
const FORMAT_VIDEO = 'video';
const FORMAT_CAROUSEL = 'carousel';
const FORMAT_STORY = 'story';
const FORMAT_FEED = 'feed';
const FORMATS = [
self::FORMAT_IMAGE,
self::FORMAT_VIDEO,
self::FORMAT_CAROUSEL,
self::FORMAT_STORY,
self::FORMAT_FEED,
];
const FORMAT_LABELS = [
self::FORMAT_IMAGE => 'Image Ad',
self::FORMAT_VIDEO => 'Video Ad',
self::FORMAT_CAROUSEL => 'Carousel Ad',
self::FORMAT_STORY => 'Story Ad',
self::FORMAT_FEED => 'Feed Ad',
];
const PLATFORM_UNIVERSAL = 'universal';
protected $table = 'ad_templates';
protected $fillable = [
'uid',
'customer_id',
'name',
'platform',
'format',
'thumbnail_url',
'content',
'category',
'is_featured',
'use_count',
];
protected $casts = [
'content' => 'json',
'is_featured' => 'boolean',
'use_count' => 'integer',
];
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class, 'customer_id');
}
public function scopeOfCustomer($query, $customerId)
{
return $query->where('customer_id', $customerId);
}
public function scopeSystem($query)
{
return $query->whereNull('customer_id');
}
public function scopeAvailableTo($query, $customerId)
{
return $query->where(function ($q) use ($customerId) {
$q->whereNull('customer_id')->orWhere('customer_id', $customerId);
});
}
public function scopeOfPlatform($query, $platform)
{
if (!$platform) return $query;
return $query->where(function ($q) use ($platform) {
$q->where('platform', $platform)->orWhere('platform', self::PLATFORM_UNIVERSAL);
});
}
public function scopeOfFormat($query, $format)
{
if (!$format) return $query;
return $query->where('format', $format);
}
public function scopeSearch($query, $keyword)
{
return $keyword ? $query->where('name', 'like', '%' . $keyword . '%') : $query;
}
public function getFormatLabelAttribute(): string
{
return self::FORMAT_LABELS[$this->format] ?? ucfirst($this->format);
}
public function getPlatformLabelAttribute(): string
{
if ($this->platform === self::PLATFORM_UNIVERSAL || !$this->platform) {
return 'Universal';
}
return AdPlatform::PLATFORM_LABELS[$this->platform] ?? ucfirst($this->platform);
}
public function isSystemTemplate(): bool
{
return $this->customer_id === null;
}
public function incrementUseCount(): void
{
$this->increment('use_count');
}
/**
* Store thumbnail in storage (same pattern as Template model).
* NOT in public/ — that's git-tracked and accumulates across reseeds.
*/
public function updateThumbnailFromPath(string $absolutePath): void
{
if (!is_file($absolutePath)) return;
$ext = pathinfo($absolutePath, PATHINFO_EXTENSION) ?: 'svg';
$dest = $this->getThumbStoragePath($ext);
if (!is_dir(dirname($dest))) {
@mkdir(dirname($dest), 0755, true);
}
copy($absolutePath, $dest);
$this->thumbnail_url = $ext; // just store extension, path derived from uid
$this->save();
}
/**
* Full storage path for the thumbnail file.
*/
public function getThumbStoragePath(?string $ext = null): string
{
$ext = $ext ?: ($this->thumbnail_url ?: 'svg');
return storage_path('app/public/ad-templates/thumb/' . $this->uid . '.' . $ext);
}
/**
* Read inline SVG content for dark-mode-compatible rendering.
* Returns null if no thumbnail exists.
*/
public function getInlineSvg(): ?string
{
$path = $this->getThumbStoragePath();
return is_file($path) ? file_get_contents($path) : null;
}
protected static function newFactory()
{
return \Database\Factories\AdTemplateFactory::new();
}
}