Agile Data ┬╗ Extensions

Agile Data is only the beginning. With it, you will be able to define a unified API for your business logic and data. Because of the unification it makes it easy to implement add-ons.


This extension makes your models automatically keep change history inside external model with ability to undo actions. Integration with the audit features is extremely simple:

$user->add(new AuditController(new AuditLog()));


This extension allows you to define a full-featured models that combine multiple other extensions:

$multi_table_search = \atk4\report\UnionModel($db);

$multi_table_search->addNestedModel(new Article())
$multi_table_search->addNestedModel(new Blog())
$multi_table_search->addNestedModel(new ShopItem())

$multi_table_search->addCondition('is_public', true);
$multi_table_search->addCondition('published', '>', new DateTime("2015-01-01"));
$multi_table_search->search("foo bar");

$results = $multi_table_search->export();


You might want to store your data encrypted in the database and keep a super-secret decryption key in the config file.

Encryption extension adds new 'Field' class that natively supports encryption based on PHP mcrypt extension. The secret can be either supplied on per-field basis or stored in your API.

$user->add(new Field_Encrypted('secret-key'), 'bank_account');

The rest of your application can continue to work normally, but the data will be stored encrypted for this individual field. Additional features:

  • support for various ciphers, shared key and public/private key encryptions
  • support for signatures, that can be verified during data load
  • hashing and password encryption

Secure Enclave

The PHP applications are usually pretty transparent which makes it quite risky to use 3rd party code in many cases. Often you would need to isolate and feed data into 3rd party plugin for safety.

Agile Data's Secure Enclave extension allows you to pass your Models to 3rd party code without risk of it being able to access more that you let them. Use of Enclave is transparent and is recommended in all applications.

// before
$user = new User($db);

// with enclave
$user = new User($db);
$grid->setModel(new Enclave($user->ref('Order')));

By defaut Enclave allows $grid to transparently work with all the records inside the supplied DataSet and perform limited traversal:

  • Read, Write, List and Delete access to all orders of user 20
  • Ability to traveres hasMany() with full access that matches scope
  • Ability to traverse hasOne() references for active record access only

Enclave will wrap around all traversals and will integrate with Agile Data models tightly.

$grid->setModel(new Enclave($user, $enclave_config));

You can supply enclave_config parameter to further specify permissions:

  • Specify which model classes are can be accessed
  • For each class specify which operations are available, load, save, etc
  • Specify which API methods can be called, e.g. sendReminder()
  • Define which fields must be removed, hidden or made read-only
  • Define custom field-based conditions
  • Extend through call-backs and enforce hooks
  • No access to database or custom queries or custom actions
  • Access to fields is permitted but they will be cloned
  • Support for API mocks

Enclave has a minimum performance degradation and can define system-wide policies that you can adjust for your use-case. As long as you don't make any global variables, Enclave makes it impossible to access more data than you allow.

Enclave cannot stop ability to manually load files.


Similarly to Enclave, proxy hides away code execution behind the RestAPI interface.

$u = new Proxy(new User(), $endpoint);
$o = $u->ref('Order');
echo $o->action('fx', ['sum', 'total']); // 3000

The proxy is actually a quite transparent class that is able to replicate Agile Data code execution through an endpoint API.

For the endpoint you'll need to run App_AgileDataAPI class:

$e = new App_AgileDataAPI();
$e->register('User', new User());

This will expose list of your users through the API. Of course there is also a security mechanism and you can also use App in conjunction with Secure Enclave to further limit access to your models.

Aggregate Models

There are many situations when you might have your data across multiple models, but you want them joined together for some reason:

  • Reports - join Sales invoices and Payments
  • Audit Log - move old entries to a different table
  • Table segmentation - collect data from table segments
  • Multiple files - read data from multiple CSV files

Aggregate model allows you to unite two separate Models that can come either from the same SQL table or from entirely different database engines. Apply conditions, set order and decide which fields you want in your aggregate table and it will always make a right decision when it comes to optimizing queries. Aggregate model will perform UNION if it's possible. Finally you get an opportunity to perform grouping or analytical operations on your data or even some map-reduce magic.

$m = new Aggregate\Model($db));
$m->addModel(new Purchase(), ['amount' => 'purchase_amount']);
$m->addModel(new Sales());
$m->addModel(new ArchivedSales($archive_db));

$m->setOrder('amount desc');


The above code will perform UNION between Pruchase and Sales models, while ArchivedSales will be added on top using a separate aggregation query on an $archive_db vendor. Results will be grouped by date and amounts will be added up. Only the first 20 results will be presented and by default only the fields will be included that appear in all models. Purchase model used column mapping, beacuse a physical one is called 'purchase_amount' and not 'amount':

  [{date: '08-12-2015', amount: 294.88}],
  [{date: '09-12-2015', amount: 4993.29}],
  [{date: '10-12-2015', amount: 0.00}],


This is a high-level extension that adds the following funcitonality:

  • Filestore model, capable of recording meta-data of arbitrary files
  • Image model, that adds handling for cropping, importing, resizing and storing original
  • Integration with 3rd party content distribution systems (S3, etc)
  • Background uploading
  • Form field for file uploads, integrating blueimp uploader
  • Image upload with manual user cropping support
  • Admin's "asset management" useful for managing galleries or recent user uploads
  • Multiple recepies how to implement common solutions (e.g. image review dashboard)
  • Integration into your database through a Model Field.
$im = $user->add(Filestore\Image(), 'thumb_id');

// later

$im = $user->ref('thumb_id');

// later

Other Extensions

There are multiple minor extensions available:

  • SoftDelete - mark records as deleted, but don't actually delete them
  • Tree - implement tree management it the databases that are not designed for it
  • UserOrder - ability to set custom order for records
  • Importer - import any CSV file efficiently without any lookup queries
  • Excel Templates - populate Excel file templates with your own data easily
  • Translations - transparently store your "string" type in a multi-linguag way

All of the above extensions will work with YOUR data structure!

Contact us if you wish to get early access to those extensions.

For Companies

Recent News

10 Mar: "or" condition

Somehow we forgot to implement "or" conditions. Spotted and implemented in version 1.1.11.

20 Dec: Reports

For all your aggregation needs. Use your Domain Models to GROUP and UNION without hardcore queries.

01 Dec: stable 1.1.6

We are now officially in the "stable" mode. Expect less releases and more focus on stability.

03 Nov: Audit

Practical event sourcing for your PHP project. Full audit trail and UNDO functionality.

27 Sep: released 1.1.0

Added a strong type support as well as many bugfixes and improvements.

11 Aug: released 1.0.2

  • Change: Renamed Field_One/Field_Many into Relation_One/Relation_Many
  • Fix: addCondition(field, [..])
  • Add: hasMany()->addFields();
  • Fix: hasOne relation traversal on unloaded model
  • Fix: hasOne accepts default value
  • Fix: subqueries are using aliases
  • Add: added advanced docs
  • Add: added Field->set()
  • Add: added Field->mandatory
  • Fix: random bugfixes

26 Jul: released 1.0.1

  • Fix: insert() cloning
  • Fix: ref() without active record works
  • Add: title_field support
  • Add: ref() hasOne save hook
  • Add: isDirty()
  • Add: afterUnload/beforeUnload hooks
  • Add: automatic model reloading
  • Add: advanced usage pattern doc
  • Add: support for related alias
  • Fix: bugs with joined table save
  • Add: withID()
  • Fix: preserve dirty flags for afterSave
  • Fix: set twice, then unset
Full Release History