232 lines
10 KiB
Markdown
232 lines
10 KiB
Markdown
# 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*
|