Previous post showed the very minimum features to make Mirage useful. Now lets take a look at what else is in the box.
A word on Prototyping
Simplx Mirage implements a prototypical style of inheritance. This means that instead of deriving attributes and functions using extending of php classes, you simply build on an existing php object. Note that i wrote object, not class.
In prototypical inheritance you don't have the concept of classes. Objects, with state and all, are simply extended at runtime. Its generally done by setting a reference to a prototype, which is then used as a starting point for building the new entity.
A neat and handy feature in prototype orientation is the possibility to add properties and methods at any time during excecution. This is used heavily in the most famous prototype based language today, which is of course Javascript.
Simplx Mirage does prototyping in a very straight forward way. Much like Javascript, you extend the MODX core model by simply creating a new class and setting its _prototype property to an instance of a modResource class. You can then add and override the prototypes properties and public methods just as if they where extended in a normal inheritance style.
How stuff works - in short
Many things can be said about the highs and lows of php. One thing is clear though, its a darn flexible language! To make Mirage tick I have used many of php's pragmatic features such as Magic Methods, Introspection, Dynamic Class invocation and more.
The Mirage package consists of three Classes at the moment,
Conventions to keep it simple
In MODX, as you might know, Template Variables have a one-to-many relationship with Templates. This is not a problem for Mirage really, but a one-to-one association is more in tune with the overall Class/Object metaphore we use. To get this working Mirage uses namespace prefixes by default. The default convention used here is to simply take the name of the class (modTemplate) as prefix. A Template Variable for the Product class could look like this:
Product_category
which would resolve to:
$myProduct->category
This general convention of using class name is used through out Mirage.
A really nice feature is the automagic matching of class/template matching using class name.
If you do the following:
class Product extends Simplx_Mirage_Object {}
Mirage very gracefully helps you at by assuming that the class 'Product' represents a modResource which uses a modTemplate named 'Product', and that its associated Template Variables are prefixed with 'Product_'.
Overriding and extending modResource
The possibilities to override properties and methods in the modResource class are not really obvious as our Mirage classes do not extend modResource but Simplx_Mirage_Object. Simplx_Mirage_Object in turn does not inherit from modResource either. So what is the secrete? Again, the Prototype concept in combination with php magic.
Let's revisit the Product class and add some new features.
class Product extends Simplx_Mirage_Object {
// Set a custom default value to the modResource pagetitle property
public $pagetitle = 'New Product';
public function save(){
// Do something customish
parent::save();
}
}
Nothing out of the ordinary taking place above right? Well thanks, I'll take that as a compliment :) That was my grand plan actually, to hide all the details from you. What actually takes place is far from rocket science thankfully.
This is what happens in the Simplx_Mirage_Object class constructor:
This is what happens in the Simplx_Mirage_Object class __set, __get and __call:
Read up on php Magic Methods if your unfamiliar with them.
Thanks for taking the time to read! Hope you have found if interesting.
I will continue this tour shortly, I hope however that i have given you enough hints to get you started :)
Be good!
Lars
A word on Prototyping
Simplx Mirage implements a prototypical style of inheritance. This means that instead of deriving attributes and functions using extending of php classes, you simply build on an existing php object. Note that i wrote object, not class.
In prototypical inheritance you don't have the concept of classes. Objects, with state and all, are simply extended at runtime. Its generally done by setting a reference to a prototype, which is then used as a starting point for building the new entity.
A neat and handy feature in prototype orientation is the possibility to add properties and methods at any time during excecution. This is used heavily in the most famous prototype based language today, which is of course Javascript.
Simplx Mirage does prototyping in a very straight forward way. Much like Javascript, you extend the MODX core model by simply creating a new class and setting its _prototype property to an instance of a modResource class. You can then add and override the prototypes properties and public methods just as if they where extended in a normal inheritance style.
How stuff works - in short
Many things can be said about the highs and lows of php. One thing is clear though, its a darn flexible language! To make Mirage tick I have used many of php's pragmatic features such as Magic Methods, Introspection, Dynamic Class invocation and more.
The Mirage package consists of three Classes at the moment,
- Simplx_Mirage - a Factory/Repository style class with static utility properties and methods. This class also handles caching and overall settings management.
- Simplx_Mirage _Class - a class which encapsulates a modTemplate object using the Prototype concept mentioned previously. Its members gives a straight forward way access what Mirage sees as Class definition: the modTemplate and its modTemplateVar associations.
- Simplx_Mirage_Object - a class that encapsulates a modResource object and lets you override and extend it thanks to php goodies like Introspection and Magic Methods. Every Mirage Object gets a reference to its corresponding Simplx_Mirage_Class as it is created.
Conventions to keep it simple
In MODX, as you might know, Template Variables have a one-to-many relationship with Templates. This is not a problem for Mirage really, but a one-to-one association is more in tune with the overall Class/Object metaphore we use. To get this working Mirage uses namespace prefixes by default. The default convention used here is to simply take the name of the class (modTemplate) as prefix. A Template Variable for the Product class could look like this:
Product_category
which would resolve to:
$myProduct->category
This general convention of using class name is used through out Mirage.
A really nice feature is the automagic matching of class/template matching using class name.
If you do the following:
class Product extends Simplx_Mirage_Object {}
Mirage very gracefully helps you at by assuming that the class 'Product' represents a modResource which uses a modTemplate named 'Product', and that its associated Template Variables are prefixed with 'Product_'.
Overriding and extending modResource
The possibilities to override properties and methods in the modResource class are not really obvious as our Mirage classes do not extend modResource but Simplx_Mirage_Object. Simplx_Mirage_Object in turn does not inherit from modResource either. So what is the secrete? Again, the Prototype concept in combination with php magic.
Let's revisit the Product class and add some new features.
class Product extends Simplx_Mirage_Object {
// Set a custom default value to the modResource pagetitle property
public $pagetitle = 'New Product';
public function save(){
// Do something customish
parent::save();
}
}
Nothing out of the ordinary taking place above right? Well thanks, I'll take that as a compliment :) That was my grand plan actually, to hide all the details from you. What actually takes place is far from rocket science thankfully.
This is what happens in the Simplx_Mirage_Object class constructor:
- The name of the class which implements the Simplx_Mirage_Object class is noted using the php function get_class(). We now know that the class being constructed is of type Product.
- The Simplx_Mirage static method getClass() using the class name as argument. A reference to a Simplx_Mirage_Class is returned, or, 'false' if no modTemplate named Product exists.
- If we got an 'id' argument in the constructor call we get the modResource using the good old MODX API. If we get a valid reference back we continue.
- Now we must check so that the modResource actually uses the Template wrapped in the Mirage class we checked previously. If it uses the Product class, we can continue.
- All the modResource properties are serialized to the internal _properties array.
This is what happens in the Simplx_Mirage_Object class __set, __get and __call:
Read up on php Magic Methods if your unfamiliar with them.
- A property or method on a Product object is called. If php can not find a match using its regular process of resolving implemented members, it defaults to its Magic Functions. This first step is where your implementations overrides modResource members.
- The method or property was not found in the Product class, or the Simplx_Mirage_Object class. Here is where a big part of the prototype coolness takes place.
- If a property was requested, the name is used to perform a lookup in the _property array. If the property is found its retrieved and returned. If the lookup returned false it is assumed that the property is a Template Variable and the MODX API is used to get or set the requested value.
- If a method call was made it is intercepted by the Magic __call function. This in turn uses php's Introspection features to lookup a matching method on the modResource prototype and simply pass the method call on, including any and all arguments. The resulting value, if any, is returned back.
Thanks for taking the time to read! Hope you have found if interesting.
I will continue this tour shortly, I hope however that i have given you enough hints to get you started :)
Be good!
Lars