Salta ai contenuti

Architettura di XOOPS

Questo documento fornisce una panoramica completa dell’architettura del sistema XOOPS, spiegando come i vari componenti lavorano insieme per creare un sistema di gestione dei contenuti flessibile ed estensibile.

XOOPS segue un’architettura modulare che separa i compiti in strati distinti. Il sistema è costruito attorno a diversi principi principali:

  • Modularità: La funzionalità è organizzata in moduli indipendenti e installabili
  • Estensibilità: Il sistema può essere esteso senza modificare il codice principale
  • Astrazione: I livelli di database e presentazione sono astratti dalla logica aziendale
  • Sicurezza: Meccanismi di sicurezza integrati proteggono dalle vulnerabilità comuni
graph TB
subgraph Presentation["🎨 Livello di presentazione"]
Themes["Temi"]
Templates["Template Smarty"]
Blocks["Blocchi"]
end
subgraph Application["⚙️ Livello applicativo"]
Modules["Moduli"]
Preloads["Preload"]
Controllers["Controller"]
BlockHandlers["Block Handler"]
end
subgraph Domain["📦 Livello di dominio"]
XoopsObject["XoopsObject"]
Handlers["Object Handler"]
Criteria["Sistema Criteria"]
end
subgraph Infrastructure["🔧 Livello infrastrutturale"]
Database["XoopsDatabase"]
Cache["Sistema di cache"]
Session["Session Manager"]
Security["Livello di sicurezza"]
end
Presentation --> Application
Application --> Domain
Domain --> Infrastructure
style Presentation fill:#e8f5e9,stroke:#388e3c
style Application fill:#e3f2fd,stroke:#1976d2
style Domain fill:#fff3e0,stroke:#f57c00
style Infrastructure fill:#fce4ec,stroke:#c2185b

Il livello di presentazione gestisce il rendering dell’interfaccia utente utilizzando il motore di template Smarty.

Componenti principali:

  • Temi: Stile visivo e layout
  • Template Smarty: Rendering del contenuto dinamico
  • Blocchi: Widget di contenuto riutilizzabili

Il livello applicativo contiene la logica aziendale, i controller e la funzionalità del modulo.

Componenti principali:

  • Moduli: Pacchetti di funzionalità autonomi
  • Handler: Classi di manipolazione dei dati
  • Preload: Listener di eventi e hook

Il livello di dominio contiene gli oggetti di dominio principale e le regole.

Componenti principali:

  • XoopsObject: Classe base per tutti gli oggetti di dominio
  • Handler: Operazioni CRUD per gli oggetti di dominio

Il livello infrastrutturale fornisce servizi principali come l’accesso ai database e la memorizzazione nella cache.

Comprendere il ciclo di vita della richiesta è fondamentale per lo sviluppo XOOPS efficace.

XOOPS 2.5.x attuale utilizza un pattern di Page Controller dove ogni file PHP gestisce la propria richiesta. I globali ($xoopsDB, $xoopsUser, $xoopsTpl, ecc.) sono inizializzati durante il bootstrap e disponibili durante tutta l’esecuzione.

