YiiYaa 1

YAA is an additional abstraction layer for Yii that aggregates a number of child models into a clean single model that is easy to cache

phpnode/YiiYaa

Written in PHP by 1 contributor

Contribute

Need Support?


we offer maintenance, support and development services for all our open source projects.

Contact Us

YAA - Yet Another Abstraction

Note: This is work in progress, it's not suitable for use in production yet

YAA is an additional abstraction layer for Yii that aggregates a number of child models into a clean single model that is easy to cache, this is known as an Aggregate Model.

YAA consists of Aggregate Models that each represent a core object in the system, aggregate models are a special kind of model that consist purely of attributes loaded from one or more child models. Aggregate objects know how to load their own data from the cache and the database based on a primary key, for example you'd load a specific user with User::load(1), or a list of users with User::load(array(1,2,3)). They can smooth over inconsistent naming formats with custom attribute names, so $member->mem_id becomes $user->id etc. These attribute names can be either specified as part of the aggregate's mapping or with getters and setters. Another important part of aggregate models is versioning, all aggregate models have their own version number that is incremented whenever a field on the aggregate changes. This makes it much easier for us to deal with full page and fragment caching, as we can use this version number as a dependency for each fragment and page that we cache, and if the dependency is invalid, we just regenerate the fragment or page, using the cached aggregate, incurring very minimal overhead.

In addition to aggregate models, we also have the AggregateChildBehavior class. As the name implies this behavior is added to the "children" of the aggregates, e.g. if you stored your users' address details in a model called "Address", then this model would be a child of the User aggregate class. When a mapped field on an aggregate child changes, it updates the relevant field on the aggregate model that the model belongs to, and recaches the aggregate model, incrementing the version number.

There are several advantages to the Aggregate system:

1. Allows a simple, consistent way of getting and setting commonly used data.
2. Allows write through caching, objects are always loaded from the cache where possible
3. Works alongside your existing code, you can start using YAA gradually.
4. Makes it far easier to switch to a NOSQL storage solution in future.
5. Provides an identity map that ensures the same object is only loaded once per request
6. Model relations are cached efficiently

Getting Started

In the following examples, we'll assume you have the following active record classes that you wish to aggregate:

Member         - represents the basic details for a member
Address     - the member's address details. Member has one Address
IsoCountry    - the country the member resides in. Address has one IsoCountry

and you wish to aggregate the above into a new class called User and a new class called Country.

class User extends AAggregateModel
{
    /**
     * @var integer the duration to cache for, 0 means forever
     */
    public static $cacheDuration = 0;

