Files
2026-02-04 01:06:15 +01:00

10 KiB

Architecture

Analysis Date: 2026-02-04

Pattern Overview

Overall: Modular Layer-based MVC with Plugin System

WinterCMS implements a three-layer modular architecture consisting of Core Modules (System, Backend, CMS) that form the framework foundation, with a Plugin system overlaid for extensibility. The framework uses Laravel 9.x as its base, with Winter's Storm library acting as a compatibility buffer.

Key Characteristics:

  • Laravel-based HTTP kernel with module-level routing
  • CMS-first approach: frontend pages route through CMS module, backend admin routes through Backend module
  • Plugin dependency resolution with automatic component/controller/model discovery
  • Extensibility through plugin interdependencies and event-driven architecture
  • YAML/JSON configuration for models, forms, lists, and behaviors
  • Static theme system with file-based page, layout, and partial management

Layers

Core Modules (modules/ directory):

  • System Module: Base framework, plugin management, mail system, asset handling, error management
  • Backend Module: Admin interface, form/list widgets, user role management, controller behaviors
  • CMS Module: Frontend page rendering, theme management, component system, layout composition

Plugin Layer (plugins/ directory):

  • Vendor-namespaced plugins (winter/, golem15/)
  • Each plugin extends and integrates with core modules
  • Plugin dependencies declared via $require arrays in Plugin.php
  • Core plugins: Apparatus (DI/scenarios), User (auth), PaymentGateway (commerce)
  • Domain plugins: Blog, Menu, Translate, AI, Chat, etc.

Frontend/Theme Layer (themes/ directory):

  • Static theme files organized in theme directories
  • Pages, layouts, partials stored as .htm files with Twig syntax
  • Assets (CSS, JS, images) co-located with pages/layouts
  • URL routing to pages via Theme manager and CMS controller

Data Flow

Frontend Request (Page View):

  1. HTTP request to any URL arrives at index.php
  2. Bootstrap loads application (bootstrap/app.php)
  3. HTTP Kernel processes request through middleware
  4. Laravel Router evaluates all registered routes
  5. Backend/System routes handled by their controllers
  6. CMS module catch-all route {slug?} routes to Cms\Classes\CmsController@run()
  7. CMS Controller delegates to Cms\Classes\Controller (primary frontend controller)
  8. Primary Controller:
    • Looks up URL in Theme using Cms\Classes\Router
    • Resolves Page, Layout, and Component objects from theme files
    • Renders page through Twig template engine
    • Components injected into page output via ComponentManager
  9. Response sent back to client

Backend Request (Admin Interface):

  1. HTTP request to /backend/... arrives
  2. Backend Router matches Backend\Classes\BackendController@run()
  3. BackendController parses remaining URL segments to determine target plugin/controller
  4. Controller loaded from plugin (e.g., Golem15\Blog\Controllers\Posts)
  5. Controller action determined by remaining URL parts
  6. Behaviors attached (FormController, ListController, etc.) handle CRUD operations
  7. Views rendered with form/list widgets
  8. JSON/HTML response returned

Component Lifecycle:

  1. Page YAML/Twig specifies component code ({% component 'componentName' %})
  2. ComponentManager resolves code to fully-qualified class name via codeMap
  3. Component class instantiated with properties from page markup
  4. Component's onRun() method called by page renderer
  5. Component renders its partial template (HTM file) in page context
  6. AJAX handlers on component (e.g., onUpdateCart) handled by Snowboard framework

State Management:

  • Models: Database-backed via Winter\Storm\Database\Model (extends Laravel Eloquent)
  • Sessions: Laravel session middleware, stored in storage/framework/sessions/
  • Cache: Laravel cache (configurable drivers: file, redis, memcached)
  • Parameters: System\Models\Parameter table for application-level configuration
  • Translation: Text keys cached in parameters, loaded by Translate plugin

Key Abstractions

Plugin Architecture:

Purpose: Enables modular, independently-deployable features with dependency resolution

  • Each plugin is a Laravel ServiceProvider extending System\Classes\PluginBase
  • Plugin.php declares: pluginDetails(), register(), boot(), registerComponents(), registerControllers(), etc.
  • Examples: golem15-wintercms-starter/plugins/golem15/blog/Plugin.php, golem15-wintercms-starter/plugins/golem15/user/Plugin.php
  • Pattern: Plugins register services, components, controllers, and extend existing models

Component System:

Purpose: Reusable, composable page elements with their own controllers and views

  • Components extend Cms\Classes\ComponentBase
  • Register in plugin via registerComponents() returning [ClassName => 'code']
  • ComponentManager loads all registered components into codeMap
  • Example: golem15-wintercms-starter/modules/cms/components/SoftComponent.php
  • Pattern: Component renders partial, handles AJAX, injects CSS/JS

Theme/Page System:

