Sukarix is an open-source modern PHP framework built to empower developers by facilitating rapid development of web and CLI applications with a focus on simplicity and efficiency. Born out of the need for a streamlined, performance-oriented framework, Sukarix builds on top of the Fat-Free Framework to offer a solid foundation that is both lightweight and feature-rich.
Introduction
Philosophy
Sukarix Framework embraces a philosophy built on principles designed to enhance your development process and deliver robust, scalable applications. Here’s what defines our approach:
-
Lean yet Robust
- Powered with F3 (Fat-Free Framework): While F3 provides a lightweight core, Sukarix builds on this foundation, adding just the right amount of structure and modern features to deliver a robust, feature-rich experience without overwhelming complexity.
-
Proven Expertise
- Real world experience: Sukarix has been rigorously tested in production environments from 2016 to 2024, covering a wide range of applications including CLI tools, web apps, React applications, APIs, middleware, and reverse proxy apps. This extensive testing under diverse conditions demonstrates the framework’s reliability and versatility, ensuring its readiness for public release in 2024.
-
Stability Over PHP Versions
- Minimalistic upgrades: Sukarix is designed to ensure stability across different PHP versions with minimal changes required. The framework is built in such a way that upgrading your PHP version typically requires no adjustments to the framework itself, simplifying maintenance and ensuring long-term compatibility.
-
Rich in features
- Best-in-Class Libraries: Sukarix incorporates the best PHP libraries available from the open-source community, offering enterprise-level features that meet the demands of complex business applications.
-
Efficiency first
- Simplicity and Performance: When multiple approaches exist for a feature, we prioritise using the Fat-Free Framework’s methods for their proven efficiency. Features are designed and continually refined to ensure the most performant outcomes while maintaining simplicity.
-
Flexibility in approach
- Multiple ways to succeed: While Sukarix standardises the use of the Fat-Free Framework (F3), it remains flexible, allowing developers to utilize F3’s core features, its plugins, and a range of open-source libraries to craft alternative solutions. This approach provides developers the freedom to choose or create the method that best fits the specific requirements of their projects.
-
Smart defaults
- Convention Over Configuration: Sukarix is built on the principle of “It just works!” By promoting conventions over configurations, the framework provides smart defaults that streamline development tasks, enabling developers to focus more on innovation and less on setup.
-
Testability
- Comprehensive Testing: Sukarix supports both CLI and browser-based unit testing, ensuring the reliability and
performance of applications through thorough testing. Statera is the Sukarix testing kit
built on top of the Fat-Free Framework’s
Testclass. It is a standalone, optional package — the framework itself uses it via arequire-devdependency for its own test suite. Applications can choose to use Statera or integrate any other testing framework (such as PHPUnit) as needed.
- Comprehensive Testing: Sukarix supports both CLI and browser-based unit testing, ensuring the reliability and
performance of applications through thorough testing. Statera is the Sukarix testing kit
built on top of the Fat-Free Framework’s
Features
- Intuitive Routing System: Define your routes intuitively, ensuring that your application logic is separated from the routing layer and stay human-readable.
- Powerful Templating Engine: Comes with a powerful templating engine that facilitates creating dynamic content in a clean and manageable way.
- Built-in Caching Solutions: Reduce load times and enhance application performance with advanced caching techniques.
- ORM Layer: Simplify database interactions with a robust ORM that supports a variety of database systems.
Getting Started
Starting with Sukarix is straightforward. Our documentation is designed to guide you through setting up your development environment, creating your first project, and exploring Sukarix’s capabilities. Whether you’re building a small website or a complex application, Sukarix provides all the tools you need to succeed.
Contributing
Sukarix is an open-source project and thrives on your contributions. Whether it’s fixing bugs, adding features, or improving documentation, your help is always welcome. Join our community and help shape the future of Sukarix!
The Sukarix Framework
What is Sukarix?
Sukarix is an open-source PHP framework built on top of the Fat-Free Framework (F3) designed to create enterprise-grade web and server/CLI applications. The name “Sukarix” is derived from the Arabic word “سُكَّر” (sukkar), which means sugar, symbolizing the framework’s goal to add sweetness and efficiency to the robust and lightweight Fat-Free Framework.
Purpose of Sukarix
The primary purpose of Sukarix is to provide developers with a powerful and efficient framework for building enterprise-level PHP applications. Whether you are developing web applications or server-side/command-line interface ( CLI) applications, Sukarix aims to streamline the development process by leveraging the strengths of Fat-Free Framework and enhancing it with additional features and tools for modern development needs. Sukarix seeks to combine the best available PHP libraries to build the most robust and usable PHP framework.
Why Choose Sukarix?
Stability Across PHP Upgrades
One of the key strengths of Sukarix, inherited from Fat-Free Framework, is its stability across PHP upgrades. The framework is designed to be robust and reliable, ensuring that your code remains functional and intact even as PHP evolves. This minimizes the need for extensive refactoring and reduces the risk of breaking changes during upgrades.
Robustness
Sukarix offers a robust foundation for building applications. It is designed to handle various use cases and edge scenarios gracefully, ensuring that your application remains stable and secure under different conditions. This robustness comes from years of development and real-world use, making it a trustworthy choice for enterprise applications.
Resource Efficiency
Sukarix is built to be resource-efficient. It has a minimal footprint and is optimized for performance, ensuring that it consumes fewer resources compared to heavier frameworks. This efficiency translates to faster response times and lower operational costs, making it ideal for high-performance applications.
Usability and Practicality
The Fat-Free Framework, which forms the backbone of Sukarix, boasts a well-established history of stability and performance. Over the years, it has been employed in numerous projects, showcasing its reliability and versatility. Sukarix capitalizes on this robust foundation, enhancing it with additional features to meet modern development needs.
Proven Track Record
Fat-Free Framework, the foundation of Sukarix, has a proven track record of stability and performance. It has been used in numerous projects over the years, demonstrating its reliability and versatility. Sukarix builds on this solid foundation, offering additional features and enhancements that cater to modern development needs.
Features
Introduction
Sukarix builds upon the robust and lightweight foundation of the Fat-Free Framework (F3), a micro-framework known for its efficiency and simplicity. We have retained the best features of F3 where it excels, ensuring a solid, stable, and high-performance core. At the same time, we have integrated or replaced certain components with more powerful and feature-rich libraries to make Sukarix enterprise-ready. These enhancements provide additional functionality, improve scalability, and offer a more comprehensive development experience for building complex, modern PHP applications.
Feature List
| Feature Name | F3 Native | Sukarix Replacement (Library) |
|---|---|---|
| Fast and clean template engine | Yes | - |
| Unit testing toolkit (Web UI & CLI) | Yes | Statera |
| Database-managed sessions | Yes | - |
| Markdown-to-HTML converter | Yes | - |
| Atom/RSS feed reader | Yes | - |
| Image processor | Yes | - |
| Geodata handler | Yes | - |
| On-the-fly Javascript/CSS compressor | Yes | Matthias Mullie Minify |
| OpenID (consumer) | Yes | - |
| Custom logger | Yes | Monolog |
| Basket/Shopping cart | Yes | - |
| Pingback server/consumer | Yes | - |
| Unicode-aware string functions | Yes | - |
| SMTP over SSL/TLS | Yes | F3 Mailer |
| Tools for communicating with other servers | Yes | - |
| Data Validation | Yes | Sukarix extends F3 |
| ORM | - | F3 Cortex |
| ACL | - | F3 Access |
| Multi-language | - | F3 Multilang |
| Event Dispatching | - | F3 Events |
| Messages to chat platforms | - | Sukarix Notifier (Zulip) |
| Database Migrations | - | Phinx |
| Debugging & Global Event Catching | - | Tracy |
| Cron job scheduler | - | peppeocchi/php-cron-scheduler |
| Queues | - | Sukarix (Redis) |
| Dependency Injection | - | Sukarix |
| Inversion of Control | - | Sukarix |
| Bash tool | - | Sukarix (coming…) |
Description of Features
- Fast and clean template engine: Provides a lightweight and efficient templating system that allows for easy creation of dynamic web pages.
- Unit testing toolkit (Web UI & CLI): Integrated tools for unit testing both web interfaces and command-line
interfaces, ensuring comprehensive code coverage and reliability. Statera is the Sukarix
testing kit built on top of the Fat-Free Framework’s
Testclass. It is an optional, standalone package — the framework itself uses it viarequire-devfor its own test suite. - Database-managed sessions: Manages user sessions through the database, enhancing security and scalability.
- Markdown-to-HTML converter: Converts Markdown syntax into HTML, facilitating easy content creation and management.
- Atom/RSS feed reader: Parses and reads Atom and RSS feeds, allowing for integration with external content sources.
- Image processor: Handles image manipulation tasks such as resizing, cropping, and format conversion.
- Geodata handler: Manages geographical data, enabling features such as location-based services and mapping.
- On-the-fly Javascript/CSS compressor: Minifies JavaScript and CSS files on the fly to improve page load times and performance.
- OpenID (consumer): Supports OpenID authentication, allowing users to log in using their existing OpenID accounts.
- Custom logger: Enhanced logging capabilities using Monolog, providing flexible and powerful logging options.
- Basket/Shopping cart: Manages e-commerce functionalities such as shopping carts and order processing.
- Pingback server/consumer: Implements pingback functionality for communication between blogs and websites.
- Unicode-aware string functions: Handles string operations with full Unicode support, ensuring compatibility with multiple languages and character sets.
- SMTP over SSL/TLS: Securely sends emails using SMTP with SSL/TLS encryption, enhancing email security.
- Tools for communicating with other servers: Provides utilities for making HTTP requests and interacting with external APIs.
- Data Validation: Sukarix extends F3 to validate input data, ensuring it meets specified rules and constraints before processing.
- ORM: Uses F3 Cortex for object-relational mapping, simplifying database interactions.
- ACL: Manages access control using F3 Access, enforcing permissions and roles.
- Multi-language: Supports multiple languages using F3 Multilang, allowing for easy localisation of content and routes.
- Event Dispatching: Handles event management using F3 Events, allowing for flexible and decoupled event-driven architecture.
- Messages to chat platforms: Sends notifications to Zulip chat streams using the Sukarix Notifier, which uses F3’s
Webclass for HTTP requests — no external notification library required. - Database Migrations: Manages database schema changes using Phinx, ensuring smooth and controlled migrations.
- Debugging & Global Event Catching: Utilizes Tracy for debugging and catching global events, providing detailed error reports and insights.
- Cron job scheduler: Schedules and manages cron jobs using peppeocchi/php-cron-scheduler, automating repetitive tasks.
- Queues: A Redis-backed FIFO queue service with deduplication and per-item attempt tracking, for passing work between the stages of a pipeline.
- Dependency Injection: Facilitates dependency management using Sukarix’s own DI container, promoting loose coupling and testability.
- Inversion of Control: Implements IoC using Sukarix, ensuring modular and maintainable code.
- Bash tool: A forthcoming feature in Sukarix for creating and managing bash scripts, enhancing CLI capabilities.
Understanding Fat-Free Framework
Introduction
Fat-Free Framework (F3) is a powerful yet lightweight PHP framework designed to help developers build dynamic web applications quickly and efficiently. One of the core concepts in F3 is the “Hive,” which is a centralized place where the framework stores and manages all application data.
The Hive and F3 Class
The Hive
The Hive is a key-value store that acts as the central repository for all configuration settings, routing information, session data, and more. It is accessible throughout the application, making it easy to manage and retrieve necessary data from anywhere in your code.
The F3 Class
The F3 class is a singleton, meaning there is only one instance of this class throughout the application’s lifecycle.
This singleton instance is accessible from anywhere in your application, providing a consistent and centralized way to
interact with the framework’s core functionalities.
How It Works
- Initialization: When the application starts, the F3 singleton is created and the Hive is initialized with system variables and configurations.
- Routing: F3 uses the Hive to manage routes, mapping URLs to specific functions or controllers.
- Session Management: The framework uses the Hive to store and manage session data, ensuring user states are maintained across different requests.
- Configuration: All configuration settings are stored in the Hive, making it easy to adjust and retrieve settings as needed.
- Template Rendering: F3’s template engine uses the Hive to access variables and directives needed to render views dynamically.
More Resources
To dive deeper into how Fat-Free Framework works and to explore its extensive features, refer to the following resources:
User Guide
For a comprehensive understanding of F3, including installation, basic usage, and advanced features, consult the User Guide.
API Reference
The API Reference provides detailed information on all the classes, methods, and properties available in F3, making it an essential resource for developers looking to utilize the framework to its fullest potential.
System Variables
System variables are predefined variables that F3 uses to manage various aspects of the application. For a quick reference on these variables, check out the System Variables page.
Template Directives
F3’s template engine comes with a set of powerful directives that make it easy to render dynamic content. You can find a list of these directives and how to use them on the Template Directives page.
By leveraging these resources, you can gain a thorough understanding of the Fat-Free Framework and harness its full potential to build efficient, scalable, and robust PHP applications.
Instructions for a new Sukarix application
- Introduction
- Step 1: Create a new Sukarix project
- Step 2: Navigate to the project directory
- Step 3: Initialize vagrant
- Step 4: Access the Application
- Configuration Details
Introduction
To set up your Sukarix application with Vagrant follow these steps:
Step 1: Create a new Sukarix project
Run the following command to create a new Sukarix project using Composer:
composer create-project sukarix/application
Tip
Using development version
It is also possible to create a new Sukarix project using the current development version of the framework by adding
--stability=devto the command.composer create-project --stability=dev sukarix/application
Step 2: Navigate to the project directory
Once the project is created, navigate to the project directory:
cd application
Step 3: Initialize vagrant
The Sukarix project includes a Vagrant setup to help streamline the development environment. Initialize Vagrant by running:
vagrant up
This command will set up the Vagrant environment and automatically install PostgreSQL and Redis.
Step 4: Access the Application
After the Vagrant setup is complete, the application will be accessible via:
http://sukarix.test
Configuration Details
- PostgreSQL and Redis are installed by default in the current version of the Sukarix project.
- Ensure your local environment is configured to handle
.testdomains (you might need to adjust your hosts file if necessary).
Accessing the Application
After running vagrant up, you can access your application at http://sukarix.test. If you encounter issues accessing
the site, ensure your system’s hosts file includes the correct entry, typically something like:
192.168.56.100 sukarix.test
Configuration
Configuration Files
Sukarix is configured via .ini files by default, allowing for clear and manageable settings. The configuration load
order ensures that settings can be overridden based on the environment.
Configuration Load Order
-
Base Configuration:
config/classes.iniconfig/default.ini
-
Additional Configurations:
- Files listed in the
CONFIGSvariable, e.g.,smtp,notifications,upload. No need to add.iniextension. config/validation.ini(loaded only when a data validation request is initiated).
- Files listed in the
-
Environment-Specific Configuration:
config/config-<environment>.ini
-
Routing and Access Control:
config/routes.iniconfig/routes-<environment>.iniconfig/access.iniorconfig/access-cli.ini(based on environment).
Note
Dynamic reconfiguration
Configuration changes are automatically reloaded, meaning there is no need to restart any service.
Tip
Automatic .ini Extension Handling
When specifying additional configuration files in the
CONFIGSvariable, you do not need to include the.iniextension. Sukarix will automatically append.inito the file name during the loading process. For example, if you setCONFIGS=notifications,smtp,upload, Sukarix will loadconfig/notifications.ini,config/smtp.ini, andconfig/upload.ini.
Environment Overrides
Any configuration setting can be overridden in the environment-specific .ini file (config/config-<environment>.ini).
This allows for tailored configurations depending on whether the application is in development, testing, or production.
Default Configuration Example
Here is an overview of the default settings found in default.ini:
-
Global Settings:
DEBUG: Stack trace verbosity.PACKAGE: Display name in requests.LOGS: Custom log location.TEMP: Temporary folder for cache and compiled templates.UPLOADS: Directory for file uploads.UI: Paths for user interface files.LOCALES: Location of language dictionaries.ENCODING: Default character encoding.LANGUAGE: Active language.FALLBACK: Fallback language.
-
Cache and Minification:
CACHE: Cache configuration.SEED: Cache seed.MINIFY_JSandMINIFY_CSS: Toggle minification.
-
Timezone and Environment:
TZ: Timezone setting.application.environment: Current environment.log.session: Log session queries.session.table: Table for session storage.pagination.limit: Default pagination limit.template.default: Default view to render.log.keep: Log retention period.server.host: Host for command-line actions.error.channel: Error notification channel.
-
Security:
csrf.enabled: Enable or disable CSRF protection.csrf.expiry: CSRF token expiry time in seconds.
Directory Structure
Structure
Understanding the directory structure of a Sukarix application is crucial for effective development and maintenance. Below is an overview of the typical directory layout and the purpose of each directory and file.
app
├── config
│ ├── access.ini
│ ├── access-cli.ini
│ ├── classes.ini
│ ├── config-development.ini
│ ├── config-test.ini
│ ├── default.ini
│ ├── notifications.ini
│ ├── routes.ini
│ ├── routes-cli.ini
│ ├── routes-test.ini
│ ├── smtp.ini
│ ├── upload.ini
│ ├── validation.ini
├── i18n
├── src
├── templates
data
db
├── data
├── migrations
├── seeds
logs
public
├── css
├── js
├── index.php
├── minified
uploads
tmp
├── mail
test
vendor
.php-cs-fixer
phinx.yml
Directory and File Descriptions
app
This is the main application directory containing configuration files, source code, templates, and localization files.
config
Contains various configuration files for the application.
- access.ini: Defines access control rules for web applications.
- access-cli.ini: Defines access control rules for CLI applications.
- classes.ini: Configuration for class mappings and dependencies.
- config-development.ini: Configuration specific to the development environment.
- config-test.ini: Configuration specific to the test environment.
- default.ini: Default configuration settings.
- notifications.ini: Settings for notifications (e.g., email, chat integrations).
- routes.ini: Defines routes for web applications.
- routes-cli.ini: Defines routes for CLI applications.
- routes-test.ini: Defines routes for test environments.
- smtp.ini: Configuration for SMTP settings.
- upload.ini: Settings for file uploads.
- validation.ini: Configuration for data validation.
i18n
Directory for internationalization (i18n) files, containing localization strings for different languages.
src
Contains the source code for the application, including controllers, models, and other classes.
templates
Directory for template files used by the application. These are typically .phtml files that define the HTML structure
and content.
data
Directory for storing the SQLite database files.
db
Contains database-related files and directories.
- data: Directory for storing the SQLite database files.
- migrations: Directory for database migration scripts.
- seeds: Directory for database seed files.
logs
Directory for log files generated by the application.
public
The web root directory containing publicly accessible files.
- css: Directory for CSS files.
- js: Directory for JavaScript files.
- index.php: The entry point for the application.
- minified: Directory for minified JavaScript and CSS files.
uploads
Directory for user-uploaded files.
tmp
Directory for temporary files.
- mail: Directory for emails sent in development and test environments, stored as files.
- cache: Directory for cache files.
test
Directory for unit tests and testing-related files.
vendor
Directory for Composer dependencies.
.php-cs-fixer
Configuration file for PHP-CS-Fixer, a tool for automatically fixing PHP coding standards issues.
phinx.yml
Configuration file for Phinx, a PHP database migration tool.
This directory structure helps to keep your application organized and maintainable, ensuring that related files and configurations are logically grouped together.
Terminology
- Hive
- Configuration File
- Action
- Bootstrapping
- Environment
- Injector
- Processor
- Session
- ErrorChannel
- User Role
- Assets
- View
- Flash
- I18n
- MailSender
- Model
- Notifier
- Constraints
- Tailored
- Template Directive
Hive
A central place where Fat-Free Framework (F3) stores and manages application data, including configuration settings, routing, and session information. The Hive acts as a global registry, making data accessible throughout the application.
Configuration File
Refers to any ini configuration file used to define application settings and dependencies. This file helps in managing
the application’s configuration in a structured and centralized manner.
Action
Refers to action-wise micro-controllers inspired by ForkCMS. These are responsible for handling specific tasks or requests within the application, typically mapped to routes and executed to perform a particular function.
Bootstrapping
The application initialization phase where the framework, akin to the kernel in other frameworks, loads configurations, sets up the environment, and prepares the application for handling requests.
Environment
The automatically detected application environment, which can be test, development, or production. This setting
can be overridden to suit specific needs during development or deployment.
Injector
A component responsible for injecting and initializing Inversion of Control (IoC) classes defined in the configuration file. It manages dependencies and ensures that required services are available throughout the application.
Processor
A component responsible for applying behaviors or traits to classes. It ensures that specific functionalities or attributes are consistently applied across relevant classes.
Session
The class responsible for managing user sessions, including session creation, data storage, and session termination.
ErrorChannel
The global exception handling component used to manage and route errors. It supports multiple channels like Zulip and email for notifying about exceptions.
User Role
Defines the various roles within the application, such as visitor, admin, customer, or api user. These roles
determine the level of access and permissions for different parts of the application.
Assets
The class responsible for injecting JavaScript and CSS assets into views, either from the action or directly within the view itself.
View
Refers to the F3 template view files, typically ending with .phtml, used to render the user interface.
Flash
Contains notifications to be displayed in the frontend. It manages temporary messages that inform users about the status of their actions.
I18n
The class that contains different types of messages depending on the localization settings. It supports internationalization and helps manage translations.
MailSender
The class responsible for sending emails within the application. It handles email composition, configuration, and delivery.
Model
A Cortex class with additional behaviors, used to represent and manage the application’s data layer. It includes ORM features for interacting with the database.
Notifier
The component responsible for sending notifications to third parties, such as Zulip, Slack, or email, ensuring that important events are communicated effectively.
Constraints
The class responsible for validating data inputs within the application. It ensures that data conforms to specified rules and constraints before processing.
Tailored
The Tailored class is a singleton that extends F3’s \Prefab, ensuring only one instance of the class exists. It has
the ability to glue trait behaviour to a class while maintaining its singleton nature and integrating it into the
dependency injection registry.
Template Directive
Directives used within F3 templates to insert dynamic content, control flow, and manage template inheritance. These directives allow developers to create flexible and reusable templates for rendering views. For a detailed list and explanation of template directives, refer to the F3 Quick Reference.
Application Lifecycle
- Entry-point
- 1. Detect if the Application is Running in CLI Mode
- 2. Create an Instance of the Fat-Free Framework (F3) Singleton Class
- 3. Set Up PHP Variables
- 4. Automatically Detect the Application Environment
- 5. Load the Configuration Files
- 6. Set Up Logging
- 7. Add the Global Exception Handler
- 8. Connect to the Database
- 9. Prepare the Session
- 10. Load Additional Application Settings
- 11. Load Additional CLI Configuration if CLI Mode is Detected
- 12. Load Routing and Access Control Lists (ACL)
- 13. Execute the Start Function
- 14. Log Performance Metrics and Finish
Entry-point
The entry point for a Sukarix application is public/index.php.
This is where initial detection happens to determine if unit tests need to be run in the browser, a process that will be covered in detail later.
Once the Application is instantiated, the following steps occur:
1. Detect if the Application is Running in CLI Mode
The application first checks if it is being executed from the command line (CLI) or through a web server. This allows for conditional loading of CLI-specific configurations and behaviors.
2. Create an Instance of the Fat-Free Framework (F3) Singleton Class
An instance of the F3 singleton class is created. This instance acts as the central hub for managing application configuration, routing, and other core functionalities.
3. Set Up PHP Variables
The application sets up necessary PHP variables, including error reporting levels, timezone settings, and memory limits, to ensure a consistent execution environment. Up to the developer to override it.
4. Automatically Detect the Application Environment
The application detects the current environment (test, development, or production). This setting can be overridden
if needed, and it dictates how the application behaves, including error reporting and debugging levels.
5. Load the Configuration Files
The application loads its configuration settings from ini configuration files. These files define various parameters
and settings required for the application’s operation.
6. Set Up Logging
Logging is set up to capture and record important events, errors, and performance metrics. This is crucial for monitoring the application and diagnosing issues.
7. Add the Global Exception Handler
A global exception handler is added to catch and manage any unhandled exceptions, ensuring that errors are logged and appropriate responses are provided without crashing the application.
8. Connect to the Database
The application establishes a connection to the database using the settings defined in the configuration files. This connection is essential for data storage and retrieval.
9. Prepare the Session
The session handler is initialized to manage user sessions, including creating, storing, and terminating sessions. This is important for maintaining user state across requests.
10. Load Additional Application Settings
Additional settings and configurations specific to the application are loaded. These can include custom parameters, feature toggles, and other application-specific settings.
11. Load Additional CLI Configuration if CLI Mode is Detected
If the application is running in CLI mode, additional configurations specific to the command-line environment are loaded. This ensures that CLI commands have the necessary settings and resources.
12. Load Routing and Access Control Lists (ACL)
The routing configuration and ACLs are loaded to define how incoming requests are handled and to enforce access permissions. This ensures that routes are correctly mapped to actions and that users have appropriate access rights.
13. Execute the Start Function
The start function of the application is executed, which in turn calls the F3 run function. This kicks off the
application, allowing it to handle incoming requests or execute CLI commands.
14. Log Performance Metrics and Finish
Finally, the application logs performance metrics for the entire lifecycle process. This includes timing information and resource usage statistics, which are useful for performance monitoring and optimization.
This comprehensive sequence ensures that the Sukarix application is thoroughly initialized, configured, and prepared to handle both web requests and CLI commands efficiently and reliably.
Dependency Injection
- Overview
- Example Usage
- Configuration & Default Dependencies
- Creating Injectable Singletons
- Storing DI Classes
Overview
Dependency Injection in Sukarix is facilitated through the singleton class Injector::instance()->get('access'). This
method allows for easy and efficient management of dependencies within your application.
Example Usage
In this example, access is the default ACL Middleware tied to f3-access:
$access = Injector::instance()->get('access');
Additionally, the Injector can find an object from its class directly:
$multiLang = Injector::instance()->get(\Multilang::class);
Configuration & Default Dependencies
These default classes can be easily changed or overridden by updating the classes.ini file. The default configuration
is in the table below:
| Key | Class |
|---|---|
mailer | Sukarix\Mail\MailSender |
notifier | Sukarix\Notification\Notifier |
session | Sukarix\Core\Session |
i18n | Sukarix\Helpers\I18n |
assets | Sukarix\Helpers\Assets |
access | \Access |
events | Sugar\Event |
template | \Template |
html | Sukarix\Helpers\HTML |
multi_language | \Multilang |
receiver | Sukarix\Helpers\Receiver |
Creating Injectable Singletons
For classes that should be singletons with behaviors, they must extend the Sukarix\Core\Tailored class and call
Processor::instance()->initialize($this) in their constructor. The Helper base class already does this, so
classes extending Helper only need to call parent::__construct(). More details on these behaviors can be found
in the Behaviors section of the documentation.
Note
Instantiating an injectable singleton object
There is no need to manually instantiate the injected object, Sukarix will do it for you.
Storing DI Classes
The F3 \Registry class is used to store these dependency-injected classes, ensuring they are easily accessible
throughout your application. However, it is recommended to use the Injector class that already wraps this
functionality, as it provides additional features and should be preferred over direct usage of \Registry.
Routing and Access Control
Introduction
Sukarix leverages the powerful routing and access control capabilities of the Fat-Free Framework (F3) to manage web and
CLI application routes. The configuration for routing and access control is handled through routes.ini
and access.ini for web applications, and routes-cli.ini and access-cli.ini for CLI applications. Additionally,
multi-language routing is supported via f3-multilang.
Routing
Concepts
Routing in Sukarix allows you to map URLs to specific actions in your application. This is managed through configuration files where you define patterns for web and CLI routes. Key concepts include:
- HTTP Methods: Define the HTTP methods (GET, POST, PUT, DELETE, etc.) that the route will respond to.
- Route Aliases: Provide named routes for easier reference.
- Tokens: Use tokens to capture parts of the URL (e.g.,
/users/@id). - Modifiers: Use
[ajax]for AJAX requests and[cli]for CLI routes. - Asterisk (*): Use wildcards to match any subpath.
- Named Routes: Assign names to routes for easy referencing.
- Rerouting: Redirect requests to different routes or actions.
- ReST: Implement RESTful APIs using standard HTTP methods.
- Multi-language Routing: Support multiple languages using
f3-multilang.
Web Application Routing (routes.ini)
In Sukarix, routes for web applications are defined in the routes.ini file.
Example Configuration
[routes]
; default route
GET @home : / = Actions\Core\Main->execute
GET @docs : /docs/* = Actions\Core\Docs->execute
POST|PUT @set_locale : /set-locale/@locale [ajax] = Actions\Account\SetLocale->execute
DELETE @user_delete : /users/@id = Actions\Users\Delete->execute
Explanation
-
GET @home : / = Actions\Core\Main->execute- GET: The HTTP method for the route.
@home: The route alias./: The URL pattern for the home page.= Actions\Core\Main->execute: The action and method that handle the request.
-
GET @docs : /docs/* = Actions\Core\Docs->execute- GET: The HTTP method for the route.
@docs: The route alias./docs/*: The URL pattern with a wildcard to match any subpath.= Actions\Core\Docs->execute: The action and method that handle the request.
-
POST|PUT @set_locale : /set-locale/@locale [ajax] = Actions\Account\SetLocale->execute- POST|PUT: The HTTP methods for the route.
@set_locale: The route alias./set-locale/@locale: The URL pattern with a token (@locale).[ajax]: Modifier indicating the route should handle AJAX requests.= Actions\Account\SetLocale->execute: The action and method that handle the request.
-
DELETE @user_delete : /users/@id = Actions\Users\Delete->execute- DELETE: The HTTP method for the route.
@user_delete: The route alias./users/@id: The URL pattern with a token (@id).= Actions\Users\Delete->execute: The action and method that handle the request.
CLI Application Routing (routes-cli.ini)
In Sukarix, routes for CLI applications are defined in the routes-cli.ini file.
Example Configuration
[routes]
; route to the main task scheduler
GET @run_job : /cli/jobs/run [cli] = Actions\Jobs\TaskScheduler->execute
GET @logs_clean : /cli/logs/clean [cli] = Sukarix\Actions\Logs\Clean->execute
GET @sessions_clean : /cli/sessions/clean [cli] = Sukarix\Actions\Core\SessionsClean->execute
Explanation
-
GET @run_job : /cli/jobs/run [cli] = Actions\Jobs\TaskScheduler->execute- GET: The HTTP method for the route.
@run_job: The route alias./cli/jobs/run: The URL pattern for running jobs.[cli]: Modifier indicating the route is for CLI mode.= Actions\Jobs\TaskScheduler->execute: The action and method that handle the request.
-
GET @logs_clean : /cli/logs/clean [cli] = Sukarix\Actions\Logs\Clean->execute- GET: The HTTP method for the route.
@logs_clean: The route alias./cli/logs/clean: The URL pattern for cleaning logs.[cli]: Modifier indicating the route is for CLI mode.= Sukarix\Actions\Logs\Clean->execute: The action and method that handle the request.
-
GET @sessions_clean : /cli/sessions/clean [cli] = Sukarix\Actions\Core\SessionsClean->execute- GET: The HTTP method for the route.
@sessions_clean: The route alias./cli/sessions/clean: The URL pattern for cleaning sessions.[cli]: Modifier indicating the route is for CLI mode.= Sukarix\Actions\Core\SessionsClean->execute: The action and method that handle the request.
Multi-language Routing
Sukarix supports multi-language routing using f3-multilang. This allows you to define routes that adapt to different
languages.
Configuration Example
[MULTILANG.languages]
en = en-GB
fr = fr-FR
ar = ar-AR
es = es-ES
[MULTILANG]
global = locale,/cli
[MULTILANG.languages]: Defines the languages and their respective locale codes.[MULTILANG]: Specifies global aliases that are not localized by default.
Access Control
Access control in Sukarix is managed through access.ini and access-cli.ini files, defining policies and rules for
both web and CLI applications.
Web Application Access Control (access.ini)
Sukarix uses the access.ini file to manage access control for web applications. The configuration defines policies and
rules for access control using the F3-Access component.
Example Configuration
[ACCESS]
; deny all routes by default
policy = deny
[ACCESS.rules]
; Routes allowed to all type of users
deny * /* = *
allow GET @home = *
allow GET @docs = admin,customer
allow @set_locale = *
allow DELETE @user_delete = admin
Explanation
-
policy = deny- Sets the default policy to deny access to all routes.
-
deny * /* = *- Denies access to all users for all routes by default.
-
allow GET @home = *- Allows access to the home route (
@home) for all users.
- Allows access to the home route (
-
allow GET @docs = admin,customer- Allows access to the documentation route (
@docs) only foradminandcustomerroles.
- Allows access to the documentation route (
-
allow @set_locale = *- Allows access to the set locale route (
@set_locale) for all users.
- Allows access to the set locale route (
-
allow DELETE @user_delete = admin- Allows access to delete user route (
@user_delete) only foradminrole.
- Allows access to delete user route (
CLI Application Access Control (access-cli.ini)
Sukarix uses the access-cli.ini file to manage access control for CLI applications.
Example Configuration
[ACCESS]
; allow all routes by default
policy = allow
Explanation
policy = allow- Sets the default policy to allow access to all CLI routes.
References
For more detailed information on F3’s routing and access control mechanisms, refer to the following resources:
Framework Variables
Fat Free Framework Variables
Detailed information on Fat-Free Framework variables can be found here.
Globals
Global variables and their usage are explained here.
Naming Rules
Naming conventions are outlined here. Sukarix follows these rules, using capital letters when possible. If F3 extensions deviate from this rule, they are used as is.
Sukarix Framework Variables
Fat-Free Framework system variables are listed here.
Example Sukarix framework variables:
MINIFY_JS
boolean Default: TRUE in production configuration
Turns JavaScript minification on or off. Should be environment dependant.
MINIFY_CSS
boolean Default in template application: TRUE in production configuration
Turns CSS minification on or off. Should be environment dependant.
CONFIGS
string Default in template application: smtp,notifications,upload
List of configuration files to load.
application.environment
string
Sets the application environment (e.g., development, testing).
Note
Sukarix Convention: Environment auto-detection
If the server hostname ends with
.testtheapplication.environmentvariable will automatically be set todevelopment.
template.default
string Default in template application: website
Default view to render.
log.keep
integer Default in template application: 14
Days to keep logs before cleanup.
server.host
string Default: NULL
Server host for command line actions.
error.channel
string Default: NULL
Error notification channel (“email” or “zulip”).
Databases Management
Database Configuration
For configuring database access, the framework follows the guidelines outlined by the Fat-Free Framework. This includes setting up database connections and handling queries efficiently.
Cortex ORM
The framework utilizes Cortex ORM for object-relational mapping, simplifying interactions with the database. For detailed usage and configuration instructions, refer to the Cortex documentation.
Database Migrations
Database migrations are managed using the Phinx library, which is included in the template application with
a phinx.json file. This file can be customised, although Phinx is the recommended tool. Comprehensive documentation
for Phinx is available here.
Model Class
The Model class provides a structured way to access data using Cortex ORM. It includes methods for pagination, data
conversion, and change detection, ensuring robust and efficient data handling.
Note
Sukarix Convention: Model timestamps
The
Modelclass follows conventions for managing timestamps:
- created_on: Automatically set when a record is created.
- updated_on: Automatically updated when a record is modified.
File Upload
Introduction
The Receiver class in Sukarix is designed to handle file uploads efficiently. It provides methods for saving uploaded
files and preparing upload directories, ensuring that your application can manage file uploads seamlessly.
Configuration
To use the Receiver class, you need to configure it in the classes.ini file:
receiver = \Helpers\Receiver
Methods
saveUploadedFile
This method saves the uploaded file to the specified destination. It checks the environment to decide whether to
use rename or move_uploaded_file for saving the file.
prepareUploadDirectory
This method prepares the upload directory by creating it if it does not exist. It throws a RuntimeException if the
directory cannot be created.
Example Usage
To use the Receiver class for handling file uploads, you can get an instance from the Injector and use
the \Web::instance()->receive method to process the uploaded files.
/**
* @var Receiver $receiver
*/
$receiver = Injector::instance()->get('receiver');
\Web::instance()->receive(static function(&$file, &$formFieldName) use (&$action, &$receiver) {
if (0 === $file['size']) {
return false;
}
$uploadDirectory = 'path/to/upload/directory';
$receiver->prepareUploadDirectory($uploadDirectory);
$destination = $uploadDirectory . '/' . $file['name'];
return $receiver->saveUploadedFile($file, $destination);
});
The Receiver class ensures that file uploads are handled efficiently and securely, with proper directory preparation
and file movement based on the environment. This setup allows for easy management of uploaded files in your Sukarix
application.
Data Validation
- Human-readable data validation syntax
- Configuration
- Using the Validator
- How Validation Works
- Available Validation Rules
Human-readable data validation syntax
Form validation is a crucial part of building robust web applications. Sukarix simplifies this process by allowing you to declare your validation rules in an easy-to-read configuration file. This page provides an overview of how to use Sukarix’s data validation capabilities.
Configuration
Validation rules are declared in an INI file. Here’s an example:
[CONSTRAINTS.users.edit]
email = email
username = length:4,32
role = in:Enum\UserRole
status = in:Sukarix\Enum\UserStatus
Using the Validator
To validate data, use the Constraints class in your controller or model. Below are various examples demonstrating
different usages.
Example: Basic Usage
public function save($f3, $params): void
{
$form = $this->getDecodedBody();
Constraints::instance()->verify($form, 'users.edit');
// Process the validated data
}
Example: Multiple Rulesets
You can validate against multiple rulesets by separating them with a pipe (|).
public function save($f3, $params): void
{
$form = $this->getDecodedBody();
Constraints::instance()->verify($form, 'settings.save.default|users.edit');
// Process the validated data
}
You can also pass ruleset names as an array.
public function save($f3, $params): void
{
$form = $this->getDecodedBody();
Constraints::instance()->verify($form, ['settings.save.default', 'users.edit']);
// Process the validated data
}
Example: Individual Checks
You can also perform individual checks using the check method.
$filePath = '/path/to/file.css';
Constraints::instance()->check($this->f3->get('ROOT') . $filePath, 'file', true, 'css_file');
How Validation Works
-
Audit Class:
- If available, validation rules are first checked in the
Auditclass.
- If available, validation rules are first checked in the
-
Constraints Class:
- If the rule is not found in the
Auditclass, it falls back to theConstraintsclass.
- If the rule is not found in the
-
Custom Validator:
- If the rule is not found in the
Constraintsclass, it checks for a user-defined validator class specified in theVALIDATORconfiguration property.
- If the rule is not found in the
Warning
Validation rule names are case insensitive
Validator names are case insensitive, meaning
notempty,notEmpty,NotEmpty, andNOTEMPTYare treated the same.
Available Validation Rules
Here is a list of available validation rules that you can use in your INI configuration file or directly in your code:
email: Validates that the input is a valid email address.length:min,max: Validates that the input length is betweenminandmax.in:Enum\ClassName: Validates that the input is one of the values in the specified enumeration.notEmpty: Validates that the input is not empty.file: Validates that the input is a valid file path.
Example: Custom Validator
You can define custom validation rules in your own validator class and configure Sukarix to use it.
class CustomValidator
{
public static function isCustom($value)
{
// Custom validation logic
return $value === 'custom';
}
}
// Usage
$customRules = [
'custom_field' => 'custom'
];
Constraints::instance()->verifyRules($form, $customRules, true);
Error Handling
When validation fails, the verify method throws an exception if the throwOnFail parameter is set to true.
try {
Constraints::instance()->verify($form, 'users.edit', true);
} catch (\RuntimeException $e) {
echo "Validation failed: " . $e->getMessage();
}
To get all validation errors, use the getErrors method.
$errors = Constraints::instance()->getErrors();
print_r($errors);
Combining Validators
You can combine multiple validation rules using the pipe (|) separator.
[CONSTRAINTS.users.edit]
email = email
username = length:4,32|notEmpty
role = in:Enum\UserRole|notEmpty
status = in:Sukarix\Enum\UserStatus|notEmpty
public function save($f3, $params): void
{
$form = $this->getDecodedBody();
Constraints::instance()->verify($form, 'users.edit');
// Process the validated data
}
Session
Session Management
Session handler documentation can be found here.
By default, sessions are stored in the database but can be configured to use the cache system. This allows session data to be debuggable in non-production environments, while in production, storing sessions in cache enhances performance.
Caution
Issues with storing sessions in transactional database
Storing a session in the database can be problematic when using transactions, as the database connection is tied to that session. Rolling back or failing a transaction may result in failed updates to the session data. It’s important to carefully consider this when designing your application’s session management strategy.
Session Functions
The session management system includes the following functions:
- authorizeUser: Authorizes a user and initiates their session.
- revokeUser: Revokes a user’s session and logs them out.
- getRole: Retrieves the role of the current user.
- isRole: Checks if the current user has a specific role.
Logging
Introduction
The framework uses Monolog by default for logging. To enable logging, use the LogWriter behavior trait in your class.
The trait provides a $logger property — a Monolog logger accepting a message and a context array:
use Sukarix\Behaviours\LogWriter;
class MyService
{
use LogWriter;
public function process(string $id): void
{
$this->logger->info('Processing started', ['id' => $id]);
}
}
Note
Initializing LogWriter
If the class does not extend the
Tailoredsingleton class, ensure to call theinitLogWritermethod in the constructor.
Log Level
The minimum level is set with log.level (defaults to info):
[globals]
log.level = debug
Console Output
CLI applications can mirror the log to standard output by enabling log.console:
[globals]
log.console = true
When the optional bramus/monolog-colored-line-formatter package is installed, console output is
coloured per level; otherwise a plain stream is used. The file handler stays active either way, so
enabling this adds console output rather than replacing the log file.
Logging Naming Conventions
Logs follow these naming patterns:
- Application Logs:
app-yyyy-mm-dd.log - Application Error Logs:
app-error-yyyy-mm-dd.log - CLI Logs:
cli-yyyy-mm-dd.log - CLI Error Logs:
cli-error-yyyy-mm-dd.log - Exception Logs:
exception.log
Log Rotation
Logs are kept for 14 days by default, configurable via the log.keep setting (an integer in days).
The Sukarix\Actions\Action\Clean action is responsible for rotating and cleaning logs.
Debugging
Introduction
Sukarix uses the Tracy library for debugging. Tracy offers powerful tools to help you debug your applications efficiently.
Basic Usage
To use Tracy, simply call the following functions in your code:
- Dumping Variables:
dump($variable)ordumpe($variable)Debugger::dump($variable)Debugger::barDump($variable)
For more detailed usage and advanced features, refer to the Tracy documentation.
Emails
MailSender Class
The MailSender class in Sukarix is used to send emails with a predefined template. The primary method for sending
emails is send(), which has the following signature:
send($template, $vars, $to, $title, $subject): bool
Method Parameters
- $template: The name of the email template, which must be located in the
/mailfolder. - $vars: An array of variables to be used within the template.
- $to: The recipient’s email address.
- $title: The title of the email.
- $subject: The subject line of the email.
Usage Example
Here’s how you might use the send() method to send an email:
/**
* @var MailSender $mailSender
*/
$mailSender = Injector::instance()->get('mailer');
$template = 'welcome';
$vars = ['name' => 'John Doe', 'link' => 'https://example.com'];
$to = 'johndoe@example.com';
$title = 'Welcome to Our Service';
$subject = 'Getting Started with Our Service';
$mailSender->send($template, $vars, $to, $title, $subject);
This example sends a welcome email using the welcome template, passing in the recipient’s name and a link to be used
within the email body.
Notifications
Notifier Class
The Notifier class in Sukarix is designed to send notifications about exceptions that occur in the application. This
class extends the Tailored class and uses the HasF3 and LogWriter traits.
Methods
notifyException
The notifyException method is responsible for sending an exception notification. It generates a unique error ID,
creates a notification message, and sends it to a specified Zulip stream.
Method Signature:
public function notifyException($exception): void
Parameters:
- $exception: An instance of
\Exceptioncontaining the exception details to be notified.
Usage
Here is an example of how to use the notifyException method:
/**
* @var Notifier $notifier
*/
$notifier = Injector::instance()->get('notifier');
try {
// Code that may throw an exception
} catch (\Exception $e) {
$notifier->notifyException($e);
}
Configuration
Ensure the following configuration settings in your .ini file:
[globals]
; error notification channel "email" or "zulip"
error.channel = zulip
[NOTIFICATIONS.zulip]
token = "your-zulip-token"
mail = "your-zulip-email"
uri = "your-zulip-uri"
stream = "your-zulip-stream"
topic = "your-zulip-topic"
Translation / i18n
- Localisation Helper Class
- Methods
- Example Usage
- locales.js
- Example Usage in locales.js
- Routing for JSON localisation
- Caching
Localisation Helper Class
The I18n class in Sukarix provides methods to retrieve localized strings from different translation tables. There are
four types of translation tables:
- Labels (
i18n.label) - Messages (
i18n.message) - Errors (
i18n.error) - Lists (
i18n.list)
Methods
lbl
Fetches a localized label.
public function lbl($key): string
msg
Fetches a localized message.
public function msg($key): string
err
Fetches a localized error message.
public function err($key): string
lst
Fetches a localized list.
public function lst($key): array
Example Usage
$i18n = Injector::instance()->get('i18n');
echo $i18n->lbl('welcome'); // Fetches the 'welcome' label
echo $i18n->msg('greeting'); // Fetches the 'greeting' message
echo $i18n->err('not_found'); // Fetches the 'not_found' error message
print_r($i18n->lst('countries')); // Fetches the 'countries' list
locales.js
The locales.js file handles loading and switching of localisation data in JSON format.
Functions
- loadLocale: Loads the locale data from a JSON file.
- init: Initializes the locale settings and language menu.
- initLanguageMenu: Sets up the language selection menu.
- setLocale: Sets the current locale.
- switchLocale: Switches to the selected locale and updates the displayed strings.
- translaterStrings: Updates all strings in the document with localized content.
- get: Retrieves a localized string based on type, module, and key.
- err: Retrieves a localized error message.
- lbl: Retrieves a localized label.
- loc: Retrieves a localized string.
- msg: Retrieves a localized message.
- lst: Retrieves a localized list item.
Example Usage in locales.js
Locale.init(); // Initializes the locale settings
Locale.setLocale('en-GB'); // Sets the current locale to 'en-GB'
Locale.switchLocale('fr-FR'); // Switches to 'fr-FR' and updates the displayed strings
Routing for JSON localisation
The routing for generating JSON localisation files is defined as follows:
GET @locale: /locale/json/@locale.json = Sukarix\Actions\Core\GetLocale->execute
Caching
JSON locale data is cached whenever the translation file is updated to improve performance and reduce load times.
Behaviours
Introduction
Behaviours in Sukarix are traits that can be plugged into classes to extend their functionality. By convention,
an init<TraitName> method should be implemented and is called immediately after the injector creates an instance of
the class using the trait.
Available Behaviours
| Trait | Property | Visibility | Description |
|---|---|---|---|
LogWriter | $logger | protected | A Monolog logger writing to the application log |
HasF3 | $f3 | protected | The Fat-Free Framework instance |
HasSession | $session | protected | The session service |
HasCache | $cache | protected | The cache service, with remember() and forget() helpers |
HasI18n | $i18n | protected | The translation service |
HasMessages | $messages | protected | Flash messages |
HasAssets | $assets | protected | Asset management |
HasQueue | $queueService | protected | The queue service; requires a registered queue service |
HasAccess | $access | private | The ACL service |
HasEvents | $events | private | The event dispatcher |
The init<TraitName> method of each trait is invoked by the Processor, so a class only needs to
use the trait to receive its property:
class MyClass {
use LogWriter;
use HasF3;
}
Warning
HasAccess and HasEvents are private
These two traits declare their property
private. A private trait property is usable inside the class that declares theuse, but is not visible to its subclasses. If you need the property in a class hierarchy, apply the trait in each class that reads it rather than only in the base class.
Singleton Classes
Any singleton class inheriting from Tailored must call Processor::instance()->initialize($this); in its constructor
to ensure that the init<TraitName> methods are called. The Helper base class already does this, so classes extending
Helper (directly or indirectly) only need to call parent::__construct().
Non-Singleton Classes
If a class does not inherit from Tailored, it must call Processor::instance()->initialize($this); in the constructor
to ensure that the init<TraitName> methods are called.
Example Usage
Here’s how you might use these behaviours in a class:
class MyService {
use LogWriter;
use HasF3;
public function __construct() {
Processor::instance()->initialize($this); // Initialise traits manually
}
public function logSomething() {
$this->logger->info('Logging something!', ['context' => 'value']);
}
public function getFrameworkInstance() {
return $this->f3;
}
}
In this example, MyService uses both the LogWriter and HasF3 traits. Since it does not extend Tailored, it
explicitly calls Processor::instance()->initialize($this); in the constructor to ensure that the traits are
initialised.
Queues
- Introduction
- Requirements
- Configuration
- Registering the service
- Using the queue in a service
- Queue operations
- Tracking failed attempts
- Consistency guarantees
- Queue logging
Introduction
Sukarix\Queue\QueueService is a Redis-backed FIFO queue for passing work between the stages of a
pipeline — typically CLI workers scheduled by TaskScheduler.
It provides three things on top of a plain Redis list:
- FIFO delivery — items are pushed onto the head and popped from the tail.
- Deduplication — a companion Redis set tracks membership, so pushing a payload that is already queued is a no-op instead of a duplicate.
- Attempt tracking — a per-queue hash counts failed processing attempts per item, so a stage can decide when an item has exhausted its retries.
Note
Retry policy stays in your application
The queue counts attempts but never decides what to do with them. Whether a failing item is retried, parked or dead-lettered is a business decision and belongs in your own stage code.
Requirements
The queue requires the redis PHP extension and a reachable Redis server.
Configuration
Connection settings are read from the hive:
[globals]
redis.host = 127.0.0.1
redis.port = 6379
; connection timeout in seconds, keep it bounded so workers fail fast
redis.timeout = 2
The constructor throws \RedisException when the connection cannot be established, so a
misconfigured worker fails immediately instead of part-way through a run.
Registering the service
Register the queue once during boot so it can be resolved through the Injector:
protected function setupQueueService(): void
{
\Registry::set('queue', \Sukarix\Queue\QueueService::instance());
}
Using the queue in a service
Add the HasQueue behaviour to get a $queueService property. See
Behaviours for how init<TraitName> methods are invoked.
use Sukarix\Behaviours\HasQueue;
use Sukarix\Core\Processor;
class MyWorker
{
use HasQueue;
public function __construct()
{
Processor::instance()->initialize($this);
}
public function run(): void
{
while (null !== $item = $this->queueService->popFromQueue('queue.work.pending')) {
// process $item
}
}
}
Warning
Register before constructing
HasQueuethrows a\LogicExceptionif noqueueservice is registered when the consuming class is constructed. This is deliberate: it surfaces the misconfiguration at boot instead of failing later with a null member access.
Queue operations
| Method | Description |
|---|---|
pushToQueue(string $queue, mixed $data): void | Enqueue a payload, skipping it if already queued |
popFromQueue(string $queue): mixed | Dequeue the oldest payload, or null when empty |
peek(string $queue): mixed | Read the next payload without removing it |
getQueueSize(string $queue): int | Number of queued items |
isEmpty(string $queue): bool | Whether the queue holds no items |
existsInQueue(string $queue, mixed $value): bool | Whether a payload is already tracked |
getQueueItems(string $queue, ?int $limit = null): array | Snapshot of queued items, oldest first |
clearQueue(string $queue): void | Delete the list, membership set and attempt counters |
Payloads are JSON-encoded, so any JSON-serialisable value works — scalars, arrays and nested structures all survive the round trip:
$queue = \Sukarix\Queue\QueueService::instance();
$queue->pushToQueue('queue.work.pending', ['order_id' => 'A-1', 'total' => 42]);
$queue->pushToQueue('queue.work.pending', ['order_id' => 'A-1', 'total' => 42]); // skipped
$queue->getQueueSize('queue.work.pending'); // 1
$item = $queue->popFromQueue('queue.work.pending'); // ['order_id' => 'A-1', 'total' => 42]
Note
getQueueItems is a snapshot
getQueueItems()is an observational read for reporting and administration. Concurrent producers and consumers may change the queue before you act on the result, so never treat it as a lock.
Tracking failed attempts
Attempt counters are keyed by the payload, independently of the queue contents:
try {
$this->process($item);
// Success clears the history so a future failure starts from a clean count
$this->queueService->clearAttempts('queue.work.failed', $item);
} catch (\Throwable $e) {
$attempts = $this->queueService->incrementAttempts('queue.work.failed', $item);
if ($attempts >= $this->f3->get('pipeline.max_retries')) {
// Your policy: park it, alert, or leave it for manual analysis
$this->logger->critical('Item exhausted its retries', ['attempts' => $attempts]);
}
}
getAttempts() returns 0 for an item that has never failed, so a fresh item is always below any
positive limit.
Consistency guarantees
Enqueue and dequeue are executed as Redis Lua scripts, which Redis runs atomically. A worker killed mid-operation can therefore never leave the list and the membership set disagreeing — an item is either fully queued and tracked, or neither.
Warning
clearQueue is an administrative operation
clearQueue()removes three keys and is not atomic with respect to a running pipeline. Do not call it while producers or consumers are active.
Queue logging
Sukarix\Queue\QueueProgressLogger emits structured queue events with a distinctive prefix and a
context array, so the output is parsable by log aggregators rather than only human-readable.
$logger = \Sukarix\Queue\QueueProgressLogger::instance();
$logger->logQueueStart('queue.work.pending', 'PROCESS', ['max_items' => 100]);
$logger->logQueueProcess('queue.work.pending', 40, 2, 58, 100);
$logger->logQueueComplete('queue.work.pending', 'PROCESS', 98, 2);
Available methods: logQueueStart(), logQueueComplete(), logQueueStatus(), logQueueFill(),
logQueueProcess(), logBatchProgress(), logQueueThroughput(), logItemAdded(),
logItemRemoved(), logQueueWarning() and logQueueError().
The queue service logs enqueue and dequeue events through this logger. Item previews are deliberately
generic — an array is reported as array[3], never with its values — so payload contents never leak
into logs.
Overriding the logger
Register your own subclass under the queue.progress_logger alias to route queue telemetry to a
different sink:
\Registry::set('queue.progress_logger', new MetricsQueueProgressLogger());
The queue validates the alias and throws \UnexpectedValueException if the registered service does
not extend QueueProgressLogger. When the alias is absent, the framework default is used.
CRON / Task Scheduling
TaskScheduler
TaskScheduler is an Action in Sukarix designed for task scheduling. The CLI toolbox installs it as a cron job by
default, utilizing the GO\Scheduler syntax.
Default Configuration
The route-cli.ini file contains the default route for task scheduling:
[routes]
; route to the main task scheduler
GET @run_job : /cli/jobs/run [cli] = Actions\Jobs\TaskScheduler->execute
Setting Up Cron
The default cron job should contain:
* * * * * /usr/bin/php /var/www/sukarix/public/index.php "/cli/jobs/run"
Defining Jobs
Each job must be defined in route-cli.ini. For example, the default log cleaning job is implemented as:
GET @logs_clean : /cli/logs/clean [cli] = Sukarix\Actions\Logs\Clean->execute
Implementing the Execute Function
The execute function should schedule tasks using the scheduler:
public function execute() {
// Clean old sessions every 8 hours at 10 minutes after the hour
$this->scheduler->php($this->documentRoot, null, ['/cli/sessions/clean' => ''], 'sessions-clean')
->onlyOne()
->at('20 */8 * * *');
}
This example schedules a session cleaning task to run every 8 hours at 10 minutes past the hour, ensuring only one instance runs at a time.
Events
Introduction
In Sukarix, events are managed using the Sukarix\Behaviours\HasEvents trait. This allows any class to emit and handle events throughout the application using the Sugar Events system integrated with the PHP Fat-Free Framework.
Key Features of Sugar Events
- Emit events from any point in your application
- Attach multiple listeners to an event with priority
- Local events on specific objects
- Send payload and context data with events
- Support for sub-events and event propagation
- Stop the event chain
- Works with F3 v3.5 and PHP v7.2+
Example Usage
Initializing Events
To initialize the event system and get the global Event instance:
$events = \Sugar\Event::instance();
Defining a Listener
You can define a listener (or hook) to an event using a typical F3 callstring, callback, or callable:
$events->on('user_login', 'Notification->user_login');
$events->on('user_login', function() {
// ...
});
$events->on('user_login', [$this, 'method']);
Emitting an Event
To emit an event and notify all listeners:
$events->emit('user_login');
Sending Payload with Event
You can send additional data (payload) with an event:
$events->on('user_login', function($username) {
\Logger::log($username . ' logged in');
});
$events->emit('user_login', 'freakazoid');
Multiple Listeners with Prioritization
Listeners can be prioritized; higher numbers are called first:
$events->on('user_login', function($username) {
\Logger::log($username . ' logged in');
}, 10);
$events->on('user_login', function() {
\Flash::addMessage('You have logged in successfully');
}, 20);
$events->emit('user_login', 'freakazoid');
Stopping the Event Chain
A listener can stop further listeners from being called:
$events->on('user_login', function($username) {
\Logger::log($username . ' logged in');
});
$events->on('user_login', function() {
\Flash::addMessage('You have logged in successfully');
return false;
}, 20);
$events->emit('user_login', 'freakazoid');
Additional Event Context Data
Send additional context data with an event:
$events->on('user_login', function($username, $context) {
if ($context['lang'] == 'en')
\Flash::addMessage('You have logged in successfully');
elseif ($context['lang'] == 'de')
\Flash::addMessage('Du hast dich erfolgreich angemeldet');
});
$events->emit('user_login', 'freakazoid', array('lang' => 'en'));
Additional Listener Options
Listeners can have additional options:
$events->on('user_login', function($username, $context, $event) {
\Flash::addMessage('You have logged in successfully', $event['options']['type']);
}, 20, array('type' => 'success'));
Filtering Payload
Listeners can modify and return the event payload:
$events->on('get_total', function($basket) {
$sum = 0;
foreach ($basket as $prod) {
$sum += $prod;
}
return $sum;
});
$products = array('a' => 2, 'b' => 8, 'c' => 15);
$sum = $events->emit('get_total', $products);
echo $sum; // 25
Adding Sub-Events
Sub-events are called after the parent event:
$events->on('get_total.tax', function($sum) {
return $sum + ($sum * 0.2);
});
$events->on('get_total.shipping', function($sum) {
return $sum + 5;
});
$sum = $events->emit('get_total', $products);
echo $sum; // 35
Removing Hooks
Remove listeners for specific events:
$events->off('get_total.tax');
$sum = $events->emit('get_total', $products);
echo $sum; // 30
Local Events for Mappers
Support for local events on specific objects:
$user = new \Model\User();
$events->watch($user)->on('update.email', '\Mailer->sendEmailActivationLink');
Error Handling
Introduction
In Sukarix, error handling is managed by a global error handler that can be overridden in the Application class. The
default implementation uses Tracy\Debugger for managing errors and handling fatal exceptions. The global exception
handling is only active in the production environment.
Default Implementation
The Application class includes a protected method handleException() that sets up the error handler. The default
implementation is capable of sending email or Zulip notifications based on the configuration of error.channel. Before
sending the email, it stores the exception stack trace in HTML format. It’s important to note that the error stack might
contain sensitive information, so sending it by default is not enabled.
Additionally, notifications for the same exception hash are sent only once every 24 hours.
Customizing Error Handling
To customize the error handling, you can override the handleException() method in your Application class:
protected function handleException(): void {
if (Debugger::$productionMode) {
Debugger::$onFatalError[] = function($exception) {
// Custom fatal error handling logic
};
}
}
Template Engine
Introduction
The template engine in Sukarix is built on top of the Fat-Free Framework’s (F3) template engine. It provides a flexible and efficient way to render views, leveraging F3’s powerful features while adding enhancements specific to Sukarix.
Template Loading
In Sukarix, templates are loaded into views using a specific pattern. By default, the view files are stored in
the templates directory and have a .phtml extension.
Mapping Actions to Templates
Sukarix maps actions to templates by following a convention-based approach. When an action
calls $this->render();, it maps to the template based on the namespace and class name, converted to snake_case.
For example:
- Action Class:
Actions\Core\Main - Mapped Template:
templates/actions/core/main.phtml
Note
Default Template Extension
The default template extension in Sukarix is
.phtmland is automatically appended.
Example Code
$this->render('commons/api/response');
This method call will automatically render the templates/commons/api/response.phtml when called from any action.
JavaScript and CSS Template Directives
Sukarix adds custom template directives for including JavaScript and CSS files in your views. These directives simplify the process of managing assets.
-
JavaScript Directive:
<js src="path/to/script.js" type="module"></js>This directive is used to include JavaScript files in your view. You can pass an optional
typeattribute, such as"module". If thetypeattribute is not provided,"text/javascript"will be chosen by default. -
CSS Directive:
<css href="path/to/style.css"></css>This directive is used to include CSS files in your view.
Tip
File Validation
The existence of the specified file is validated when the directive attempts to load it. If the file is not found, an exception will be thrown. This ensures that developers can handle missing files during the development phase before deploying to production.
By utilizing these custom directives, Sukarix ensures that assets are managed efficiently and that any issues with missing files are caught early in the development cycle.
F3 Template Directives
F3 provides a set of powerful template directives that make it easy to render dynamic content, control flow, and manage template inheritance. Some of the key directives include:
-
Include Directive:
<include href="partial.phtml" />This directive includes another template file within the current template.
-
Repeat Directive:
<repeat group="{{ @items }}" value="{{ @item }}"> <!-- Content to repeat --> </repeat>This directive repeats a block of content for each item in a collection.
-
Conditional Directive:
<check if="{{ @condition }}"> <!-- Content to show if condition is true --> </check>This directive conditionally renders content based on a boolean expression.
-
Set Directive:
<set name="variable" value="value" />This directive sets a variable to a specified value within the template.
-
Session Directive:
<session name="variable" />This directive retrieves a value from the session.
-
Cookie Directive:
<cookie name="variable" />This directive retrieves a value from cookies.
-
Locale Directive:
<locale name="variable" />This directive retrieves a localized value.
Additional Resources
For more detailed information on F3’s template engine and directives, you can refer to the F3 Views and Templates Documentation.
Assets
Introduction
Sukarix uses the Assets class to manage and render CSS and JavaScript files efficiently. By default, it looks for CSS
files under public/css and JavaScript files under public/js.
Default Storage Locations
- CSS Files:
public/css - JavaScript Files:
public/js - Minified Files:
public/minified
The Assets class automatically handles the minification of CSS and JS files and places the minified versions in
the public/minified directory.
Tip
Default Storage Locations
By default, CSS files are stored in
public/css, JavaScript files inpublic/js, and minified files inpublic/minified.
Rendering Groups
Sukarix provides two rendering groups named head and footer to organize asset rendering. To render these groups in
your template, use:
{{ \Sukarix\Helpers\Assets::instance()->renderGroup('footer') }}
JavaScript Initialization
The Assets class can also call JavaScript functions and initialize them. Example:
<script>
jQuery(document).ready(function () {
{{ \Sukarix\Helpers\Assets::instance()->currentJsLocale() }}
{{ \Sukarix\Helpers\Assets::instance()->setUserRole() }}
{{ \Sukarix\Helpers\Assets::instance()->initJsClasses() }}
});
</script>
Example Usage
Adding CSS and JS Files in a View
In your action, you can add CSS and JS files like this:
$this->assets->addJs('core.js');
$this->assets->addJs('core/servers.js');
$this->assets->addJs('vendors/datatables.min.js');
$this->assets->addCss('datatables.min.css');
$f3->push('init.js', 'Servers');
Rendering Assets
To render assets in the head group:
{{ \Sukarix\Helpers\Assets::instance()->renderGroup('head') }}
To render assets in the footer group:
{{ \Sukarix\Helpers\Assets::instance()->renderGroup('footer') }}
By using these functionalities, Sukarix ensures efficient management and rendering of assets, enhancing the performance and maintainability of your web application.
JavaScript
Introduction
The default Sukarix application template includes locale.js, which downloads the session locale using AJAX and
provides functions to access localized strings. Additionally, Common.userRole is accessible via JavaScript and is set
from the session.
locale.js
locale.js handles the localization of strings in your application. It downloads the session locale and provides easy
access to localized strings. This ensures that your application can support multiple languages and dynamically switch
between them based on the user’s session.
Common.userRole
The Common.userRole variable is set from the session and is accessible via JavaScript. This allows you to manage user
roles on the client side and adjust your application’s behavior based on the user’s role.
Minimalistic Implementation
Sukarix provides this minimalistic implementation, giving developers the flexibility to use modern frontend frameworks as needed. You can integrate libraries and frameworks such as React, Vue, or Angular to build more complex and interactive user interfaces.
Example Usage
Accessing Localized Strings
var welcomeMessage = Locale.msg('welcome');
console.log(welcomeMessage);
Using Common.userRole
if (Common.userRole === 'admin') {
console.log('User is an admin');
} else {
console.log('User is not an admin');
}
Users
Introduction
The User Model class in Sukarix is the central class for managing users. It includes user status, roles, and
authentication mechanisms.
User Status
User status can be either active or inactive, managed using the Sukarix\Enum\UserStatus enum.
User Roles
Sukarix provides four default user roles:
- visitor: Default role, represented as
*in the routing ACL. - admin
- customer
- api: A user that can authenticate through HTTP basic authentication.
These roles impact the access control list (ACL) in the configuration and can be extended by developers as needed.
Extending User Roles
Developers can extend user roles by adding new roles to the UserRole enum and updating the ACL configuration
accordingly. This allows for greater flexibility and customization to fit the needs of your application.
Authentication
Introduction
Sukarix provides a straightforward method for authenticating users using models and session management. Below are examples and explanations on how to implement authentication and handle user verification in Sukarix.
Authenticating a User
To authenticate a user, retrieve the user model by their email, check their status and role, and verify their password. If all conditions are met, authorize the user in the session.
Example Code
$user = new UserModel();
$user = $user->getByEmail($email);
if (UserStatus::ACTIVE === $user->status && UserRole::API !== $user->role && $user->verifyPassword($password)) {
$this->session->authorizeUser($user);
}
Authorizing a User
The authorizeUser method is used to authorize a user in the session. This method sets the necessary session variables
to mark the user as authenticated.
Verifying API Users
In the Action class, the isApiUserVerified() method checks if a user has authenticated via the HTTP Basic Auth
header. This is useful for API endpoints where HTTP Basic Authentication is preferred.
Example Usage
if ($this->isApiUserVerified()) {
// API user is authenticated
}
Authorisation System
Introduction
The authorisation system in Sukarix is managed through the f3-access library. The documentation for f3-access is
available in the f3-access repository.
Access Instance
The access instance is available in classes using the HasAccess behaviour trait. This trait integrates the access
control mechanisms provided by f3-access into your Sukarix application.
Default Authorization System
The beforeroute method of the Action class implements the default authorization system. This method checks the
user’s permissions before allowing access to specific routes or actions.
Security Best Practices
By default, everything is set to deny in the template application for security reasons. This default setting ensures
that only explicitly allowed actions are accessible, enhancing the overall security of your application.
Caution
Recommended Authorization Policy
For security, it is recommended to maintain the default
denysetting and explicitly allow access to necessary routes and actions.
CSRF Protection
Overview
Sukarix provides built-in CSRF (Cross-Site Request Forgery) protection mechanisms to ensure the security of your forms and requests. By enabling CSRF protection, you can safeguard your application from unauthorized actions performed by malicious users.
Configuration
CSRF protection is configured in the config.ini file. The following default settings enable CSRF protection and set
the token expiry time:
[SECURITY]
csrf.enabled = true
csrf.expiry = 3600
- csrf.enabled: Enables or disables CSRF protection.
- csrf.expiry: Sets the expiry time for the CSRF token in seconds (default is 3600 seconds or 1 hour).
Note
CSRF Token Expiry
The CSRF token has an expiry time configured in the
config.inifile. If the token has expired, it will be considered invalid. Ensure your application handles token expiry by prompting the user to refresh the form or session.
Generating CSRF Token
To include a hidden CSRF token input in your forms, use the <csrf/> template directive. This directive generates a
hidden input field with the CSRF token, ensuring that each form submission includes a valid token.
Example Usage
<form method="post" action="{{ @ALIASES.login }}">
<csrf/>
<!-- other form fields -->
<input type="submit" value="Submit">
</form>
This example shows how to include a CSRF token in a form. The <csrf/> directive automatically generates and includes
the token.
Validating CSRF Token
To validate the CSRF token, use the isCsrfValid() method from the session. This method checks whether the token
submitted with the form matches the token stored in the user’s session.
Example Usage
if ($this->session->isCsrfValid()) {
// Token is valid, proceed with form processing
} else {
// Token is invalid, handle the error
}
This code snippet shows how to validate the CSRF token when processing a form submission. If the token is valid, you can proceed with the form processing. If the token is invalid, handle the error appropriately.
Tip
Single CSRF Token Per Session
Like many other frameworks, Sukarix handles a single CSRF token per session. This means that each user’s session is associated with one unique CSRF token, which is used to validate all form submissions within that session.
Statera: The Testing Package
Overview
Statera is a testing package designed to work with Sukarix, offering an alternative to PHPUnit. It supports generating coverage reports in formats like Clover, HTML, and Text. Statera operates in both Web and CLI modes, providing flexible testing options.
Statera is an optional, standalone package — applications can choose whether or not to use it for unit testing. The
Sukarix framework itself uses Statera for its own test suite via a require-dev dependency.
Key Concepts
TestGroup
A TestGroup is used to group multiple TestScenario instances. It helps organize related test scenarios into logical
groups, making it easier to manage and run tests collectively.
TestScenario
A TestScenario represents a specific test case or scenario. It encompasses multiple TestCase instances that define
the individual tests to be run as part of the scenario.
TestCase
A TestCase is an individual test case created inside a TestScenario. It extends the Fat-Free Framework’s Test
class and provides the expect() method for assertions to verify the expected behavior of the code under test.
Running Tests
Statera can run tests in both Web and CLI modes, providing detailed coverage reports.
Sukarix Shell Toolbox
Introduction
The Sukarix Shell Toolbox is a versatile utility designed to assist with the configuration, development, monitoring, and
administration of Sukarix applications. It is installed by default in the tools directory of the template application
when running vagrant up and is currently optimized for Ubuntu 22.04.
Functionality
Configuration
- –version: Display Sukarix application version.
- –selfinstall: Make Sukarix runnable from anywhere.
Development
- –enabletests: Enable running unit tests.
- –test <-c>
: Run unit tests with a test name. Use -cfor coverage. - –fix: Fix PHP code style.
- –migrate: Run database migrations.
- –metrics: Generate code metrics.
Monitoring
- –check: Check configuration files and processes for problems.
Administration
- –pull: Pull source code from its repository.
- –deploy: Deploy the application on a production server.
- –build-docs: Build the documentation.
- –jobs: Install the cron jobs.
- –restart: Restart Sukarix Stack.
- –stop: Stop Sukarix Stack.
- –start: Start Sukarix Stack.
- –clean: Restart and clean all log files.
- –cleansessions: Clean sessions from the database.
- –status: Display the running status of components.
- –zip: Zip up log files for reporting an error.
Example Usage
# Display Sukarix application version
sukarix --version
# Enable running unit tests
sukarix --enabletests
# Run unit tests with a test name and coverage
sukarix --test -c <name>
# Check configuration files and processes for problems
sukarix --check
# Restart Sukarix Stack
sukarix --restart
Testing with Sukarix
The Sukarix Shell Toolbox provides several commands to facilitate testing, ensuring your application maintains high quality and reliability. Here’s how you can leverage these testing commands:
Enabling and Running Tests
Enable Tests
To enable the testing environment, use:
sukarix --enabletests
Running Unit Tests
Run unit tests with an optional coverage report using:
sukarix --test <-c> <name>
-c: Generates a coverage report.<name>: Specify the name of the test to run.
Statera Test Runner
Sukarix uses the Statera test runner, which is built on top of the Fat-Free Framework’s
Test class. Tests are organised into groups and scenarios.
Test Structure
- TestGroup: A collection of test scenario classes. Extends
Sukarix\TestGroup. - TestScenario: A class containing test methods (methods starting with
test). ExtendsSukarix\TestScenario. - TestCase: Individual test assertions. Extends
Sukarix\TestCase.
Registering Test Groups
Create a Statera class in your application’s tests/src/Core/ directory:
namespace Core;
use Sukarix\Statera as SukarixStatera;
use Suite\ConfigurationTest;
use Suite\ModelTest;
class Statera extends SukarixStatera
{
public static function registerGroups(): void
{
self::setGroups([
ConfigurationTest::class,
ModelTest::class,
]);
}
}
Writing a Test Suite
A test suite groups related scenarios:
namespace Suite;
use Test\TestGroup;
final class ConfigurationTest extends TestGroup
{
protected $classes = [
\Core\ConfigurationTest::class,
];
}
Writing a Test Scenario
namespace Core;
use Test\Scenario;
final class ConfigurationTest extends Scenario
{
protected $group = 'Framework Configuration';
public function testDefaultConfiguration($f3)
{
$test = $this->newTest();
$test->expect('UTC' === date_default_timezone_get(), 'Timezone set to UTC');
$test->expect('UTF-8' === \ini_get('default_charset'), 'Default charset is UTF-8');
return $test->results();
}
}
Running Tests via CLI
Create a tools/statera.php entry point in your application:
use Application\Application;
use Core\Statera;
// load composer autoload
require_once __DIR__ . '/../vendor/autoload.php';
// Change to application directory to execute the code
chdir(realpath(__DIR__ . '/../app'));
$GLOBALS['test_cli'] = PHP_SAPI === 'cli';
// Activate test environment so detectEnvironment() loads config-test.ini
$f3 = Base::instance();
if (!$f3->exists('GET.statera')) {
$f3->set('GET.statera', 'all');
}
Statera::registerGroups();
Statera::startCoverage('Application Bootstrapping');
$app = new Application();
Statera::stopCoverage();
$app->start();
Run with: php tools/statera.php
For coverage reports, pass the query string:
php tools/statera.php "?statera=withCoverage"
Test Environment
The test environment is activated by setting GET.statera in the F3 hive. When detected, Sukarix loads
config-test.ini and uses the test database. The config-test.ini should use a separate database and
can use file-based cache to avoid Redis dependency during testing.
Deployment
Introduction
Deploying a Sukarix application involves several steps to ensure your code is properly set up on the production server.
Sukarix Deployment Basics
-
Upload Your Code:
- Transfer your application’s codebase to the production server using your preferred method (e.g., FTP, SCP, or Git).
-
Ensure
sukarix.shis in thetoolsDirectory:- Make sure the
sukarix.shscript is located in thetoolsdirectory of your application.
- Make sure the
-
Run the Deployment Script:
- Execute the deployment script with the
-doption:./tools/sukarix.sh -d - This command performs the following actions:
- Pulls the latest code from the Git repository.
- Runs Composer to install dependencies.
- Applies default permissions to the
www-datauser. - Runs database migrations.
- Clears the application cache.
- Execute the deployment script with the
Deploying Documentation
The Sukarix documentation is built with mdBook and deployed automatically to GitHub Pages via GitHub Actions — at no cost.
How It Works
- A GitHub Actions workflow (
.github/workflows/deploy-docs.yml) triggers on every push to themainbranch. - It installs the Rust toolchain, then builds mdBook along with the
mdbook-tocpreprocessor. mdbook buildgenerates the static site in thebook/output directory.- The output is published to GitHub Pages, served at
docs.sukarix.com.
Prerequisites
- The docs repository must be public (GitHub Pages is free for public repos).
- The custom domain
docs.sukarix.comis set via thecnamefield inbook.tomland configured in GitHub Pages settings. - GitHub Pages must be enabled in the repository settings (see steps below).
One-Time Setup
-
Enable GitHub Pages:
- Go to the repository on GitHub → Settings → Pages.
- Under Source, select GitHub Actions.
- Save.
-
Configure DNS:
- In your domain registrar, add a CNAME record:
CNAME docs <your-github-org-or-username>.github.io. - Wait for DNS propagation (can take up to a few minutes to a few hours).
- GitHub will automatically provision an HTTPS certificate once DNS is verified.
- In your domain registrar, add a CNAME record:
Manual Deployment
To trigger a deployment outside of a push, go to the Actions tab in the repository, select the Deploy Docs to GitHub Pages workflow, and click Run workflow.
Contribution Guide
How to Contribute
We welcome contributions from the community! Here’s how you can help.
- Fork the Repository: Create a fork of the Sukarix repository.
- Create a Branch: Make a new branch for your feature or bugfix.
- Commit Changes: Commit your changes with clear commit messages.
- Create a Pull Request: Submit a pull request to the main repository.
Reporting Issues
If you find any bugs or have feature requests, please report them through GitHub Issues.
Community Help
We encourage everyone to contribute to Sukarix and be part of our vibrant community. Whether you have ideas for new features, need support with testing, or want to discuss CLI tools, your input is valuable. Join the conversations and help us improve Sukarix together:
Your contributions make a difference!
Code of Conduct
We strive to maintain a welcoming and inclusive community. Please read our Code of Conduct before contributing.
Thank you for your contributions!
Code of Conduct
Our Pledge
In the interest of fostering an open and welcoming environment, we pledge to make participation in our project and community a harassment-free experience for everyone.
Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior include:
- The use of inappropriate or unwelcome language or imagery
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others’ private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [contact@riadvice.com]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
Attribution
This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html.
Release Notes
Support Policy
Sukarix is currently supported for PHP 8.4+.
Released versions
v0.4.0
🚀 Features & Improvements
- Version Number: 0.4.0
- Release Date: 2026-08-16
- General Overview: Adds a Redis-backed queue service for pipeline workloads, a
HasQueuebehaviour to consume it, and optional coloured console logging. The release is additive — no existing API changed, so upgrading from v0.3.2 requires no application changes.
Changes
- Queue Service (
sukarix): NewSukarix\Queuenamespace providingQueueService, a Redis-backed FIFO queue for passing work between pipeline stages. It adds membership-based deduplication (pushing an already-queued payload is a no-op) and per-item attempt counters on top of a Redis list. Enqueue and dequeue are executed as Redis Lua scripts, so a worker terminated mid-operation can never leave the list and the membership set disagreeing — an item is either fully queued and tracked, or neither. The queue counts attempts but intentionally owns no retry policy: deciding when a failing item is retried or parked stays with the application. See Queues. - Queue Logging (
sukarix): NewQueueProgressLoggeremitting structured queue events (start, progress, completion, throughput, batch progress, per-item add/remove, warnings and errors) with a machine-parsable context array. Item previews are generic by design — an array is reported asarray[3], never with its values — so payload contents never leak into logs. Applications can route queue telemetry elsewhere by registering a subclass under thequeue.progress_loggerInjector alias; a service that does not extendQueueProgressLoggeris rejected with an\UnexpectedValueException. - HasQueue Behaviour (
sukarix): New behaviour trait exposing the resolved queue service as a typed$queueServiceproperty. Resolution is strict by design: constructing a consumer without a registeredqueueservice throws a\LogicExceptionnaming the class, and a service that does not extendQueueServiceis rejected with an\UnexpectedValueException. This surfaces a misconfiguration at boot rather than at the first queue call, where a null member access would point at the wrong place. - Console Logging (
sukarix):LogWritergained an optional standard-output handler enabled withlog.console = true, intended for CLI applications. Whenbramus/monolog-colored-line-formatteris installed the output is coloured per level, otherwise a plain stream is used. The file handler remains active, so console output is added rather than substituted. See Logging. - Redis Connection Timeout (
sukarix): The queue honoursredis.timeout(default 2 seconds) and throws\RedisExceptionwhen the connection cannot be established, so a misconfigured worker fails immediately instead of part-way through a run. - Documentation: Added a Queues page. Rewrote the Behaviours page to list every available trait with the property it injects and its visibility, documenting that
HasAccessandHasEventsexpose aprivateproperty that subclasses cannot read. Corrected its example, which called a non-existent$this->log->write()instead of the$this->loggerMonolog instance theLogWritertrait actually provides. Expanded Logging with the logger API,log.leveland the newlog.consolesetting. Added Queues to the feature list.
v0.3.2
🐛 Bug Fixes
- Version Number: 0.3.2
- Release Date: 2026-08-04
- General Overview: Bug-fix release addressing cache, JSON encoding, and documentation accuracy issues found via static analysis.
Changes
- HasCache::remember() (
sukarix):Cache::get()returnsfalseboth on a cache miss and when the stored value is legitimatelyfalse, soremember()could never recognise a cached falsy value as a hit and recomputed it on every call. Switched toCache::exists()to distinguish a real hit from a miss. The accompanyingResponseTestwas rewritten to exercise the trait directly (the previous test asserted hardcoded literals against themselves) and a regression test for the falsy-value case was added. - Model::__construct() PHPDoc (
sukarix): Corrected the@paramtags, which inaccurately claimed$db,$tableand$fluidmust always benull. They mirror Cortex’s constructor and acceptobject,stringandboolrespectively; the wrong annotations caused PHPStan to flag the subsequent null-check as dead code. - TestScenario::postJsonData() (
statera): The method declared astringreturn type butjson_encode()can returnfalseon failure, which understrict_typeswould throw aTypeErrorinstead of a clear JSON error. Now passesJSON_THROW_ON_ERROR, matching the convention already used elsewhere in the class. - TestScenario::run() cleanup (
statera): Removed an orphaned@var CodeCoverage $coveragedocblock and its accompanyingusestatement left over from a prior refactor; they no longer corresponded to any variable in the method.
v0.3.1
🚀 Features & Improvements
- Version Number: 0.3.1
- Release Date: 2026-07-18
- General Overview: Statera migration, trait initialization refactor, cursor-based pagination, cache helpers, and open-source readiness.
Changes
- PHPUnit Removal: Dropped
phpunit/phpunitandphpunit/php-code-coveragefromrequire-devand removedphpunit.xml.dist. The framework’sInjectorTestwas converted from a PHPUnitTestCaseto a StateraTestScenariousingexpect()assertions. Code coverage is now provided transitively by Statera’s ownphpunit/php-code-coveragedependency. - Statera Dependency: Added
sukarix/stateratorequire-devso the framework uses its own testing kit for its test suite. Statera remains an optional, standalone package for applications. - Test Runner: Added
tools/statera.phpand test infrastructure (tests/src/Test/,tests/src/Suite/) to run the framework’s tests via Statera. - Statera Package: Declared the previously-undeclared
sukarix/sukarixruntime dependency insukarix/statera’scomposer.json(Statera usesSukarix\Utils\CliUtilsandSukarix\Utils\Time). - Trait Initialization: Moved
Processor::initialize()fromTailored::instance()to class constructors. EachTailoredsubclass must now callProcessor::instance()->initialize($this)in its constructor. TheHelperbase class does this automatically. - LogWriter: Added
initLogger()backward-compatible alias forinitLogWriter(). - TestCase: Removed
finalkeyword to allow subclassing in application test suites. - Action: Added
Processorimport. Made$view,$argv,$headerAuthorization, and$templatesDirnullable to prevent uninitialized typed property errors. - MailSender:
smtpSend()andgenerateId()changed fromprivatetoprotectedfor extensibility. - Assets: Constructor now calls
parent::__construct()for proper trait initialization. - TestScenario:
loadResult()handles missing template files gracefully. - Cursor Pagination: Added
Response::cursor()for cursor-based API pagination — stable under concurrent inserts, efficient on large datasets. Returns{ field, limit, has_more, next }structure. - Cache Remember: Added
HasCache::remember()for get-or-set cache pattern andHasCache::forget()for invalidation. - Paginate Fix:
Response::paginate()now castspagestoint(wasfloatfromceil()). - Open Source: Added
AGENTS.mdwith contribution guidelines and AI usage transparency across all repositories.
v0.2.0
🚀 Features
- Version Number: 0.2.0
- Release Date: 2025-01-20
- General Overview: Added CSRF protection, enhanced session management, and improved validation.
v0.1.0
🚀 Introduction
- Version Number: 0.1.0
- Release Date: 2024-06-14
- General Overview: First version of the Sukarix Framework.