Modelli e database
Il livello dati di TubePress: classi modello, l'helper PDO Database, prepared statement, lo schema del database e le migrazioni SQL versionate spiegate.
TubePress comunica con MySQL/MariaDB attraverso due livelli sottili: i modelli (una classe statica per entità) e il helper Database (un piccolo wrapper su PDO). Non c'è nessun ORM e nessun query builder da imparare — solo prepared statement e nomi di metodo prevedibili.
Il livello dei modelli
Ogni entità principale ha un modello in src/Models/ che espone metodi statici. I modelli disponibili sono Video, Category, Tag, Performer, Channel, Comment, Page, User, Setting, Favorite, History, Report, ContactMessage, MenuConfig e FooterConfig.
$video = Video::find($id); // one row (or null)
$latest = Video::all(['status' => 'published', 'limit' => 20]);
$id = Video::create($data); // returns new id
Video::update($id, ['title' => 'New title']);
Video::delete($id);I modelli incapsulano i join e i filtri specifici della loro entità — ad esempio Video::find() restituisce il video con le sue categorie, tag, performer e canali allegati, in modo che i controller e i template rimangano semplici.
Il helper Database
Per tutto ciò che un modello non copre già, utilizza il helper Database direttamente. Ogni metodo usa prepared statement — non concatenare mai l'input dell'utente in SQL.
| Metodo | Restituisce | Scopo |
|---|---|---|
Database::fetchOne($sql, $params) | array\|null | Prima riga corrispondente. |
Database::fetchAll($sql, $params) | array | Tutte le righe corrispondenti. |
Database::insert($table, $data) | int | Inserisce un array associativo; restituisce il nuovo id. |
Database::update($table, $data, $where, $whereParams) | int | Aggiorna; restituisce le righe interessate. |
Database::delete($table, $where, $params) | int | Elimina; restituisce le righe interessate. |
Database::count($table, $where, $params) | int | Conteggio righe. |
Database::query($sql, $params) | PDOStatement | Qualsiasi istruzione, per il controllo completo. |
Database::transaction($callback) | mixed | Esegue una closure in una transazione (commit/rollback automatici). |
$rows = Database::fetchAll(
"SELECT * FROM videos WHERE status = ? ORDER BY id DESC LIMIT ?",
['published', 20]
);
$newId = Database::insert('categories', [
'name' => 'Amateur',
'slug' => 'amateur',
]);utf8mb4, veri prepared statement (senza emulazione) e la modalità di errore a eccezione, e si riconnette automaticamente una volta in caso di un genuino errore "server has gone away" — in modo che i worker a lunga esecuzione sopravvivano a un timeout MySQL inattivo.Transazioni
Avvolgi le scritture multi-step in modo che abbiano tutte successo o vengano tutte annullate:
Database::transaction(function () use ($videoId, $catIds) {
Database::delete('video_categories', 'video_id = ?', [$videoId]);
foreach ($catIds as $cid) {
Database::insert('video_categories', [
'video_id' => $videoId, 'category_id' => $cid,
]);
}
});Lo schema
Il database utilizza uno schema MySQL pulito e normalizzato. Le tabelle principali includono users, settings, categories, tags, performers, channels, videos e le tabelle di join video_categories, video_tags, video_performers — più comments, user_favorites, user_history, video_likes, pages, plugins, themes e migrations. I sottosistemi opzionali aggiungono le proprie tabelle (job di importazione, archivi multimediali, job/server di transcodifica, zone/spot pubblicitari, report, fonti di feed, tabelle di traduzione e altro ancora) man mano che li abiliti.
Migrazioni
Le modifiche allo schema risiedono in sql/ come file numerati — 001_users.sql, 002_settings.sql, … — applicati in ordine da Migrator::run() durante l'installazione e dopo ogni aggiornamento. Ogni migrazione è additiva e registrata nella tabella migrations, quindi non viene mai eseguita due volte.
- Per estendere lo schema da un plugin, includi le istruzioni
CREATE TABLEed eseguile nel metodoinstall()del plugin (vedi Hook e plugin). - Non rinumerare né modificare una migrazione già applicata — aggiungi una nuova con numero più alto.
Scrivere un modello
Un modello è semplicemente una classe statica che avvolge il helper Database per una singola tabella:
class Promo
{
public static function current(): ?array
{
return Database::fetchOne(
"SELECT * FROM promos WHERE active = 1
ORDER BY id DESC LIMIT 1"
);
}
}Passi successivi
Ancora bloccato?
Apri un ticket dalla tua dashboard e il nostro team ti aiuterà.