Purpose: File-based, non-database-backed content management

  • Theme directory contains pages/, layouts/, partials/ subdirectories
  • Page class Cms\Classes\Page extends CmsCompoundObject - represents page file as object
  • Page file format: URL metadata → YAML → Twig markup
  • Page references layout (inherited structure) and components (functional blocks)
  • Example page structure: themes/demo/pages/home.htm
  • Pattern: Page objects loaded on-demand from disk, cached in memory

Backend Form/List System:

Purpose: YAML-driven admin CRUD interfaces

  • Controllers use FormController and ListController behaviors
  • forms.yaml/fields.yaml define form structure and validation
  • lists.yaml/columns.yaml define table columns and filtering
  • FormController handles create/read/update/delete operations
  • Example files: plugins/*/models/*/fields.yaml, plugins/*/models/*/columns.yaml
  • Pattern: Behaviors parse YAML and generate HTML forms/tables dynamically

Service Providers & Dependency Injection:

Purpose: Central registration of services and extensibility hooks

  • Plugins register services in register() and boot() methods
  • Services bound to Laravel's DI container via $this->app->singleton()
  • Example: Apparatus framework registers DI container for component auto-wiring
  • Pattern: Late binding allows plugin A to extend plugin B's services

Entry Points

Frontend (CMS Page Serving):

  • Location: golem15-wintercms-starter/modules/cms/classes/CmsController.php (HTTP entry), golem15-wintercms-starter/modules/cms/classes/Controller.php (business logic)
  • Triggers: Any URL not matching backend or other routes
  • Responsibilities:
    • Routes URL to page via Theme manager
    • Loads Page, Layout, and Components
    • Renders through Twig with component injection
    • Returns HTML response

Backend (Admin Interface):

  • Location: golem15-wintercms-starter/modules/backend/classes/BackendController.php
  • Triggers: URLs prefixed with /backend/
  • Responsibilities:
    • Parses plugin.controller.action URL pattern
    • Instantiates controller from plugin
    • Applies middleware and behaviors
    • Routes to controller action
    • Renders admin interface

System Initialization:

  • Location: golem15-wintercms-starter/bootstrap/app.php, golem15-wintercms-starter/index.php
  • Triggers: Every HTTP request
  • Responsibilities:
    • Creates Laravel application instance
    • Binds kernel, console kernel, exception handler
    • Loads plugin manager and auto-discovers plugins
    • Registers module routes

CLI Commands:

  • Location: golem15-wintercms-starter/artisan (entry point), golem15-wintercms-starter/modules/*/console/ (command classes)
  • Triggers: php artisan <command>
  • Responsibilities:
    • Plugin scaffold commands
    • Database migrations
    • Asset management
    • Cache management
    • Payment gateway operations (via golem15/paymentgateway)

Error Handling

Strategy: Exception-driven with error page rendering

Patterns:

  • All exceptions thrown as SystemException, ApplicationException, or Framework exceptions
  • HTTP exceptions converted to error pages by Exception Handler (modules/system/classes/ErrorHandler.php)
  • In production: Shows generic error page, logs details
  • In debug mode: Shows full stack trace and context
  • Model validation: Throws ApplicationException with validation messages
  • Frontend: 404 errors trigger Page not found response
  • Backend: 404 errors redirect to backend dashboard, show toast notifications

Cross-Cutting Concerns

Logging:

  • Uses Laravel's log facade (Log::info(), Log::error())
  • Stored in storage/logs/
  • Configured in config/app.php and environment variables
  • EventLog model (modules/system/models/EventLog.php) tracks application events
  • RequestLog model tracks HTTP requests for debugging

Validation:

  • Model-level via $rules property (Laravel validation rules)
  • Form widget validation via fields.yaml validation property
  • Backend behaviors apply validation before save
  • Errors returned as JSON validation responses in AJAX handlers

Authentication:

  • Winter Backend: Database-backed user with role-based access control
  • Frontend API: JWT tokens (via golem15/user plugin)
  • Middleware: Backend\Middleware\AuthenticateBackend, User\Middleware\JwtAuth
  • Guards: web (session-based), api (JWT)

Extensibility Mechanisms

Model Extension:

  • Plugins extend models dynamically using Model::extend(Closure)
  • Example: User::extend(function($model) { $model->hasMany['payments'] = ...; })
  • Used for adding relationships, attributes, query scopes without modifying core

Event System:

  • Global events via Event::listen() and Event::fire()
  • Module-level events: system.route, cms.beforeRoute, cms.route, backend.beforeRoute
  • Model events: model.saveInternal, model.afterCreate, model.afterUpdate, model.afterDelete
  • Custom events fired by plugins for extensibility

Behaviors:

  • Controllers implement behaviors via $implement array
  • Backend behaviors: FormController, ListController, RelationController, ImportExportController
  • Each behavior adds methods (e.g., create, update, index) to controller
  • Example: modules/backend/behaviors/FormController.php

Architecture analysis: 2026-02-04