This page explains the concept of metadata in AtroCore and how developers can work with it to define and extend entity structures.
What is Metadata?
Metadata stores various useful data in the system that can be extended by any other modules, like data about entities,
including options, fields, relationships, frontend controllers, custom services and more.
These data are defined in JSON format in the Resources/metadata
folder, located in the root directory of an
application or custom module.
Metadata is loaded and merged into a single structure during system initialization.
AtroCore uses metadata in two main layers:
- Application Layer: Metadata tells the system how to render fields in the UI (e.g.,
varchar
→ input,text
→ textarea), how to filter/search, and how to manage relationships. - Database Layer: Metadata defines which fields and indexes should exist in the database.
Common Metadata
Here are some commonly used metadata available in AtroCore:
Data | Description |
---|---|
scopes |
Defines entity parameters, such as the type. Each file is name as {EntityName}.json (e.g. Product.json) |
entityDefs |
Describes the structure of an entity: its fields, relationships, indexes, and collection behavior. Each file is name as {EntityName}.json |
clientDefs |
Stores data about frontend controllers, views, panels, and dashlets. This data determines the frontend behavior for entities. each file is name as {EntityName}.json |
twig |
Contains filters.json and functions.json , which register filters and functions used in script fields. Learn more in Twig Templating. |
app |
Defines application-level data. with data like acl.json or adminPanels listing the links in the Admin panel |
Storing new data
Let's store a new data by creating the file Resources/metadata/examples/images.json
with the content:
{
"image1": "image1-url",
"image2": "image2-url",
"thumbnail":{
"iphone": "iphone-thumbnail-url"
},
"sizes" : [20, 40]
}
Accessing Metadata
To access data from metadata, get metadata
from the service container:
/** @var \Atro\Core\Utils\Metadata::class $metadata */
$metadata = $container->get('metadata')
$image1 = $metadata->get(['examples', 'images', 'image1'])
// $image1 is "image1-url"
$image2 = $metadata->get(['examples', 'images', 'image2'])
// $$image2 is image2-url
$image3 = $metadata->get(['examples', 'images', 'image3'])
// $image3 is null
$image3 = $metadata->get(['examples', 'images', 'image3'], 'default-image3-url')
// $image3 is 'default-image3-url'
$thumbnail = $image3 = $metadata->get(['examples', 'images', 'thumbnail', 'iphone'])
// is iphone-thumbnail-url
The PhpStorm plugin AtroCore Toolkit can help you with the autocompletion of metadata keys.
In the frontend the metadata can be accessed from any view like this:
let image1 = this.getMetadata().get(['examples', 'images', 'image1'])
Extending Metadata
Core metadata is loaded first, followed by metadata from modules in their defined loading order. This means that a later module can extend or override any existing metadata.
This powerful extending ability of metadata is frequently used by custom module to add new fields on existing entity
There are two ways to extend metadata:
Static Extension
Metadata content can be extended by any module by following the same path. For example, a module can overwrite an
existing key or add new ones.
For arrays, you can use the __APPEND__
keyword to add new values instead of overwriting the entire array.
Example:
A module adds the file Resources/metadata/examples/images.json
with the following content:
{
"image2": "new-content",
"image3": "https://picsum.photos/id/2/50/50",
"sizes": [
"__APPEND__",
50
]
}
This file will be merged with the original definition. Now, accessing the data:
/** @var \Atro\Core\Utils\Metadata::class $metadata */
$metadata = $container->get('metadata')
$image1 = $metadata->get(['examples', 'images', 'image1'], 'defaultImageValue')
// $image1 is "image1-url"
$image2 = $metadata->get(['examples', 'images', 'image2'])
// $image2 is "new-content"
$image3 = $metadata->get(['examples', 'images', 'image3'])
// $image3 is https://picsum.photos/id/2/50/50
$sizes = $metadata->get(['examples', 'images', 'sizes'])
// $sizes is [20, 40, 50]
Dynamic Extension via Listener
Use a Listeners\Metadata.php
listener to modify metadata programmatically. This is useful when:
- Metadata should be added conditionally
- Complex merging logic is required
Example:
namespace {ModuleNamespace}\Listeners;
use Atro\Listeners\AbstractListener;
class Metadata extends AbstractListener
{
public function modify(Event $event): void
{
$data = $event->getArgument('data');
$data['examples']['images']['image1'] = 'modify-programmatically'
}
}
Now, accessing the data:
/** @var \Atro\Core\Utils\Metadata::class $metadata */
$metadata = $container->get('metadata')
$image1 = $metadata->get(['examples', 'images', 'image1'])
// $image1 is modify-programmatically
You can check a real life example in Metadata.php in AtroPim module
Metadata entityDefs
entityDefs
metadata is used to define fields, relationships, indexes, and collection behavior. This information helps
the system to:
- Generate database schemas.
- Determine which fields and links exist.
- Define how fields are rendered in the UI.
- Enable filtering and sorting.
- Ensure consistency across modules.
Example: Brand.json
The Brand
entity is defined in the Pim
module. You
can find its metadata at /app/Resources/metadata/entityDefs/Brand.json
.
{
"fields": {
"name": {
"type": "varchar",
"required": true,
"trim": true,
"isMultilang": true
},
"description": {
"type": "text",
"required": false,
"rowsMax": 4,
"lengthOfCut": 400,
"seeMoreDisabled": false,
"readOnly": false,
"tooltip": false,
"isMultilang": true
},
"files": {
"type": "linkMultiple",
"layoutDetailDisabled": true,
"massUpdateDisabled": true,
"noLoad": true
},
"createdAt": {
"type": "datetime",
"readOnly": true
},
"modifiedAt": {
"type": "datetime",
"readOnly": true
},
"createdBy": {
"type": "link",
"readOnly": true,
"view": "views/fields/user"
},
"modifiedBy": {
"type": "link",
"readOnly": true,
"view": "views/fields/user"
},
"products": {
"type": "linkMultiple",
"layoutDetailDisabled": true,
"layoutListDisabled": true,
"massUpdateDisabled": true,
"noLoad": true,
"importDisabled": true
},
"code": {
"type": "varchar",
"trim": true,
"unique": true
}
},
"links": {
"files": {
"type": "hasMany",
"relationName": "brandFile",
"foreign": "brands",
"entity": "File"
},
"createdBy": {
"type": "belongsTo",
"entity": "User"
},
"modifiedBy": {
"type": "belongsTo",
"entity": "User"
},
"products": {
"type": "hasMany",
"foreign": "brand",
"entity": "Product"
}
},
"collection": {
"sortBy": "createdAt",
"asc": false,
"textFilterFields": [
"name",
"code"
]
},
"indexes": {
"name": {
"columns": [
"name",
"deleted"
]
}
}
}
Let breaks down this.
Fields
As you may have noticed, each field of your entity is defined as a key in fields
, and it values are options about the field like type
, required
or isMultilang
for multilingual fields.
the available supported types are int
, float
, bool
, varchar
, text
, color
, markdown
, wysiwyg
, url
, email
, password
, date
, datetime
, enum
, multiEnum
, extensibleEnum
, extensibleMultiEnum
, measure
, file
, link
, linkMultiple
Fields should be named in camel case format.
Links
Any field that is a relation should be defined in links
to give more information about the relation.
After doing any change in the entityDefs folder, it directly as and impact on the database layer, to see the change to make your database consistent with your modification, run the command
php console.php sql diff --show
the system will generate SQL queries. To apply the query to make the database and the App consistent runphp console.php sql diff --run
Entity Management and custom Metadata
AtroCore Allow in the administration any users with appropriate rights on Entity Entity
to:
- Add fields and links to existing entities
- Create entirely new entities
These changes are stored as metadata files in: data/metadata/entityDefs/
, where data is in the root of your
application in your server.
Getting Metadata
The metadata are loaded, merged and cached in the backend to data/cache/metadata.json
. This file is recreated everytime the system cache is cleared.
When doing any modifications on metadata files inResources/metadata
, make sure to clear the system cache, by running the command php console.php clear cache
.
Disabling the
useCache
setting indata/config.php
prevents the application from utilizing the cache. When this option is set to false, metadata is rebuilt with every request. This feature is highly beneficial for developers, as it streamlines the development workflow by removing the requirement to repeatedly clear the cache.
You can also get the metadata using the API GET route /api/v1/Metadata
. You can learn more about on how to interact with the API here.
Summary
- Metadata define data available in the backend and frontend
- Metadata defines entity structure for both DB and UI.
- It is stored in JSON files and merged across modules.
- You can extend metadata statically or dynamically.
- Entity Manager-generated metadata is stored in /data/metadata and loaded last.