Introduction to Models

Model is a class which mimics real-life objects. If you are building on-line store, then your objects would be items, categories, customers and orders.

Fields

Each model can contain a number of fields. Each field is also described as an object and can contain some meta-information or specific behaviours.

Database

Models are often associated with the database tables. Most of PHP frameworks assume that one model corresponds to a single table, however Agile Toolkit introduces a certain flexibility which is essential to your development stability.

Relations

Some models just like SQL tables may relate to other models. There are two primary relations - one-to-many and many-to-one. Each model contain information about some of the relations.

Operating with Models

Adding an model object is as easy as adding any other object in Agile Toolkit. Model object can be either empty or has one record "loaded". Below is a code demonstrating how to create model object and load it:

$item $this->add('Model_Item');

$res $item->loaded(); // will contain false

$item->load($_GET['item_id']);

$res $item->loaded(); // will contain true

Editing, Saving and Deleting records

Any model, once loaded, can have it's fields changed through the same syntax you are using for working with arrays. Alternatively you can use set() and get() methods, which are chain-able.

$item $this->add('Model_Item');

$item->tryLoadAny();

$item['price'] = 14.99;
$item['name'] = 'Mouse Pad';

$item->save();

The above example will attempt to load ANY record into the model, update price and name then save back into database. If record couldn't be loaded, then a new record will be added. If record already exists in the database and field properties are exactly as specified, then save() will not perform database update.

Multi-row queries

Agile Toolkit models can access records one at a time by implementing pattern "active record". However model can also use SQL language to perform actions on multiple records.

$item $this->add('Model_Item');

$item->dsql()
  ->
set('price',14.99)
  ->
set('name','Mouse Pad')
  ->
update();

In contrast with the previous example, this will produce a SQL query which will update all the item prices to 14.99 and names to 'Mouse Pad'.

Defining the Model

Just now I have skipped over the necessary step of defining model. Model is described by a class and to start using new model, you need to create a new class. Open lib/Model/Item.php file with your editor and add the following code:

To demonstrate how Models in Agile Toolkit can address multiple tables, here is another model definition:

This new class is completely independent from the "Model_Item" therefore adding discount feature must have NO EFFECT on any of your existing code-base which operates with Items already. Adding new functionality without changes in your stable code is a significant benefit Agile Toolkit offers you and in practice will improve stability of your project greatly and will help multiple people working at your project simultaniously.

Table Relationship

The other major feature of Agile Toolkit models is ability to keep number of queries to the absolute minimum. If your old ORM library could only describe one table with a single model, then you were forced to increase number of database queries and subsequently introduce caching. Agile Toolkit can make your queries more sophisticated and reduce response latency. Consider the new version of your Model_Item class:

First, let me note that all the changes we added to the "Model_Item" are also inherited by "Model_Item_Discounted". We do not need to implement the same change for multiple classes independently. Next let's look at each line and analyze what's been done there.

join() and leftJoin()

Model has two methods which introduce a join into a table. join() would have create a model which operates with two tables simultaneously. leftJoin is similar, but it will not attempt to populate "category" table when the item is added.

In practice you may have as many joins in a model as you think is necessary. Agile Toolkit will insert records into all the related tables in the proper order. By default Agile Toolkit assumes that your main table has "category_id" field (which it does) but if name of the field is different or the dependency is handled differently, you can define it through additional arguments to join()/leftJoin() method as described in documentation.

The whole idea of a join is that fields physically distributed across several tables appear in the same logical model.

hasOne(), hasMany()

These methods allow you to establish relationship between different models (not tables). Because each model may join multiple tables, there is no way to join models, that would be too complicated for Agile Toolkit to figure out. However the methods hasOne and hasMany describe relationship between models.

It's important to understand the difference between table relationship and model relationship. As you can see even though there is only one relationship between 'order' and 'item' in the database, we have defined two relationships between Model_Item, Model_Order and Model_Order_Completed. You must also remember that 'Model_Item_Discounted' also inherits relationship definitions.

addExpressions(), ref() and refSQL()

Typically ORM will only work with physical fields, but Agile Toolkit allows you to define calculated fields: expressions. Expression may use a SQL expression or sub-query to calculate it's value. In the example above the expression is set to a subQuery calculating number of completed orders. This might be a little difficult to figure out right now if you are new to Agile Toolkit, but I will get back to this syntax several times.

You must understand that for this code to work, we also need Model_Order and Model_Order_Completed classes defined:

Agile Toolkit is already helping you greatly to avoid code duplication. The definition of a completed order describes that the field is_completed must be true for completed orders, yet when we are traversing relationships to build a sub-query for a number of purchases, this condition is automatically used.

Now that we have increased the number of models and made them much more sophisticated, how did it reflect on your presentation logic? Does it require significant changes? Not a single change! Your presentation logic will continue to work unchanged:

Of course you can now address more fields and traverse relations, but you do not need to worry about breaking your existing code.

Use With Views

A significant feature of Agile Toolkit models is their integration with views. You can easily populate a Grid or a Form object with the fields from a grid.

$this->add('Form')->setModel('Book');

This is sufficient to show a form with the fields necessary to enter book model data.

Demo

To view the above code in action, see Manipulating Database Records in PHP with Agile Toolkit

Conclusion

Agile Toolkit contains one of the most powerful ORMs ever built for PHP which contains many unique features and focuses on scalability and flexibility. Features demonstrated here are only a tip of the iceberg. As you become more familiar with Agile Toolkit, you will be able to use many other more powerful features.

But there is one huge advantage I still haven't demonstrated. That's the integration between Model and Views

The code will produce a grid listing the current items (and their category names) as well as showing a form for adding new orders. The form would also feature a drop-down for selecting item and amount and will refresh the grid after successful submission.

All this is implemented using only the few lines of code you see, there are no additional controllers, custom views or additional templates.

This book and Agile Toolkit will teach you how to build complete on-line systems in the similar and extremely efficient way.

Direct use of Models

  • Define all the fields of the model and the type of those fields
  • Completely define model-related business logic inside the model body
  • Provide and encourage inheritance of models: User, User_Expired, User_Admin etc
  • Implement two-way references between models
  • When it comes to SQL, the model can use either single or multiple tables to store data (joins)
  • Provide the ability for the model to add mandatory conditions to SQL tables
  • Track which fields are changed
  • Encourage model-level validation and default values
  • Allow adding behaviours, either manually inside model functions or as extensions
  • Support SQL expression fields
  • Offer extensions such as strong encryptions, audit log, timestamps, soft delete, and so on
  • Contain custom methods for business operations

Interface integration features

  • Bind Form with Model. Populate fields, validations, conditions and will offer to save form data automatically through model
  • Bind Grid with Model. Displays properly formatted fields, both physical, calculated, foreign and related
  • Define which fields and in which order you want to show when binding
  • Add more fields, more conditions or even remove fields before you bind with the view
  • Use custom controller when binding. This can allow you implement custom layouts or field arrangements
  • Validation exceptions inside models bubble up to the view and displayed as pretty errors
  • After binding with model, tweak dynamic SQL statement even more, such as by joining to more tables
  • All user interface can also work with non-relational models