Overview
AtroCore integrates Twig templating throughout the platform, enabling developers to create dynamic content and implement business logic in script fields, workflows, export feeds, and UI handlers.
How to Use Twig in AtroCore
Available Contexts
Twig is accessible in several contexts, each with specific variables and use cases:
Context | Purpose | Available Variables |
---|---|---|
Script Fields | Dynamic field content | config , entity |
Workflow Conditions | Business rule evaluation | entity , user , importJobId |
Workflow Actions | Data manipulation | entity , triggeredEntity |
Export Feed Templates | Data formatting | entities , feed |
Action Scripts | Bulk operations | sourceEntities , triggeredEntity |
UI Handler Scripts | Frontend behavior | entity , entityFrom |
System Configuration Access
The config
variable provides access to system settings:
{{ config.siteUrl }}
{{ config.defaultLanguage }}
{{ config.timeZone }}
Monaco Editor Features
AtroCore uses Monaco Editor (VS Code's editor) for enhanced development experience:
IntelliSense and Auto-completion
- Function Suggestions: Auto-complete shows available custom functions
- Filter Completion: Type
|
to see available Twig filters - Context-Aware: Suggestions adapt to your current context
Development Tools
- Syntax Highlighting: Full Twig syntax support
- Error Detection: Real-time validation and error highlighting
- Code Formatting: Auto-indentation and beautification
- Documentation on Hover: Function signatures and parameter info
Getting Help
- Hover Documentation: Hover over functions to see signatures and examples
- Ctrl+Space: Trigger IntelliSense manually
- Error Squiggles: Red underlines show syntax issues
Context-Specific Examples
Script Fields
{# Access entity properties #}
{{ entity.name }} - {{ entity.createdAt|date('Y-m-d') }}
{# Use system config #}
Generated on {{ config.siteUrl }}
Workflow Conditions
{# Boolean expression for workflow triggers #}
{{ entity.isActive and user.id != 'system' and importJobId is empty }}
Export Feed Templates
[
{% for entity in entities %}
{
"id": "{{ entity.id }}",
"name": "{{ entity.name|escapeDoubleQuote }}"
}{% if not loop.last %},{% endif %}
{% endfor %}
]
UI Handler Scripts
{# Prompt field - generates AI prompts #}
Generate a description for product "{{ entity.name }}" in category "{{ entity.category.name }}"
{# UpdateScript field - returns JSON for entity updates #}
{
"description": "{{ 'Auto-generated description for ' ~ entity.name }}"
}
Where to find twig functions and filters
Twig functions and filters are registered in metadata files that determine their availability:
Global Functions & Filters (All Contexts)
- Functions:
Resources/metadata/twig/functions.json
- Filters:
Resources/metadata/twig/filters.json
These are available everywhere Twig is used (script fields, workflows, actions, UI handlers, etc.)
Export Feed Specific Functions & Filters
- Functions:
Resources/metadata/app/twigFunctions.json
- Filters:
Resources/metadata/app/twigFilters.json
These are only available in Export Feed templates for specialized data export functionality.
Module Extensions
Each module can extend Twig capabilities by adding entries to their own metadata files
Adding Custom Twig Functions
Creating a New Twig Function
- Create the Function Class:
<?php
namespace CustomModule\TwigFunction;
use Atro\Core\Twig\AbstractTwigFunction;
use Espo\ORM\EntityCollection;
use Espo\ORM\EntityManager;
class FindEntities extends AbstractTwigFunction
{
protected EntityManager $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function run(string $entityName, array $where = [], string $orderField = 'id', string $orderDirection = 'ASC', int $offset = 0, int $limit = \PHP_INT_MAX, bool $withDeleted = false): EntityCollection
{
return $this->entityManager->getRepository($entityName)
->where($where)
->order($orderField, $orderDirection)
->limit($offset, $limit)
->find(['withDeleted' => $withDeleted]);
}
}
- Register in metadata (
CustomModule/Resources/metadata/twig/functions.json
):
{
"findEntities": {
"handler": "\\CustomModule\\TwigFunction\\FindEntities",
"insertText": "findEntities(${1:entityName}, ${2:{}})"
}
}
handler
property is the defined twig function class name.
insertText
property is the text for autocompletion in monaco editor.
- Usage in Twig:
{% set activeProducts = findEntities('Product', {isActive: 'true'}, 'name', 'ASC', 0, 10}) %}
Function Development Guidelines
- Extend
Atro\Core\Twig\AbstractTwigFunction
base class - Use dependency injection for services
- Handle errors gracefully with try-catch
- Return appropriate data types
- Document parameters and return values
Adding Custom Twig Filters
Creating a New Twig Filter
- Create the Filter Class:
<?php
namespace CustomModule\TwigFilter;
use Atro\Core\Twig\AbstractTwigFilter;
class Md5 extends AbstractTwigFilter
{
public function filter($value)
{
if (!is_string($value)) {
return null;
}
return md5($value);
}
}
- Register in metadata (
CustomModule/Resources/metadata/twig/filters.json
):
{
"md5": {
"handler": "\\CustomModule\\TwigFilter\\Md5"
}
}
- Usage in Twig:
{{ fileContent | md5 }}
Filter Development Guidelines
- Extend
Atro\Core\Twig\AbstractTwigFilter
base class - First parameter is always the value being filtered
- No Support for additional parameters
- Return modified value of appropriate type
- Chain-friendly design
Base Classes Reference
AbstractTwigFunction
abstract class AbstractTwigFunction
{
public function setTemplateData(array $templateData): void
public function getTemplateData(string $name)
abstract public function run(...$args);
}
AbstractTwigFilter
abstract class AbstractTwigFilter extends Injectable
{
public function setTemplateData(array $templateData): void
public function getTemplateData(string $name)
abstract public function filter($value);
}
Best Practices
Performance
- Cache expensive operations
- Avoid database queries in loops
- Use findEntities with limits for large datasets
Security
- Always escape user input:
{{ userInput|escape }}
- Validate parameters in custom functions
- Use
|raw
filter carefully and only for trusted content
Maintainability
- Use descriptive function/filter names
- Document complex logic with comments
Migration and Updates
When updating AtroCore:
- Check
twig
property in the metadata object for new functions/filters - Review changelog for Twig-related changes