Model plugins are somewhat similar to controller plugins, but the important difference is that instead of being triggered on controller execution they are bound to data actions. For example, if you wish to do some action every time a new user account is created, it would be a better choice to use the model plugin, because the user account can be created from various controllers, so it's easier to target model events.
LiveCart models are almost always directly mapped to database tables. For example, class Product is directly mapped to the Product table. Of course, the data structures are usually more complicated (related objects). You can take a look at database schema structure and relations as well as model class documentation.
Currently two types of data events/actions can be triggered:
There are some differences as to when these events are triggered. Upon insertion the plugins are called after the object has already been saved to the database. So, if you're making any changes to the object itself, do not forget to call its save() method to propagate the changes to the database.
However, when updating an existing object, the plugins are called before saving, so there's no need to save the object from plugin (and you shouldn't do this as it might break the model logic). Calling the plugins before saving provides the additional benefit of being able to see which object properties have been modified. This would be useful, for example, if you wanted to monitor the product inventory levels (example below) or react to any other specific data changes.
Another supported event, that is not related to data manipulations, but rather to presentation:
This event is triggered when either toArray() or transformArray() methods are called, which usually happens when the object data is passed to view template. You can use the array event if you need to pass some custom data with the object, whenever it is passed to a template for rendering.
Each plugin class must extend the abstract ModelPlugin class. The only method that needs to be implemented is process(). The process() method would do all the actual work.
The plugin class file must have the same name as the plugin class. So, if the class name is TestPlugin, the file name would have to be TestPlugin.php
To install a plugin, simply add the plugin class file to /plugin/model/ModelClass/ActionName/ directory. For example, if you wanted to create a plugin for the insert action of User model, the plugin class file would have to be added to the /plugin/model/User/insert/ directory. There can be multiple plugins assigned to the same model action. Please note that the plugin directory name must have exactly the same case as model class name.
Sending a welcome e-mail is actually built in LiveCart already, but just for the sake of example...
<?php
class WelcomeUser extends ModelPlugin
{
public function process()
{
// $this->object is the instance of the new User object
mail($this->object->email->get(), $this->object->getName() . ', welcome to our store!', ' .. your text here.. ');
}
}
?>
An easy example that simple customizations do not require to change any existing code. The only thing to do to make this work, would be to copy the file to /plugin/model/User/insert/WelcomeUser.php.
Would you like to receive an e-mail notification when a product becomes low on stock?
<?php
class LowStockNotify extends ModelPlugin
{
public function process()
{
$product = $this->object;
// you can call isModified() method on object's property to find out if its value has been changed
if ($product->stockCount->isModified() && ($product->stockCount->get() < 4))
{
mail('admin@admin.com', 'Low stock warning', 'Product #' . $product->getID() . ' is low on stock');
}
}
}
?>
In this case the plugin file would have to be copied to /plugin/model/Product/update/LowStockNotify.php.
Contrary to the examples provided, the possibilities of plugins are way more sophisticated than just sending e-mail notifications. The whole LiveCart API is available, so practically anything can be done within a plugin.
Although LiveCart will show an "image missing" picture near a product that doesn't have an image uploaded, it can be customized to show different "image missing" pictures for different store categories to improve the look and feel of your store.
<?php
class MissingImage extends ModelPlugin
{
public function process()
{
// for this event type the $object variable is an array representation of the object
// you can modify it directly, but if you want to use a different variable to hold the object
// assign it by reference, like this:
// $product =& $this->object;
if (!isset($this->object['DefaultImage']))
{
switch ($this->object['Category']['ID'])
{
22:
$path = 'image/missing/computers.gif';
break;
26:
$path = 'image/missing/phones.gif';
break;
default:
$path = null;
break;
}
if ($path)
{
for ($k = 0; $k <= 3; $k++)
{
$this->object['DefaultImage']['paths'] = $path;
}
}
}
}
}
?>