Skip to content

XOOPS 4.0 Core Specification

This document defines the technical specification for XOOPS 4.0. Keywords MUST, SHOULD, and MAY are normative per RFC 2119.

Terminal window
php bin/xoops module:scaffold hello --level=standard

The manifest file with IDE autocompletion support via JSON Schema:

{
"$schema": "https://xoops.org/schemas/module/v1.json",
"schemaVersion": 1,
"identity": {
"slug": "hello",
"namespace": "Xoops\\Module\\Hello",
"name": "@modinfo.name",
"version": "1.0.0"
},
"requirements": {
"xoops": "^4.0",
"php": ">=8.4"
},
"routes": {
"index": {
"path": "/",
"method": ["GET"],
"action": "Controller\\IndexController::index"
}
}
}

Controllers MUST return a ResponseInterface:

namespace Xoops\Module\Hello\Controller;
use Xoops\Core\View\ViewRendererInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use Xoops\Core\Http\ApiResponse;
class IndexController
{
public function __construct(
private readonly ViewRendererInterface $view,
private readonly ApiResponse $response
) {}
public function index(ServerRequestInterface $request): ResponseInterface
{
$html = $this->view->render('@modules/hello/index', [
'name' => $request->getAttribute('name', 'World')
]);
return $this->response->html($html);
}
}

The Core processes requests via a PSR-15 Middleware Pipeline:

flowchart TB
Request["📥 HTTP Request (PSR-7)"]
Kernel["⚙️ Kernel"]
Middleware["🔒 Middleware Stack<br/>• Security<br/>• CSRF<br/>• RateLimit<br/>• Session"]
Router["🔀 Router"]
Controller["🎮 Controller"]
Response["📤 Response (PSR-7)"]
Request --> Kernel
Kernel --> Middleware
Middleware --> Router
Router --> Controller
Controller --> Response
style Request fill:#e3f2fd,stroke:#1976d2
style Kernel fill:#fff3e0,stroke:#f57c00
style Middleware fill:#fce4ec,stroke:#c2185b
style Router fill:#f3e5f5,stroke:#7b1fa2
style Controller fill:#e8f5e9,stroke:#388e3c
style Response fill:#e3f2fd,stroke:#1976d2

Modules MUST NOT depend on specific routing library internals:

interface RouteMatchInterface {
public function getName(): ?string;
public function getParams(): array;
public function getModuleSlug(): ?string;
}

Limits queryF() usage and toggles via XOOPS_SECURITY_LEVEL:

  • Contract: queryF() calls MUST be wrapped in a $db->unsafe() closure in strict mode
  • Re-entrancy: The unsafe() wrapper MUST be re-entrant and restore previous state even if callback throws
ConceptDescription
Canonical Typeblog.post (Immutable identifier)
Alias RegistryMaps old types to new handlers
RegistrationModules register types/aliases
FinalizationCore validates (no cycles, all canonicals exist)

JSON manifests are compiled to PHP arrays:

  • Hash Strategy: Compiler MUST use fast non-cryptographic hash (xxh3/xxh128) if available, falling back to sha256
  • Schema Stability: $schema URLs MUST be versioned and immutable
Path TypeDescriptionExample
List PathArray where order mattersadmin.menu, assets.css
Object PathObject with named keysroutes, config
Path TypeInputBehaviorValidation (Strict)
List Path[]Clears ListValid
List Path{}ErrorFatal
Object Path{}No-opValid
Object Path[]ErrorFatal
ModeBehavior
MergeDeep merge objects, replace indexed arrays
AppendAdd to end
UniqueBase + Override, dedupe (first occurrence wins)
ReplaceOverwrite entire node

Search providers MUST return a PermissionHint for efficient Core evaluation.

Policies MUST return cache key components composed ONLY of:

  • null
  • bool
  • int
  • string
  • array of these types

Rules:

  • Core MUST sort associative arrays recursively
  • Indexed arrays MUST preserve order
  • Floats are forbidden (use strings for precision)

Solves the “Pagination Trap” using Bounded Overfetch strategy:

Query
├──► Provider A ──► Top N Results ──┐
│ │
├──► Provider B ──► Top N Results ──┼──► Sort Global ──► Slice Page ──► Results
│ │
└──► Provider C ──► Top N Results ──┘

Providers MUST return:

  • isTotalExact (bool): True if count is not estimated
  • wasCapped (bool): True if internal budget limit was hit

isPageAccurate is TRUE if and only if:

  1. No provider asserted an error
  2. For every provider: fetchedCount >= requestedCount OR providerExhausted = true
  3. requestedCount is defined as min(providerCap, limit + offset)

isTotalAccurate is TRUE if and only if all(providers.isTotalExact) AND no_errors

Precedence Order (highest to lowest):

  1. Theme
  2. Site
  3. Module Locale
  4. Module Fallback (en)

Collision Rule: Higher precedence layer wins

interface ViewRendererInterface {
public function render(string $template, array $data = []): string;
}

Implementations:

  • Smarty (Default)
  • Twig (Optional)

Contract for Admin Dashboard and Blocks:

interface WidgetProviderInterface {
public function render(WidgetContext $ctx): string;
public function getCacheTtl(): int;
/** MUST return scalar/array-of-scalar components */
public function getCacheKeyComponents(WidgetContext $ctx): array;
/** MAY return events that trigger namespace invalidation */
public function getInvalidationEvents(): array;
}

Normalization Rules:

  • Namespace MUST match [a-z0-9._:-]{1,64}
  • Key MUST be hashed (preferred xxh3, fallback sha256) and encoded as lowercase hex

Safety Mechanisms:

  • Null Safety: Uses internal NULL_SENTINEL
  • Miss Detection: Single-round-trip get($key, $sentinel)
ConceptInterfaceKey Method
RoutingRouteMatchInterfacegetParams(): array
ViewsViewRendererInterfacerender(string $tpl, array $data)
SearchSearchProviderInterfacesearch(Query $q, Context $c)
CacheVersionedCacheremember(string $ns, string $k, callable $f)
WidgetsWidgetProviderInterfacegetCacheKeyComponents(Context $c)
DecisionContextRationale
Sentinel CacheNeed to cache nullUnique object allows single-round-trip reads
Hex Hash KeysBackend limitsBinary strings cause issues in Redis drivers
Bounded SearchFederated pagination costPrioritizes top results/performance
Immutable EntitiesModule renamesRewriting DB references is risky
Path-Based MergeAmbiguity of []assets.css: [] intuitively means “clear”
  • XOOPS 4.0 Roadmap
  • Architecture Vision
  • PSR Standards Overview
  • Migration Guide

#xoops-4.0 #specification #architecture #psr-standards #technical