Pular para o conteúdo

Arquitetura XOOPS

Este documento fornece uma visão geral abrangente da arquitetura do sistema XOOPS, explicando como os vários componentes funcionam juntos para criar um sistema de gerenciamento de conteúdo flexível e extensível.

O XOOPS segue uma arquitetura modular que separa as preocupações em camadas distintas. O sistema é construído em torno de vários princípios principais:

  • Modularidade: A funcionalidade é organizada em módulos independentes e instaláveis
  • Extensibilidade: O sistema pode ser estendido sem modificar o código principal
  • Abstração: As camadas de banco de dados e apresentação são abstraídas da lógica de negócio
  • Segurança: Mecanismos de segurança integrados protegem contra vulnerabilidades comuns
graph TB
subgraph Presentation["🎨 Camada de Apresentação"]
Themes["Temas"]
Templates["Templates Smarty"]
Blocks["Blocos"]
end
subgraph Application["⚙️ Camada de Aplicação"]
Modules["Módulos"]
Preloads["Preloads"]
Controllers["Controladores"]
BlockHandlers["Manipuladores de Blocos"]
end
subgraph Domain["📦 Camada de Domínio"]
XoopsObject["XoopsObject"]
Handlers["Manipuladores de Objetos"]
Criteria["Sistema de Critérios"]
end
subgraph Infrastructure["🔧 Camada de Infraestrutura"]
Database["XoopsDatabase"]
Cache["Sistema de Cache"]
Session["Gerenciador de Sessão"]
Security["Camada de Segurança"]
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

A camada de apresentação lida com a renderização da interface do usuário usando o mecanismo de templates Smarty.

Componentes Principais:

  • Temas: Estilo visual e layout
  • Templates Smarty: Renderização de conteúdo dinâmico
  • Blocos: Widgets de conteúdo reutilizáveis

A camada de aplicação contém a lógica de negócio, controladores e funcionalidade do módulo.

Componentes Principais:

  • Módulos: Pacotes de funcionalidade independentes
  • Manipuladores: Classes de manipulação de dados
  • Preloads: Ouvintes de eventos e ganchos

A camada de domínio contém objetos de negócio principais e regras.

Componentes Principais:

  • XoopsObject: Classe base para todos os objetos de domínio
  • Manipuladores: Operações CRUD para objetos de domínio

A camada de infraestrutura fornece serviços principais como acesso a banco de dados e cache.

Entender o ciclo de vida da requisição é crucial para o desenvolvimento eficaz do XOOPS.

O XOOPS 2.5.x atual usa um padrão Page Controller onde cada arquivo PHP lida com sua própria requisição. As globais ($xoopsDB, $xoopsUser, $xoopsTpl, etc.) são inicializadas durante o bootstrap e disponíveis em toda a execução.

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 de Bootstrap (mainfile.php)
Entry->>Main: include mainfile.php
Main->>Kernel: Inicializar Core
Kernel->>DB: Criar XoopsDatabase (singleton)
Kernel->>User: Carregar Sessão → $xoopsUser
Kernel->>Tpl: Inicializar Smarty → $xoopsTpl
Main-->>Entry: Globais Prontas
end
rect rgb(255, 250, 240)
Note over Entry,Handler: Execução do Controlador de Página
Entry->>Handler: xoops_getModuleHandler('myobject')
Handler->>DB: consultar via Critérios
DB-->>Handler: Conjunto de Resultados
Handler-->>Entry: XoopsObject[]
end
rect rgb(240, 255, 240)
Note over Entry,Theme: Fase de Renderização
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: Página HTML Completa
end
GlobalTipoInicializadoPropósito
$xoopsDBXoopsDatabaseBootstrapConexão com banco de dados (singleton)
$xoopsUserXoopsUser|nullCarregamento de sessãoUsuário atualmente conectado
$xoopsTplXoopsTplInicialização de templateMecanismo de templates Smarty
$xoopsModuleXoopsModuleCarregamento de móduloContexto do módulo atual
$xoopsConfigarrayCarregamento de configuraçãoConfiguração do sistema
// mainfile.php é o ponto de entrada
include_once XOOPS_ROOT_PATH . '/mainfile.php';
// Inicialização do core
$xoops = Xoops::getInstance();
$xoops->boot();

Passos:

  1. Carregar configuração (mainfile.php)
  2. Inicializar autoloader
  3. Configurar tratamento de erros
  4. Estabelecer conexão com banco de dados
  5. Carregar sessão do usuário
  6. Inicializar mecanismo de templates Smarty
