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($ilog(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 = ('
').($output.'
'); 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; } }