Skip to content

Instantly share code, notes, and snippets.

@larscwallin
Created November 9, 2011 09:49
Show Gist options
  • Save larscwallin/1350981 to your computer and use it in GitHub Desktop.
Save larscwallin/1350981 to your computer and use it in GitHub Desktop.
SIMPLX MIRAGE
* WELCOME TO THE SIMPLX MIRAGE EXPERIMENT! *
PURPOSE:
The idea behind this little project is to hide the quite quirky MODx notion that a Resource (or document) does not
"own" its extended properties. In MODx these are called Template Variables and, as the name suggests, they are
bound to one or more Templates. This means that the normal concept that a Template conforms to the data in an Object
is reversed. As a result, in MODx a Resource potentially "looses" properties when a user changes its Template.
I want a solid way of using the current MODx Template Variable concept to quickly build custom content types
without having to go beyond the core MODx features. The good news is that its pretty easy, and fun too!
STRATEGY:
Ever since i started working with MODx, back in the Evo days, i saw Templates as Classes more or less.
The Mirage project rides this train of thought further by implementing a means of "wrapping" the original MODx
conventions behind a facade-like Class library.
In this library a Mirage Class actually represents a MODx Template, and an instance of an Mirage Class is a Resource.
So to retrieve an Object, or instance, you would call the getObject(objectid) factory method of the Mirage Class.
The Mirage Object then helps the developer by, among other things, hiding the fact that Template Variables are not
really members of the Class.
Mirage will strictly use the standard MODx API in its internals, thus keeping access control, cache, validation etc
intact.
I am using this concept in a current project together with forms customization and it works great!
Have fun :)
UPDATE 121121 22:41
Fixed indentation to only use tab
UPDATE 121121 21:58
NEW FEATURES
Minor stuff
UPDATE 120302 21:41
NEW FEATURES
Added a Simplx.Mirage.Class PropertySet which all modTemplate objects used by Mirage should
implement. The properties are the same as the public meta properties of the Simplx_Mirage_Class class
and are used as initial config for the Mirage class if not overridden by a custom instance.
UPDATE 120228 23:45
Massive bug fixes in addComposite and addAggregate.
UPDATE 120228 15:00
Bug fixes
UPDATE 120226 15:30
NEW FEATURES
Added a Snippet which queries Mirage and returns json representations of Simplx_Mirage_Object's.
The Snippet also checks whether the setup snippet has run, and if it has'nt it does :)
Fixed bugs in the query engine.
Did general spring cleaning in the code :)
UPDATE 120225 22:30
NEW FEATURES
I made it possible again to use Mirage without explicitly creating php classes as wrappers which extend
Simplx_Mirage_Object. I still recommend it though.
You can now do this:
$myClass = new Simplx_Mirage_Class('myClassName');
$objects = Simplx_Mirage_Class->getObjects(array(
'anyField:='=>'foo'
));
foreach($objects as $obj){
print $obj->id;
print $obj->myVeryOwnSuperCoolFieldWhichIsReallyAtemplateVar;
}
UPDATE 120221 11:25
Adding DocBlock annotations
UPDATE 120216 12:55
Fixed so that Simplx_Mirage_Object->toArray/toJSON always include the modResource instance id.
UPDATE 120216 12:45
NEW FEATURES
* Implemented proper behaviour when overriding Simplx_Mirage_Object property defaults.
UPDATE 120215 13:12
Adding DocBlock annotations
UPDATE 120120 13:12
NEW FEATURES
* Simplx_Mirage_Class (a modTemplate remember) is now configured by default by using the templates
default PropertySet.
The Property Set can be found in the "simplx.mirage.class.json" below. Just import to use.
* Simplx_Mirage_Object now inherits all config from its Mirage Class. See point above.
BUG FIXES
* Fixed a misstake in the addAggregate method.
UPDATE 120119 12:50
NEW FEATURES
* Simplx_Mirage_Class->newObject() now also creates modResource containers for all associations declared in the
_aggregates, _composites and _associations arrays. These arrays will later be populated by modTemplate's
Property Set.
UPDATE 120119 12:10
NEW FEATURES
* Simplx_Mirage_Class now has a newObject(array defaults, [modResource prototype]) method which creates a new instance of modResource which uses
the correct modTemplate for that particular Mirage Class.
* Simplx_Mirage_Class has a new _defaultObjectLocation property which tells Mirage where in the structure to save
the new modResource objects of a particular Mirage Class by default. Can be overridden in the newObject() method.
UPDATE 120104 14:50
API CHANGES
* Added Simplx_Mirage_Object->renderAspect($aspect) method.
$aspect is a Snippet name which in turn gets called with all Object state serialized to an array as only param.
Very flexible way to render views. Also remember that there is a identical method in Simplx_Mirage_Class.
UPDATE 120103 17:35
API CHANGES
* Added a Simplx_Mirage_Object->_parent property to ensure that every object always have a reference of their parent.
The _parent property display the correct parent from Mirage's perspective. This means that if a Composite object is
located in a folder beneath the parent _parent will ignore this "symbolic" folder and point to what Mirage sees as
the parent object.
UPDATE 120102 10:19
API CHANGES
* Added an optional "$useClassNameWrap" parameter to Simplx_Mirage_Object->toJSON() and
Simplx_Mirage_Object->toArray(). This tells Mirage if to wrap the serialized object like this:
{"myObjectTypeName":{"myProperty":"whatever"}}
or, without class name:
{"myProperty":"whatever"}
Default "$useClassNameWrap" value is false.
UPDATE 111227 13:26
NEW FEATURES
* Added rudemental MODx to JSON schema type conversion.
UPDATE 111227 12:55
NEW FEATURES
* Added JSON-SCHEMA compliant toJSON output from Simplx_Mirage_Class->toJSON()
* Added the possibility to add JSON-SCHEMA validations etc to the Simplx_Mirage_Class using the
_propertyValidationRules array.
* Lots and lots more
UPDATE 111220 15:00
BUG FIXES
Fixed issue relating to TV Prefixing.
Fixed issue with Simplx_Mirage_Object->save(). Now respects _persistOnAssign setting.
UPDATE 111217 23:40
NEW FEATURES
* Finished implementing the getAggregates() and getComposites() methods.
* Implemented the option to store Aggregates and Composites in sub folders. Folders are named
the same as the class they contain by default.
* Started to put more logic in to the Simplx_Mirage_Class class.
* Ditched the usage of static members, except for the debugmode flag which is still static.
* Optimized modResource/view query function so that joins with the view are only used when really needed.
UPDATE 111214 14:15
NEW FEATURES
Simplx_Mirage_Object now implements two new cool methods getAggregates() and getComposites().
* Simplx_Mirage_Object->getAggregates($className,$query)
This method gets sym-linked modResources which are children of the current modResource used as prototype
by Simplx_Mirage_Object.
The Resources must also use the modTemplate object specified in the $className argument.
It automatically translates the modSymLink to the linked modResources, in other words you get the
actual resource back in the result list.
The query argument is just a regular xpdo style constraint array.
* Simplx_Mirage_Object->getComposites($className,$query)
This method gets all modResources which are children of the current modResource used as prototype
by Simplx_Mirage_Object.
The Resources must also use the modTemplate object specified in the $className argument.
It automatically translates the modSymLink to the linked modResources, in other words you get the
actual resource back in the result list.
The query argument is, again, just a regular xpdo style constraint array.
UPDATE 111212 15:50
NEW FEATURES
Implemented the first version of fromArray(). This is an important step forward as it will make it
possible, and very simple, to take a json/array representation of the Resource, including TV's, and
simply load them and save.
*Important*
Its not tested yet so hold your horses a bit.
UPDATES
Updated the save() method for the Mirage object a bit.
Added more debug output.
Probably more that i forgot ;p
UPDATE 111125 17:10
NEW FEATURES
Finally! I implemented the first version of Simplx_Mirage_Class::getObjects()!
This lets you use XPDO query style to select objects. The getObjects method takes care of
resolving which query parameters that are modResource properties and which are TV's.
Example:
$objectList = Simplx_Mirage_Class::getObjects('Aircraft',array(
'registration_number:>'=>10,
'template:='=>3
));
Cool thing is that this works just fine for getting modResources in general :) No more akward special treatment
of TV's!
* INSTALL *
Copy paste and run the "simplx.mirage.setup" Snippet to create the necessary MySQL view.
Thats it :)
UPDATE 111122 15:11
BUG FIXES
Forgot to add prefix separator.
UPDATE 111122 15:00
NEW FEATURES
- Added prefix support for TV's. This means that a Class can use its Class name to distinguish it's own TV's.
If prefixes are used the default prefix would look like this "Aircraft_registration_number".
Prefixing is meant to distinguish TV's from each other, like namespaces. They are not used for
getting or setting of properties. So retrieving a property would look like this "$aircraft->registration_number"
even with prefixing in use.
BUG FIXES
<?php
require_once($modx->getOption('core_path').'/components/simplx/mirage/simplx_mirage.php');
/***********************************************
4
0. Save the simplx_mirage.php file in "core/components/simplx/mirage/".
1. Paste this in to a Snippet.
2. Create a new Template called Aircraft.
3. Add a TV called registration_number.
4. Create a new Resource and assign the Aircraft template.
5. Put in some value into the TV.
6. Call the Snippet in any page you like and see what happens :)
***********************************************/
/*
Create a new simple php class that extends Simplx_Mirage_Object. This is not really necessary,
but its good practice when working with generic concepts such as used in Mirage. It helps things become more
concrete and intuitive from an developer api perspective.
*/
class Aircraft extends Simplx_Mirage_Object {
public $_excludeModResourceFields = false;
public $_useFoldersForAssoc = true;
/*
In this class definition you can actually override any modResource properties and/or methods event though
though we extend the Simplx_Mirage_Object. This is done through using the concept of "Prototypical Inheritance".
Prototypical Inheritance uses an existing Object rather than a Class to create new data types.
Check out the save method below for an example.
*/
/*
The constructor takes the id of an existing modResource object. The modResource object is used as
prototype for the Aircraft Class. The loading of the modResource is done in the __construct() method
of the Simplx_Mirage_Object class.
*/
function __construct($id){
global $modx;
$result = false;
if(isset($id)){
$modx->log(modX::LOG_LEVEL_DEBUG, 'Aircraft->__construct(): Got id parameter "'.$id.'".');
/*
This class does not use prefixed tvs.
If prefixes had been used the default prefix would be the class name followed by an underscore
(like this "Aircraft_registration_number").
Prefixing is meant to distinguish TVs from each other, like namespaces. They are not used for
getting or setting properties. So retrieving a property would look like this "$aircraft->registration_number"
even with prefixing in use.
*/
$this->_prefixTvs = false;
/*
Remember that the Aircraft Class is only a facade for a MODX Resource to add behavior and more on the fly.
So, next, we need to add a prototype object to the Aircraft instance.
*/
$result = parent::__construct($id);
if($result){
$modx->log(modX::LOG_LEVEL_DEBUG, 'Aircraft->__construct(): Simplx_Mirage_Object->__construct(): Returned true.');
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Aircraft->__construct(): Simplx_Mirage_Object->__construct(): Returned false. Aborting.');
return false;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Aircraft->__construct(): id parameter was empty. Aborting.');
return false;
}
}
/*
EXAMPLE: Override modResource->save()
You dont need to implement this if you dont have any special, class specific, stuff to do.
Maybe you need to call a webservice to notify of the update, or maybe you need to change the
state of another system object. Or simply just write to the log as i do below :)
*/
public function save(){
global $modx;
$result = false;
$modx->log(modX::LOG_LEVEL_DEBUG, 'Aircraft->save(): Saving Aircraft specific stuff.');
$result = parent::save();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Aircraft->save(): Simplx_Mirage_Object->save() returned false. Check your error log.');
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Aircraft->save(): Save was successfull.');
}
}
}
class Cockpit extends Simplx_Mirage_Object {
public $_useFoldersForAssoc = true;
/*
In this class definition you can actually override any modResource properties and/or methods event though
though we extend the Simplx_Mirage_Object. This is done through using the concept of "Prototypical Inheritance".
Prototypical Inheritance uses an existing Object rather than a Class to create new data types.
Check out the save method below for an example.
*/
/*
The constructor takes the id of an existing modResource object. The modResource object is used as
prototype for the Aircraft Class. The loading of the modResource is done in the __construct() method
of the Simplx_Mirage_Object class.
*/
function __construct($id){
global $modx;
$result = false;
if(isset($id)){
$this->_prefixTvs = true;
$result = parent::__construct($id);
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Cockpit->__construct(): id parameter was empty. Aborting.');
return false;
}
}
}
class Activity extends Simplx_Mirage_Object {
public $_useFoldersForAssoc = true;
function __construct($id){
global $modx;
$result = false;
if(isset($id)){
$this->_prefixTvs = false;
$result = parent::__construct($id);
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Activity->__construct(): id parameter was empty. Aborting.');
return false;
}
}
}
/**********************************************************
Lets use it!
***********************************************************/
$modx->setLogLevel(modX::LOG_LEVEL_DEBUG);
Simplx_Mirage::$_debugmode = false;
Simplx_Mirage_Class::$_debugmode = true;
Simplx_Mirage_Object::$_debugmode = false;
/*
Create an instance of our Aircraft Class. We are assuming that we have a Resource with id 6 that uses the
template "Aircraft". This template has all the properties (just ordinary TV's) for our Aircraft Class.
*/
$cockpit = new Cockpit(8);
$aircraft = new Aircraft(6);
/*
We can now access and set Resource properties and Template Variables in a uniform fashion.
In this case we read the TV "registration_number", print it, change its value and saves.
*/
print 'Aircraft:'.$aircraft->registration_number.'<br/><br/>';
print 'Cockpit:'.$cockpit->registration_number.'<br/><br/>';
// Lets change the object property (which is really a TV).
$aircraft->registration_number = 4567;
$aircraft->save();
// Print out the state of the Aircraft as JSON.
print '<br/><br/>Aircraft instance as JSON:'.$aircraft->toJSON();
print '<br/><br/>Cockpit instance as JSON:'.$cockpit->toJSON();
/*
NEW STUFF BELOW
*/
/*
* getAggregates()
If you have made a sym-link to a Cockpit object as a child to an Aircraft you can fetch the
Cockpit object using this method.
* getComposites()
If you have made a child modResource as a child to an Aircraft you can fetch the
this object using this method.
*/
$list = $aircraft->getAggregates('Cockpit');
print ('<h2>Simplx_Mirage_Object->getAggregates</h2><div>'.json_encode($list).'</div>');
$list = $aircraft->getComposites('Activity');
print ('<h2>Simplx_Mirage_Object->getComposites</h2><div>'.json_encode($list).'</div>');
/*
The new Simplx_Mirage_Class encapsulates features which are specific Class behaviour.
Such behaviour includes getting derived objects of course.
*/
$AircraftClass = new Simplx_Mirage_Class('Aircraft');
$list = $AircraftClass->getObjects(array(
'registration_number:='=>777
));
print ('<h2>Simplx_Mirage_Class->getObjects</h2><div>'.json_encode($list).'</div>');
$list = Simplx_Mirage::getObjects('Activity');
print ('<h2>Simplx_Mirage::getObjects</h2><div>'.json_encode($list).'</div>');
/*
Lets set some Class more meta stuff for the class using the new "Simplx_Mirage_Class" class.
*/
// Get an instance (modResource) of the Aircraft class (modTemplate)
$simpleAircraft = $AircraftClass->getObject(3);
print '<br/><br/>Aircraft:'.$simpleAircraft->registration_number.'<br/><br/>';
// Render a form view for the "Class" Aircraft.
print $AircraftClass->renderAspect('form');
<?php
require_once($modx->getOption('core_path').'/components/simplx/mirage/simplx_mirage.php');
/**********************************************************
Example without all those annoying comments ;)
***********************************************************/
class Aircraft extends Simplx_Mirage_Object {
function __construct($id){
global $modx;
$result = false;
if(isset($id)){
self::$_prefixTvs = false;
$result = parent::__construct($id);
if(!$result){
return false;
}
}else{
return false;
}
}
public function save(){
global $modx;
$result = false;
$result = parent::save();
if(!$result){
return false;
}
}
}
/**********************************************************
Lets use it!
***********************************************************/
$aircraft = new Aircraft(6);
print 'Aircraft:'.$aircraft->registration_number.'<br/><br/>';
$aircraft->registration_number = 3333;
$aircraft->save();
print 'Aircraft instance as JSON:'.$aircraft->toJSON();
[{"name":"useFoldersForAssoc","desc":" /**\n * Should associations created for Objects of this Class be stored in \n * folders, as child resources?\n *\n * @access public\n * @var boolean \n */ \n public $_useFoldersForAssoc = false;","xtype":"combo-boolean","options":[],"value":false,"lexicon":null,"overridden":false,"desc_trans":" /**\n * Should associations created for Objects of this Class be stored in \n * folders, as child resources?\n *\n * @access public\n * @var boolean \n */ \n public $_useFoldersForAssoc = false;","menu":null},{"name":"composites","desc":"","xtype":"textarea","options":[],"value":"{}","lexicon":null,"overridden":false,"desc_trans":"","menu":null},{"name":"defaultObjectLocation","desc":" /**\n * This property sets the default location in the site structure for modResources using this\n * this modTemplate wrapper. \n *\n * @access public\n * @var int \n */ \n public $_defaultObjectLocation = 0;","xtype":"numberfield","options":[],"value":"0","lexicon":null,"overridden":false,"desc_trans":" /**\n * This property sets the default location in the site structure for modResources using this\n * this modTemplate wrapper. \n *\n * @access public\n * @var int \n */ \n public $_defaultObjectLocation = 0;","menu":null},{"name":"classUri","desc":" /**\n * Class URI should point to the URI (ex. http://mysite.com/api/Whatnot/) where Objects (modResource's) \n * of this type are found. \n *\n * @access public\n * @var string \n */ \n public $_classUri;","xtype":"textfield","options":[],"value":"","lexicon":null,"overridden":false,"desc_trans":" /**\n * Class URI should point to the URI (ex. http://mysite.com/api/Whatnot/) where Objects (modResource's) \n * of this type are found. \n *\n * @access public\n * @var string \n */ \n public $_classUri;","menu":null},{"name":"classTypeName","desc":" /**\n * Class name is the Simplx Mirage moniker, or alias, for the modTemplate object. \n * By default, this is the same the template instance name.\n *\n * @access public\n * @var string \n */ \n public $_classTypeName;","xtype":"textfield","options":[],"value":"","lexicon":null,"overridden":false,"desc_trans":" /**\n * Class name is the Simplx Mirage moniker, or alias, for the modTemplate object. \n * By default, this is the same the template instance name.\n *\n * @access public\n * @var string \n */ \n public $_classTypeName;","menu":null},{"name":"excludeModResourceFields","desc":" /**\n * If excludeModResourceFields is set to true, toJSON/toArray will exclude all modResource fields for this\n * Simplx Mirage Class. The serialized data only contain the TV's. Handy when you want to really emulate custom \n * object types.\n *\n * @access public\n * @var boolean \n */ \n public $_excludeModResourceFields = false;","xtype":"combo-boolean","options":[],"value":false,"lexicon":null,"overridden":false,"desc_trans":" /**\n * If excludeModResourceFields is set to true, toJSON/toArray will exclude all modResource fields for this\n * Simplx Mirage Class. The serialized data only contain the TV's. Handy when you want to really emulate custom \n * object types.\n *\n * @access public\n * @var boolean \n */ \n public $_excludeModResourceFields = false;","menu":null},{"name":"prefixTvs","desc":" /**\n * Should prefixes be used to indicate which modTemplate (Simplx_Mirage_Class) a modTemplateVar belongs to?\n * Its HIGHLY recommended to set this to true as it makes your model infinitly more intuitive. \n *\n * @access public\n * @var boolean \n */ \n public $_prefixTvs = true; ","xtype":"combo-boolean","options":[],"value":true,"lexicon":null,"overridden":false,"desc_trans":" /**\n * Should prefixes be used to indicate which modTemplate (Simplx_Mirage_Class) a modTemplateVar belongs to?\n * Its HIGHLY recommended to set this to true as it makes your model infinitly more intuitive. \n *\n * @access public\n * @var boolean \n */ \n public $_prefixTvs = true; ","menu":null},{"name":"tvPrefix","desc":" /**\t\n * Actual TV prefix to use. This default to ($_classTypeName.'_'.TV name)\n *\n * @access public\n * @var string \n */ \n public $_tvPrefix;","xtype":"textfield","options":[],"value":"","lexicon":null,"overridden":false,"desc_trans":" /**\t\n * Actual TV prefix to use. This default to ($_classTypeName.'_'.TV name)\n *\n * @access public\n * @var string \n */ \n public $_tvPrefix;","menu":null},{"name":"tvPrefixSeparator","desc":" /**\n * Prefix separator. This default to '_'.\n *\n * @access public\n * @var string \n */ \n public $_tvPrefixSeparator = '_';","xtype":"textfield","options":[],"value":"_","lexicon":null,"overridden":false,"desc_trans":" /**\n * Prefix separator. This default to '_'.\n *\n * @access public\n * @var string \n */ \n public $_tvPrefixSeparator = '_';","menu":null},{"name":"tvPrefixToLower","desc":" /**\n * Should we accept prefix regardless of case? A good convention is to use upper case names\n * for our Simplx Mirage Classes (modTemplates). By default TV prefixing is case sensitive.\n *\n * @access public\n * @var boolean \n */ \n public $_tvPrefixToLower = false; ","xtype":"combo-boolean","options":[],"value":false,"lexicon":null,"overridden":false,"desc_trans":" /**\n * Should we accept prefix regardless of case? A good convention is to use upper case names\n * for our Simplx Mirage Classes (modTemplates). By default TV prefixing is case sensitive.\n *\n * @access public\n * @var boolean \n */ \n public $_tvPrefixToLower = false; ","menu":null},{"name":"forceTypeCheck","desc":" /**\n * Should we force \"type check\" the $_classTypeName against the name of the modTemplate prototype?\n *\n * @access public\n * @var boolean \n */ \n public $_forceTypeCheck = true;","xtype":"combo-boolean","options":[],"value":false,"lexicon":null,"overridden":false,"desc_trans":" /**\n * Should we force \"type check\" the $_classTypeName against the name of the modTemplate prototype?\n *\n * @access public\n * @var boolean \n */ \n public $_forceTypeCheck = true;","menu":null},{"name":"createFoldersForAssoc","desc":" /**\n * If folders for associated objects are not present, should we create them? \n *\n * @access public\n * @var boolean \n */ \n public $_createFoldersForAssoc = true;","xtype":"combo-boolean","options":[],"value":true,"lexicon":null,"overridden":false,"desc_trans":" /**\n * If folders for associated objects are not present, should we create them? \n *\n * @access public\n * @var boolean \n */ \n public $_createFoldersForAssoc = true;","menu":null},{"name":"assocNameMap","desc":" /**\n * This map is used to map associated types to custom folder names when $_useFoldersForAssoc is true.\n *\n * @access public\n * @var array \n */ \n public $_assocNameMap = array();","xtype":"textarea","options":[],"value":"{}","lexicon":null,"overridden":false,"desc_trans":" /**\n * This map is used to map associated types to custom folder names when $_useFoldersForAssoc is true.\n *\n * @access public\n * @var array \n */ \n public $_assocNameMap = array();","menu":null},{"name":"aggregates","desc":" /**\n * Valid aggregate types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)\n *\n * @access public\n * @var array \n */ \n public $_aggregates = array(); ","xtype":"textarea","options":[],"value":"{}","lexicon":null,"overridden":false,"desc_trans":" /**\n * Valid aggregate types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)\n *\n * @access public\n * @var array \n */ \n public $_aggregates = array(); ","menu":null},{"name":"associations","desc":" /**\n * Valid association types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)\n *\n * @access public\n * @var array \n */ \n public $_associations = array();","xtype":"textarea","options":[],"value":"{}","lexicon":null,"overridden":false,"desc_trans":" /**\n * Valid association types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)\n *\n * @access public\n * @var array \n */ \n public $_associations = array();","menu":null}]
<?php
$objectPropertiesViewName = isset($objectPropertiesViewName) ? $objectPropertiesViewName : 'view_mirage_object_properties';
$tablePrefix = ('`'.$modx->getOption(xPDO::OPT_TABLE_PREFIX).'`');
$modTemplateVarTemplateTable = $modx->getTableName('modTemplateVarTemplate');
$modTemplateVarTable = $modx->getTableName('modTemplateVar');
$modTemplateVarResourceTable = $modx->getTableName('modTemplateVarResource');
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_remove: $objectPropertiesViewName = '.$objectPropertiesViewName);
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_remove: $tablePrefix = '.$tablePrefix);
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_remove: $modTemplateVarTemplateTable = '.$modTemplateVarTemplateTable );
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_remove: $modTemplateVarTable = '.$modTemplateVarTable);
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_remove: $modTemplateVarResourceTable = '.$modTemplateVarResourceTable);
$result = false;
/*******************************************************************************************
SYSTEM SECTION
********************************************************************************************/
/*
System Setting "simplx.mirage.setup.hasrun"
*/
$simplx_mirage_setting = $modx->getObject('modSystemSetting',array(
'key' => 'simplx.mirage.setup.hasrun'
));
if($simplx_mirage_setting){
$result = $simplx_mirage_ns->remove();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx.mirage.remove Exception: Could not delete Setting "simplx.mirage.setup.hasrun". Please do this manually.');
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.remove Exception: Deleted Setting "simplx.mirage.setup.hasrun".');
}
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.remove Exception: Could not find Setting "simplx.mirage.setup.hasrun".');
}
/*
System Setting "simplx.mirage.object.viewname"
*/
$simplx_mirage_setting = $modx->getObject('modSystemSetting',array(
'key' => 'simplx.mirage.object.viewname'
));
if($simplx_mirage_setting){
$result = $simplx_mirage_ns->remove();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx.mirage.remove Exception: Could not delete Setting "simplx.mirage.object.viewname". Please do this manually.');
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.remove Exception: Deleted Setting "simplx.mirage.object.viewname".');
}
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.remove Exception: Could not find Setting "simplx.mirage.object.viewname".');
}
unset($simplx_mygit_setting);
/*
System Namespace "simplxmirage"
*/
$simplx_mirage_ns = $modx->getObject('modNamespace',array(
'name' => 'simplxmirage'
));
if($simplx_mirage_ns){
$result = $simplx_mirage_ns->remove();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx.mirage.remove Exception: Could not delete Namespace "simplxmirage". Please do this manually.');
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.remove Exception: Deleted Namespace "simplxmirage".');
}
}
unset($simplx_mirage_ns);
/*
System Namespace "simplx.mirage"
*/
$simplx_mirage_cat = $modx->getObject('modCategory',array(
'name' => 'simplx.mirage'
));
if($simplx_mirage_cat){
$result = $simplx_mirage_cat->remove();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx.mirage.remove Exception: Could not delete Category "simplx.mirage". Please do this manually.');
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.remove Exception: Deleted Category "simplx.mirage".');
}
}
unset($simplx_mirage_cat);
/*******************************************************************************************
SQL VIEW SECTION
********************************************************************************************/
$createViewQuery = 'DROP VIEW `'.$objectPropertiesViewName.'`';
$result = $modx->exec($createViewQuery);
if($result === false){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx_mirage_remove Exception: Unable to remove view from database. Please do this manually.');
return false;
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_remove: Successfully removed view from database.');
return true;
}
<?php
/*******************************************************************************************
Simplx Mirage Setup Snippet
This Snippet sets up, most importantly, the mysql view needed to query template vars
with efficiance.
********************************************************************************************/
$objectPropertiesViewName = isset($objectPropertiesViewName) ? $objectPropertiesViewName : 'view_mirage_object_properties';
$tablePrefix = ('`'.$modx->getOption(xPDO::OPT_TABLE_PREFIX).'`');
$modTemplateVarTemplateTable = $modx->getTableName('modTemplateVarTemplate');
$modTemplateVarTable = $modx->getTableName('modTemplateVar');
$modTemplateVarResourceTable = $modx->getTableName('modTemplateVarResource');
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.setup: $objectPropertiesViewName = '.$objectPropertiesViewName);
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.setup: $tablePrefix = '.$tablePrefix);
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.setup: $modTemplateVarTemplateTable = '.$modTemplateVarTemplateTable );
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.setup: $modTemplateVarTable = '.$modTemplateVarTable);
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage.setup: $modTemplateVarResourceTable = '.$modTemplateVarResourceTable);$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_setup: $modTemplateVarResourceTable = '.$modTemplateVarResourceTable);
$result = false;
$handle;
$contents = '';
$success = false;
$properties = array();
/*******************************************************************************************
* SYSTEM SETUP SECTION
********************************************************************************************/
/*
* Create a new Namespace and get rid of the one that PackMan created.
*/
$simplx_mirage_ns = $modx->getObject('modNamespace',array(
'name' => 'simplxmirage'
));
if($simplx_mirage_ns){
$result = $simplx_mirage_ns->remove();
if($result){
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: Could not delete Namespace "simplxmirage". Please do this manually.');
}
}
unset($simplx_mirage_ns);
$simplx_mirage_ns = $modx->newObject('modNamespace');
if($simplx_mirage_ns){
$simplx_mirage_ns->set('name','simplx.mirage');
$simplx_mirage_ns->set('path',($modx->getOption('assets_path').'components/simplx/mirage/'));
$result = $simplx_mirage_ns->save();
if($result === false){
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mygit.setup() Exception: Could create Namespace "simplx.mirage". Please do this manually to keep things in good order.');
}
}
unset($simplx_mirage_cat);
/*
* Create a Settings
*/
$simplx_mirage_setting = $modx->getObject('modSystemSetting',array(
'key' => 'simplx.mirage.setup.hasrun'
));
if($simplx_mirage_setting !== 1){
unset($simplx_mirage_setting);
$simplx_mirage_setting = $modx->newObject('modSystemSetting');
$simplx_mirage_setting->set('key','simplx.mirage.setup.hasrun');
$simplx_mirage_setting->set('value','0');
$simplx_mirage_setting->set('namespace','simplx.mirage');
$result = $simplx_mirage_setting->save();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: Could not create System Setting "simplx.mygit.username". Please do this manually.');
}
unset($simplx_mirage_setting);
$simplx_mirage_setting = $modx->newObject('modSystemSetting');
$simplx_mirage_setting->set('key','simplx.mirage.object.viewname');
$simplx_mirage_setting->set('value',$objectPropertiesViewName);
$simplx_mirage_setting->set('namespace','simplx.mirage');
$result = $simplx_mirage_setting->save();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: Could not create System Setting "simplx.mirage.object.viewname". This is a critical Setting. Please do this manually.');
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: "simplx.mirage.setup.hasrun" exists so executing setup is not necessary. Aborting.');
}
unset($simplx_mygit_setting);
/*
*
* Set up the simplx.mirage.class Property Set
*
*/
$simplx_mirage_class_ps = $modx->getObject('modPropertySet',array(
'name' => 'simplx.mirage.class'
));
// If there is no 'simplx.mirage.class' yet, lets create it.
if(!$simplx_mirage_class_ps){
$filename = $modx->getOption('core_path')."components/simplx/mirage/simplx_mirage_class_properties.js";
if (!file_exists($file_name)) {
$handle = fopen($filename, "rb");
$contents = fread($handle, filesize($filename));
fclose($handle);
// Create an array with all properties.
$properties = json_decode($contents,true);
if(is_array($properties)){
$simplx_mirage_class_ps = $modx->newObject('modPropertySet');
$simplx_mirage_class_ps->set('name','simplx.mirage.class');
$simplx_mirage_class_ps->set('description','Property Set which must be implemented by all Templates wanting to use with Mirage.');
$simplx_mirage_class_ps->setProperties($properties);
$success = $simplx_mirage_class_ps->save();
if(!$success){
// Could not set the properties.
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: Could not create Property Set "simplx.mirage.class". Please do this manually.');
}else{
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: Could not decode the "simplx.mirage.class" Property Set. Please import the Property Set manually.');
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'simplx.mirage.setup() Exception: Could not create Property Set "simplx.mirage.class". Please do this manually.');
}
}else{
$modx->log(modX::LOG_LEVEL_DEBUG, 'simplx.mirage.setup(): The "simplx.mirage.class" Property Set is already installed.');
}
/*******************************************************************************************
* SQL VIEW SETUP SECTION
********************************************************************************************/
/*
I suggest not removing the MERGE algorithm since not using it would ditch the underlying table indexes.
Remember however that MERGE does not work well with aggregate functions and DISTINC, ORDER BY etc
*/
$createViewQuery = '
CREATE OR REPLACE ALGORITHM=MERGE VIEW `'.$objectPropertiesViewName.'` AS
SELECT
`val`.`contentid` AS `modresource.id`,
`var`.`id` AS `modtemplatevar.id`,
`tpl`.`templateid` AS `modtemplate.id`,
`var`.`name` AS `modtemplatevar.name`,
`val`.`value` AS `modtemplatevarresource.value`
FROM
'.$modTemplateVarTable.' AS `var`,
'.$modTemplateVarResourceTable.' AS `val`,
'.$modTemplateVarTemplateTable.' AS `tpl`
WHERE
`val`.`tmplvarid` = `var`.`id`
AND
`tpl`.`tmplvarid` = `var`.`id`;
';
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx_mirage_setup: $createViewQuery = '.$createViewQuery);
$result = $modx->exec($createViewQuery);
if($result === false){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx_mirage_setup: CREATE VIEW returned false. Aborting.');
return false;
}else{
// All's well that ends well. We can now set the "simplx.mirage.setup.hasrun" setting to 1.
$simplx_mirage_setting = $modx->getObject('modSystemSetting',array(
'key' => 'simplx.mirage.setup.hasrun'
));
$simplx_mirage_setting->set('value','1');
$result = $simplx_mirage_setting->save();
// And return true.
return true;
}
/*******************************************************************************************
*
*
********************************************************************************************/
<?php
require_once($modx->getOption('core_path').'/components/simplx/mirage/simplx_mirage.php');
$result = false;
if($debugmode){
$modx->setLogLevel(modX::LOG_LEVEL_DEBUG);
Simplx_Mirage::$_debugmode = true;
Simplx_Mirage_Class::$_debugmode = true;
Simplx_Mirage_Object::$_debugmode = true;
}
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx.mirage : ');
/*
Check if the Simplx Mirage setup Snippet has run. Otherwise do so.
The "simplx.mirage.setup.hasrun" flag is a System Setting which is
is only present if the setup has run.
*/
if(!$modx->getOption('simplx.mirage.setup.hasrun')){
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage : Setting "simplx.mirage.setup.hasrun" was either false or did not exist. Running Snippet "simplx.mirage.setup".');
$result = $modx->runSnippet('simplx.mirage.setup');
if($result === true){
$modx->log(modX::LOG_LEVEL_DEBUG, 'Snippet simplx.mirage : Running "simplx.mirage.setup" returned true.');
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet simplx.mirage : Running "simplx.mirage.setup" returned false. Aborting.');
return false;
}
}else{
}
switch($get){
case 'objects':
if(!$class){
return false;
}
if(!$query){
$query = array();
}else{
$query = json_decode($query,true);
if(!is_array($query)){
$modx->log(modX::LOG_LEVEL_ERROR, 'Snippet "simplx.mirage", case "objects": Malformed JSON query "'.$query.'".');
$query = array();
}
}
$mirageClass = new Simplx_Mirage_Class($class);
$list = $mirageClass->getObjects($query);
$result = array();
foreach($list as $obj){
$result[] = $obj->toArray();
}
break;
case 'schema':
if(!$class){
return false;
}
$mirageClass = new Simplx_Mirage_Class($class);
$result = $mirageClass->toJSON();
break;
case 'object':
if(!$id) return false;
$mirageObject = new Simplx_Mirage_Object($id);
$result = $mirageObject->toJSON();
break;
default:
}
return json_encode($result);
<?php
/*
class Simplx_Mirage {
public static $logger;
public static setLogger($logger){
}
}
*/
/**
* Simplx_Mirage is the base class which govern all Simplx_Mirage_Class / Simplx_Mirage_Object
* instances. The class also contains utility functionality which is global in the scope of the package.
* @package Simplx_Mirage
*/
class Simplx_Mirage {
/**
* Should Simplx_Mirage automatically determine where to place objects?
*
* @access public
* @static
* @var boolean
*/
public static $_autoMapObjectLocation = false;
/**
* Should Simplx_Mirage automatically create location for objects if they are missing?
*
* @access public
* @static
* @var boolean
*/
public static $_autoCreateObjectLocation = false;
/**
* Should Simplx_Mirage use strict name matching of Classes extending Simplx_Mirage_Object?
*
* @access public
* @static
* @var boolean
*/
public static $_forceTypeCheck = true;
/**
* Should Simplx_Mirage output debug info to the modx console?
*
* @access public
* @static
* @var boolean
*/
public static $_debugmode = false;
public static $_usePreflight = true;
/**
* Global cache array which store initialized instances of Simplx_Mirage_Class objects for
* duration of the request.
*
* @access public
* @static
* @var array
*/
public static $_classStore = array();
/**
* Global cache array which store initialized instances of Simplx_Mirage_Object objects for
* duration of the request.
*
* @access public
* @static
* @var array
*/
public static $_objectStore = array();
/**
* Class constructor. Not implemented at this time.
*
* @param
* @return
*/
public function __construct($id){
}
/**
* This is a global utility method which will return an object of a specific id.
* This method is NOT IMPLEMENTED at this time.
*
* @static
* @param $className The class name of the Object which to fetch.
* @param $id The id of the Object which to fetch.
* @return Simplx_Mirage_Object|false
*
*
* @param
* @return
**/
public static function getObject($id = null, $prototype = null){
global $modx;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObject(): Param $id = "'.$id.'", $prototype = "'.$prototype.'".');
$object = new Simplx_Mirage_Object($id, $prototype);
if($object){
return $object;
}else{
return false;
}
}
/**
* Returns a Simplx_Mirage_Class object wrapping its corresponding modTemplate object.
*
* @static
* @param @className Any existing MODx modTemplate object.
* @return Simplx_Mirage_Class|false
*/
public static function getClass($className){
global $modx;
$result = null;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getClass(): Param $className = "'.$className.'".');
if($className){
if(!array_key_exists($className,self::$_classStore)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getClass(): Class was not in the store. Lets create it and cache it.');
$result = new Simplx_Mirage_Class($className);
if($result){
$className = $result->_prototype->get('templatename');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getClass(): Storing Class "'.$className.'".');
self::$_classStore[$className] = &$result;
return $result;
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getClass(): Unable to create an instance of Class "'.$className.'". Aborting.');
return false;
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getClass(): Class "'.$className.'" was in the store. Getting and returning it.');
$result = self::$_classStore[$className];
return $result;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getClass(): Param $className was empty. Aborting.');
return false;
}
}
/**
* Returns an array of id's based on Simplx_Mirage Class name and optionally a
* constraining query in XPDO format.
*
* @static
* @param
* @return array|false
*/
public static function getIds($className,$query=array(),$prototypeName = null,$fields = null){
global $modx;
$resultList = array();
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): Params $className = "'.$className.'", $query = "'.json_encode($query).'", $prototypeName = "'.$prototypeName.'".');
// Lets prepare the query statement by normalizing it to contain field, operator and constraint
$query = self::prepareQueryStatement($query);
if($query === false){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getIds(): Exception, query is invalid. Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): query parsed successfully.');
}
if(!isset($prototypeName)) $prototypeName = 'modResource';
$prototype = $modx->newObject($prototypeName);
$sqlString = '';
/*
If we could not create the prototype object we have recieved an invalid class key in $prototypeName.
This in turn mean that we can not get the default class properties for the prototype which a deal
breaker, so we return false.
*/
if(!$prototype){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getIds(): Exception, Could not create prototype object. Aborting.');
return false;
}
/*
The $className parameter represents the Mirage Class (modTemplate) to get extended properties (TV's) from.
$className is required, if its not there we return false.
*/
if(!$className){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getIds(): Exception, Required param className was empty. Aborting.');
return false;
}
if(!class_exists($className)){
//if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getIds(): Exception, No Class named "'.$className.'" was found, did you include your class lib? Aborting.');
//return false;
}
// Turn the prototype to an array to make property checking easy.
$prototype = $prototype->toArray('');
if(is_array($prototype)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): Created prototype array which will be used for property checks.');
$prototype = array('classkey' => $prototypeName,$prototype);
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): Calling constructQuery().');
// Should we specify fields to be returned?
if(!isset($fields)){
$sqlString = self::constructQuery($query,$prototype);
}else{
$sqlString = self::constructQuery($query,$prototype,$fields);
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): constructQuery() returned "'.$sqlString.'".');
if($sqlString){
$objects = $modx->query($sqlString)->fetchAll();
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): Result from $modx->query() "'.json_encode($objects).'".');
foreach($objects as $obj){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getIds(): Getting id from "'.$className.'".');
$resultList[] = $obj;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getIds(): sqlString was empty. Aborting.');
return false;
}
if(is_array($objects)){
return $resultList;
}else{
return false;
}
}
/**
* Returns an array of Simplx_Mirage_Object instances each wrapping its corresponding
* modResource object.
*
* @static
* @param $className Name of the Simplx_Mirage_Class/modTemplate object.
* @param $query XPDO query style array constraining results.
* @return array|false
*/
public static function getObjects($className,$query=array(),$prototypeName = 'modResource',$fields=null){
global $modx;
$resultList = array();
$classExists = false;
$class = '';
$tmpQuery = '';
$prefix = '';
$separator = '';
$classProperties = array();
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Params $className = "'.$className.'", $query = "'.json_encode($query).'", $prototypeName = "'.$prototypeName.'".');
// Get the Simplx_Mirage_Class which wraps the modTemplate.
$class = Simplx_Mirage::getClass($className);
// Without a Class we cant go any further.
if(!$class){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): Exception, Could not create Simplx_Mirage_Class object. Aborting.');
return false;
}
// Get a local ref of the properties array. This is good practice when it will be used
// repeatedly, in a loop for example.
$classProperties =& $class->_properties;
// Make sure that we specify class id (template id) in the query.
if(!array_key_exists('template',$query)){
$query['template:='] = $class->_id;
}
// Lets prepare the query statement by normalizing it to contain field, operator and constraint
$query = self::prepareQueryStatement($query);
if($query === false){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): Exception, query is invalid. Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): query parsed successfully.');
}
$prototype = $modx->newObject($prototypeName);
$sqlString = '';
/*
If we could not create the prototype object we have recieved an invalid class key in $prototypeName.
This in turn mean that we can not get the default class properties for the prototype which a deal
breaker, so we return false.
*/
if(!$prototype){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): Exception, Could not create prototype object. Aborting.');
return false;
}
/*
The $className parameter represents the Mirage Class (modTemplate) to get extended properties (TV's) from.
$className is required, if its not there we return false.
*/
if(!$className){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): Exception, Required param className was empty. Aborting.');
return false;
}
if(!class_exists($className)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): No Class named "'.$className.'" was found, using the generic Simplx_Mirage_Object class.');
$classExists = false;
}else{
$classExists = true;
}
// Turn the prototype to an array to make property checking easy.
$prototype = $prototype->toArray('');
if(is_array($prototype)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Created prototype array which will be used for property checks.');
$prototype = array('classkey' => $prototypeName,$prototype);
}
$prefix = ($class->_tvPrefix != '') ? $class->_tvPrefix : $class->_classTypeName;
$separator = $class->_tvPrefixSeparator;
$prefix = $prefix.$separator;
/* Lets prefix the query fields if necessary */
if($class->_prefixTvs){
foreach($query as &$constr){
if(!array_key_exists($constr['field'],$prototype[0])){
$constr['field'] = ($prefix.$constr['field']);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Property "'.$constr['field'].'" was prefixed.');
}
}
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Query after prefixing "'.json_encode($query).'".');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Calling constructQuery().');
// Should we specify fields to be returned?
//if(!isset($fields)){
$sqlString = self::constructQuery($query,$prototype,array('c.*'));
//}else{
// $sqlString = self::constructQuery($query,$prototype,$fields);
//}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): constructQuery() returned "'.$sqlString.'".');
if($sqlString){
$criteria = new xPDOCriteria($modx, $sqlString);
$objects = $modx->getCollection($prototypeName,$criteria);
foreach($objects as &$obj){
if($classExists){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Creating Object "'.$obj->toJSON().'" of Class "'.$className.'".');
$resultList[] = new $className($obj->get('id'),$obj);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Creating Object "'.$obj->toJSON().'" of Class "'.$className.' using Simplx_Mirage_Object.".');
$resultList[] = new Simplx_Mirage_Object($obj->get('id'),$obj,$className);
}
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): sqlString was empty. Aborting.');
return false;
}
if(is_array($objects)){
return $resultList;
}else{
return false;
}
}
/**
* Prepares the XPDO style query by splitting it into an array.
*
* @static
* @param $query The XPDO style query array.
* @param $prototype The modResource object which is to be used when checking which fields "native" and which are TV's.
* @return string|false
*/
private static function prepareQueryStatement($query){
$fieldArray = array();
$operator = '';
$parsedQuery = array();
global $modx;
/*
Lets start looping through the query array to build the constraint section.
The query array has the following structure, array("field:operator"=>"constraint")
*/
if(is_array($query)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): Looping through the query array().');
foreach($query as $field => $constr){
/*
The query is likely to contain operators such as this, "field:>=". We need to explode apart such query strings.
*/
$fieldArray = explode(':',$field);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->prepareQueryStatement(): $fieldArray = "'.json_encode($fieldArray).'".');
if(count($fieldArray)>1){
$operator = $fieldArray[1];
}else{
$operator = '=';
$constr = $fieldArray[1];
}
$parsedQuery[] = array(
'field' => $fieldArray[0],
'operator' => $operator,
'constraint' => $constr
);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->prepareQueryStatement(): $fieldArray = "'.json_encode($fieldArray).'".');
}
return $parsedQuery;
}else{
return false;
//Not a valid query format
}
}
/**
* Builds a SQL query from a XPDO query syntax. This is a central part of the Mirage concept as
* its lets the user constrain query results using template variables.
*
* @static
* @param $query The XPDO style query array.
* @param $prototype The modResource object which is to be used when checking which fields "native" and which are TV's.
* @return string|false
*/
private static function constructQuery($query,$prototype,$fields = array()){
global $modx;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): Params $query = "'.json_encode($query).'", $prototype = "'.json_encode($prototype).'".');
$whereClause = '';
$count = 0;
$i = 0;
$parsedQuery = array();
$operator = '';
$viewName = '';
$tableName = '';
$defaultProperties = null;
$useJoin = false;
$fields[] = 'c.id';
$fields = implode($fields,',');
if(is_array($prototype)){
$defaultProperties = $prototype[0];
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): Set $defaultProperties to "'.json_encode($defaultProperties).'".');
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->constructQuery(): Exception, the prototype array is invalid. Aborting.');
return false;
}
$viewName = $modx->getOption('simplx.mirage.object.viewname');
if(!$viewName){
$viewName = 'view_mirage_object_properties';
}
$tableName = $modx->getTableName($prototype['classkey']);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): Set $tableName to "'.$tableName.'", and $viewName to "'.$viewName.'".');
/*
Ok we can now build the actual SQL statement
*/
$count = 0;
foreach($query as $constr){
/*
If the field is in the prototype array, its part of the default properties for the mod* class.
If not, we handle them as tv's.
*/
if(!array_key_exists($constr['field'],$defaultProperties)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): The field "'.$constr['field'].'" is not a modResource field.');
// Set $useJoin to true for later use.
$useJoin = true;
if($count > 0){
$whereClause .= ' AND (';
}else{
$whereClause .= ' (';
}
/*
First we need to constrain the result on tv name.
*/
$whereClause .= 'p.`modtemplatevar.name` = "'.$constr['field'].'" ';
$whereClause .= ' AND ';
/*
Then we add the actual value constrain.
*/
$whereClause .= 'p.`modtemplatevarresource.value` ';
// See if we have an operator. If not, we default to equals ("=").
if($constr['operator']){
$whereClause .= (' '.$constr['operator'].' ');
}else{
$whereClause .= ' = ';
}
$constraint = $constr['constraint'];
if(!is_numeric($constraint)){
$constraint = ('"'.$constraint.'"');
}
$whereClause .= $constraint;
$whereClause .= ')';
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): The field "'.$constr['field'].'" is a modResource field.');
if($count > 0){
$whereClause .= ' AND ';
}
$whereClause .= ' c.`'.$constr['field'].'` ';
// See if we have an operator. If not, we default to equals ("=").
if($constr['operator']){
$whereClause .= (' '.$constr['operator'].' ');
}else{
$whereClause .= ' = ';
}
$constraint = $constr['constraint'];
// Make sure we quote any string.
if(!is_numeric($constraint)){
$constraint = ('"'.$constraint.'"');
}
$whereClause .= $constraint;
}
$count = $count + 1;
}
// This should be it. Lets build and return the query string.
// Build the initial part of the SQL string which joins the table name for the prototype (defaults to 'modResource') and the view.
if($useJoin){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): Got more than just the id field so we use a join.');
$sqlString = 'SELECT DISTINCT '.$fields.' FROM '.$tableName.' AS c LEFT JOIN `'.$viewName.'` AS p ON c.id = p.`modresource.id` WHERE ';
}else{
$sqlString = 'SELECT '.$fields.' FROM '.$tableName.' AS c WHERE ';
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->constructQuery(): The sqlString is set to "'.$sqlString.'".');
$sqlString .= ($whereClause.';');
return $sqlString;
}
}
/**
* Simplx_Mirage_Class wraps a named modTemplate object.
* Any Simplx_Mirage_Object using a particular Simplx_Mirage_Class will "inherit" many
* of it's public properties as defaults.
*
* @package Simplx_Mirage
*/
class Simplx_Mirage_Class {
/**
* Unique id key for the Class. This is always the same as the modTemplate object which it wraps.
*
* @access public
* @var int
*/
public $_id;
/**
* This property sets the default location in the site structure for modResources using this
* this modTemplate wrapper.
*
* @access public
* @var int
*/
public $_defaultObjectLocation = 0;
/**
* Class URI should point to the URI (ex. http://mysite.com/api/Whatnot/) where Objects (modResource's)
* of this type are found.
*
* @access public
* @var string
*/
public $_classUri;
/**
* The prototype is an instance of the actual modTemplate being wrapped.
*
* @access public
* @var modTemplate
*/
public $_prototype;
/**
* Class name is the Simplx Mirage moniker, or alias, for the modTemplate object.
* By default, this is the same the template instance name.
*
* @access public
* @var string
*/
public $_classTypeName;
/**
* The properties collection is an array where all the Simplx Mirage Class properties (TV's)
* are cached for snappy retrieval. This should not really be used on its own
* and should probably really be protected.
*
* @access public
* @var array
*/
public $_properties = array();
/**
* If excludeModResourceFields is set to true, toJSON/toArray will exclude all modResource fields for this
* Simplx Mirage Class. The serialized data only contain the TV's. Handy when you want to really emulate custom
* object types.
*
* @access public
* @var boolean
*/
public $_excludeModResourceFields = false;
/**
* Should prefixes be used to indicate which modTemplate (Simplx_Mirage_Class) a modTemplateVar belongs to?
* Its HIGHLY recommended to set this to true as it makes your model infinitly more intuitive.
*
* @access public
* @var boolean
*/
public $_prefixTvs = true;
/**
* Actual TV prefix to use. This default to ($_classTypeName.'_'.TV name)
*
* @access public
* @var string
*/
public $_tvPrefix;
/**
* Prefix separator. This default to '_'.
*
* @access public
* @var string
*/
public $_tvPrefixSeparator = '_';
/**
* Should we accept prefix regardless of case? A good convention is to use upper case names
* for our Simplx Mirage Classes (modTemplates). By default TV prefixing is case sensitive.
*
* @access public
* @var boolean
*/
public $_tvPrefixToLower = false;
/**
* Should we force "type check" the $_classTypeName against the name of the modTemplate prototype?
*
* @access public
* @var boolean
*/
public $_forceTypeCheck = true;
/**
* Should we persist (save) property values directly on assignment?
* NOT IMPLEMENTED
*
* @access public
* @var boolean
*/
public $_persistOnAssign = false;
/**
*
*
* @access public
* @var array
*/
public $_propertyObjects = array();
/**
*
*
* @access public
* @var array
*/
public $_propertyValidationRules = array();
/**
* Maps TV input formats to php types. Used for serialization.
*
* @access public
* @var array
*/
public $_propertyTypeMap = array(
'text'=>'string',
'checkbox'=>'boolean',
'resourcelist'=>'integer',
'date'=>'date',
'time'=>'time',
'*'=>'string'
);
/**
* Should associations created for Objects of this Class be stored in
* folders, as child resources?
*
* @access public
* @var boolean
*/
public $_useFoldersForAssoc = false;
/**
* If folders for associated objects are not present, should we create them?
*
* @access public
* @var boolean
*/
public $_createFoldersForAssoc = true;
/**
* This map is used to map associated types to custom folder names when $_useFoldersForAssoc is true.
*
* @access public
* @var array
*/
public $_assocNameMap = array();
/**
* Valid composite types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)
*
* @access public
* @var array
*/
public $_composites = array();
/**
* Valid aggregate types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)
*
* @access public
* @var array
*/
public $_aggregates = array();
/**
* Valid association types. The type names should be those used by the referd to Simplx Mirage Classes (modTemplates)
*
* @access public
* @var array
*/
public $_associations = array();
private $_prototypePropertySet = array();
public static $_debugmode = false;
/**
*
*
* @static
* @param
* @return
*/
public function __construct($className=null,&$prototype=null){
global $modx;
$query;
$ruleSet;
$propertyName;
$elementArray;
$inputPropertiesTmp;
$inputProperties;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Constructor args, $className = "'.$className.'".');
if(isset($prototype)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): $prototype is set.');
if(!$prototype instanceof modTemplate){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Class->__construct(): $prototype parameter was not of type "modTemplate". Aborting.');
return false;
}
$this->_prototype = &$prototype;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): $prototype is not set.');
// Get the modTemplate which represents our Class. If class name is an int we get it using id.
if(!is_numeric($className)){
$query = array('templatename' => $className);
}else{
$query = array('id' => $className);
}
$prototype = $modx->getObject('modTemplate',$query);
if(!$prototype){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Class->__construct(): Could not get a valid modTemplate named "'.$className.'". Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Setting $_prototype property.');
$this->_prototype = $prototype;
$this->_classTypeName = $className;
$this->_tvPrefix = $className;
$this->_id = $prototype->get('id');
}
}
/*
We hould now have a valid modTemplate object to play with.
*/
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Using prototypes PropertySet to assign defaults.');
/*
Get the modTemplates PropertySet
*/
$this->_prototypePropertySet = $this->_prototype->getPropertySet('simplx.mirage.class');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): PropertySet holds "'.json_encode($this->_prototypePropertySet).'".');
/*
Apply all defaults for the Simplx Mirage Class. Defaults are specified in the default Property Set for the
modTemplate prototype.
*/
if(is_array($this->_prototypePropertySet) && count($this->_prototypePropertySet) > 0 ){
$this->_excludeModResourceFields = array_key_exists('excludeModResourceFields',$this->_prototypePropertySet) ? $this->_prototypePropertySet['excludeModResourceFields'] : $this->_excludeModResourceFields;
$this->_prefixTvs = array_key_exists('prefixTvs',$this->_prototypePropertySet) ? $this->_prototypePropertySet['prefixTvs'] : $this->_prefixTvs;
$this->_tvPrefix = array_key_exists('tvPrefix',$this->_prototypePropertySet) ? $this->_prototypePropertySet['tvPrefix'] : $this->_tvPrefix;
$this->_tvPrefixSeparator = array_key_exists('tvPrefixSeparator',$this->_prototypePropertySet) ? $this->_prototypePropertySet['tvPrefixSeparator'] : $this->_tvPrefixSeparator;
$this->_tvPrefixToLower = array_key_exists('tvPrefixToLower',$this->_prototypePropertySet) ? $this->_prototypePropertySet['tvPrefixToLower'] : $this->_tvPrefixToLower;
$this->_forceTypeCheck = array_key_exists('forceTypeCheck',$this->_prototypePropertySet) ? $this->_prototypePropertySet['forceTypeCheck'] : $this->_forceTypeCheck;
$this->_persistOnAssign = array_key_exists('persistOnAssign',$this->_prototypePropertySet) ? $this->_prototypePropertySet['persistOnAssign'] : $this->_persistOnAssign;
$this->_useFoldersForAssoc = array_key_exists('useFoldersForAssoc',$this->_prototypePropertySet) ? $this->_prototypePropertySet['useFoldersForAssoc'] : $this->_useFoldersForAssoc;
$this->_createFoldersForAssoc = array_key_exists('createFoldersForAssoc',$this->_prototypePropertySet) ? $this->_prototypePropertySet['createFoldersForAssoc'] : $this->_createFoldersForAssoc;
$this->_defaultObjectLocation = array_key_exists('defaultObjectLocation',$this->_prototypePropertySet) ? $this->_prototypePropertySet['defaultObjectLocation'] : $this->_defaultObjectLocation;
$this->_classUri = array_key_exists('classUri',$this->_prototypePropertySet) ? $this->_prototypePropertySet['classUri'] : $this->_classUri;
$this->_aggregates = array_key_exists('aggregates',$this->_prototypePropertySet) ? json_decode($this->_prototypePropertySet['aggregates'],true) : $this->_aggregates;
$this->_composites = array_key_exists('composites',$this->_prototypePropertySet) ? json_decode($this->_prototypePropertySet['composites'],true) : $this->_composites;
$this->_associations = array_key_exists('associations',$this->_prototypePropertySet) ? json_decode($this->_prototypePropertySet['associations'],true) : $this->_associations;
if($this->_prefixTvs && $this->_tvPrefix === ''){
$this->_tvPrefix = $className;
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): PropertySet was empty.');
}
/*
Get Properties (TV's)
*/
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Fetching all TVs.');
$properties = $this->_prototype->getTemplateVars();
// Reseting the array just in case.
reset($properties);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Number of $properties "'.count($properties).'".');
if(!is_array($properties)){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Class->__construct(): Could not get the modTemplateVars array from the modTemplate "'.$className.'". Aborting.');
return false;
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Setting $_properties property.');
// Persist the TV object collection
$this->_propertyObjects = $properties;
// Iterate through the collection and serialize a simplified version of each TV.
foreach($properties as $prop){
$propertyName = $prop->get('name');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Current property "'.$propertyName.'".');
// Split the input elements list to array
$elementArray = explode('||',$prop->elements);
// Get the input options which will be used for validation.
$inputPropertiesTmp = $prop->input_properties;
if($inputPropertiesTmp !== ''){
// Fix the input_properties string which for some utterly illogical reason is malformed json.
$preg = '/[a-z].[0-9]?[0-9]:/i';
$inputPropertiesTmp = preg_replace($preg ,'' ,$inputPropertiesTmp);
$inputPropertiesTmp = str_replace('{','[',$inputPropertiesTmp);
$inputPropertiesTmp = str_replace(';}',']',$inputPropertiesTmp);
$inputPropertiesTmp = str_replace(';',',',$inputPropertiesTmp);
}else{
// If we have no input properties for the TV we default the inputProperties variable to an empty array.
$inputPropertiesTmp = '[]';
}
// Turn the properties string to array format.
$inputPropertiesTmp = json_decode($inputPropertiesTmp);
if($inputPropertiesTmp){
$i=0;
while($i<count($inputPropertiesTmp)){
$inputProperties[$inputPropertiesTmp[$i++]] = $inputPropertiesTmp[$i++];
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Input validators "'.json_encode($inputProperties).'".');
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Got no Input validators.');
$inputProperties = array();
}
// If we your tv prefixes we must make sure not to return any incomp. properties.
if($this->_prefixTvs){
$pos = strpos($propertyName,$this->_tvPrefix);
if($pos !== 0){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->__construct(): Got an incompatible TV. "'.$propertyName.'" does not match prefix.');
unset($inputPropertiesTmp);
unset($inputProperties);
continue;
}else{
$pos = strpos($propertyName,$this->_tvPrefixSeparator);
if($pos){
$propertyName = substr($propertyName,($pos+1));
}
}
}
if(array_key_exists($propertyName,$this->_propertyValidationRules)){
// Get possible validation rules specified by the overriding Simplx_Mirage_Class
$ruleSet = $this->_propertyValidationRules[$propertyName];
}else{
// No custom validation rules set at this time.
$ruleSet = array(
'required'=>(array_key_exists('allowBlank',$inputProperties) ? $inputProperties['allowBlank'] : 'false'),
'pattern'=>(array_key_exists('pattern',$inputProperties) ? $inputProperties['pattern'] : ''),
'maximum'=>(array_key_exists('maxValue',$inputProperties) ? $inputProperties['maxValue'] : ''),
'minimum'=>(array_key_exists('minValue',$inputProperties) ? $inputProperties['minValue'] : ''),
'minItems'=>(array_key_exists('minItems',$inputProperties) ? $inputProperties['minItems'] : ''),
'maxItems'=>(array_key_exists('maxItems',$inputProperties) ? $inputProperties['maxItems'] : ''),
'uniqueItems'=>(array_key_exists('uniqueItems',$inputProperties) ? $inputProperties['uniqueItems'] : ''),
'enum'=>json_encode($elementArray),
'minLength'=>(array_key_exists('minLength',$inputProperties) ? $inputProperties['minLength'] : ''),
'maxLength'=>(array_key_exists('maxLength',$inputProperties) ? $inputProperties['maxLength'] : ''),
'default' => $prop->get('default_text')
);
}
$this->_properties[$propertyName] = array(
'id' => $prop->get('id'),
'type' => (array_key_exists($prop->get('type'),$this->_propertyTypeMap) ? $prop->get('type') : $this->_propertyTypeMap['*']),
'title' => $propertyName
);
// Merge the custom/default ruleSet with then mandatory "property properties".
$this->_properties[$propertyName] = array_merge($this->_properties[$propertyName],$ruleSet);
}
//$this->_properties = $properties;
return true;
}
/**
*
*
* @param
* @return
*/
public function toJSON(){
$result = $this->toArray();
$result = json_encode($result);
if(!$result){
return false;
}else{
return $result;
}
}
public function toArray(){
$result = array(
'name'=>$this->_classTypeName,
'type'=>'object',
'properties'=>$this->_properties
);
if(!$result){
return false;
}else{
return $result;
}
}
/**
*
*
* @param
* @return
*/
public function createClassContainer($location=null,$alias=null,$defaults=array()){
global $modx;
if($location === null){
$location = $this->_defaultObjectLocation;
}else{
}
if($alias === null){
$alias = $this->_classTypeName;
}else{
}
$res = $modx->newObject('modResource');
if($res){
$res->set('parent',$location);
$res->set('isfolder',true);
$res->set('pagetitle',$alias);
$res->set('published',true);
$result = $res->save();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->createClassContainer(): Unable to create save object for associated class "'.$alias.'".');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->createClassContainer() : Created container "'.$alias.'".');
return true;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->createClassContainer(): Unable to create folder for associated class "'.$alias.'".');
return false;
}
}
/**
*
*
* @param
* @return
*/
public function newObject($defaults = array(),&$prototype = null){
global $modx;
$result = false;
$prototypeId = 0;
$assoc = array();
$res;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject()');
if($this->_id){
if(!$prototype){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : No prototype for the new Object was supplied.');
$prototype = $modx->newObject('modResource',$defaults);
if(!$prototype){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->newObject(): Unable to create object of type "'.$className.'". $modx->newObject() returned false. Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Successfully created a modResource for the new Object.');
}
}else{
if(!(is_object($prototype) && ($prototype instanceof modResource || $prototype instanceof modResourceInterface))){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->newObject(): Unable to create object. Prototype was of invalid type. Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Prototype was of correct type.');
}
}
// Make sure it ends up in the right place in the site structure.
if(!array_key_exists('parent',$defaults)){
$prototype->set('parent',$this->_defaultObjectLocation);
}
// Make sure we have a name (pagetitle).
if(!array_key_exists('pagetitle',$defaults)){
$prototype->set('pagetitle',$this->_classTypeName);
}
// Default to public.
if(!array_key_exists('published',$defaults)){
$prototype->set('published',true);
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Setting template property of the prototype to "'.$this->_id.'".');
// Reset the Resource template to the Class id just in case.
$prototype->set('template',$this->_id);
$result = $prototype->save();
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->newObject(): Unable to create object. modResource->save() returned false. Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Successfully saved prototype. Got new id "'.$prototype->get('id').'"');
}
$prototypeId = $prototype->get('id');
if($prototypeId){
if($this->_useFoldersForAssoc){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Using folders for assoc objects.');
$assoc = array_merge($this->_aggregates,$this->_composites,$this->_associations);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Assoc objects "'.json_encode($this->_aggregates).'".');
foreach($assoc as $className => $alias){
$result = $this->createClassContainer($prototypeId,$alias);
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Not using folders for assoc objects.');
}
if(!class_exists($this->_classTypeName)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Creating the Simplx_Mirage_Object instance.');
$result = new Simplx_Mirage_Object($prototypeId,$prototype);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->newObject() : Creating the custom class instance.');
$result = new $this->_classTypeName($prototypeId,$prototype);
}
if($result){
return $result;
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->newObject(): Unable to create Simplx_Mirage_Object object for resource.');
return false;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->newObject(): New object is missing valid id. Aborting.');
return false;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->newObject(): Class not is missing its internal _id reference to modTemplate. Aborting.');
return false;
}
}
/**
*
*
* @param
* @return
*/
public function getObject($id = null, $prototype = null){
/*
if(!class_exists($className)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): No Class named "'.$className.'" was found, using the generic Simplx_Mirage_Object class.');
$classExists = false;
}else{
$classExists = true;
}
if($classExists){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Creating Object "'.$obj->toJSON().'" of Class "'.$className.'".');
$resultList[] = new $className($obj->get('id'),$obj);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Creating Object "'.$obj->toJSON().'" of Class "'.$className.' using Simplx_Mirage_Object.".');
$resultList[] = new Simplx_Mirage_Object($obj->get('id'),$obj,$className);
}
*/
$object = new Simplx_Mirage_Object($id, $prototype);
if($object){
return $object;
}else{
return false;
}
}
/**
*
*
* @param
* @return
*/
public function getObjects($query){
global $modx;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->getObjects()');
$prefix = $this->_tvPrefix.$this->_tvPrefixSeparator;
$objectQuery = array();
/*
Moved prefixing to Simplx_Mirage::getObjects()
*/
$result = Simplx_Mirage::getObjects($this->_classTypeName,$query);
if(is_array($result)){
return $result;
}else{
return false;
}
}
/**
*
*
* @param
* @return
*/
public function renderAspect($aspect='',$aspectParameters = array(),$forInstance = 0){
global $modx;
$output = '';
$aspectString = '';
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Class->renderAspect()');
if(!$this->_properties){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Class->__renderAspect(): The $_properties array is empty. Aborting.');
return false;
}
switch($aspect){
case 'input':
foreach($this->_propertyObjects as &$property){
$output = $output . $property->renderInput($forInstance);
}
$aspectString = ('<form name="'.$this->_classTypeName.'" data-class_key="modResource" id="" data-classtypename="'.$this->_classTypeName.'">').($output.'</form>');
break;
case 'output':
foreach($this->_propertyObjects as &$property){
$output = $output . $property->renderOutput($forInstance);
}
break;
default;
$aspectString = $modx->runSnippet($aspect,$aspectParameters);
}
return $aspectString;
}
}
/**
* Simplx_Mirage_Object wraps a modResource object.
* The Simplx_Mirage_Object "inherits" many default property values from its assocciated
* Simplx_Mirage_Class object.
*
* @package Simplx_Mirage
*/
class Simplx_Mirage_Object {
public $_excludeModResourceFields = null;
public $_prefixTvs = null;
public $_tvPrefix = null;
public $_tvPrefixSeparator = null;
public $_tvPrefixToLower = null;
public $_forceTypeCheck = null;
public $_persistOnAssign = null;
public $_useFoldersForAssoc = null;
public $_createFoldersForAssoc = null;
public $_id;
public $_tvsLoaded = false;
public $_assocNameMap = array();
public $_assocIdMap = array();
public $_parent = null;
protected $_prototype;
protected $_classTypeName;
protected $_class;
protected $_classId;
protected $_properties = array();
protected $_aggregates = array();
protected $_composites = array();
public static $_debugmode = false;
/**
*
*
* @param
* @return
*/
public function __construct($id=null,&$prototype=null,$classTypeName=null){
global $modx;
$state = null;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Constructor args, id= '.$id.', prototype = '.isset($prototype).' and classtypeName = "'.$classTypeName.'".');
if(isset($id) || isset($prototype)){
/*
Remember that the Mirage Class is only a facade for a MODX Resource to add behavior and more on the fly.
So, next, we need to add a prototype object to the Mirage Class instance. This prototype is always a
modResource with one assigned modTemplate.
*/
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Got an id parameter OR a prototype.');
/*
Lets check if we have a prototype object. If so this should take precedence over any id param.
We also make sure that we have a valid id as fallback, if not we abort.
*/
if(is_null($prototype)){
// If we landed here there wasnt any prototype available so lets
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Got no prototype parameter. Creating a modResource instance.');
$prototype = $modx->getObject('modResource',$id);
}else{
if(!$prototype instanceof modResource){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object: __construct(), The prototype is not of type "modResource". Aborting.');
return false;
}
}
// So now we should have a modResource prototype.
if(isset($prototype)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Prototype is valid. '.$prototype->toJSON());
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Setting internal id variable to prototype id '.$prototype->get('id'));
$id = $prototype->get('id');
/*
Default the $_classTypeName variable to the class name.
This means that Mirage will expect that there is a modTemplate with the same name
in the MODx system.
*/
if(!isset($classTypeName)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Setting the _classTypeName variable to "'.get_class($this).'".');
$this->_classTypeName = get_class($this);
}else{
// If we got a class name as parameter we use this.
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Using classTypeName parameter "'.$classTypeName.'" as class name.');
$this->_classTypeName = $classTypeName;
}
/*
Get the name and the id of the modTemplate that the Resource uses.
*/
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Trying to get the modTemplate object from the prototype.');
$typeName = $prototype->getOne('Template');
$typeName = $typeName->get('templatename');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): The modTemplate is named "'.$typeName.'".');
//if(!$this->_class){
// $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object: __construct(), Can not get modTemplate. Type "'.$typeName.'" is not a compatible Class.');
//return false;
//}
/*
If the instance returned Simplx_Mirage_Object as class name the class has not
been extended. This meens that we have to default the class name to the modTemplate name.
*/
if($this->_classTypeName == 'Simplx_Mirage_Object'){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Class name is "Simplx_Mirage_Object" so we set it to the name of its modTemplate "'.$typeName.'".');
$this->_classTypeName = $typeName;
}
if(!$typeName){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object: __construct(), Can not get modTemplate from the modResource object. Aborting.');
return false;
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): modTemplate name is "'.$typeName.'".');
/*
Lets now check so that the modResource actually is of type Aircraft, in other words
uses the correct Template.
*/
// Only fail though if the $classTypeName is not set to the default modResource.
if($typeName != $this->_classTypeName){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object: __construct(), Type "'.$typeName.'" not a compatible Class.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): classTypeName is the same as modTemplate name and is therefor valid.');
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Finally assigning the $prototype object to the internal _prototype variable.');
// Get a ref to the Simplx_Mirage_Class associated with this object. The Mirage Class has all default settings
// for the object.
$this->_class =& Simplx_Mirage::getClass($typeName);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Assigning all defaults from the Class.');
// If we got a valid reference we assign all defaults. The Class defaults are stored in the Classes
// default PropertySet.
if($this->_class){
// Defaults for the public meta properties
/*
public $_excludeModResourceFields = false;
public $_prefixTvs = false;
public $_tvPrefix;
public $_tvPrefixSeparator = '_';
public $_tvPrefixToLower = false;
public $_forceTypeCheck = true;
public $_persistOnAssign = false;
public $_useFoldersForAssoc = false;
public $_createFoldersForAssoc = true;
*/
/*
Inherit and apply all property defaults from the assoc Simplx_Mirage_Class
IF the class which extends the Simplx_Mirage_Object does not specify a custom default.
*/
$this->_excludeModResourceFields = is_null($this->_excludeModResourceFields) ? $this->_class->_excludeModResourceFields : $this->_excludeModResourceFields;
$this->_prefixTvs = is_null($this->_prefixTvs) ? $this->_class->_prefixTvs : $this->_prefixTvs;
$this->_tvPrefix = is_null($this->_tvPrefix) ? $this->_class->_tvPrefix : $this->_tvPrefix;
$this->_tvPrefixSeparator = is_null($this->_tvPrefixSeparator) ? $this->_class->_tvPrefixSeparator : $this->_tvPrefixSeparator;
$this->_tvPrefixToLower = is_null($this->_tvPrefixToLower) ? $this->_class->_tvPrefixToLower : $this->_tvPrefixToLower;
$this->_forceTypeCheck = is_null($this->_forceTypeCheck) ? $this->_class->_forceTypeCheck : $this->_forceTypeCheck;
$this->_persistOnAssign = is_null($this->_persistOnAssign) ? $this->_class->_persistOnAssign : $this->_persistOnAssign;
$this->_useFoldersForAssoc = is_null($this->_useFoldersForAssoc) ? $this->_class->_useFoldersForAssoc : $this->_useFoldersForAssoc;
$this->_createFoldersForAssoc = is_null($this->_createFoldersForAssoc) ? $this->_class->_createFoldersForAssoc : $this->_createFoldersForAssoc;
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object: __construct(), Unable to get a valid Simplx_Mirage_Class reference.');
return false;
}
$this->_prototype = $prototype;
/*
If we are supposed to use prefixed TVs, lets see that we have it configured.
Per default, we use the Class name as prefix.
*/
if($this->_prefixTvs){
if(!isset($this->_tvPrefix)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Using Class name as default prefix.');
$tempClsName = $this->_classTypeName;
}else{
$tempClsName = $this->_tvPrefix;
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Using prefix "'.$tempClsName.'" for TVs.');
/*
Have we configured to use only lcase prefixes? If so fix class name before
building the prefix string.
*/
if($this->_tvPrefixToLower){
$tempClsName = strtolower($tempClsName);
}
$this->_tvPrefix = ($tempClsName.$this->_tvPrefixSeparator);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Complete prefix is "'.$this->_tvPrefix.'".');
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->__construct(): Could not find any modResource instance with id '.$id.'. Aborting.');
return false;
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): id parameter was empty.');
/*
Create new Resource?
*/
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Assigning internal id '.$id.'.');
// All went well so we set the internal _id variable to reflect the prototypes id.
$this->_id = $id;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Assigning parent id.');
// Also set the parent.
$this->_parent = $this->_prototype->get('parent');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__construct(): Returning Object.');
return true;
}
/**
*
*
* @param
* @return
*/
public function setClass(&$object){
if($object instanceof Simplx_Mirage_Class){
$this->_class = $object;
return true;
}else{
return false;
}
}
/**
*
*
* @param
* @return
*/
public function getClass(){
if(isset($this->_class)){
return $this->_class;
}
}
/**
*
*
* @param
* @return
*/
public function setPrototype(&$object){
if($object instanceof modResource){
$this->_prototype = $object;
return true;
}else{
return false;
}
}
/**
*
*
* @param
* @return
*/
public function getPrototype(){
if(isset($this->_prototype)){
return $this->_prototype;
}
}
/*
"Overides" the default modResource behaviour.
This enables us to persist the TV values stored in the Mirage object.
*/
/**
*
*
* @param
* @return
*/
public function save(){
global $modx;
$result;
if(isset($this->_prototype)){
if(!$this->_persistOnAssign){
$result = $this->setTVValues();
}else{
$result = true;
}
if($result){
$result = $this->_prototype->save();
if(!$result){
return true;
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->save(): Unable to save prototype modResource.');
return false;
}
return true;
}else{
// Unable to save TV values.
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->save(): Unable to save TVs.');
return false;
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->save(): Invalid prototype. Unable to save.');
return false;
}
}
/**
*
*
* @param
* @return
*/
public function getAggregates($className,$query = array()){
global $modx;
$resultList = array();
$assocFolderId = null;
$assocFolderName = null;
$assocQuery = array();
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getAggregates(): $className = "'.$className.'", $query="'.json_encode($query).'".');
if($this->_useFoldersForAssoc){
if(array_key_exists($className,$this->_assocNameMap)){
$assocFolderName = $this->_assocNameMap[$className];
// Lets get the custom folder mapping for the class name.
$assocQuery['parent:='] = $this->_id;
$assocQuery['pagetitle:='] = $className;
$assocQuery['isfolder:='] = '1';
$result = Simplx_Mirage::getIds($className,$assocQuery);
if($result){
$assocFolderId = $result[0]['id'];
}
}else{
// No custom class name to folder name mapping was specified so we default to the $className parameter.
$assocQuery['parent:='] = $this->_id;
$assocQuery['pagetitle:='] = $className;
$assocQuery['isfolder:='] = '1';
$result = Simplx_Mirage::getIds($className,$assocQuery);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getAggregates(): Found the following aggr result "'.json_encode($result).'".');
if($result){
$assocFolderId = $result[0]['id'];
}
}
}
if(!$assocFolderId){
$assocFolderId = $this->_id;
}
// Save the id of the folder which contains the current aggregate class.
$this->_assocIdMap[$className] = $assocFolderId;
$query['parent:='] = $assocFolderId;
$query['class_key:='] = 'modSymLink';
$result = Simplx_Mirage::getIds($className,$query,null,array('c.content'));
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getAggregates(): Result from Simplx_Mirage::getIds() "'.json_encode($result).'".');
if(!is_array($result)) return false;
// Lets get the actual objects which the symlinks point to
foreach($result as $row){
$id = $row[0];
if($id){
$obj = new Simplx_Mirage_Object($id);
if($obj){
$obj->_parent = $this->_id;
$resultList[] = &$obj;
}
}
}
if(is_array($resultList)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getAggregates(): '.count($resultList).' Objects of class = "'.$className.'" was found.');
// Store the aggretages in a Class wide store.
$this->_aggregates[$className] = $resultList;
return $resultList;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getAggregates(): No Objects of class = "'.$className.'" was found.');
return false;
}
}
/**
*
*
* @param
* @return
*/
public function getComposites($className,$query = array()){
global $modx;
$assocFolderId = null;
$assocFolderName = null;
$assocQuery = array();
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getComposites(): $className = "'.$className.'", $query="'.json_encode($query).'".');
if($this->_useFoldersForAssoc){
if(array_key_exists($className,$this->_assocNameMap)){
$assocFolderName = $this->_assocNameMap[$className];
// Lets get the custom folder mapping for the class name.
$assocQuery['parent:='] = $this->_id;
$assocQuery['pagetitle:='] = $className;
$assocQuery['isfolder:='] = '1';
$result = Simplx_Mirage::getIds($className,$assocQuery);
if($result){
$assocFolderId = $result[0]['id'];
}
}else{
// No custom class name to folder name mapping was specified so we default to the $className parameter.
$assocQuery['parent:='] = $this->_id;
$assocQuery['pagetitle:='] = $className;
$assocQuery['isfolder:='] = '1';
$result = Simplx_Mirage::getIds($className,$assocQuery);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getComposites(): Found the following result "'.json_encode($result).'".');
if($result){
$assocFolderId = $result[0]['id'];
}
}
}
if(!$assocFolderId){
$assocFolderId = $this->_id;
}
// Save the id of the folder which contains the current composite class.
$this->_assocIdMap[$className] = $assocFolderId;
$query['parent:='] = $assocFolderId;
$query['class_key:='] = 'modDocument';
$query['template:='] = Simplx_Mirage::getClass($className)->_id;
$result = Simplx_Mirage::getObjects($className,$query);
if(is_array($result)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getComposites(): '.count($result).' Objects of class = "'.$className.'" was found.');
// Set a proper reference to the parent of each resource. If using folders for associated objects this gets get screwed otherwise
foreach($result as &$obj){
$obj->_parent = $this->_id;
}
// Reset the array pointer before returning it
reset($result);
// Store the composites in a Class wide store.
$this->_composites[$className] = $result;
return $result;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getComposites(): No Objects of class = "'.$className.'" was found.');
return false;
}
}
/**
*
*
* @param
* @return
*/
private function getAssocFolders(){
global $modx;
$folders = array();
$modx->getObject('modResource',array('parent'=>$this_id,'isfolder'=>true));
if(is_array($folders)){
return $folders;
}else{
return false;
}
}
/**
*
*
* @param
* @return
*/
public function addComposite($classTypeName=null,$prototype = null){
global $modx;
$composite;
$result;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): Class name "'.$classTypeName.'".');
if(isset($classTypeName)){
// As the Class name was specified we assume that no prototype was supplied.
$compositeClass = &Simplx_Mirage::getClass($classTypeName);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): Got a reference to the Composite Class.');
if($this->_useFoldersForAssoc){
// Get the id of the Container Resource in which to place the new composite Resource.
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): Folders are used to store Composites.');
$result = false;//array_key_exsits($classTypeName,$this->_assocIdMap);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): Does the Composite container id exist in the store? "'.$result.'".');
if($result){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): The id for the Composites folder was in the assocIdMap collection. It is "'.$parent.'".');
$parent = $this->_assocIdMap[$classTypeName];
}else{
// If the requested composite class name was not in the Id map we load and store it.
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): There was no reference to the id of Composite Resource in the assocIdMap collection.');
$result = $modx->getObject('modResource',array('parent'=>$this->_id,'pagetitle'=>$classTypeName));
if(!$result){
// $result was false which meens that the class name is not valid where found.
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->addComposite(): Unable to load Composites folder. Aborting.');
return false;
}
$containerId = $result->get('id');
$this->_assocIdMap[$classTypeName] = $containerId;
$parent = $containerId;
}
}else{
// Not using folders for associated object.
$parent = $this->_id;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): Not using folders for associated object. id used is "'.$this->_id.'".');
}
if($compositeClass){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addComposite(): Creating new Resource with Class/Template "'.$compositeClass->_id.'".');
$composite = $modx->newObject('modResource');
$composite->set('pagetitle',$classTypeName);
$composite->set('parent',$parent);
$composite->set('template',$compositeClass->_id);
$composite->set('published',true);
$composite->save();
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->addComposite(): Unable to get the Composite Class object. Simplx_Mireage::getClass() returned false. Aborting.');
return false;
// Unable to create class. Aborting.
}
/*
if(!class_exists($className)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage->getObjects(): No Class named "'.$className.'" was found, using the generic Simplx_Mirage_Object class.');
$classExists = false;
}else{
$classExists = true;
}
if($classExists){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Creating Object "'.$obj->toJSON().'" of Class "'.$className.'".');
$resultList[] = new $className($obj->get('id'),$obj);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage->getObjects(): Creating Object "'.$obj->toJSON().'" of Class "'.$className.' using Simplx_Mirage_Object.".');
$resultList[] = new Simplx_Mirage_Object($obj->get('id'),$obj,$className);
}
*/
return $composite;
}elseif(isset($prototype)){
if($prototype instanceof modResource){
}else{
// Prototype must be of type modResource
}
}else{
// Missing required params. Abort.
}
}
/**
*
*
* @param
* @return
*/
public function addAggregate($referenceId,$altObjectName=null){
global $modx;
$aggregateClass;
$aggregateObject;
$classTypeName;
$result;
$list;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Object ref id "'.$referenceId.'".');
if(isset($referenceId)){
// An aggregate is represented as a SymLink, so we need to load the original, source Resource first.
$aggregateObject = $modx->getObject('modResource',$referenceId);
if(!$aggregateObject){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->addAggregate(): The associated object with id "'.$referenceId.'" does not exist. Aborting.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Found Object id "'.$referenceId.'".');
}
// Getting the Class / Template
// Temporary hack to get template name. This should be done in the Simplx_Mirage class.
$aggregateClass = $modx->getObject('modTemplate',$aggregateObject->get('template'));
$classTypeName = $aggregateClass->get('templatename');
unset($aggregateClass);
$aggregateClass = Simplx_Mirage::getClass($classTypeName);
if(!$aggregateClass){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->addAggregate(): Unable to get class "'.$aggregateObject->get('template').'" does not exist. Aborting.');
}
$classTypeName = $aggregateClass->_prototype->get('templatename');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Got a reference to the Composite Class "'.$classTypeName.'".');
if($this->_useFoldersForAssoc){
// Get the id of the Container Resource in which to place the new aggregate Resource.
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Folders are used to store Aggregate.');
$result = false;//array_key_exsits($classTypeName,$this->_assocIdMap);
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Does the Aggregate container id exist in the store? "'.$result.'".');
if($result){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): The id for the Aggregates folder was in the assocIdMap collection. It is "'.$parent.'".');
$parent = $this->_assocIdMap[$classTypeName];
}else{
// If the requested composite class name was not in the Id map we load and store it.
$result = $modx->getObject('modResource',array('parent'=>$this->_id,'pagetitle'=>$classTypeName));
if(!$result){
// $result was false which meens that the class name is not valid where found.
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->addComposite(): Unable to load Composites folder. Aborting.');
return false;
}
$containerId = $result->get('id');
$this->_assocIdMap[$classTypeName] = $containerId;
$parent = $containerId;
}
}else{
// Not using folders for associated object.
$parent = $this->_id;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Not using folders for associated object. id used is "'.$parent.'".');
}
if($aggregateClass){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->addAggregate(): Creating new Resource with Class/Template "'.$aggregateClass->_id.'".');
$aggregate = $modx->newObject('modSymLink');
$aggregate->set('pagetitle',$classTypeName);
$aggregate->set('parent',$parent);
$aggregate->set('template',$aggregateClass->_id);
$aggregate->set('content',$aggregateObject->get('id'));
$aggregate->set('published',true);
$aggregate->save();
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->addAggregate(): Unable to get the Aggregate Class object. Simplx_Mireage::getClass() returned false. Aborting.');
return false;
// Unable to create class. Aborting.
}
return $aggregate;
}else{
// Missing required params. Abort.
}
}
/**
*
*
* @param
* @return
*/
public function __get($name){
global $modx;
$result;
$tvName = '';
if(array_key_exists($name,$this->_properties)){
return $this->_properties[$name];
}
// If the property was not found, defer to the prototype.
if(isset($this->_prototype)){
$result = $this->_prototype->get($name);
if(isset($result)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__get("'.$name.'"): Found a get() property for "'.$name.'" has value "'.json_encode($result).'".');
// Cache the value locally
$this->_properties[$name] = $result;
return $result;
}else{
// Lets check and see if its a template variable we are looking for.
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__get("'.$name.'"): Found no matching get() method. Checking for a matching TV.');
// Add prefix if configured so
if($this->_prefixTvs){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__get("'.$name.'"): Prefixing TV using "'.$this->_tvPrefix.'".');
$tvName = ($this->_tvPrefix.$name);
}else{
$tvName = $name;
}
$result = $this->_prototype->getTVValue($tvName);
if(isset($result)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__get("'.$name.'"): Matching TV has value "'.$result.'".');
// Cache the value locally
$this->_properties[$name] = $result;
return $result;
}else{
// Sorry, this property does not exist in this context.
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__get("'.$name.'"): Found no matching TV returning null.');
return null;
}
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__get("'.$name.'"): Object prototype not set. Returning null.');
}
}
/**
*
*
* @param
* @return
*/
public function __set($name,$value){
global $modx;
$result;
// If the property was not found, defer to the prototype.
if(isset($this->_prototype)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__set("'.$name.'","'.$value.'")');
$result = $this->_prototype->get($name);
if(isset($result)){
// We got a valid prototype property, lets set the value.
$this->_properties[$name] = $value;
return $this->_prototype->set($name,$value);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__set("'.$name.'","'.$value.'"): Found no matching set() method. Checking for a matching TV.');
// Lets check and see if its a template variable we are looking for.
// Add prefix if configured so
if($this->_prefixTvs){
$tvName = ($this->_tvPrefix.$name);
}else{
$tvName = $name;
}
$result = $this->_prototype->getTVValue($tvName);
if(isset($result)){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object__set("'.$name.'","'.$value.'"): Saving value "'.$value.'" to TV "'.$name.'".');
// We got a valid prototype property, lets set the value.
$this->_properties[$name] = $value;
if($this->_persistOnAssign){
return $this->_prototype->setTVValue($tvName,$value);
}
}else{
// The property was not found in the prototype either. Return false.
return false;
}
}
}
}
/**
*
*
* @param
* @return
*/
public function __call($name,$params){
global $modx;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__call("'.$name.'","'.json_encode($value).'")');
// If the method was not found, defer to the prototype.
if(isset($this->_prototype)){
$reflectionClass = new ReflectionClass(get_class($this->_prototype));
return $reflectionClass->getMethod($name)->invokeArgs($params);
}
}
/**
*
*
* @param
* @return
*/
public static function __callStatic($name,$params){
global $modx;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->__callStatic("'.$name.'","'.json_encode($value).'")');
// If the method was not found, defer to the prototype.
if(isset($this->_prototype)){
$reflectionClass = new ReflectionClass(get_class($this->_prototype));
// I think this should work even on static methods...
return $reflectionClass->getMethod($name)->invokeArgs($params);
}
}
/**
*
*
* @param
* @return
*/
protected function getTVValues(){
global $modx;
$name = '';
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getTVValues()');
$tvs = $this->_prototype->getTemplateVars();
if(is_array($tvs)){
foreach($tvs as $tv){
$name = $tv->get('name');
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->getTVValues(): Adding "'.$tv->get('name').'" => "'.$tv->get('value').'" to _properties.');
// Strip prefix away if configured to use prefixes.
if($this->_prefixTvs){
$name = str_replace($this->_tvPrefix,'',$name);
}
$this->_properties[$name] = $tv->get('value');
}
$this->_tvsLoaded = true;
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->__construct(): Could not load TVs.');
return false;
}
return true;
}
/**
*
*
* @param
* @return
*/
protected function setTVValues($validateOnly=false){
global $modx;
$name = '';
$tvName = '';
$val;
$result;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->setTVValues()');
/*
We cant really rely on that the Class signature (its public properties etc) have not
changed since we last loaded them so we reload them.
This way we let the current existing TV's decided which Mirage properties that are relevant
at the moment of saving.
*/
$tvs = $this->_prototype->getTemplateVars();
if(is_array($tvs)){
foreach($tvs as $tv){
unset($val);
$tvName = $tv->get('name');
// Strip prefix away if configured to use prefixes.
if($this->_prefixTvs){
$name = str_replace($this->_tvPrefix,'',$tvName);
}else{
$name = $tvName;
}
// Check so that the property actually exists in the _properties array. Otherwise just skip it.
if(array_key_exists($name,$this->_properties)){
// Get the current value from Mirage.
$val = $this->_properties[$name];
// If the value is valid we save it back to the TV object.
if($val){
if(!$validateOnly){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->setTVValues(): Saving "'.$name.'" => "'.$val.'".');
$result = $this->_prototype->setTVValue($tvName,$val);
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->setTVValues(): modResource->setTVValue() returned false.');
return false;
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->setTVValues(): Saving TV "'.$tvName.'" => "'.$val.'" went well.');
}
}else{
// Do some type of type checking later.
}
}
}
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->setTVValues(): Could not load TVs.');
return false;
}
return true;
}
/**
*
*
* @param
* @return
*/
public function toArray($excludeDefault = false,$useClassNameWrap = false){
global $modx;
$defaultProperties;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray()');
if(!$this->_tvsLoaded){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray(): Calling getTVValues().');
if(!$this->getTVValues()){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray(): getTVValues() returned false. Aborting.');
return false;
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray(): tvsLoaded == true. _properties contains "'.json_encode($this->_properties).'"');
}
if($this->_excludeModResourceFields || $excludeDefault){
// Even if we exclude the modResource fields we still need the id for the object.
if(!array_key_exists('id',$this->_properties)){
$this->_properties['id'] = $this->_id;
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray(): Excluding modResource default Class properties.');
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray(): Including modResource default Class properties.');
$defaultProperties = $this->_prototype->toArray('');
if(is_array($defaultProperties)){
$this->_properties = array_merge($this->_properties,$defaultProperties);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toArray(): modResource->toArray() returned a non array object.');
}
$this->_properties[] = $this->_prototype->toArray('');
}
if($useClassNameWrap && $this->_classTypeName != ''){
return array($this->_classTypeName => $this->_properties);
}else{
return $this->_properties;
}
}
/**
*
*
* @param
* @return
*/
public function toJSON($excludeDefault = false,$useClassNameWrap = false){
global $modx;
$defaultProperties;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON()');
if(!$this->_tvsLoaded){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON(): Calling getTVValues().');
if(!$this->getTVValues()){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON(): getTVValues() returned false. Aborting.');
return false;
}
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON(): tvsLoaded == true. _properties contains "'.json_encode($this->_properties).'"');
}
if($this->_excludeModResourceFields || $excludeDefault){
// Even if we exclude the modResource fields we still need the id for the object.
if(!array_key_exists('id',$this->_properties)){
$this->_properties['id'] = $this->_id;
}
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON(): Excluding modResource default Class properties.');
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON(): Including modResource default Class properties.');
$defaultProperties = $this->_prototype->toArray('');
if(is_array($defaultProperties)){
$this->_properties = array_merge($this->_properties,$defaultProperties);
}else{
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->toJSON(): modResource->toArray() returned a non array object.');
}
}
if($useClassNameWrap && $this->_classTypeName != ''){
return json_encode(array($this->_classTypeName => $this->_properties));
}else{
return json_encode($this->_properties);
}
}
/**
*
*
* @param
* @return
*/
public function fromArray($arr,$persist = false){
global $modx;
$defaultProperties;
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->fromArray()');
if($this->_forceTypeCheck){
if(!array_key_exists($this->_classTypeName,$arr)){
/*
This serialized state array does not explicitly signal that it is in fact of
the correct heritage. This helps to implement a loose type of type safety.
*/
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->fromArray(): $_forceTypeCheck is set to true, and the object state array is missing a type name key. Unable to validate object type. Aborting.');
return false;
}else{
/* If we got a type name, its value is expected to be the property collection ({"Aircraft":{"registration_number":"1234"}}).
So, we re-assign the $arr variable to hold the properties.
*/
$arr = $arr[$this->_classTypeName];
if(!is_array($arr)){
// Hey! There were no properties here. Aborting.
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->fromArray(): $_forceTypeCheck is set to true however no property collection was found. Aborting.');
return false;
}
}
}
if($this->_excludeModResourceFields && $excludeDefault){
if(self::$_debugmode) $modx->log(modX::LOG_LEVEL_DEBUG, 'Simplx_Mirage_Object->fromArray(): Excluding modResource default modResource Class properties.');
$defaultProperties = $this->_prototype->toArray('');
// Got a valid properties array?
if(is_array($defaultProperties)){
/*
Loop through all modResource properties and set its values.
*/
foreach($arr as $prop => &$val){
/*
If the modResource property is stored in the $defaultProperties array we do NOT store it since $_excludeDefault is set to true.
*/
if(!array_key_exists($prop,$defaultProperties)){
$result = $this->__set($prop,$val);
// If we had problems storing the value.
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->fromArray(): Unable to set the modResource property "'.$prop.'".');
}
}
}
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->fromArray(): Unable to get the modResource properties. modResource->toArray() returned false.');
}
}else{
/*
Loop through all modResource properties and set its values.
*/
foreach($arr as $prop => &$val){
$result = $this->__set($prop,$val);
if(!$result){
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->fromArray(): Unable to set the property "'.$prop.'".');
}
}
}
if($this->_classTypeName == ''){
// Reset the array just to be sure.
reset($arr);
// And get first key which is presumed to be class name. This is not the best of solutions. will fix.
$this->_classTypeName = key($arr);
}
return true;
}
/**
*
*
* @param
* @return
*/
public function fromJSON($json){
}
/**
*
*
* @param
* @return
*/
public function renderAspect($aspect='input'){
global $modx;
$result = '';
$params = $this->toArray();
if(is_array($params)){
$result = $this->_class->renderAspect($aspect,$params);
}else{
$modx->log(modX::LOG_LEVEL_ERROR, 'Simplx_Mirage_Object->renderAspect(): Unable to get object state. $this->toArray() returned false.');
return false;
}
return $result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment