Skip to content

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 Permission class.

  • RBAC (Role-Based Access Control) using the Assignment class.

  • 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 dismiss Message objects 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.