To respond with consistent data the BEdita object types are transformed and formatted using the ApiFormatter
Component that deals with cleaning objects from useless data and casting and trasforming some fields in correct format.
If you have a look at /objects/:id
response you'll see that fields as 'id' are integer other like 'latitude' and 'longitude' of geo tag are float and dates are formatted in ISO-8601. ApiFormatter
Component with a little help from Models takes care of it.
When you load an object or list of objects you should always use the ApiFromatter
Component to have data always formatted in the same way.
// load an object
$object = $this->loadObj($id);
$result = $this->ApiFormatter->formatObject($object);
// in $result['object'] you have the formatted object
// list of objects
$objects = $this->loadSectionObjects($id, array('itemsTogether' => true));
$result = $this->ApiFormatter->formatObjects($objects['children']);
// in $result['objects'] you have the formatted objects
ApiFormatter::formatObject()
and ApiFormatter::formatObjects()
accept as second argument an array of options with which it is possible add to the formatted object the count of relations and children.
$result = $this->ApiFormatter->formatObject($object, array(
'countRelations' => true,
'countChildren' => true
));
By default no count is done.
When formatting BEdita object ApiFormatter
asks help to related object type Model to know which fields have to be cast in the right type. Basically every object type returns an array of fields that are defined in database as 'integer', 'float', 'date', 'datetime', 'boolean'. This array is returned from BEAppObjectModel::apiTransformer()
method and it is something similar to
array(
'id' => 'integer',
'start_date' => 'datetime',
'end_date' => 'datetime',
'duration' => 'integer',
'object_type_id' => 'integer',
'created' => 'datetime',
'modified' => 'datetime',
'valid' => 'boolean',
'user_created' => 'integer',
'user_modified' => 'integer',
'fixed' => 'boolean',
'GeoTag' => array(
'id' => 'integer',
'object_id' => 'integer',
'latitude' => 'float',
'longitude' => 'float',
'gmaps_lookat' => array(
'latitude' => 'float',
'longitude' => 'float',
'zoom' => 'integer',
)
)
'Tag' => array(
'id' => 'integer',
'area_id' => 'integer',
'object_type_id' => 'integer',
'priority' => 'integer',
'parent_id' => 'integer',
),
'Category' => array(
'id' => 'integer',
'area_id' => 'integer',
'object_type_id' => 'integer',
'priority' => 'integer',
'parent_id' => 'integer',
)
)
By default only tables that form the object chain plus 'categories', 'tags' and 'geo_tags' are automatically returned, but that method can be overridden to customize the result. For example the Event
model add to basic transformer the DateItem
transformer:
public function apiTransformer(array $options = array()) {
$transformer = parent::apiTransformer($options);
$transformer['DateItem'] = $this->DateItem->apiTransformer($options);
return $transformer;
}
The ApiFormatter
uses these transformers merged to common object transformer ApiFormatterComponent::$transformers['object']
to present consistent data to client. It is possible to use some special transformer types that are:
underscoreField
that underscorize a camelcase field maintaining value unchangedintegerArray
that cast to integer all array values
Another useful task of ApiFormatter
is to clean unwanted fields from data exposed to client. To do that it uses ApiFormatter::$objectFieldsToRemove
array that can be customized through configuration or on the fly in controller.
In config/frontend.ini.php
or config/frontend.cfg.php
is possible to customize which fields exposed by default you want to remove from results.
$config['api'] = array(
'baseUrl' => '/api/v1',
...
'formatting' => array(
'fields' => array(
// fields that should be added
// to ApiFormattingComponent::objectFieldsToRemove
// i.e. removed from formatted object
'remove' => array(
'description',
'title',
'Category' => array('name'),
'GeoTag' => array('title'),
'Tag'
)
)
)
);
In this way you say to ApiFormatter
that 'description', 'title', 'name' of 'Category', 'title' of 'GeoTag' and all 'Tag' array must be cleaned from final results. Every time ApiFormatter::formatObject()
or ApiFormatter::formatObjects()
is called the data are cleaned up using ApiFormatter::cleanObject()
.
In your ApiController
you can decide in every moment to change which fields remove from results using ApiFormatter::objectFieldsToRemove()
method.
// get the current value
$currentFieldsToRemove = $this->ApiFormatter->objectFieldsToRemove();
// to ovveride all. It completely replaces current fields to remove with new one
$this->ApiFormatter->objectFieldsToRemove(
array(
'title',
'description'
),
true
);
// to add new fields to remove
$this->ApiFormatter->objectFieldsToRemove(array(
'remove' => array('title', 'description')
));
Sometime you could want to present to client some fields that normally are cleaned up. Likewise to what seen with fields to remove, it is possible do it from configuration or on the fly.
In config/frontend.cfg.php
$config['api'] = array(
'baseUrl' => '/api/v1',
...
'formatting' => array(
'fields' => array(
// fields that should be removed
// to ApiFormattingComponent::objectFieldsToRemove
// i.e. kept in formatted object
'keep' => array(
'fixed',
'ip_created',
'Category' => array('object_type_id', 'priority')
)
)
)
);
In this way you say to ApiFormatter
that 'fixed', 'ip_created' and 'object_type_id', 'priority' of 'Category' must be preserved and presented to client.
In your ApiController
// to keep fields
$this->ApiFormatter->objectFieldsToRemove(array(
'keep' => array('ip_created', 'fixed')
));
It is possible to mix 'remove' and 'keep' options both in configuration and in controller.