- Added support for uploading and compressing GLB models using Draco in the backoffice. - Implemented commands for importing and re-compressing 3D models. - Updated model resource to handle 3D model uploads and validations. - Introduced a new script for compressing GLB files with Draco. - Modified Vite configuration to remove GLB files from the build output. - Updated package dependencies to include GLTF-transform libraries for handling 3D models. - Added tests to ensure proper functionality of 3D model handling and compression.
171 lines
5.5 KiB
PHP
171 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use App\Support\Configuratore\Media;
|
|
use App\Support\Configuratore\Modelli3d;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
class Modello extends Model
|
|
{
|
|
protected $table = 'modelli';
|
|
|
|
// Categorie usate dal configuratore (es. per scegliere altezza_maniglia_<categoria>.json).
|
|
public const CATEGORIE = [
|
|
'finestre' => 'Finestre',
|
|
'porte' => 'Porte',
|
|
'scorrevoli' => 'Scorrevoli',
|
|
'scuretti' => 'Scuretti',
|
|
'accessori' => 'Accessori',
|
|
];
|
|
|
|
// Moduli base del configuratore (sezioni del menu e voci di prezzo); quelli dei gruppi
|
|
// di opzioni si aggiungono da GruppoOpzioni (vedi moduliDisponibili).
|
|
public const MODULI = [
|
|
'listino' => 'Listino',
|
|
'modello' => 'Finiture',
|
|
'finitura_esterna' => 'Finitura esterna (bicolore)',
|
|
'maniglia' => 'Maniglia',
|
|
'altezza_maniglia' => 'Altezza maniglia',
|
|
'vetro' => 'Vetro',
|
|
'avvolgibile' => 'Avvolgibile',
|
|
'select_finiture' => 'Select finiture',
|
|
];
|
|
|
|
protected $fillable = [
|
|
'sistema_id', 'codice', 'nome', 'descrizione', 'titolo', 'icona', 'ordine', 'attivo',
|
|
'cartella', 'file_modello', 'categoria', 'cartella_texture', 'moduli',
|
|
'regola_vetro_id', 'listino_aggiornato_at',
|
|
];
|
|
|
|
protected $casts = [
|
|
'ordine' => 'integer',
|
|
'attivo' => 'boolean',
|
|
'moduli' => 'array',
|
|
'listino_aggiornato_at' => 'datetime',
|
|
'modello_3d_dimensione' => 'integer',
|
|
'modello_3d_draco_dimensione' => 'integer',
|
|
'modello_3d_aggiornato_at' => 'datetime',
|
|
];
|
|
|
|
public function sistema(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Sistema::class);
|
|
}
|
|
|
|
public function listino(): HasMany
|
|
{
|
|
return $this->hasMany(ListinoPrezzo::class);
|
|
}
|
|
|
|
public function regolaVetro(): BelongsTo
|
|
{
|
|
return $this->belongsTo(RegolaVetro::class);
|
|
}
|
|
|
|
/** Opzioni personalizzate del modello (sostituiscono i gruppi del sistema). */
|
|
public function opzioni(): HasMany
|
|
{
|
|
return $this->hasMany(Opzione::class);
|
|
}
|
|
|
|
/** Tutte le finiture del profilo del sistema (per scegliere quali usare nel modello). */
|
|
public function finitureDelSistema(): HasMany
|
|
{
|
|
return $this->hasMany(Finitura::class, 'sistema_id', 'sistema_id')->where('tipo', 'profilo');
|
|
}
|
|
|
|
/** Moduli selezionabili: quelli base più uno per ogni gruppo di opzioni con un controllo. */
|
|
public static function moduliDisponibili(): array
|
|
{
|
|
$gruppi = GruppoOpzioni::query()
|
|
->where('ui', '!=', 'nessuna')
|
|
->orderBy('ordine')
|
|
->pluck('etichetta', 'modulo')
|
|
->all();
|
|
|
|
return self::MODULI + $gruppi;
|
|
}
|
|
|
|
public function haModulo(string $modulo): bool
|
|
{
|
|
return in_array($modulo, $this->moduli ?? [], true);
|
|
}
|
|
|
|
public function scopeAttivi(Builder $query): Builder
|
|
{
|
|
return $query->where('attivo', true)->orderBy('ordine')->orderBy('id');
|
|
}
|
|
|
|
/**
|
|
* Modelli mostrati nel configuratore: attivi, con un listino (senza prezzi non si possono
|
|
* vendere) e con il modello 3D caricato.
|
|
*/
|
|
public function scopeNelConfiguratore(Builder $query): Builder
|
|
{
|
|
return $query->attivi()->whereNotNull('modello_3d_draco')->whereHas('listino');
|
|
}
|
|
|
|
/** URL del modello 3D compresso (Draco) letto dal configuratore. */
|
|
public function getModello3dUrlAttribute(): ?string
|
|
{
|
|
return Media::url($this->modello_3d_draco);
|
|
}
|
|
|
|
public function getIconaUrlAttribute(): ?string
|
|
{
|
|
return $this->icona ? Storage::disk('public')->url($this->icona) : null;
|
|
}
|
|
|
|
/**
|
|
* Rinumera l'ordine dei modelli del sistema mettendo i disattivi in fondo,
|
|
* senza cambiare l'ordine relativo all'interno dei due gruppi.
|
|
*/
|
|
public static function normalizzaOrdine(int $sistemaId): void
|
|
{
|
|
$ids = static::query()
|
|
->where('sistema_id', $sistemaId)
|
|
->orderByDesc('attivo')
|
|
->orderBy('ordine')
|
|
->orderBy('id')
|
|
->pluck('id');
|
|
|
|
DB::transaction(function () use ($ids) {
|
|
foreach ($ids as $i => $id) {
|
|
// Query diretta: niente eventi del modello (e niente ricorsione).
|
|
static::query()->whereKey($id)->update(['ordine' => $i + 1]);
|
|
}
|
|
});
|
|
}
|
|
|
|
protected static function booted(): void
|
|
{
|
|
// Attivando o disattivando un modello (o creandone uno), i disattivi tornano in fondo.
|
|
static::saved(function (Modello $modello): void {
|
|
if ($modello->wasRecentlyCreated || $modello->wasChanged(['attivo', 'sistema_id'])) {
|
|
static::normalizzaOrdine($modello->sistema_id);
|
|
}
|
|
});
|
|
|
|
// Rimuove il file dell'icona sostituita o del modello eliminato.
|
|
static::updated(function (Modello $modello): void {
|
|
$vecchia = $modello->getOriginal('icona');
|
|
if ($modello->wasChanged('icona') && $vecchia) {
|
|
Storage::disk('public')->delete($vecchia);
|
|
}
|
|
});
|
|
|
|
static::deleted(function (Modello $modello): void {
|
|
if ($modello->icona) {
|
|
Storage::disk('public')->delete($modello->icona);
|
|
}
|
|
app(Modelli3d::class)->elimina($modello);
|
|
});
|
|
}
|
|
}
|