// Roteamento de requisição para módulo apropriado
$module = $GLOBALS['xoopsModule'];
$controller = $module->getController();
$controller->dispatch($request);

Passos:

  1. Analisar URL da requisição
  2. Identificar módulo alvo
  3. Carregar configuração do módulo
  4. Verificar permissões
  5. Rotear para manipulador apropriado
// Execução do controlador
$data = $handler->getObjects($criteria);
$xoopsTpl->assign('items', $data);

Passos:

  1. Executar lógica do controlador
  2. Interagir com a camada de dados
  3. Processar regras de negócio
  4. Preparar dados da visualização
// Renderização de template
include XOOPS_ROOT_PATH . '/header.php';
$xoopsTpl->display('db:module_template.tpl');
include XOOPS_ROOT_PATH . '/footer.php';

Passos:

  1. Aplicar layout do tema
  2. Renderizar template do módulo
  3. Processar blocos
  4. Gerar resposta

A classe base para todos os objetos de dados no 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);
}
}

Métodos Principais:

  • initVar() - Definir propriedades do objeto
  • getVar() - Recuperar valores de propriedade
  • setVar() - Definir valores de propriedade
  • assignVars() - Atribuição em massa a partir de array

Lida com operações CRUD para instâncias de 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);
}
}

Métodos Principais:

  • create() - Criar nova instância de objeto
  • get() - Recuperar objeto por ID
  • insert() - Salvar objeto no banco de dados
  • delete() - Remover objeto do banco de dados
  • getObjects() - Recuperar múltiplos objetos
  • getCount() - Contar objetos correspondentes

Cada módulo XOOPS segue uma estrutura de diretório padrão:

modules/mymodule/
├── class/ # Classes PHP
│ ├── MyModuleItem.php
│ └── MyModuleItemHandler.php
├── include/ # Arquivos de inclusão
│ ├── common.php
│ └── functions.php
├── templates/ # Templates Smarty
│ ├── mymodule_index.tpl
│ └── mymodule_item.tpl
├── admin/ # Área de administrador
│ ├── index.php
│ └── menu.php
├── language/ # Traduções
│ └── english/
│ ├── main.php
│ └── modinfo.php
├── sql/ # Esquema de banco de dados
│ └── mysql.sql
├── xoops_version.php # Informações do módulo
├── index.php # Entrada do módulo
└── header.php # Cabeçalho do módulo

O desenvolvimento moderno do XOOPS pode aproveitar a injeção de dependência para melhor testabilidade.

<?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
// Registro de serviço
$container = new XoopsDependencyContainer();
$container->register('database', function () {
return XoopsDatabaseFactory::getDatabaseConnection();
});
$container->register('userHandler', function ($c) {
return new XoopsUserHandler($c->resolve('database'));
});
// Resolução de serviço
$userHandler = $container->resolve('userHandler');
$user = $userHandler->get($userId);

O XOOPS fornece vários mecanismos de extensão:

Os preloads permitem que os módulos se conectem a eventos principais.

modules/mymodule/preloads/core.php
<?php
class MymoduleCorePreload extends XoopsPreloadItem
{
public static function eventCoreHeaderEnd($args)
{
// Executar quando o processamento do cabeçalho termina
}
public static function eventCoreFooterStart($args)
{
// Executar quando o processamento do rodapé começa
}
}

Os plugins estendem funcionalidades específicas dentro dos módulos.

modules/mymodule/plugins/notify.php
<?php
class MymoduleNotifyPlugin
{
public function onItemCreate($item)
{
// Enviar notificação quando item é criado
}
}

Os filtros modificam dados conforme passam pelo sistema.

<?php
// Exemplo de filtro de conteúdo
$myts = MyTextSanitizer::getInstance();
$content = $myts->displayTarea($rawContent, 1, 1, 1);
  1. Use namespaces para novo código:

    namespace XoopsModules\MyModule;
    class Item extends \XoopsObject
    {
    // Implementação
    }
  2. Siga autoload PSR-4:

    {
    "autoload": {
    "psr-4": {
    "XoopsModules\\MyModule\\": "class/"
    }
    }
    }
  3. Separe responsabilidades:

    • Lógica de domínio em class/
    • Apresentação em templates/
    • Controladores na raiz do módulo
  1. Use cache para operações custosas
  2. Carregue lazy recursos quando possível
  3. Minimize consultas ao banco de dados usando lote de critérios
  4. Otimize templates evitando lógica complexa
  1. Valide toda entrada usando Xmf\Request
  2. Escape output em templates
  3. Use prepared statements para consultas ao banco de dados
  4. Verifique permissões antes de operações sensíveis

#xoops #arquitetura #core #design #system-design