XOOPS 4.0 Architecture Diagrams
Visual representations of the Clean Architecture patterns used in XOOPS 4.0 modules.
Overview: Clean Architecture Layers
Section titled “Overview: Clean Architecture Layers”graph TB subgraph External["External World"] Browser["🌐 Browser"] API["📡 API Client"] CLI["💻 CLI"] end
subgraph Presentation["Presentation Layer"] Controllers["Controllers"] Templates["Smarty Templates"] APIControllers["API Controllers"] end
subgraph Application["Application Layer"] Commands["Commands"] Queries["Queries"] Handlers["Handlers"] end
subgraph Domain["Domain Layer (Core)"] Entities["Entities"] ValueObjects["Value Objects"] RepoInterfaces["Repository Interfaces"] DomainServices["Domain Services"] Exceptions["Domain Exceptions"] end
subgraph Infrastructure["Infrastructure Layer"] Repositories["MySQL Repositories"] XoopsIntegration["XOOPS Integration"] Container["DI Container"] end
subgraph External2["External Systems"] Database[("MySQL Database")] XoopsCore["XOOPS Core"] end
Browser --> Controllers API --> APIControllers CLI --> Handlers
Controllers --> Commands Controllers --> Queries APIControllers --> Commands APIControllers --> Queries
Commands --> Handlers Queries --> Handlers Handlers --> Entities Handlers --> ValueObjects Handlers --> RepoInterfaces
RepoInterfaces -.->|implemented by| Repositories Repositories --> Database XoopsIntegration --> XoopsCore Container --> Repositories Container --> Handlers
classDef domain fill:#e1f5fe,stroke:#01579b classDef application fill:#fff3e0,stroke:#e65100 classDef infrastructure fill:#f3e5f5,stroke:#7b1fa2 classDef presentation fill:#e8f5e9,stroke:#2e7d32 classDef external fill:#fce4ec,stroke:#c2185b
class Entities,ValueObjects,RepoInterfaces,DomainServices,Exceptions domain class Commands,Queries,Handlers application class Repositories,XoopsIntegration,Container infrastructure class Controllers,Templates,APIControllers presentation class Browser,API,CLI,Database,XoopsCore externalHTTP Request Flow
Section titled “HTTP Request Flow”sequenceDiagram autonumber participant B as Browser participant C as Controller participant H as CommandHandler participant E as Entity participant R as Repository participant DB as MySQL
B->>C: POST /articles (title, content) C->>C: Validate request C->>H: CreateArticleCommand
H->>H: Create Value Objects Note over H: ArticleTitle::create()<br/>ArticleContent::create()
H->>E: Article::create() Note over E: Generate ULID<br/>Set initial status
H->>R: save(article) R->>DB: INSERT INTO articles... DB-->>R: Success
R-->>H: void H-->>C: Article entity C->>C: Format response C-->>B: 201 Created + JSONCommand/Query Separation (CQRS)
Section titled “Command/Query Separation (CQRS)”flowchart LR subgraph Write["Write Side (Commands)"] CC[CreateArticleCommand] UC[UpdateArticleCommand] DC[DeleteArticleCommand]
CH[CreateArticleHandler] UH[UpdateArticleHandler] DH[DeleteArticleHandler]
CC --> CH UC --> UH DC --> DH end
subgraph Read["Read Side (Queries)"] GQ[GetArticleQuery] LQ[ListArticlesQuery] SQ[SearchArticlesQuery]
GH[GetArticleHandler] LH[ListArticlesHandler] SH[SearchArticlesHandler]
GQ --> GH LQ --> LH SQ --> SH end
subgraph Domain["Domain Model"] E[Article Entity] R[Repository Interface] end
CH --> E UH --> E DH --> R
GH --> R LH --> R SH --> R
style Write fill:#ffecb3 style Read fill:#e3f2fd style Domain fill:#e8f5e9Entity Lifecycle
Section titled “Entity Lifecycle”stateDiagram-v2 [*] --> Draft: Article::create()
Draft --> Published: publish() Draft --> Archived: archive()
Published --> Archived: archive()
Archived --> Draft: restore()
note right of Draft Initial state Can edit content end note
note right of Published Visible to public Limited editing end note
note right of Archived Hidden from public Can be restored end noteValue Object Validation Flow
Section titled “Value Object Validation Flow”flowchart TD Input["Raw Input String"]
subgraph Validation["Value Object Creation"] Trim["trim(input)"] CheckMin{"length >= MIN?"} CheckMax{"length <= MAX?"} Create["new ArticleTitle(value)"] end
subgraph Exceptions["Domain Exceptions"] TooShort["InvalidArticleTitle::tooShort()"] TooLong["InvalidArticleTitle::tooLong()"] end
Output["Valid ArticleTitle"]
Input --> Trim Trim --> CheckMin CheckMin -->|No| TooShort CheckMin -->|Yes| CheckMax CheckMax -->|No| TooLong CheckMax -->|Yes| Create Create --> Output
TooShort --> Error["❌ Exception thrown"] TooLong --> Error
style Output fill:#c8e6c9 style Error fill:#ffcdd2Repository Pattern
Section titled “Repository Pattern”flowchart TB subgraph Application["Application Layer"] Handler["Command Handler"] end
subgraph Domain["Domain Layer"] Interface["ArticleRepositoryInterface"] Entity["Article Entity"] end
subgraph Infrastructure["Infrastructure Layer"] MySQL["MySqlArticleRepository"] InMemory["InMemoryArticleRepository"] end
subgraph Tests["Test Environment"] TestHandler["Test Handler"] end
Handler --> Interface Interface -.->|implements| MySQL Interface -.->|implements| InMemory
MySQL --> DB[("Production DB")] InMemory --> Memory["In-Memory Storage"]
TestHandler --> InMemory
style Interface stroke:#01579b,stroke-width:3px style MySQL fill:#f3e5f5 style InMemory fill:#fff3e0Dependency Injection Container
Section titled “Dependency Injection Container”flowchart TD subgraph Container["Service Container"] GetRepo["getArticleRepository()"] GetCreate["getCreateArticleHandler()"] GetUpdate["getUpdateArticleHandler()"] GetQuery["getGetArticleHandler()"] GetController["getArticleController()"] end
subgraph Services["Instantiated Services"] Repo["MySqlArticleRepository"] CreateH["CreateArticleHandler"] UpdateH["UpdateArticleHandler"] QueryH["GetArticleHandler"] Ctrl["ArticleController"] end
subgraph Deps["Dependencies"] DB["XoopsDatabase"] end
GetRepo --> Repo GetCreate --> CreateH GetUpdate --> UpdateH GetQuery --> QueryH GetController --> Ctrl
Repo -.->|needs| DB CreateH -.->|needs| Repo UpdateH -.->|needs| Repo QueryH -.->|needs| Repo Ctrl -.->|needs| CreateH Ctrl -.->|needs| UpdateH Ctrl -.->|needs| QueryHAPI Request/Response Cycle
Section titled “API Request/Response Cycle”sequenceDiagram autonumber participant Client as API Client participant Router as Router participant Auth as Auth Middleware participant Controller as API Controller participant Handler as Query Handler participant Repo as Repository
Client->>Router: GET /api/v1/articles/01HV8X... Router->>Auth: Validate JWT Token Auth->>Auth: Decode & Verify
alt Token Invalid Auth-->>Client: 401 Unauthorized end
Auth->>Controller: Authenticated Request Controller->>Controller: Validate ULID format
alt Invalid ULID Controller-->>Client: 422 Validation Error end
Controller->>Handler: GetArticleQuery(id, userId) Handler->>Repo: findById(ArticleId)
alt Not Found Repo-->>Handler: ArticleNotFound Handler-->>Controller: Exception Controller-->>Client: 404 Not Found end
Repo-->>Handler: Article Handler->>Handler: Check permissions
alt No Permission Handler-->>Controller: DomainException Controller-->>Client: 403 Forbidden end
Handler-->>Controller: Article Controller->>Controller: Format JSON response Controller-->>Client: 200 OK + JSONULID vs Auto-Increment ID
Section titled “ULID vs Auto-Increment ID”flowchart LR subgraph AutoIncrement["Auto-Increment (Legacy)"] AI1["1"] AI2["2"] AI3["3"] AI4["..."] AI1 --> AI2 --> AI3 --> AI4 end
subgraph ULID["ULID (XOOPS 4.0)"] U1["01HV8X5Z0K..."] U2["01HV8X5Z0M..."] U3["01HV8X5Z0N..."] U4["..."] U1 --> U2 --> U3 --> U4 end
subgraph Benefits["ULID Benefits"] B1["✓ Time-sortable"] B2["✓ URL-safe"] B3["✓ No collisions"] B4["✓ Better indexing"] B5["✓ Works distributed"] end
ULID --> Benefits
style AutoIncrement fill:#ffcdd2 style ULID fill:#c8e6c9 style Benefits fill:#e3f2fdModule Directory Structure
Section titled “Module Directory Structure”flowchart TD Root["modules/mymodule/"]
subgraph Domain["Domain/ (No Dependencies)"] DE["Entity/"] DV["ValueObject/"] DR["Repository/"] DX["Exception/"] end
subgraph Application["Application/ (Uses Domain)"] AC["Command/"] AQ["Query/"] end
subgraph Infrastructure["Infrastructure/ (Implements)"] IP["Persistence/"] IX["Xoops/"] IA["Api/"] end
subgraph Presentation["Presentation/ (User Interface)"] PC["Controller/"] PT["templates/"] end
Root --> Domain Root --> Application Root --> Infrastructure Root --> Presentation
Application -.->|depends on| Domain Infrastructure -.->|implements| Domain Presentation -.->|uses| Application
style Domain fill:#e1f5fe style Application fill:#fff3e0 style Infrastructure fill:#f3e5f5 style Presentation fill:#e8f5e9Exception Handling Flow
Section titled “Exception Handling Flow”flowchart TD Request["HTTP Request"]
subgraph Controller["Controller Layer"] Try["try { ... }"] Catch["catch blocks"] end
subgraph Exceptions["Exception Types"] Domain["DomainException"] NotFound["EntityNotFound"] Validation["ValidationException"] Auth["UnauthorizedException"] end
subgraph Responses["HTTP Responses"] R400["400 Bad Request"] R401["401 Unauthorized"] R404["404 Not Found"] R422["422 Unprocessable"] R500["500 Server Error"] end
Request --> Try Try --> Catch
Catch --> Domain Catch --> NotFound Catch --> Validation Catch --> Auth
Domain --> R400 NotFound --> R404 Validation --> R422 Auth --> R401
Catch -->|Unexpected| R500
style R400 fill:#fff3e0 style R401 fill:#ffcdd2 style R404 fill:#f3e5f5 style R422 fill:#fff3e0 style R500 fill:#ffcdd2Test Structure
Section titled “Test Structure”flowchart TB subgraph Unit["Unit Tests"] VO["Value Object Tests"] ET["Entity Tests"] HT["Handler Tests"] end
subgraph Fixtures["Test Fixtures"] IM["InMemory Repository"] MO["Object Mothers"] FA["Factories"] end
subgraph Integration["Integration Tests"] RT["Repository Tests"] AT["API Tests"] end
VO --> Fixtures ET --> Fixtures HT --> Fixtures
RT --> DB[("Test Database")] AT --> API["Test Server"]
style Unit fill:#e8f5e9 style Fixtures fill:#fff3e0 style Integration fill:#e3f2fdComplete Request Lifecycle
Section titled “Complete Request Lifecycle”flowchart TB subgraph External["1. External"] User["👤 User"] Browser["🌐 Browser"] end
subgraph Presentation["2. Presentation"] Route["Route Matching"] Controller["Controller"] Template["Template Rendering"] end
subgraph Application["3. Application"] Command["Command/Query"] Handler["Handler"] Validation["Input Validation"] end
subgraph Domain["4. Domain"] Entity["Entity"] VO["Value Objects"] Rules["Business Rules"] end
subgraph Infrastructure["5. Infrastructure"] Repo["Repository"] Container["DI Container"] end
subgraph Database["6. Database"] MySQL[("MySQL")] end
User -->|1| Browser Browser -->|2| Route Route -->|3| Controller Controller -->|4| Command Command -->|5| Handler Handler -->|6| Validation Validation -->|7| VO VO -->|8| Entity Entity -->|9| Rules Handler -->|10| Repo Repo -->|11| MySQL MySQL -->|12| Repo Repo -->|13| Handler Handler -->|14| Controller Controller -->|15| Template Template -->|16| Browser Browser -->|17| User
style External fill:#fce4ec style Presentation fill:#e8f5e9 style Application fill:#fff3e0 style Domain fill:#e1f5fe style Infrastructure fill:#f3e5f5 style Database fill:#fafafaRelated Documentation
Section titled “Related Documentation”- ../Tutorials/Getting-Started-with-XOOPS-4.0-Module-Development
- ../Quick-Reference-Card
- ../Implementation-Guides/CQRS-Pattern-Guide
- ../Implementation-Guides/Domain-Exception-Handling-Guide