sequenceDiagram
participant Browser
participant Entry as modules/mymod/index.php
participant Main as mainfile.php
participant Kernel as XOOPS Kernel
participant DB as $xoopsDB
participant User as $xoopsUser
participant Handler as MyObjectHandler
participant Tpl as $xoopsTpl (Smarty)
participant Theme
Browser->>Entry: GET /modules/mymod/index.php
rect rgb(240, 248, 255)
Note over Entry,User: Fase di bootstrap (mainfile.php)
Entry->>Main: include mainfile.php
Main->>Kernel: Inizializza Core
Kernel->>DB: Crea XoopsDatabase (singleton)
Kernel->>User: Carica sessione → $xoopsUser
Kernel->>Tpl: Inizializza Smarty → $xoopsTpl
Main-->>Entry: Globali pronti
end
rect rgb(255, 250, 240)
Note over Entry,Handler: Esecuzione del controller di pagina
Entry->>Handler: xoops_getModuleHandler('myobject')
Handler->>DB: query via Criteria
DB-->>Handler: Set di risultati
Handler-->>Entry: XoopsObject[]
end
rect rgb(240, 255, 240)
Note over Entry,Theme: Fase di rendering
Entry->>Tpl: $xoopsTpl->assign('items', $objects)
Entry->>Theme: include header.php
Entry->>Tpl: $xoopsTpl->display('mymod_index.tpl')
Entry->>Theme: include footer.php
Theme-->>Browser: Pagina HTML completa
end
GlobaleTipoInizializzatoScopo
$xoopsDBXoopsDatabaseBootstrapConnessione al database (singleton)
$xoopsUserXoopsUser|nullCaricamento sessioneUtente attualmente collegato
$xoopsTplXoopsTplInizializzazione templateMotore di template Smarty
$xoopsModuleXoopsModuleCaricamento moduloContesto del modulo attuale
$xoopsConfigarrayCaricamento configConfigurazione del sistema
// mainfile.php è il punto di ingresso
include_once XOOPS_ROOT_PATH . '/mainfile.php';
// Inizializzazione principale
$xoops = Xoops::getInstance();
$xoops->boot();

Passaggi:

  1. Caricare la configurazione (mainfile.php)
  2. Inizializzare l’autoloader
  3. Impostare la gestione degli errori
  4. Stabilire la connessione al database
  5. Caricare la sessione utente
  6. Inizializzare il motore di template Smarty
// Routing delle richieste al modulo appropriato
$module = $GLOBALS['xoopsModule'];
$controller = $module->getController();
$controller->dispatch($request);

Passaggi:

  1. Analizzare l’URL della richiesta
  2. Identificare il modulo di destinazione
  3. Caricare la configurazione del modulo
  4. Controllare i permessi
  5. Instradare al gestore appropriato
// Esecuzione del controller
$data = $handler->getObjects($criteria);
$xoopsTpl->assign('items', $data);

Passaggi:

  1. Eseguire la logica del controller
  2. Interagire con il livello dati
  3. Elaborare le regole aziendali
  4. Preparare i dati della vista
// Rendering del template
include XOOPS_ROOT_PATH . '/header.php';
$xoopsTpl->display('db:module_template.tpl');
include XOOPS_ROOT_PATH . '/footer.php';

Passaggi:

  1. Applicare il layout del tema
  2. Rendering del template del modulo
  3. Elaborare i blocchi
  4. Emettere la risposta

La classe base per tutti gli oggetti dati in XOOPS.

<?php
class MyModuleItem extends XoopsObject
{
public function __construct()
{
$this->initVar('id', XOBJ_DTYPE_INT, null, false);
$this->initVar('title', XOBJ_DTYPE_TXTBOX, '', true, 255);
$this->initVar('content', XOBJ_DTYPE_TXTAREA, '', false);
$this->initVar('created', XOBJ_DTYPE_INT, time(), false);
}
}

Metodi principali:

  • initVar() - Definire le proprietà dell’oggetto
  • getVar() - Recuperare i valori delle proprietà
  • setVar() - Impostare i valori delle proprietà
  • assignVars() - Assegnazione bulk da array

Gestisce le operazioni CRUD per le istanze XoopsObject.

<?php
class MyModuleItemHandler extends XoopsPersistableObjectHandler
{
public function __construct(\XoopsDatabase $db)
{
parent::__construct($db, 'mymodule_items', 'MyModuleItem', 'id', 'title');
}
public function getActiveItems($limit = 10)
{
$criteria = new CriteriaCompo();
$criteria->add(new Criteria('status', 1));
$criteria->setSort('created');
$criteria->setOrder('DESC');
$criteria->setLimit($limit);
return $this->getObjects($criteria);
}
}

Metodi principali:

  • create() - Creare una nuova istanza dell’oggetto
  • get() - Recuperare l’oggetto per ID
  • insert() - Salvare l’oggetto nel database
  • delete() - Rimuovere l’oggetto dal database
  • getObjects() - Recuperare più oggetti
  • getCount() - Contare gli oggetti corrispondenti

Ogni modulo XOOPS segue una struttura di directory standard:

