Files
acai-scaffold/docs/hooks-and-api.md
2026-03-21 10:28:42 +00:00

7.8 KiB

Hooks & Server-Side API

Hooks

Hooks are PHP files in the hooks/ directory that execute server-side logic. They can also live inside a module at template/estandar/modulos/<module-id>/hook.php.

Testing Hooks

To test hooks, the site's Docker container must be running. Make a curl request to the Docker URL with the hook path. For example, if a hook is named hooks.example_hook.php:

curl http://{DOCKER_URL_AND_PORT}/hooks/example_hook/

Replace {DOCKER_URL_AND_PORT} with your local Docker address (e.g., localhost:8080) and parse hook name for url endpoint.

Do not use X-Hooks-Token because its not needed on developer environment.

How to Call Hooks

From Twig:

{{ 'hooks/module_id/' | hook({param1: 'value1', param2: variable}) }}

From HTML (with result):

<hook result="myVar" endpoint="/hooks/module_id/" :param1="value1" :param2="'string'"></hook>
<p>{{ myVar }}</p>

From JavaScript:

CmsApi.hook('/hooks/module_id/', { param1: 'value1' }, function(response) {
  console.log(response);
});

From c-form: Hooks are automatically triggered on form submission when configured.

Hook Parameters

Parameters are received as PHP variables:

<?php
// Called with: 'hooks/my_hook/' | hook({category: 'electronics', limit: 10})
// Available as:
$category; // 'electronics'
$limit;    // 10

Hook Return Values

Hooks can echo or return values. When called from Twig or <hook> tag, the output is captured into the result variable.

CmsApi (PHP)

Server-side API for database operations. Available in all hooks.

Read Records

// Get all records
$products = CmsApi::get('productos');

// With WHERE condition
$active = CmsApi::get('productos', ['active' => 1]);

// With order and limit
$latest = CmsApi::get('noticias', [], 'fecha DESC', 5);

// With operators
$expensive = CmsApi::get('productos', ['precio' => ['>=' => 100]]);
$search = CmsApi::get('productos', ['nombre' => ['LIKE' => '%keyword%']]);
$inList = CmsApi::get('productos', ['categoria_num' => ['IN' => [1, 2, 3]]]);

Insert Records

$newRecord = CmsApi::insert('contacto', [
    'nombre' => 'John',
    'email' => 'john@example.com',
    'mensaje' => 'Hello',
]);

Update Records

CmsApi::update('productos',
    ['precio' => 29.99, 'activo' => 1],  // fields to update
    ['num' => 42]                          // where condition
);

Delete Records

CmsApi::delete('productos', ['num' => 42]);

Important Rules

  • Table names without cms_ prefix
  • Primary key is always num, never id
  • Upload fields are handled separately (not via insert/update)
  • Operators: =, !=, >, >=, <, <=, LIKE, IN

CmsApi (JavaScript — Client-Side)

// Hook call
CmsApi.hook('/hooks/module_id/', { param: 'value' }, function(response) {
  // response is the hook output
});

// Record operations (if exposed via hooks)
CmsApi.get('tableName', { where: conditions }, function(records) {
  // records array
});

CocoDB

Low-level database abstraction layer used internally by CmsApi. Use directly from hooks when you need more control.

CocoDB::get($table, $where, $order, $limit, $options)

Reads records from a table. This is the same method CmsApi::get wraps.

// Basic query
$records = CocoDB::get('productos', ['activo' => 1], 'orden ASC', 10);

// With advanced where (array syntax for operators)
$records = CocoDB::get('productos', [
    ['column' => 'precio', 'value' => 100, 'operator' => '>='],
    ['column' => 'categoria_num', 'value' => [1, 2, 3], 'operator' => 'IN'],
]);

// OR conditions
$records = CocoDB::get('productos', [
    ['column' => 'nombre', 'value' => '%keyword%', 'operator' => 'LIKE'],
    ['column' => 'descripcion', 'value' => '%keyword%', 'operator' => 'LIKE', 'or' => true],
]);

// NOT condition
$records = CocoDB::get('productos', [
    ['column' => 'estado', 'value' => 'borrador', 'operator' => '=', 'not' => true],
]);

// IS NULL
$records = CocoDB::get('productos', [
    ['column' => 'fecha_baja', 'value' => '', 'operator' => 'IS NULL'],
]);

// Limit with offset
$records = CocoDB::get('productos', [], 'num DESC', ['limit' => 10, 'offset' => 20]);

Options for get()

Option Type Default Description
uploads bool true Include upload field data
relations bool/array true Resolve foreign key relations. Pass array to limit: ['category']
relationsDepth int 2 Depth of nested relation resolution
translates string current lang Language code for translations
groupBy string null GROUP BY clause
aggregates array [] Aggregate functions
onlyFields array null Select specific fields only
debug bool false Output SQL query for debugging
redis bool null Force Redis cache
redis_expire int 60 Redis cache TTL in seconds

CocoDB::insertRecords($table, $records, $functions, $options)

Insert one or multiple records.

// Single record
$count = CocoDB::insertRecords('contacto', [
    'nombre' => 'John',
    'email' => 'john@example.com',
]);
// Returns number of inserted records. Use mysql_insert_id() to get the new num.

// Multiple records
$count = CocoDB::insertRecords('productos', [
    ['nombre' => 'Product A', 'precio' => 10],
    ['nombre' => 'Product B', 'precio' => 20],
]);

Options for insert/update

Option Description
forceNum Allow setting the num field manually
ignoreSchema Skip schema validation
ignoreFields Array of field names to skip

CocoDB::updateRecords($table, $records, $where, $functions, $options)

Update records matching a where condition.

CocoDB::updateRecords('productos',
    ['precio' => 29.99, 'activo' => 1],   // fields to update
    ['num' => 42]                           // where condition
);

// With operator in where
CocoDB::updateRecords('productos',
    ['activo' => 0],
    [['column' => 'stock', 'value' => 0, 'operator' => '<=']]
);

CocoDB::deleteRecords($table, $where, $options)

Delete records matching a where condition.

CocoDB::deleteRecords('productos', ['num' => 42]);

// With operator
CocoDB::deleteRecords('logs', [
    ['column' => 'fecha', 'value' => '2024-01-01', 'operator' => '<']
]);

Where Clause Syntax

The $where parameter supports two formats:

Simple (key-value):

['campo' => 'valor']  // campo = 'valor'

Advanced (array of conditions):

[
    'column'   => 'field_name',   // Required
    'value'    => 'match_value',  // Required
    'operator' => '=',            // =, !=, <, >, <=, >=, LIKE, IN, IS NULL
    'or'       => false,          // Use OR instead of AND
    'not'      => false,          // Negate the condition
    'raw_key'  => false,          // Skip column existence check
]

Functions Parameter

The $functions parameter lets you apply MySQL functions to values during insert/update:

CocoDB::insertRecords('logs', [
    'mensaje' => 'Login exitoso',
    'fecha' => '',
], [
    'fecha' => 'NOW()',  // Will use MySQL NOW() instead of the value
]);

Table Schemas

Table schemas are stored as JSON in cms/data/schema/. Each file defines:

  • Field names and types
  • Validation rules
  • Relationships (foreign keys)
  • Display configuration

Field Format Types

Type PHP Format Notes
Text String Plain text
Date/time YYYY-MM-DD HH:mm:ss MySQL datetime format
Checkbox 1 or 0 Boolean as integer
WYSIWYG HTML string Rich text with Tailwind classes
List String or num Foreign key if linked to table
Multivalores JSON string Serialized array
Upload Handled separately, never in insert/update