    /**
     * Declares the models that are being aggregated.
     * This should be an array in the format:
     * 
     *  array(
     *      "ModelName", // will load a model with the same PK as the aggregate ID
     *      "AnotherModelName" => "someField" // will load models which have the field "someField" set to the aggregate's ID
     *  )
     * 
*/ public static function models() { return array( "Member", "Address" => "mem_id", ); } /** * Assembles the new model instances that should be * populated and saved when creating new aggregates. * @return array of models, modelName => model instance */ public static function assemble() { $member = new Member(); $address = new Address(); return array( "Member" => $member, "Address" => $address, ); } /** * Gets the mapping of attributes for this model. * This should be an array in the format: *
     *  array(
     *      "cleanedUpAttributeName" => array("ModelName", "attribute_name"),
     *      "relationAttributeName" => array("ModelName", "relationName.field_name"),
     *  )
     * 
*/ public static function mapping() { return array( // get the following from the "Member" model "id" => array("Member", "mem_id"), "isActive" => array("Member", "active"), "firstName" => array("Member", "fname"), "lastName" => array("Member", "lname"), "isOnline" => array("Member", "is_online"), "about" => array("Member", "about"), "email" => array("Members","email"), // get the following from the "Address" model "addressLine1" => array("Address", "line1"), "addressLine2" => array("Address", "line2"), "city" => array("Address", "city"), "postcode" => array("Address", "postcode"), "countryId" => array("Address", "country") ); } /** * @return array the default values for the aggregate */ public function defaults() { return array( "countryId" => "GB", ); } /** * @return array the aggregate relations */ public function relations() { return array( "country" => array( self::BELONGS_TO, "Country", "attribute" => "countryId" ), ); } /** * Gets the name of the user's country * @return string the country name */ public function getCountryName() { return $this->country->name; } } /** * Represents a country */ class Country extends AAggregateModel { /** * Declares the models that are being aggregated. * This should be an array in the format: *
     *  array(
     *      "ModelName", // will load a model with the same PK as the aggregate ID
     *      "AnotherModelName" => "someField" // will load models which have the field "someField" set to the aggregate's ID
     *  )
     * 
*/ public static function models() { return array( "IsoCountry" ); } /** * Gets the mapping of attributes for this model. * This should be an array in the format: *
     *  array(
     *      "cleanedUpAttributeName" => array("ModelName", "attribute_name"),
     *      "relationAttributeName" => array("ModelName", "relationName.field_name"),
     *      "someReadOnlyAttribute" => array("modelName", "readOnlyAttributeName", true),
     *  )
     * 
*/ public static function mapping() { return array( "id" => array("IsoCountry", "iso"), "name" => array("IsoCountry", "printable_name"), "currency" => array("IsoCountry", "currency"), "iso3" => array("IsoCountry", "iso3"), "latitude" => array("IsoCountry", "latitude"), "longitude" => array("IsoCountry", "longitude"), ); } /** * Assembles the new model instances that should be * populated and saved when creating new aggregates. * @return array of models, modelName => model instance */ public static function assemble() { return array( "IsoCountry" => new IsoCountry() ); } }

With the above, it's possible to load and save user details with the following syntax:

$user = User::load(1); // load the user with the member id of 1, this object is now cached forever
echo $user->firstName." ".$user->lastName."\n";
echo "Country:".$user->country->name."\n";

// separately load the country again (actually returns a reference to the same $user->country object)
$country = Country::load($user->countryId);
$country->name = "Test Country";
$country->save();

$user->country->name == $country->name;

$user->firstName = "Test";
$user->save(); // the "Member" model will be used to save this attribute

$user->addressLine1 = "123 Fake Street";
$user->save(); // the "Address" model will be used to save this attribute
$user->save(); // no attributes are dirty so does nothing

$member = Member::model()->findByPk(1);
$member->lname = "fake";
$member->save();
$user->lastName == "fake"; // automatically updates the aggregate





43 other PHP projects


phpwkhtmltopdfPHP 716

A slim PHP wrapper around wkhtmltopdf with an easy to use and clean OOP interface

php-pdftkPHP 213

A PDF conversion and form utility based on pdftk

yii2-localeurlsPHP 189

Automatic locale/language management for URLs

YiiRedisPHP 131

A set of wrappers for different data types in redis

yiipasswordPHP 81

Password strategies for Yii

yii2-dockerizedPHP 64

A template for docker based Yii 2 applications

YiiSolrPHP 50

A wrapper for the pecl solr library that provides common Yii constructs, such as models, data providers etc

php-shellcommandPHP 48

A simple object oriented interface to execute shell commands in PHP

Yii-Docs-GeneratorPHP 47

Generates HTML documentation for Yii applications

YiiGitPHP 36

A git wrapper for Yii, allows access to all git commands programatically

YiiElasticSearchPHP 32

Elastic Search client for Yii

YiiCurlPHP 30

A curl library for Yii

YiiStateMachinePHP 28

A state machine behavior for Yii

yii2-streamlogPHP 19

A Yii 2 log target for streams in URL format

oauth2yiiPHP 18

An OAuth2 client / server extension for the Yii framework

packagecompressorPHP 16

A Javascript/CSS compressor based on Yii's package system

restyiiPHP 16

A RESTful extension for Yii.

localeurlsPHP 12

Automatic locale/language management for URLs

php-excel-readerPHP 12

It reads the binary format of XLS files directly and can return values and formats from any cell. This project is the fork of http://code.google.com/p/php-excel-reader/ that, apparently, is no longer maintained.

pdfablePHP 10

A Yii extension to create PDFs with PHPWkHtmlToPdf/wkhtmltopdf

yii-api-vimPHP 8

Yii API manual plugin for VIM

yii2-excel-messagePHP 7

Translate messages via Excel files

xcrudcontrollerPHP 7

A base class to quickly build customized CRUD interfaces.

yii2-bs3activeformPHP 7

A Bootstrap 3 enhanced ActiveForm for Yii 2

Yii-Package-ManagerPHP 6

A package manager for Yii

php-tmpfilePHP 6

A convenience class for temporary files

handlebarsphpPHP 6

Transpiles handlebars templates into native PHP templates

yii2-apidoc-vimPHP 5

Yii2 apidoc as Vim helpfiles

php-orientdbPHP 5

A fast PHP driver for the OrientDB binary protocol.

YiiUsersPHP 4

User management for Yii

translatablePHP 4

Transparent attribute translation for ActiveRecords

Yii-Resource-ManagerPHP 3

Helpers to allow Yii to interact with resources (files) of different types

flushablePHP 3

Yii dependency that allows to flush records from the cache

bs3activeformPHP 2

A lightweight utility to render Bootstrap 3 forms in Yii

YiiEmailerPHP 2

Emailing functions for Yii

AccessRestrictablePHP 2

A Yii ActiveRecordBehavior that automatically applies conditions for access restriction to every query.

YiiLinkablePHP 1

A simple extension for Yii allowing easy and consistent access to model URLs and appropriate anchor text.

hybridauthmanagerPHP 1

An AuthManager for Yii that stores the hierarchy in a flat PHP file and the assignments in DB

defaultpersisterPHP 1

Yii extension to save and restore model values in user session.

YiiAbstractArrayModelPHP

Work with PHP files in Active Record way

twittonioPHP

simple useless twitter client

yii2-base-appPHP

An alternative Yii2 application template for purists

xreturnablePHP

Yii extension to create URLs that allow to return to a page by storing its GET Parameters on a stack.