PageRenderTime 1031ms CodeModel.GetById 32ms RepoModel.GetById 2ms app.codeStats 1ms

/classes/core/StaticTools/dev/StaticTools_dev.php

https://bitbucket.org/xananax/yelobox
PHP | 1446 lines | 863 code | 124 blank | 459 comment | 221 complexity | ec932d5cc03df815fbf78110a804b88f MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. class StaticTools{
  3. /**
  4. * inherits the contents of self::$options recursively
  5. * @param string $class
  6. * @param int|string $recursionLimit either a className to stop looking after, or a number of classes. Pass 0 for no limit.
  7. * @param boolean $applyToParents if true, options will be recursively set on parents
  8. */
  9. public static function staticPropertiesInherit($class=null, $recursionLimit = 'DoDb',$applyToParents=true){
  10. if(!$class){$class = get_called_class();}
  11. if(!isset(self::$_inherited[$class])){
  12. $props = array();
  13. $ancestors = self::ancestors($class,$recursionLimit);
  14. if($ancestors){
  15. $ancestors = array_reverse($ancestors);
  16. while($ancestors){
  17. $className = array_shift($ancestors);
  18. $ancestorProps = self::getStaticProperties($className);
  19. $props = self::extendArray($props, $ancestorProps);
  20. if($applyToParents || !$ancestors){
  21. self::$options[$className] = $props;
  22. self::$_inherited[$className] = true;
  23. }
  24. }
  25. }
  26. }
  27. }
  28. /**
  29. * Returns an option from the $options array
  30. **/
  31. private static function &staticOptionGet($option,$className=null){
  32. if(!$class){$class = get_called_class();}
  33. if(!isset(self::$_inherited[$class])){self::staticPropertiesInherit($className);}
  34. if(is_array($option)){
  35. $ref = &self::$options[$className];
  36. while($option){
  37. $key = array_shift($option);
  38. if(array_key_exists($key,$ref) && is_array($ref[$key])){
  39. $ref = &$ref[$key];
  40. }else{
  41. return null;
  42. }
  43. }
  44. return $ref;
  45. }
  46. else if(isset(self::$options[$className][$option])){return self::$options[$className][$option];}
  47. $null = null;
  48. return $null;
  49. }
  50. private static function staticOptionSet($option,$value,$className=null){
  51. if(!$class){$class = get_called_class();}
  52. if(!isset(self::$_inherited[$class])){self::staticPropertiesInherit($className);}
  53. if(is_array($option)){
  54. $ref = &self::$options[$className];
  55. while($option){
  56. $key = array_shift($option);
  57. if(array_key_exists($key,$ref)){
  58. if(!is_array($ref[$key])){throw new Exception('Invalid path for staticOptionSet',E_USER_ERROR); return null;}
  59. }else{
  60. $ref[$key] = array();
  61. }
  62. $ref = &$ref[$key];
  63. }
  64. if($value===null){unset($ref);}else{$ref = $value;}
  65. }
  66. self::$options[$className][$option] = $value;
  67. }
  68. /**
  69. * Gets inherited static variables from parent classes and actually commits the inherited data to the classe's properties.
  70. * This is not useful as you'd be better off calling staticOptionGet()
  71. **/
  72. private static function staticPropertiesCommit($className=null){
  73. if(!$class){$class = get_called_class();}
  74. if(!isset(self::$_inherited[$className]) || !self::$_inherited[$className]){self::inheritOptions($className);}
  75. if(isset(self::$options[$className])){
  76. $options = self::$options[$className];
  77. foreach($options as $property=>$value){
  78. if(class_exists($className) && property_exists($className, $property)){
  79. eval($className.'::$'.$property.'=$value;');
  80. };
  81. }
  82. }
  83. }
  84. public static function staticPropertiesGet($class=null){
  85. if(!$class){$class = get_called_class();}
  86. if(!isset(self::$_properties[$class])){
  87. $classRef = new ReflectionClass($class);
  88. self::$_properties[$class] = $classRef->getStaticProperties();
  89. }
  90. return self::$_properties[$class];
  91. }
  92. // <editor-fold defaultstate="collapsed" desc="constants">
  93. const GETSET_ASSOC_APPEND = 1;
  94. const GETSET_ASSOC_REPLACE = 2;
  95. const GETSET_ASSOC_MERGE = 4;
  96. const GETSET_NUM_APPEND = 8;
  97. const GETSET_NUM_REPLACE = 16;
  98. const GETSET_NUM_MERGE = 32;
  99. const GETSET_STRING_CONVERT = 64;
  100. const GETSET_STRING_REPLACE = 128;
  101. const GETSET_CREATE_IF_NOT_EXISTS = 256;
  102. const GETSET_USE_OBJECT_METHODS = 512;
  103. const GETSET_USE_OBJECT_CALL = 1024;
  104. const GETSET_USE_WILDCARD = 2048;
  105. const GETSET_BYPASS_CHECK = 4096;
  106. const ERRORS_DO_REPORT = 8192;
  107. const CRLF = "\n\r";
  108. const TAB = "\t";
  109. // </editor-fold>
  110. // <editor-fold defaultstate="collapsed" desc="static vars">
  111. static private $_throwErrorsLimit = E_USER_ERROR;
  112. static private $_ancestors = array();
  113. static protected $_instances = null;
  114. static protected $_log = null;
  115. static protected $_language = 'en_US';
  116. static protected $_delimiter = '/';
  117. static protected $_doLog = true;
  118. static protected $_translations = array(
  119. 'en_US' => array(
  120. 'ERRORS' => array(
  121. )
  122. )
  123. );
  124. static $static = array();
  125. protected static $_hooks = array();
  126. // </editor-fold>
  127. // <editor-fold defaultstate="collapsed" desc="static methods">
  128. /*******************************************************************************
  129. * STATIC INITIALIZATION METHODS
  130. ******************************************************************************/
  131. // <editor-fold defaultstate="collapsed" desc="static init">
  132. /**
  133. * Initiates a static class, effectively calling a kind of a "constructor" on the class.
  134. * Stores initialized classes so this function is called only once per class
  135. * @param string|array $options the options to initialize the class
  136. * @param string $class the class name. Defaults to StaticTools
  137. * @param string $method a public static method of the class. if no method is defined, internal methods will be used
  138. * @param string|array $mergeStatics if set, static properties passed will be merged
  139. * @param string|int $recursionLimit used by staticPropertyMerged
  140. */
  141. public static function staticInit($options=null,$class=null,$method=null,$mergeStatics=null,$recursionLimit='StaticTools'){
  142. if(!$class){$class = get_called_class();}
  143. if(!isset(self::$static[$class]['init'])){
  144. if(!isset(self::$static[$class])){self::$static[$class] = array();}
  145. if($options){
  146. if($method){$class::$method($options);}
  147. else if(is_string($options)){self::_staticInitString($options,$class);}
  148. else if(is_array($options)){self::_staticInitArray($options,$class);}
  149. else if(is_object($options)){self::_staticInitObject($object, $class);}
  150. else{self::error('ERRORS>>MAIN>>unrecognized configuration type %%config%%',E_USER_ERROR,array('config'=>(string)$options));}
  151. }
  152. if($mergeStatics){
  153. self::staticPropertyMerge($class, $mergeStatics, $recursionLimit, false);
  154. }
  155. self::callHook('StaticToolsHook_staticInit', $class);
  156. $static[$class]['init'] = true;
  157. }else{self::error('ERRORS>>MAIN>>class %%class%% is already initialized',E_USER_NOTICE,array('class'=>$class));}
  158. }
  159. protected static function _staticInitString($option,$class){
  160. $found = self::callHook('StaticToolsHook_staticInitString', $options=array('options'=>$string,'class'=>$class));
  161. if(!$found){
  162. self::error(
  163. 'ERRORS>>MAIN>>a string constructor %%string%% was passed to %%class%%, but no suitable handler was found',
  164. E_USER_WARNING,
  165. array('class'=>$class,'string'=>$option)
  166. );
  167. }
  168. }
  169. protected static function _staticInitArray(array $options,$class){
  170. self::callHook('StaticToolsHook_staticInitArray', $options=array('options'=>$options,'class'=>$class));
  171. self::array_merge_recursive(self::$static[$class], $options);
  172. }
  173. protected static function _staticInitObject($object,$class){
  174. self::callHook('StaticToolsHook_staticInitArray', $options=array('options'=>$object,'class'=>$class));
  175. $object = (array)$object;
  176. self::array_merge_recursive(self::$static[$class], $object);
  177. }
  178. /**
  179. * Merges all static properties of a class with parent classes properties
  180. * @param string $class the base class
  181. * @param string|array $properties a property to merge, or several properties. The property has to be public
  182. * @param string|int $recursionLimit where to stop in finding ancestors
  183. * @param boolean $mergeAtParents if true, parent's properties will be merged with their own parents
  184. * @param boolean $refresh if true, will refresh parent classes
  185. */
  186. public static function staticPropertyMerge($class,$properties,$recursionLimit='StaticTools',$mergeAtParents=false,$refresh=false){
  187. $ancestors = self::ancestors($class, $recursionLimit, $refresh);
  188. if(!is_array($properties)){$properties = array($properties);}
  189. if(!$mergeAtParents){
  190. array_shift($ancestors);
  191. foreach($ancestors as $parentClass){
  192. foreach($properties as $property){
  193. if(isset($parentClass::$$property)){
  194. self::extendArray($class::$$property, $parentClass::$$property);
  195. }
  196. }
  197. }
  198. }else{
  199. while($ancestors){
  200. $parentClass = array_pop($ancestors);
  201. $class = array_pop($ancestors);
  202. if($parentClass && $class){
  203. foreach($properties as $property){
  204. if(isset($parentClass::$$property)){
  205. self::extendArray($class::$$property, $parentClass::$$property);
  206. }
  207. }
  208. }
  209. }
  210. }
  211. }
  212. // </editor-fold>
  213. /*******************************************************************************
  214. * STATIC CONSTRUCTORS METHODS
  215. ******************************************************************************/
  216. // <editor-fold defaultstate="collapsed" desc="static constructors">
  217. /**
  218. * Allows you to return an instance of the called class;
  219. * This is the same as using the "new" constructor, with two advantages:<br><ol>
  220. * <li>it allows you to chain methods directly</li>
  221. * <li>it allows you to return a particular instance of the object by passing an id, thus using
  222. * something close to a singleton pattern</li>
  223. * </ul>
  224. * @param mixed $options constructor options. If the was previously instanciated, this does nothing
  225. * @param string|int $id some string to remember the object by, or an integer. This is passed by reference, so you can pass
  226. * a null id and get the assigned id
  227. * @return StaticTools
  228. */
  229. public static function getClassInstance($options=null,&$id=null,$class=null){
  230. if(!$class){$class = get_called_class();}
  231. if(!isset(self::$_instances[$class])){self::$_instances[$class] = array();}
  232. if($id!==null){
  233. if(isset(self::$_instances[$class][$id])){return self::$_instances[$class][$id]['object'];}
  234. return false;
  235. }else{
  236. $id = count(self::$_instances[$class]);
  237. }
  238. $object = new $class($options);
  239. self::$_instances[$self][$id] = array('object'=>$object);
  240. self::callHook('StaticToolsHook_getClassInstance', $options=array('options'=>$options,'class'=>$class,'id'=>$id,'object'=>$object));
  241. return $object;
  242. }
  243. /**
  244. * Gets the number of instances of a particular class
  245. * @param string $class
  246. * @return int
  247. */
  248. public function classInstancesCount($class=null){
  249. if(!$class){$class = get_called_class();}
  250. if(isset(self::$_instances[$class])){return count(self::$_instances[$class]);}
  251. return 0;
  252. }
  253. /**
  254. * Wrapper for getObject() that uses '_singleton' as a key.
  255. * Allows you to use a cached singleton for your calls
  256. * @param mixed $options constructor options. If the was previously instanciated, this does nothing
  257. * @return StaticTools
  258. */
  259. public static function singleton($options=null){
  260. return self::getClassInstance('_singleton', $options);
  261. }
  262. /**
  263. * Removes an instance from the instances pool and returns that instance
  264. * @param int|string|object $idOrObj either the key of the object, or the object instance itself (slower)
  265. * @param string $class the class type. Defaults to the object's class if an object was passed, or StaticTools
  266. * @return boolean|object the unset object in an array, or false if the object was not found
  267. */
  268. public static function unsetClassInstance($idOrObj,$class=null){
  269. $isObj = is_object($idOrObj);
  270. if(!$class){
  271. if($isObj){$class = get_class($idOrObj);}
  272. else{$class=get_called_class();}
  273. }
  274. if(!isset(self::$_instances[$class])){return false;}
  275. if($isObj){$idOrObj = array_search($idOrObj, self::$_instances[$class]);}
  276. if($idOrObj!==null && $idOrObj!==false && isset(self::$_instances[$class][$idOrObj])){
  277. $obj = self::$_instance[$class][$idOrObj];
  278. unset(self::$_instances[$class][$idOrObj]);
  279. return $obj;
  280. }
  281. return false;
  282. }
  283. // </editor-fold>
  284. /*******************************************************************************
  285. * STATIC OPTIONS
  286. ******************************************************************************/
  287. // <editor-fold defaultstate="collapsed" desc="static global options">
  288. /**
  289. * Sets or retrieves the delimiter used in paths. Defaults to '/'
  290. * @param string $delimiter
  291. * @return string
  292. */
  293. public static function delimiter($delimiter=NULL){
  294. if(func_num_args()){self::$_delimiter = $delimiter;}
  295. return self::$_delimiter;
  296. }
  297. /**
  298. * By defaults, returns the class name.
  299. * @param string $name the name to pass
  300. * @param string $class default to this class
  301. */
  302. public static function systemName($class=null,$name=null){
  303. if(!$class){$class = get_called_class();}
  304. if($name){self::$static[$class]['strings']['systemName'] = $name;}
  305. if(!isset(self::$static[$class]['strings']['systemName'])){self::$static[$class]['strings']['systemName'] = $class;}
  306. return self::$static[$class]['strings']['systemName'];
  307. }
  308. /**
  309. * Sets or Returns the singular name of the class. Defaults to the class name
  310. * @param string $name
  311. * @return string
  312. */
  313. public function singularName($name=null){
  314. if(!$class){$class = get_called_class();}
  315. if($name){self::$static[$class]['strings']['singularName'] = $name;}
  316. if(!isset(self::$static[$class]['strings']['singularName'])){self::$static[$class]['strings']['singularName'] = self::systemName($class,null);}
  317. return self::$static[$class]['strings']['singularName'];
  318. }
  319. /**
  320. * Sets or Returns the singular name of the class. Defaults to the class name, pluralized
  321. * @param string $name
  322. * @return string
  323. */
  324. public function pluralName($name=null){
  325. if(!$class){$class = get_called_class();}
  326. if($name){self::$static[$class]['strings']['pluralName'] = $name;}
  327. if(!isset(self::$static[$class]['strings']['pluralName'])){self::$static[$class]['strings']['pluralName'] = self::systemName($class,null);}
  328. return self::$static[$class]['strings']['pluralName'];
  329. }
  330. /**
  331. * Returns ancestors classes
  332. * @param string $class the startic class name. Defaults to this class
  333. * @param string|int $recursionLimit either a className to stop looking after, or a number of classes
  334. * @param boolean $refresh will discard cached ancestors
  335. * @return array an array of ancestors
  336. */
  337. public static function ancestors($class=null,$recursionLimit='StaticTools',$refresh=false){
  338. if(!$class){$class = get_called_class();}
  339. if($refresh || !isset(self::$_ancestors[$class])){
  340. $ancestors = array($class);
  341. $r = ($recursionLimit && is_int($recursionLimit))? $recursionLimit : 0;
  342. $n = 0;
  343. while($class && (!$recursionLimit || $class!=$recursionLimit) && (!$r || $n<$r)){
  344. $class = get_parent_class($class);
  345. if(isset(self::$_ancestors[$class])){
  346. $ancestors = array_merge($ancestors,self::$_ancestors[$class]);
  347. $class=null;
  348. }else{$ancestors[] = $class;}
  349. }
  350. self::$_ancestors[$class] = $ancestors;
  351. }
  352. return self::$_ancestors[$class];
  353. }
  354. // </editor-fold>
  355. // <editor-fold defaultstate="collapsed" desc="static options">
  356. /**
  357. * sets a static option
  358. * @param string $class defaults to this class
  359. * @param array|string $path the keys chain to get to the value
  360. * @param string|int $recursionLimit either a className to stop looking after, or a number of classes
  361. */
  362. public static function setStaticOption($class, $path,$value){
  363. if(!$class){$class = get_called_class();}
  364. $path = self::makePath($path);
  365. if(!isset(self::$static[$class])){self::$static[$class] = array();}
  366. $opts = &self::$static[$class];
  367. while($path){
  368. $key = array_shift($path);
  369. if($path && !isset($opts[$key])){
  370. $opts[$key] = array();
  371. }
  372. $opts = &$opts[$key];
  373. }
  374. $opts = $value;
  375. }
  376. /**
  377. * Unsets a static option
  378. * @param string $class the class name
  379. * @param array $path
  380. * @return boolean true if the value was unset, false if it was not found
  381. */
  382. public static function unsetStaticOption($class, $path){
  383. if(!$class){$class = get_called_class();}
  384. if(!isset(self::$static[$class])){return null;}
  385. $path = self::makePath($path);
  386. $opts = &self::$static[$class];
  387. while($path){
  388. $key = array_shift($path);
  389. if($path && isset($opts[$key])){
  390. if($path){$opts = &$opts[$key];}
  391. else{unset($opts[$key]); return true;}
  392. }
  393. }
  394. return false;
  395. }
  396. /**
  397. * returns a static option. The option is returned by reference so you can modify it.<br>
  398. * If the option is not found, ancestors will be searched for it until the key is found.<br>
  399. * If you don't want the function to look for the value in parent classes, pass 0 to the recursion limit.
  400. * @param string $class defaults to this class
  401. * @param array|string $path the keys chain to get to the value
  402. * @param string|int $recursionLimit either a className to stop looking after, or a number of classes
  403. * @param boolean $throwExceptionIfNotFound if true and the value is not found, will throw a E_USER_NOTICE
  404. * @return mixed the option, or null
  405. */
  406. public static function &getStaticOption($class, $path,$recursionLimit='StaticTools',$throwExceptionIfNotFound=false){
  407. if(!$class){$class = get_called_class();}
  408. $ancestors = ($recursionLimit)? self::ancestors($class, $recursionLimit) : array($class);
  409. $path = self::makePath($path);
  410. foreach($ancestors as $class){
  411. if(isset(self::$static[$class])){
  412. $_path = $path;
  413. $opts = &self::$static[$class];
  414. $valid = true;
  415. while($valid && $_path){
  416. $key = array_shift($_path);
  417. if(isset($opts[$key])){$opts = &$opts[$key];}
  418. else{$valid = false;}
  419. }
  420. if($valid){return $opts;}
  421. }
  422. }
  423. $null=null;
  424. if($throwExceptionIfNotFound){
  425. self::error(
  426. 'ERRORS>>MAIN>>%%key%% was not found in %%class%%',
  427. E_USER_NOTICE,
  428. array('key'=>implode('/',$path),'class'=>$class)
  429. );
  430. }
  431. return $null;
  432. }
  433. // </editor-fold>
  434. /*******************************************************************************
  435. * STATIC STRING METHODS
  436. ******************************************************************************/
  437. // <editor-fold defaultstate="collapsed" desc="translation">
  438. static public function t($string,array $replacements=null,$lang=null){
  439. if(!$lang){$lang = self::lng();}
  440. $path = explode('>>',$string);
  441. $string = array_pop($path);
  442. if($lang && isset(self::$_language[$lang])){
  443. $ref = &self::$_language[$lang];
  444. if($path){
  445. $found = true;
  446. while($path){
  447. $key = array_shift($path);
  448. if(isset($ref[$key])){$ref = &$ref[$key];}
  449. else{$found=false;break;}
  450. }
  451. }
  452. if($found){$string = $ref;}
  453. }
  454. if($replacements){
  455. $string = self::string_replace($string,$replacements);
  456. }
  457. return $string;
  458. }
  459. public static function ln($lang=null){
  460. if($lang){self::$_language = $lang;}
  461. return $lang;
  462. }
  463. public static function string_replace($string,$replacements){
  464. $keys = array_keys($replacements);
  465. foreach($keys as &$k){$k = '%%'.$k.'%%';}
  466. $string = str_replace($key, $replacements, $string);
  467. return $string;
  468. }
  469. // </editor-fold>
  470. /*******************************************************************************
  471. * STATIC ERROR REPORTING METHODS
  472. ******************************************************************************/
  473. // <editor-fold defaultstate="collapsed" desc="error reporting and debugging">
  474. /**
  475. * Logs a message in an array. This does not get printed anywhere
  476. * @param string $message
  477. * @param array $replacements
  478. * @param mixed $code this determines the importance of the message. The lower the more important
  479. * @return string the rendered message
  480. */
  481. static public function log($message=null,array $replacements=null,$code=null,$class=null){
  482. if(!$class){$class = get_called_class();}
  483. if($message){
  484. if(!isset(self::$_log[$class])){self::$_log[$class] = array();}
  485. $message = self::t($message, $replacements);
  486. self::$_log[$class][] = array(
  487. 'code' => $code,
  488. 'message' => $message
  489. );
  490. return $message;
  491. }
  492. }
  493. static public function log_get($class=null){
  494. if($class){return (isset(self::$_log[$class]))? self::$_log[$class]:false;}
  495. return self::$_log;
  496. }
  497. /**
  498. * Prints the debug messages in an organized list
  499. * @param string $class the class name
  500. * @param boolean $doPrint if false, will return the array without printing it. defaults to true
  501. * @param int $code anything lower than $code will be printed. If $code=null, everything will be printed
  502. * @return string the rendered log
  503. */
  504. static public function log_print($class=null,$doPrint=true,$code=null){
  505. $log = self::log_get($class);
  506. $r = '';
  507. if($log){
  508. $r.='<div class="DoLog log"><h3>'.$class.' log</h3><ul>'.self::CRLF;
  509. foreach($log as $l){
  510. if($code===null || $code>=$l['code']){
  511. $r.=self::TAB.'<li>'.$l['message'].'</li>'.self::CRLF;
  512. }
  513. }
  514. $r.='</ul></div>'.self::CRLF;
  515. }
  516. if($doPrint){echo $r;}
  517. return $r;
  518. }
  519. /**
  520. * Gets or sets the limit after which errors will throw exceptions. Defaults to E_USER_ERROR (1024)
  521. * @param int $n
  522. * @return int
  523. */
  524. static public function throwErrorsFrom($n=null){
  525. if($n!==null){self::$_throwErrorsLimit = $n;}
  526. return self::$_throwErrorsLimit;
  527. }
  528. /**
  529. * Logs an error and/or outputs it
  530. * @param string $message you can pass a translatable message, such as key>>secondKey>>message
  531. * @param int $error_type error type constant (defaults to E_USER_NOTICE)
  532. * @param array $replacements
  533. * @return string the rendered message
  534. */
  535. static public function error($message=NULL, $error_type=E_USER_NOTICE, array $replacements=NULL,$class=null){
  536. $t = debug_backtrace();
  537. array_shift($t);
  538. $trigger = array_shift($t);
  539. $start = array_pop($t);
  540. if(!$class){$class = get_called_class();}
  541. $system_message = $self::log('ERRORS>>MAIN>>Error %%errorType%%: Occurred in %%fileTriggered%% on line %%lineTriggered%% in function %%functionTriggered%% and started in %%fileStarted%% on %%lineStarted%% in function %%functionStarted%%, with message:%%message%%', array(
  542. 'fileTriggered' => $trigger['file'],
  543. 'lineTriggered' => $trigger['line'],
  544. 'functionTriggered' => $trigger['function'],
  545. 'fileStarted' => $start['file'],
  546. 'lineStarted' => $start['file'],
  547. 'functionStarted' => $start['function'],
  548. 'message' => self::t($message,$replacements),
  549. 'errorType' => $error_type
  550. ),
  551. $error_type,
  552. $class
  553. );
  554. if($error_type<=self::throwErrorsFrom()){$self::handleError($system_message,$error_type);}
  555. return $system_message;
  556. }
  557. /**
  558. * Throws an exception. Override in children
  559. * @param <type> $message
  560. * @param <type> $error_type
  561. */
  562. static public function handleError($message,$error_type){
  563. $found = self::callHook('StaticToolsHook_handleError', $options=array('message'=>$message,'code'=>$error_type));
  564. if(!$found){
  565. throw new Exception($message, $error_type);
  566. }
  567. }
  568. // </editor-fold>
  569. /*******************************************************************************
  570. * HOOKS AND EVENT LISTENERS
  571. ******************************************************************************/
  572. // <editor-fold defaultstate="collapsed" desc="hooks & events listeners">
  573. /**
  574. * Sets a hook
  575. * @param string $hookName
  576. * @param array | string $hookFunction
  577. */
  578. public static function hook($hookName,$hookFunction){
  579. if(!isset(self::$_hooks[$hookName])){self::$_hooks[$hookName] = array($hookFunction);}
  580. else{self::$_hooks[$hookName][] = $hookFunction;}
  581. }
  582. /**
  583. * Calls hooks
  584. * @param string $hook
  585. * @param mixed &$params parameters to pass
  586. * @return boolean true if the hook was found
  587. */
  588. public static function callHook($hook,&$params=null){
  589. if(isset(self::$_hooks[$hookName])){
  590. $hooks = self::$_hooks[$hookName];
  591. foreach($hooks as $function){
  592. $f = self::analyzeCallBack($function);
  593. $method = $f['method'];
  594. $obj = $f['obj'];
  595. switch($f['type']){
  596. case 'class':
  597. $obj::$method($params,$function['parameters']);
  598. break;
  599. case 'object':
  600. $obj->$method($params,$function['parameters']);
  601. break;
  602. case 'function':
  603. $method($params);
  604. break;
  605. default:
  606. self::error('ERRORS>>MAIN>>hook %%hook%% is invalid', E_USER_ERROR, array('hook'=>(string)$function));
  607. break;
  608. }
  609. }
  610. return true;
  611. }
  612. return false;
  613. }
  614. /**
  615. * Analyzes a callback object. Returns a string with keys: type,obj,method,parameters<br>
  616. * type can be 'class', 'object', 'function', for which you respectively call the function as
  617. * $obj::$method(), $obj->$method(), $method().<br>
  618. * the 'parameters' array holds whatever is left from the provided callback
  619. * @param string|array $callBack
  620. * @return array
  621. */
  622. public static function analyzeCallBack($callBack){
  623. $r = array(
  624. 'type' => null,
  625. 'obj' => null,
  626. 'method' => null,
  627. 'parameters'=> null
  628. );
  629. if(is_array($callBack)){
  630. $r['obj'] = array_shift($function);
  631. $r['method'] = array_shift($function);
  632. $r['type'] = is_string($obj) ? 'class':'object';
  633. $r['parameters'] = $callBack;
  634. }
  635. else if(is_string($callBack)){
  636. $r['type'] = 'function';
  637. $r['method'] = $callBack;
  638. }
  639. return $r;
  640. }
  641. // </editor-fold>
  642. // <editor-fold defaultstate="collapsed" desc="static plugins management">
  643. /**
  644. *
  645. * @param string $baseClass the class that calls the plugin
  646. * @param string $pluginClass the plugin name
  647. * @param mixed $options options to pass to the constructor
  648. * @param boolean $throwErrorIfAlreadyRegistered if true and the plugin has already been registered, will throw an error
  649. */
  650. public static function pluginRegisterForClass($baseClass,$pluginClass,$options=null,$throwErrorIfAlreadyRegistered=true){
  651. if(!isset(self::$static[$baseClass]['plugins'][$pluginClass])){
  652. self::$static[$baseClass]['plugins'][$pluginClass] = $options;
  653. }
  654. else if($throwErrorIfAlreadyRegistered){
  655. self::error('ERRORS>>PLUGINS>>Plugin %%plugin%% already registered', E_USER_WARNING, array('plugin'=>$pluginClass));
  656. }
  657. }
  658. /**
  659. *
  660. * @param string $baseClass the class that calls the plugin
  661. * @param string $pluginClass the plugin name
  662. * @param boolean $throwErrorIfNotExists if true and the plugin was not registered, will throw an error
  663. */
  664. public static function pluginUnregisterForClass($baseClass,$pluginClass,$throwErrorIfNotExists=false){
  665. if(isset(self::$static[$baseClass]['plugins'][$pluginClass])){unset(self::$static[$baseClass]['plugins'][$pluginClass]);}
  666. else if($throwErrorIfNotExists){
  667. self::error('ERRORS>>PLUGINS>>Plugin %%plugin%% was never registered', E_USER_NOTICE, array('plugin'=>$pluginClass));
  668. }
  669. }
  670. /**
  671. * Returns true if the plugin is registered to the class. It does not tell if the plugin has been initialized
  672. * for a particular object! For this, use pluginIsInitializedForObject()
  673. * @param string $baseClass
  674. * @param string $pluginClass
  675. * @return boolean
  676. */
  677. public static function pluginIsRegisteredForClass($baseClass,$pluginClass){
  678. return isset(self::$static[$baseClass]['plugins'][$pluginClass]);
  679. }
  680. /**
  681. * Returns all plugins registered for a class. This does not tell if the plugins of an object
  682. * have been initialized or not! For this, use pluginsGetAll()
  683. * @param string $baseClass
  684. * @return array
  685. */
  686. public static function pluginsNamesForClass($baseClass){
  687. if(isset(self::$static[$baseClass]['plugins'])){return self::$static[$baseClass]['plugins'];}
  688. return null;
  689. }
  690. /**
  691. * Returns the options set for a plugin
  692. * @param string $baseClass the class that calls the plugin
  693. * @param string $pluginClass the plugin name
  694. * @return mixed
  695. */
  696. public static function pluginOptionsForClass($baseClass,$pluginClass){
  697. if(isset(self::$static[$baseClass]['plugins'][$pluginClass])){return self::$static[$baseClass]['plugins'][$pluginClass];}
  698. return null;
  699. }
  700. /**
  701. * Initializes all registered plugins for a particular object
  702. * @param string $baseClass the class that calls the plugin
  703. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  704. * @param array $initializedPlugins an array passed by reference that will be populated with the initialized plugins
  705. * @param boolean $throwErrorIfAlreadyRegistered if true and the plugin is already registered, will throw an error
  706. * @return array the initialized plugins
  707. */
  708. public static function pluginsInitializeAllForObject($baseClass,$uniqueId,&$initializedPlugins = array(),$throwErrorIfAlreadyRegistered=true){
  709. $plugins = self::pluginsNamesForClass($baseClass);
  710. if($plugins){
  711. foreach($plugins as $pluginClass=>$options){
  712. $initializedPlugins[$pluginClass] = self::pluginInitializeForObject($baseClass, $uniqueId, $pluginClass, $options, $throwErrorIfAlreadyRegistered);
  713. }
  714. }
  715. return $initializedPlugins;
  716. }
  717. /**
  718. * Creates an instance of a plugin to be used with a particular ID. If the plugin was not previously registered
  719. * with pluginRegister, an notice will be thrown
  720. * @param string $baseClass the class that calls the plugin
  721. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  722. * @param string $pluginClass the plugin name
  723. * @param mixed $options options to pass to the constructor. Defaults to the options passed to pluginRegister()
  724. * @param boolean $throwErrorIfAlreadyInit if the plugin is already initialized and this is true, an error will be thrown
  725. * @return <type>
  726. */
  727. public static function pluginInitializeForObject($baseClass,$uniqueId,$pluginClass,$options=null,$throwErrorIfAlreadyInit=true){
  728. if(!isset(self::$_instances[$baseClass][$uniqueId]['plugins'])){self::$_instances[$baseClass][$uniqueId]['plugins']=array();}
  729. if(!isset(self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass])){
  730. if(!self::pluginIsRegisteredForClass($baseClass, $pluginClass)){
  731. self::error(
  732. 'ERRORS>>PLUGINS>>plugin %%plugin%% is not registered for class %%class%%',
  733. E_USER_NOTICE,
  734. array('plugin'=>$pluginClass,'class'=>$baseClass),
  735. $baseClass
  736. );
  737. }
  738. if(!$options){$options = self::pluginOptionsForClass($baseClass, $pluginClass);}
  739. self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass] = new $pluginClass($options);
  740. }else if($throwErrorIfAlreadyInit){
  741. self::error(
  742. 'ERRORS>>PLUGINS>>plugin %%plugin%% is already registered for class %%class%%',
  743. E_USER_ERROR,
  744. array('plugin'=>$pluginClass,'class'=>$baseClass),
  745. $baseClass
  746. );
  747. }
  748. return self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass];
  749. }
  750. /**
  751. * checks if the plugin has been initialized for the object
  752. * @param string $baseClass the class that calls the plugin
  753. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  754. * @param string $pluginClass the plugin name
  755. * @return boolean
  756. */
  757. public static function pluginIsInitializedForObject($baseClass,$uniqueId,$pluginClass){
  758. return isset(self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass]);
  759. }
  760. /**
  761. * Returns a particular plugin. The plugin has to be initialized prior
  762. * @param string $baseClass the class that calls the plugin
  763. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  764. * @param string $pluginClass the plugin name
  765. * @param boolean $throwErrorIfNotExists if the plugin is not initialized, and this is true, then an error will be thrown
  766. * @return object the plugin, or false if the plugin was not found
  767. */
  768. public static function pluginGet($baseClass,$uniqueId,$pluginClass,$throwErrorIfNotExists=true){
  769. if(!self::pluginIsInitializedForObject($baseClass, $uniqueId, $pluginClass)){
  770. if($throwErrorIfNotExists){
  771. self::error(
  772. 'ERRORS>>PLUGINS>>plugin %%plugin%% does not exist for class %%class%% with id %%id%%',
  773. E_USER_ERROR,
  774. array('plugin'=>$pluginClass,'class'=>$baseClass,'id'=>$uniqueId),
  775. $baseClass
  776. );
  777. }
  778. return false;
  779. }
  780. return self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass];
  781. }
  782. /**
  783. * Returns all initialized plugins objects
  784. * @param string $baseClass the class that calls the plugin
  785. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  786. * @return array an array of plugins objects
  787. */
  788. public static function pluginsGetAll($baseClass,$uniqueId){
  789. return isset(self::$_instances[$baseClass][$uniqueId]['plugins'])?self::$_instances[$baseClass][$uniqueId]['plugins']:null;
  790. }
  791. /**
  792. * Checks if the plugin has the provided method
  793. * @param string $baseClass the class that calls the plugin
  794. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  795. * @param string $pluginClass the plugin name
  796. * @param string $method_name the method name
  797. * @param boolean $throwErrorIfNotExists if the plugin is not initialized, and this is true, then an error will be thrown
  798. * @return boolean
  799. */
  800. public static function pluginHasMethod($baseClass,$uniqueId,$pluginClass,$method_name,$throwErrorIfNotExists=true){
  801. if(!self::pluginIsInitializedForObject($baseClass, $uniqueId, $pluginClass)){
  802. if($throwErrorIfNotExists){
  803. self::error(
  804. 'ERRORS>>PLUGINS>>plugin %%plugin%% does not exist for class %%class%% with id %%id%%',
  805. E_USER_ERROR,
  806. array('plugin'=>$pluginClass,'class'=>$baseClass,'id'=>$uniqueId),
  807. $baseClass
  808. );
  809. }
  810. return false;
  811. }
  812. return method_exists(self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass], $method_name);
  813. }
  814. /**
  815. * Runs a method on the plugin
  816. * @param string $baseClass the class that calls the plugin
  817. * @param string|int $uniqueId the unique identifier of the object calling the plugin
  818. * @param string $pluginClass the plugin name
  819. * @param string $method_name the method name
  820. * @param object $obj the object calling the method
  821. * @param mixed $args arguments for the method
  822. * @param boolean $throwErrorIfNotExists
  823. * @return mixed the result of the function
  824. */
  825. public static function pluginRunMethod($baseClass,$uniqueId,$pluginClass,$method_name,$obj,&$args=null,$throwErrorIfNotExists=true){
  826. if(self::pluginHasMethod($baseClass, $uniqueId, $pluginClass, $method_name, $throwErrorIfNotExists)){
  827. $return = null;
  828. self::$_instances[$baseClass][$uniqueId]['plugins'][$pluginClass]->$method_name($args,$obj,$return);
  829. return $return;
  830. }
  831. return null;
  832. }
  833. /**
  834. * Either cycles through all plugins, calling $method on each of them, or returns the value of the first method found
  835. * @param string $baseClass the base class
  836. * @param int|string uniqueID the identifier of the object. You can use the same identifier for multiple objects, if it not
  837. * important to create a new instance of the plugins for each object
  838. * @param string $method the name of the method the method will receive two arguments: $args, and $this (the current object)
  839. * @param object $obj the object running the plugins
  840. * @param mixed $args arguments to be passed to the method
  841. * @param boolean $stopOnSuccess if true, will stop when it finds the method on any plugin
  842. * @return mixed the result of the first plugin to have the method if $stopOnSuccess, or nothing
  843. */
  844. public static function pluginRunAll($baseClass,$uniqueId,$method,$obj,&$args=null,$stopOnSuccess=false){
  845. $plugins = self::pluginsGetAll($baseClass, $uniqueId);
  846. $return = null;
  847. if($plugins){
  848. foreach($plugins as $plugin){
  849. if(method_exists($plugin, $method)){
  850. $plugin->$method($args,$obj,$return);
  851. if($stopOnSuccess){return $return;}
  852. }
  853. }
  854. }
  855. }
  856. /**
  857. * This method will attempt to run the method on the calling object first, then will cycle through all plugins
  858. * until it finds the method. The results of the method are then cached so any subsequent calls to this method
  859. * return the same result.
  860. * @param string $baseClass the base class
  861. * @param int|string uniqueID the identifier of the object. You can use the same identifier for multiple objects, if it not
  862. * important to create a new instance of the plugins for each object
  863. * @param string $method the name of the method the method will receive two arguments: $args, and $this (the current object)
  864. * @param object $obj the object running the plugins
  865. * @param mixed $args arguments to be passed to the method
  866. * @param boolean $stopOnSuccess if true, will stop when it finds the method on any plugin
  867. * @param boolean $refresh if true, discards the previous result and refreshes the cache
  868. * @return mixed
  869. */
  870. public static function pluginRunMethodCached($baseClass,$uniqueId,$method_name,$obj,&$args=null,$stopOnSuccess=false,$refresh=false){
  871. if($refresh || !isset(self::$_instances[$baseClass][$uniqueId]['cache'][$method_name])){
  872. if(method_exists($obj, $method_name)){
  873. $result = $obj->$method_name($args);
  874. }else{
  875. $result = false;
  876. $plugins = self::pluginsGetAll($baseClass, $uniqueId);
  877. if($plugins){
  878. foreach($plugins as $plugin){
  879. if(method_exists($plugin, $method)){
  880. $plugin->$method($args,$obj,$result);
  881. if($stopOnSuccess){break;}
  882. }
  883. }
  884. }
  885. }
  886. self::$_instances[$baseClass][$uniqueId]['cache'][$method_name] = $result;
  887. }
  888. return self::$_instances[$baseClass][$uniqueId]['cache'][$method_name];
  889. }
  890. /**
  891. * Checks if the class has that method, taking into account all registered plugins
  892. * @param string $baseClass the base class
  893. * @param int|string uniqueID the identifier of the object. You can use the same identifier for multiple objects, if it not
  894. * important to create a new instance of the plugins for each object
  895. * @param string $method the name of the method the method will receive two arguments: $args, and $this (the current object)
  896. * @param object $obj the object with plugins
  897. * @return boolean|string if the method is found on the object, true will be returned; if the method is found on a plugin, the
  898. * plugin name is returned. If the method is not found at all, false is returned
  899. */
  900. public static function classHasMethod($baseClass,$uniqueId,$method_name,$obj){
  901. if(method_exists($obj, $method_name)){return true;}
  902. $plugins = self::pluginsGetAll($baseClass, $uniqueId);
  903. if($plugins){
  904. foreach($plugins as $plugin){
  905. if(method_exists($plugin, $method)){
  906. return $plugin;
  907. }
  908. }
  909. }
  910. return false;
  911. }
  912. // </editor-fold>
  913. /*******************************************************************************
  914. * PATH MANAGEMENT FOR ARRAYS
  915. ******************************************************************************/
  916. // <editor-fold defaultstate="collapsed" desc="path management">
  917. /**
  918. * Explodes a string path into chunks, according to delimiter()
  919. * @param array|string $path
  920. * @param array $prepent prepends values to the path
  921. * @param string $delimiter leave this empty to use the default delimiter
  922. * @return array
  923. */
  924. static public function makePath(&$path,array $prepend=NULL,$delimiter=null){
  925. if(!is_array($path) && $path){$path = explode(($delimiter? $delimier : self::$_delimiter), $path);}
  926. if($prepend){$path = ($path) ? array_merge($prepend,$path):$prepend;}
  927. return $path;
  928. }
  929. // </editor-fold>
  930. /*******************************************************************************
  931. * ARRAY FUNCTIONS
  932. ******************************************************************************/
  933. // <editor-fold defaultstate="collapsed" desc="array management">
  934. /**
  935. * Gets a value by a certain path.
  936. * @param string $path
  937. * @param array $array
  938. * @param binary $flags<br/> Available flags:<pre>
  939. * StaticTools::GETSET_ASSOC_APPEND If an associative array is found, the new value will be appended: ('a'=>1) becomes ('a'=>array(1,2))
  940. * StaticTools::GETSET_ASSOC_REPLACE If an associative array is found, the new value will replace itL ('a'=>1) becomes ('a'=>2)
  941. * StaticTools::GETSET_ASSOC_MERGE If an associating array is found, both values will be merged. This will mostly yield to the same results
  942. * as GETSET_ASSOC_APPEND, but can differ. Uses array_merge_recursive().
  943. * StaticTools::GETSET_NUM_APPEND If a numeric array is found, the new value will be appended: (0=>'a') becomes (0=>'a',1=>'b')
  944. * StaticTools::GETSET_NUM_REPLACE If an associative array is found, the new value will replace itL (1=>'a') becomes (1=>'b')
  945. * StaticTools::GETSET_NUM_MERGE If an associating array is found, both values will be merged: (0=>'a') becomes (0=>array('a', 'b')).
  946. * StaticTools::GETSET_STRING_CONVERT
  947. * StaticTools::GETSET_STRING_REPLACE
  948. * StaticTools::GETSET_CREATE_IF_NOT_EXISTS
  949. * StaticTools::GETSET_USE_OBJECT_METHODS
  950. * StaticTools::GETSET_USE_OBJECT_CALL
  951. * StaticTools::GETSET_USE_WILDCARD
  952. * StaticTools::GETSET_BYPASS_CHECK
  953. * StaticTools::ERRORS_DO_REPORT
  954. * </pre>
  955. * @param string $wildcard defaults to '*'
  956. * @return array | mixed the array retrieved
  957. */
  958. static public function &getByPath(array $path, array &$array, $flags=NULL, $wildcard = '*'){
  959. if(!$flags){$flags = StaticTools::GETSET_USE_WILDCARD;}
  960. $return = NULL;
  961. $doUseWildcard = $flags & StaticTools::GETSET_USE_WILDCARD;
  962. if(!$path){return $array;}
  963. $r = &$array;
  964. while($path){
  965. $p = array_shift($path);
  966. if($doUseWildcard && $p===$wildcard){
  967. if(is_array($r)){
  968. $return = array();
  969. foreach($r as $k=>$v){
  970. $return[$k] = & static::getByPath($path, $r[$k], $flags, $wildcard);
  971. }
  972. return $return;
  973. }
  974. }
  975. if(isset($r[$p]) && is_array($r)){
  976. $r = &$r[$p];
  977. }
  978. else{
  979. $doReportErrors = $flags & StaticTools::ERRORS_DO_REPORT;
  980. if($doReportErrors){self::error('ERRORS>>MAIN>>key %%key%% was not found', E_USER_NOTICE, array('key'=>$p));}
  981. return $return;
  982. }
  983. }
  984. return $r;
  985. }
  986. static public function unsetByPath(array $path, array &$array, $flags=NULL, $wildcard = '*'){
  987. if(!$flags){$flags = StaticTools::GETSET_USE_WILDCARD;}
  988. $return = NULL;
  989. $doUseWildcard = $flags & StaticTools::GETSET_USE_WILDCARD;
  990. if(!$path){return $array;}
  991. $r = &$array;
  992. while($path){
  993. $p = array_shift($path);
  994. if($doUseWildcard && $p===$wildcard){
  995. if(is_array($r)){
  996. $return = array();
  997. foreach($r as $k=>$v){
  998. $return[$k] = static::unsetByPath($path, $r[$k], $flags, $wildcard);
  999. }
  1000. return $return;
  1001. }
  1002. }
  1003. if(isset($r[$p])){
  1004. if(!$path){
  1005. $return = $r[$p];
  1006. unset($r[$p]);
  1007. if(count($r)==0){$r = NULL;}
  1008. return $return;
  1009. }
  1010. $r = &$r[$p];
  1011. }
  1012. else{
  1013. $doReportErrors = $flags & StaticTools::ERRORS_DO_REPORT;
  1014. if($doReportErrors){
  1015. self::error('ERRORS>>MAIN>>key %%key%% was not found', E_USER_NOTICE, array('key'=>$p));
  1016. }
  1017. return $return;
  1018. }
  1019. }
  1020. }
  1021. static public function _setByPath(array $path, &$array, $value, $flags=NULL, $object=NULL){
  1022. if($flags===NULL){
  1023. $flags = StaticTools::ERRORS_DO_REPORT |
  1024. StaticTools::GETSET_STRING_REPLACE |
  1025. StaticTools::GETSET_STRING_CONVERT |
  1026. StaticTools::GETSET_ASSOC_MERGE |
  1027. StaticTools::GETSET_NUM_APPEND |
  1028. StaticTools::GETSET_CREATE_IF_NOT_EXISTS;
  1029. }
  1030. $doReportErrors = $flags & StaticTools::ERRORS_DO_REPORT;
  1031. $r = &$array;
  1032. while($path){
  1033. $p = array_shift($path);
  1034. if($path){
  1035. if(!isset($r[$p])){
  1036. $doCreateIfNotExists = $flags & StaticTools::GETSET_CREATE_IF_NOT_EXISTS;
  1037. if($doCreateIfNotExists){
  1038. $r[$p] = array();
  1039. $r = &$r[$p];
  1040. }else if($doReportErrors){
  1041. self::error('ERRORS>>MAIN>>index %%key%% was not set in array', E_USER_NOTICE, array('key'=>$p));
  1042. }else{return NULL;}
  1043. }
  1044. else if(is_string($r[$p])){
  1045. $doConvertString = $flags & StaticTools::GETSET_STRING_CONVERT;
  1046. if($doConvertString){
  1047. $str = $r[$p];
  1048. $r = array($p=>array(), $str);
  1049. $r = &$r[$p];
  1050. }else if($doReportErrors){
  1051. self::error('ERRORS>>MAIN>>index %%key%% cannot be set on string %%string%%', E_USER_NOTICE, array('key'=>$p,'string'=>$r));
  1052. }else{return NULL;}
  1053. }
  1054. else if(is_array($r[$p])){
  1055. $r = &$r[$p];
  1056. }
  1057. else if($doReportErrors){
  1058. self::error('ERRORS>>MAIN>>object %%key%% could not be set', E_USER_NOTICE, array('key'=>(string)$p));
  1059. }
  1060. }else if(isset($r[$p]) && is_array($r[$p])){
  1061. if(is_numeric($p)){
  1062. $doNumericAppend = $flags & StaticTools::GETSET_NUM_APPEND;
  1063. $doNumericReplace = $flags & StaticTools::GETSET_NUM_REPLACE;
  1064. $doNumericMerge = $flags & StaticTools::GETSET_NUM_MERGE;
  1065. if($doNumericAppend){
  1066. if($r[$p]){$r[] = $value;}
  1067. else{$r[$p] = $value;}
  1068. }else if($doNumericReplace){
  1069. $r[$p] = $value;
  1070. }else if($doNumericMerge){
  1071. array_merge_recursive((array)$r[$p], (array)$value);
  1072. }else if($doReportErrors){
  1073. self::error('ERRORS>>MAIN>>value %%value%% could not be set', E_USER_NOTICE, array('value'=>$value));
  1074. }else{
  1075. return $object;
  1076. }
  1077. }else{
  1078. $doAssocAppend = $flags & StaticTools::GETSET_ASSOC_APPEND;
  1079. $doAssocReplace = $flags & StaticTools::GETSET_ASSOC_REPLACE;
  1080. $doAssocMerge = $flags & StaticTools::GETSET_ASSOC_MERGE;
  1081. if($doAssocReplace){
  1082. $r[$p] = $value;
  1083. }else if($doAssocAppend){
  1084. if($r[$p]){
  1085. $oldVal = $r[$p];
  1086. $r[$p] = array($oldVal, $value);
  1087. }else{
  1088. $r[$p] = (array)$value;
  1089. }
  1090. }else if($doAssocMerge){
  1091. $r[$p] = array_merge_recursive((array)$r[$p],(array)$value);
  1092. }else if($doReportErrors){
  1093. self::error('ERRORS>>MAIN>>value %%value%% could not be set', E_USER_NOTICE, array('value'=>$value));
  1094. }
  1095. }
  1096. }else{
  1097. $doReplaceString = $flags & StaticTools::GETSET_STRING_REPLACE;
  1098. if(isset($r[$p])){
  1099. if($doReplaceString){$r[$p] = &$value;}
  1100. else{
  1101. if($doReportErrors){
  1102. self::error('ERRORS>>MAIN>>value %%value%% could not be replaced', E_USER_NOTICE, array('value'=>$value));
  1103. }
  1104. }
  1105. }
  1106. else{
  1107. $r[$p] = &$value;
  1108. }
  1109. }
  1110. }
  1111. return $object;
  1112. }
  1113. /**
  1114. * Merges two or more arrays
  1115. * @param array $data the array to extend
  1116. * @param array $extend the data to merge with
  1117. * @param array $extend... pass as many arrays as you want
  1118. * @return array
  1119. */
  1120. public static function extendArray($data,$extend){
  1121. $arrays = func_get_args();
  1122. $c = count($arrays);
  1123. if($c<2){
  1124. self::error('extendArray uses two or more arguments, only %%n%% arguments passed', E_USER_ERROR, array('n'=>$c));
  1125. return null;
  1126. }
  1127. $data = array_shift($arrays);
  1128. while($arrays){
  1129. $extend = array_shift($arrays);
  1130. if(is_array($data) && is_array($extend)){
  1131. foreach($extend as $k=>$v){
  1132. if(!isset($data[$k])){$data[$k] = $extend[$k];}
  1133. else{
  1134. if(is_numeric($k)){$data[] = $v;}
  1135. else{$data[$k] = self::extendArray($data[$k],$extend[$k]);}
  1136. }
  1137. }
  1138. }else if(is_array($data)){
  1139. $data[] = $extend;
  1140. }else if(is_array($extend)){
  1141. array_unshift($extend, $data);
  1142. $data = $extend;
  1143. }else{
  1144. $data = $extend;
  1145. }
  1146. }
  1147. return $data;
  1148. }
  1149. // </editor-fold>
  1150. /*******************************************************************************
  1151. * FEEDING FUNCTIONS
  1152. ******************************************************************************/
  1153. // <editor-fold defaultstate="collapsed" desc="feeding">
  1154. /**
  1155. * Returns or sets the unique identifier of the object<br/>
  1156. * This is used in debug strings mainly, but also to generate classes for the object,
  1157. * and acts as a default for several settings.<br/>
  1158. * defaults to the class name.<br/>
  1159. * This method is chainable.
  1160. * @param string $systemName
  1161. * @return string| StaticTools
  1162. */
  1163. public function systemName($systemName=NULL){
  1164. if(!func_num_args()){
  1165. if(!isset($this->_vars['system']['name'])){$this->_vars['system']['name'] = static::systemId().'_'.$this->InstanceId();}
  1166. return $this->_vars['system']['name'];
  1167. }
  1168. $this->_vars['system']['name'] = $systemName; return $this;
  1169. }
  1170. /**
  1171. * Sets several options at the same time. This is used to initiate the object<br/>
  1172. * You can pass either a string, which will set a default variable, or an array.<br/>
  1173. * The array can be used either to set the variables directly, or get passed to the object's methods.
  1174. * In other words, <code>
  1175. * array('systemName'=>'something')
  1176. * </code>
  1177. * can either set <code>
  1178. * systemName('something')
  1179. * </code>
  1180. * or
  1181. * <code>
  1182. * ->systemName = 'something'
  1183. * </code>
  1184. * You can set flags:<ul>
  1185. * <li><strong>StaticTools::GETSET_USE_OBJECT_CALL</strong> : Will call the object's methods. If __call() is set, the function
  1186. * will make use of it</li>
  1187. * <li><strong>StaticTools::GETSET_USE_OBJECT_METHODS</strong> : same, but will call only native functions</li>
  1188. * <li><strong>StaticTools::GETSET_BYPASS_CHECK</strong> : will bypass method_exists() and is_callable() functions, making the function
  1189. * run faster</li>
  1190. * </ul>
  1191. * Pass either of the flags to use methods instead of pass the variables directly.<br/>
  1192. * This method is chainable.
  1193. * @param object $object the object to feed
  1194. * @param array $objectVar the array to feed options to
  1195. * @param array | string $options
  1196. * @param int $flags
  1197. * @return StaticTools
  1198. */
  1199. public static function feedObject($object,&$objectVar,$options,$flags = NULL){
  1200. if($options){
  1201. if(is_array($options) || is_object($options)){
  1202. $doUseFunctions = $flags & StaticTools::GETSET_USE_OBJECT_CALL;
  1203. $doUseMethods = $flags & StaticTools::GETSET_USE_OBJECT_METHODS;
  1204. if($doUseFunctions || $doUseMethods){
  1205. return self::_feedFunctions($object, $options, $flags);
  1206. }else{
  1207. return self::_feedArray($object, $options);
  1208. }
  1209. }
  1210. else{return self::_feedString($object, $options);}
  1211. }
  1212. return $object;
  1213. }
  1214. /**
  1215. * This function is called by feed(). For each key in the array, it will call the relevant
  1216. * method on the object.<br/>
  1217. * You can pass flags:<ul>
  1218. * <li><strong>StaticTools::GETSET_USE_OBJECT_CALL</strong> : Will call the object's methods. If __call() is set, the function
  1219. * will make use of it</li>
  1220. * <li><strong>StaticTools::GETSET_USE_OBJECT_METHODS</strong> : same, but will call only native functions</li>
  1221. * <li><strong>StaticTools::GETSET_BYPASS_CHECK</strong> : will bypass method_exists() and is_callable() functions,
  1222. * thus making the function faster</li>
  1223. * </ul>
  1224. * @param object $object the object to run methods of
  1225. * @param array $options
  1226. * @param int $flags flags to pass
  1227. * @return StaticTools the object passed
  1228. */
  1229. protected static function _feedFunctions($object, array $options, $flags =

Large files files are truncated, but you can click here to view the full file