modules/mymodule/
├── class/ # Classi PHP
│ ├── MyModuleItem.php
│ └── MyModuleItemHandler.php
├── include/ # File di inclusione
│ ├── common.php
│ └── functions.php
├── templates/ # Template Smarty
│ ├── mymodule_index.tpl
│ └── mymodule_item.tpl
├── admin/ # Area amministrazione
│ ├── index.php
│ └── menu.php
├── language/ # Traduzioni
│ └── english/
│ ├── main.php
│ └── modinfo.php
├── sql/ # Schema del database
│ └── mysql.sql
├── xoops_version.php # Info sul modulo
├── index.php # Entry del modulo
└── header.php # Header del modulo

Lo sviluppo moderno di XOOPS può sfruttare l’iniezione di dipendenze per una migliore testabilità.

<?php
class XoopsDependencyContainer
{
private array $services = [];
public function register(string $name, callable $factory): void
{
$this->services[$name] = $factory;
}
public function resolve(string $name): mixed
{
if (!isset($this->services[$name])) {
throw new \InvalidArgumentException("Service not found: $name");
}
$factory = $this->services[$name];
if (is_callable($factory)) {
return $factory($this);
}
return $factory;
}
public function has(string $name): bool
{
return isset($this->services[$name]);
}
}
<?php
namespace Xmf\Di;
use Psr\Container\ContainerInterface;
class BasicContainer implements ContainerInterface
{
protected array $definitions = [];
public function set(string $id, mixed $value): void
{
$this->definitions[$id] = $value;
}
public function get(string $id): mixed
{
if (!$this->has($id)) {
throw new \InvalidArgumentException("Service not found: $id");
}
$entry = $this->definitions[$id];
if (is_callable($entry)) {
return $entry($this);
}
return $entry;
}
public function has(string $id): bool
{
return isset($this->definitions[$id]);
}
}
<?php
// Registrazione del servizio
$container = new XoopsDependencyContainer();
$container->register('database', function () {
return XoopsDatabaseFactory::getDatabaseConnection();
});
$container->register('userHandler', function ($c) {
return new XoopsUserHandler($c->resolve('database'));
});
// Risoluzione del servizio
$userHandler = $container->resolve('userHandler');
$user = $userHandler->get($userId);

XOOPS fornisce diversi meccanismi di estensione:

I Preload consentono ai moduli di agganciarsi agli eventi principali.

modules/mymodule/preloads/core.php
<?php
class MymoduleCorePreload extends XoopsPreloadItem
{
public static function eventCoreHeaderEnd($args)
{
// Esegui quando l'elaborazione dell'header termina
}
public static function eventCoreFooterStart($args)
{
// Esegui quando il rendering del footer inizia
}
}

I Plugin estendono funzionalità specifiche all’interno dei moduli.

modules/mymodule/plugins/notify.php
<?php
class MymoduleNotifyPlugin
{
public function onItemCreate($item)
{
// Inviare una notifica quando l'elemento viene creato
}
}

I filtri modificano i dati mentre passano attraverso il sistema.

<?php
// Esempio di filtro dei contenuti
$myts = MyTextSanitizer::getInstance();
$content = $myts->displayTarea($rawContent, 1, 1, 1);
  1. Usare gli spazi dei nomi per il nuovo codice:

    namespace XoopsModules\MyModule;
    class Item extends \XoopsObject
    {
    // Implementazione
    }
  2. Seguire l’autoloading PSR-4:

    {
    "autoload": {
    "psr-4": {
    "XoopsModules\\MyModule\\": "class/"
    }
    }
    }
  3. Separare i compiti:

    • Logica di dominio in class/
    • Presentazione in templates/
    • Controller nella radice del modulo
  1. Usare la cache per operazioni costose
  2. Caricare in modo pigro le risorse quando possibile
  3. Minimizzare le query al database usando batch di criteria
  4. Ottimizzare i template evitando logica complessa
  1. Convalidare tutto l’input usando Xmf\Request
  2. Escapare l’output nei template
  3. Usare dichiarazioni preparate per le query al database
  4. Controllare i permessi prima delle operazioni sensibili

#xoops #architettura #core #design #system-design