Controllers¶
Introduction¶
Controllers are the backbone of the eQual framework's backend logic. They are regular PHP scripts that follow the CQRS (Command-Query Responsibility Separation) architectural pattern.
eQual allows attaching URIs to any operation defined in these controllers, making them accessible via HTTP, CLI, or internal PHP calls.
Controllers are organized into three specific directories within a Package:
| FOLDER | TYPE | METHOD | DESCRIPTION |
|---|---|---|---|
actions |
Action Handlers | DO |
Processing operations involving data manipulation (Commands) such as CREATE, UPDATE, DELETE. |
data |
Data Providers | GET |
Data providers responsible for retrieving and querying data (Queries/READ operations). |
apps |
Application Providers | SHOW |
Operations involving UI data generated by the back-end (Server-Side Rendering). |
About Controllers
- Controllers are re-usable and can be interdependent.
- Controllers can act as data funnels and dispatchers.
- While they have access to global variables, variables declared within a controller remain separate from the global scope.
Controller Anatomy¶
A controller script typically begins with an announcement using the eQual::announce method. This method handles Dependency Injection and validates input parameters.
Announcement Structure¶
The announcement array defines the controller's contract:
- description: What the controller does.
- params: Expected input parameters, their types, and constraints.
- response: Output format (content-type) and CORS settings.
- access: Access control configuration.
- providers: Required services to be injected.
- constants: Package-specific constants used by the script.
description¶
A simple string describing the controller's purpose. This is used for documentation and by the Workbench.
params¶
An associative array defining the input API. Each key is a parameter name, and its value is a definition array.
'params' => [
'user_id' => [
'description' => "Target user identifier",
'type' => 'integer',
'required' => true
]
]
access¶
The access property defines the security context required to execute the controller.
| PROPERTY | DESCRIPTION |
|---|---|
visibility |
The visibility level: 'public' (anonymous), 'protected' (authenticated), or 'private' (internal). |
groups |
An array of group names allowed to access the controller. |
users |
An array of specific user IDs allowed to access the controller. |
Examples:
// Public access
'access' => [ 'visibility' => 'public' ]
// Restricted to a specific group
'access' => [
'visibility' => 'protected',
'groups' => ['sales.bookings.users']
]
response¶
Defines the output format and CORS policy.
'response' => [
'content-type' => 'application/json',
'charset' => 'utf-8',
'accept-origin' => '*' // Allows access from any domain
]
constants¶
Lists constants required by the controller. These can be defined globally in config/config.inc.php or overridden at the Package level.
'constants' => ['AUTH_ACCESS_TOKEN_VALIDITY', 'AUTH_TOKEN_HTTPS']
examples¶
An optional property providing usage examples for documentation purposes.
'examples' => [
'CLI' => './equal.run --get=contractika_sd_absences --id=16',
'HTTP' => '/?get=contractika_sd_absences&id=16',
'PHP' => "eQual::run('get', 'contractika_sd_absences', ['id' => 16]);"
]
Dependency Injection¶
eQual uses dependency injection to provide controllers with parameters and services.
Usage¶
Services are requested via the providers key in the announcement. The eQual::announce function returns two arrays:
1. $params: The validated input parameters.
2. $providers: The requested service instances.
<?php
// 1. Announce requirements
list($params, $providers) = eQual::announce([
'params' => [...],
'providers' => ['context', 'orm', 'auth']
]);
// 2. Extract services
/**
* @var \equal\php\Context $context
* @var \equal\orm\ObjectManager $orm
* @var \equal\auth\AuthenticationManager $auth
*/
list($context, $orm, $auth) = [$providers['context'], $providers['orm'], $providers['auth']];
Predefined Services¶
| Service Name | Class | Role |
|---|---|---|
context |
equal\php\Context |
Manages runtime context (user, language, environment). |
orm |
equal\orm\ObjectManager |
Interfaces with the database and manages entities. |
auth |
equal\auth\AuthenticationManager |
Handles user authentication and session management. |
access |
equal\access\AccessController |
Manages permissions and policies (RBAC/ABAC). |
validate |
equal\data\DataValidator |
Validates data against schemas. |
adapt |
equal\data\DataAdapter |
Transforms data formats. |
| log | equal\log\Logger |
Handles application logging. |
report |
equal\error\Reporter |
Manages error reporting. |
dispatch |
equal\dispatch\Dispatcher |
Handles alerts and messaging. |
route |
equal\route\Router |
Manages URL routing. |
cron |
equal\cron\Scheduler |
Manages scheduled tasks. |
Custom Services¶
Developers can register custom services or override existing ones in eq.lib.php or config.inc.php.
Example: Overriding AccessController
'providers' => [
'auth',
'access' => 'custom\AccessController' // Use custom implementation
]
Invoking Controllers¶
Controllers can be invoked in three different contexts. The framework ensures consistent execution regardless of the invocation method.
1. HTTP Request¶
The most common method, used by frontend applications and APIs.
-
GET:
http://equal.local/?get=demo_simple -
DO:
http://equal.local/?do=core_user_create
2. CLI (Command Line Interface)¶
Controllers can be executed from the terminal using equal.run. Parameters are passed using long option notation (--arg=value).
# Get data
./equal.run --get=model_collect --entity=core\\User --domain="[id,>,100]"
# Perform action
./equal.run --do=init_package --package=todolist
Escaping
When using CLI, ensure complex parameter values (like JSON objects or arrays) are encapsulated within double quotes to prevent shell interpretation issues.
3. PHP Script (Internal)¶
Controllers can be called directly from other PHP scripts using eQual::run.
$result = eQual::run('get', 'core_model_read', [
'entity' => 'core\User',
'id' => 1
]);
Advanced Logic¶
Access Control in Controllers¶
The AccessController service (equal\access\AccessController) is central to enforcing granular permissions using:
-
ACL (Access Control Lists) based on the
Permissionclass. -
RBAC (Role-Based Access Control) using the
Assignmentclass. -
Policies for conditional workflows.
Common Methods¶
hasRight: Checks generic CRUD permissions (e.g., can this user create a User entity?).canPerform: Checks if a specific action allowed by business policies.
Direct Check Example¶
if(!Report::ids($params['ids'])->can('publish')) {
throw new Exception('cannot_publish', QN_ERROR_NOT_ALLOWED);
}
Action Handlers (getActions)¶
For complex workflows, entities can define a getActions() method. This allows standardizing actions and their required policies.
Definition in Entity:
public static function getActions() {
return [
'publish' => [
'policies' => ['publishable'], // Required policy
'function' => 'doPublish' // Method to execute
]
];
}
Usage in Controller:
// Check policies automatically and execute if allowed
Report::ids($ids)->do('publish');
Alerts & Consistency¶
Controllers can interact with the Dispatcher service to manage system alerts.
- Check Controllers: Extending
model_check, these controllers validate data consistency. They are "Alert-aware" and can create or dismissMessageobjects based on the result of the check.
Passkey Authentication¶
Specific controllers serve the WebAuthn standard:
* user_passkey-register*: Handles challenge generation and public key storage.
* user_passkey-auth*: Manages challenge verification and session creation.
Pipelines¶
Controllers can be chained into Pipelines to process data in stages. See the Pipeline Editor Documentation for visual configuration.