PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/application/libraries/Engine/Api.php

https://github.com/shopaholiccompany/shopaholic
PHP | 645 lines | 340 code | 82 blank | 223 comment | 59 complexity | 991de860ad8ab92c66a898f46252efbf MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-3.0, LGPL-2.1
  1. <?php
  2. /**
  3. * SocialEngine
  4. *
  5. * @category Engine
  6. * @package Engine_Api
  7. * @copyright Copyright 2006-2010 Webligo Developments
  8. * @license http://www.socialengine.net/license/
  9. * @version $Id: Api.php 7244 2010-09-01 01:49:53Z john $
  10. * @author John Boehr <j@webligo.com>
  11. */
  12. /**
  13. * @category Engine
  14. * @package Engine_Api
  15. * @copyright Copyright 2006-2010 Webligo Developments
  16. * @license http://www.socialengine.net/license/
  17. */
  18. class Engine_Api
  19. {
  20. /**
  21. * The singleton Api object
  22. *
  23. * @var Engine_Api
  24. */
  25. protected static $_instance;
  26. /**
  27. * The current application instance
  28. *
  29. * @var Engine_Application
  30. */
  31. protected $_application;
  32. /**
  33. * An array of module api objects
  34. *
  35. * @var array
  36. */
  37. protected $_modules = array();
  38. /**
  39. * Contains the current set module name
  40. * @var string
  41. */
  42. protected $_currentModuleName;
  43. /**
  44. * @var array assoc map of item type => module
  45. */
  46. protected $_itemTypes;
  47. /**
  48. * Get or create the current api instance
  49. *
  50. * @return Engine_Api
  51. */
  52. public static function getInstance()
  53. {
  54. if( is_null(self::$_instance) )
  55. {
  56. self::$_instance = new self();
  57. }
  58. return self::$_instance;
  59. }
  60. /**
  61. * Shorthand for getInstance
  62. *
  63. * @return Engine_Api
  64. */
  65. public static function _()
  66. {
  67. return self::getInstance();
  68. }
  69. /**
  70. * Set or unset the current api instance
  71. *
  72. * @param Engine_Api $api
  73. * @return Engine_Api
  74. */
  75. public static function setInstance(Engine_Api $api = null)
  76. {
  77. return self::$_instance = $api;
  78. }
  79. public function getAutoloader()
  80. {
  81. if( null === $this->_autoloader )
  82. {
  83. throw new Exception('Autoloader not set');
  84. }
  85. return $this->_autoloader;
  86. }
  87. public function setAutoloader(Engine_Application_Autoloader $autoloader)
  88. {
  89. $this->_autoloader = $autoloader;
  90. return $this;
  91. }
  92. // Application
  93. /**
  94. * Sets the current application instance
  95. *
  96. * @param Engine_Application $application
  97. * @return Engine_Api
  98. */
  99. public function setApplication(Engine_Application $application)
  100. {
  101. $this->_application = $application;
  102. return $this;
  103. }
  104. /**
  105. * Gets the current application object
  106. *
  107. * @return Engine_Application
  108. * @throws Engine_Api_Exception If application is not set
  109. */
  110. public function getApplication()
  111. {
  112. if( is_null($this->_application) )
  113. {
  114. throw new Engine_Api_Exception('Application instance not set');
  115. }
  116. return $this->_application;
  117. }
  118. // Bootstraps
  119. /**
  120. * Checks if the specfied module has been bootstrapped
  121. *
  122. * @param string $name The module name
  123. * @return bool
  124. */
  125. public function hasModuleBootstrap($name)
  126. {
  127. return isset($this->_modules[$name]);
  128. }
  129. /**
  130. * Sets the local copy of a module bootstrap
  131. *
  132. * @param Zend_Application_Module_Bootstrap $bootstrap
  133. * @return Engine_Api
  134. */
  135. public function setModuleBootstrap(Engine_Application_Bootstrap_Abstract $bootstrap)
  136. {
  137. $name = strtolower($bootstrap->getModuleName());
  138. $this->_modules[$name] = $bootstrap;
  139. return $this;
  140. }
  141. /**
  142. * Gets a module bootstrap
  143. *
  144. * @param string $name The module name
  145. * @return Zend_Application_Module_Bootstrap|Zend_Application_Bootstrap_Bootstrap
  146. * @throws Engine_Api_Exception If module not found
  147. */
  148. public function getModuleBootstrap($name = null)
  149. {
  150. if( !$name )
  151. {
  152. $name = Zend_Controller_Front::getInstance()->getDefaultModule();
  153. }
  154. if( !isset($this->_modules[$name]) )
  155. {
  156. // Special case, default module can be detected and set
  157. if( $name == Zend_Controller_Front::getInstance()->getDefaultModule() )
  158. {
  159. $this->_modules[$name] = $this->getApplication()->getBootstrap();
  160. }
  161. // Normal modules must be registered manually
  162. else
  163. {
  164. throw new Engine_Api_Exception(sprintf('Module "%s" not found', $name));
  165. }
  166. }
  167. return $this->_modules[$name];
  168. }
  169. // Loading
  170. /**
  171. * Shorthand for loadModuleApi
  172. *
  173. * @return Engine_Application_Module_Api
  174. * @throws Engine_Api_Exception If given improper arguments or module is missing
  175. */
  176. public function __call($method, $args)
  177. {
  178. if( 'get' == substr($method, 0, 3) )
  179. {
  180. $type = strtolower(substr($method, 3));
  181. if( empty($args) )
  182. {
  183. throw new Engine_Api_Exception("Cannot load resources; no resource specified");
  184. }
  185. $resource = array_shift($args);
  186. $module = array_shift($args);
  187. if( $module === null )
  188. {
  189. if( $this->_currentModuleName === null )
  190. {
  191. throw new Engine_Api_Exception("Cannot load resources; no module specified");
  192. }
  193. else
  194. {
  195. $module = $this->_currentModuleName;
  196. $this->_currentModuleName = null;
  197. }
  198. }
  199. return $this->load($module, $type, $resource);
  200. }
  201. // Backwards
  202. if( isset($this->_modules[$method]) )
  203. {
  204. return $this->load($method, 'api', 'core');
  205. //return $this->load($method, 'model', 'api');
  206. }
  207. // Boo
  208. throw new Engine_Exception("Method '$method' is not supported");
  209. }
  210. /**
  211. * Used to shorten some api calls, sets the default module to load resources
  212. * from
  213. *
  214. * @param string $module
  215. * @return Engine_Api
  216. */
  217. public function setCurrentModule($module)
  218. {
  219. if( is_string($module) )
  220. {
  221. $this->_currentModuleName = $module;
  222. }
  223. else if( is_object($module) && method_exists($object, 'getModuleName') )
  224. {
  225. $this->_currentModuleName = $object->getModuleName();
  226. }
  227. else
  228. {
  229. $this->_currentModuleName = null;
  230. }
  231. return $this;
  232. }
  233. /**
  234. * Loads a singleton instance of a module resource
  235. *
  236. * @param string $module The module name
  237. * @param string $type The resource type
  238. * @param string $resource The resource name
  239. * @return mixed The requested singleton object
  240. */
  241. public function load($module, $type, $resource)
  242. {
  243. if( strtolower($type) == 'dbtable' )
  244. {
  245. $type = 'Model_DbTable';
  246. }
  247. return Engine_Loader::getInstance()->load(ucfirst($module) . '_' . ucfirst($type) . '_' . ucfirst($resource));
  248. //return $this->getModuleBootstrap($module)->getResourceLoader()->load($resource, $type);
  249. }
  250. /**
  251. * Loads a singleton instance of a module resource using a full class name
  252. *
  253. * @param string $class The class name
  254. * @return mixed The requested singleton object
  255. */
  256. public function loadClass($class)
  257. {
  258. return Engine_Loader::getInstance()->load($class);
  259. }
  260. // Item handling stuff
  261. /**
  262. * Checks if the item of $type has been registered
  263. *
  264. * @param string $type
  265. * @return bool
  266. */
  267. public function hasItemType($type)
  268. {
  269. $this->_loadItemInfo();
  270. return isset($this->_itemTypes[$type]);
  271. }
  272. /**
  273. * Gets an item given a type and identity
  274. *
  275. * @param string $type
  276. * @param int $identity
  277. * @return Core_Model_Item_Abstract
  278. */
  279. public function getItem($type, $identity)
  280. {
  281. $this->_loadItemInfo();
  282. $api = $this->getItemApi($type);
  283. $method = 'get'.ucfirst($type);
  284. if( method_exists($api, $method) )
  285. {
  286. return $api->$method($identity);
  287. }
  288. else if( method_exists($api, 'getItem') )
  289. {
  290. return $api->getItem($type, $identity);
  291. }
  292. return $this->getItemTable($type)->find($identity)->current();
  293. }
  294. /**
  295. * Gets multiple items of a type from an array of ids
  296. *
  297. * @param string $type
  298. * @param array $identities
  299. * @return Engine_Db_Table_Rowset
  300. */
  301. public function getItemMulti($type, array $identities)
  302. {
  303. $this->_loadItemInfo();
  304. $api = $this->getItemApi($type);
  305. $method = 'get'.ucfirst($type).'Multi';
  306. if( method_exists($api, $method) )
  307. {
  308. return $api->$method($identities);
  309. }
  310. else if( method_exists($api, 'getItemMulti') )
  311. {
  312. return $api->getItemMulti($type, $identities);
  313. }
  314. return $this->getItemTable($type)->find($identities);
  315. }
  316. /**
  317. * Gets an item using a guid array or string
  318. *
  319. * @param array|string $guid
  320. * @return Core_Model_Item_Abstract
  321. * @throws Engine_Api_Exception If given improper arguments
  322. */
  323. public function getItemByGuid($guid)
  324. {
  325. $this->_loadItemInfo();
  326. if( is_string($guid) )
  327. {
  328. $guid = explode('_', $guid);
  329. if( count($guid) > 2 )
  330. {
  331. $id = array_pop($guid);
  332. $guid = array(join('_', $guid), $id);
  333. }
  334. }
  335. if( !is_array($guid) || count($guid) !== 2 || !is_string($guid[0]) || !is_numeric($guid[1]) )
  336. {
  337. throw new Engine_Api_Exception(sprintf('Malformed guid passed to getItemByGuid(): %s', join('_', $guid)));
  338. }
  339. return $this->getItem($guid[0], $guid[1]);
  340. }
  341. /**
  342. * Gets the name of the module that an item type belongs to
  343. *
  344. * @param string $type The item type
  345. * @return string The module name
  346. * @throws Engine_Api_Exception If item type isn't registered
  347. */
  348. public function getItemModule($type)
  349. {
  350. $this->_loadItemInfo();
  351. return $this->getItemInfo($type, 'module');
  352. }
  353. /**
  354. * Gets info about an item
  355. *
  356. * @param string $type The item type
  357. * @param string (OPTIONAL) $key The info key
  358. * @return mixed
  359. */
  360. public function getItemInfo($type, $key = null)
  361. {
  362. $this->_loadItemInfo();
  363. if( empty($this->_itemTypes[$type]) )
  364. {
  365. throw new Engine_Api_Exception(sprintf("Unknown item type: %s", $type));
  366. }
  367. if( null === $key )
  368. {
  369. return $this->_itemTypes[$type];
  370. }
  371. else if( array_key_exists($key, $this->_itemTypes[$type]) )
  372. {
  373. return $this->_itemTypes[$type][$key];
  374. }
  375. return null;
  376. }
  377. /**
  378. * Gets the class of an item
  379. *
  380. * @param string $type The item type
  381. * @return string The class name
  382. */
  383. public function getItemClass($type)
  384. {
  385. $this->_loadItemInfo();
  386. // Check api for overriding method
  387. $api = $this->getItemApi($type);
  388. if( method_exists($api, 'getItemClass') )
  389. {
  390. return $api->getItemClass($type);
  391. }
  392. // Generate item class manually
  393. $module = $this->getItemModule($type);
  394. return ucfirst($module) . '_Model_' . self::typeToClassSuffix($type, $module);
  395. }
  396. /**
  397. * Gets the class of the dbtable that an item type belongs to
  398. *
  399. * @param string $type The item type
  400. * @return string The table class name
  401. */
  402. public function getItemTableClass($type)
  403. {
  404. $this->_loadItemInfo();
  405. // Check api for overriding method
  406. $api = $this->getItemApi($type);
  407. if( method_exists($api, 'getItemTableClass') )
  408. {
  409. return $api->getItemTableClass($type);
  410. }
  411. // Generate item table class manually
  412. $module = $this->getItemInfo($type, 'moduleInflected');
  413. $class = $module . '_Model_DbTable_' . self::typeToClassSuffix($type, $module);
  414. if( substr($class, -1, 1) === 'y' ) {
  415. $class = substr($class, 0, -1) . 'ies';
  416. } else if( substr($class, -1, 1) !== 's' ) {
  417. $class .= 's';
  418. }
  419. return $class;
  420. }
  421. /**
  422. * Gets a singleton instance of the dbtable an item type belongs to
  423. *
  424. * @param string $type The item type
  425. * @return Engine_Db_Table The table object
  426. */
  427. public function getItemTable($type)
  428. {
  429. $this->_loadItemInfo();
  430. // Check api for overriding method
  431. $api = $this->getItemApi($type);
  432. if( method_exists($api, 'getItemTable') )
  433. {
  434. return $api->getItemTable($type);
  435. }
  436. $class = $this->getItemTableClass($type);
  437. return $this->loadClass($class);
  438. }
  439. /**
  440. * Gets the item api object that an item type belongs to
  441. *
  442. * @param string $type The item type
  443. * @return Engine_Application_Module_Api
  444. */
  445. public function getItemApi($type)
  446. {
  447. $this->_loadItemInfo();
  448. $module = $this->getItemInfo($type, 'moduleInflected');
  449. return $this->load($module, 'api', 'core');
  450. }
  451. /**
  452. * Load item info from manifest
  453. */
  454. protected function _loadItemInfo()
  455. {
  456. if( null === $this->_itemTypes )
  457. {
  458. $manifest = Zend_Registry::get('Engine_Manifest');
  459. if( null === $manifest )
  460. {
  461. throw new Engine_Api_Exception('Manifest data not loaded!');
  462. }
  463. $this->_itemTypes = array();
  464. foreach( $manifest as $module => $config )
  465. {
  466. if( !isset($config['items']) ) continue;
  467. foreach( $config['items'] as $key => $value )
  468. {
  469. if( is_numeric($key) ) {
  470. $this->_itemTypes[$value] = array(
  471. 'module' => $module,
  472. 'moduleInflected' => self::inflect($module),
  473. );
  474. } else {
  475. $this->_itemTypes[$key] = $value;
  476. $this->_itemTypes[$key]['module'] = $module;
  477. $this->_itemTypes[$key]['moduleInflected'] = self::inflect($module);
  478. }
  479. }
  480. }
  481. }
  482. }
  483. // Utility
  484. static public function inflect($string)
  485. {
  486. return str_replace(' ', '', ucwords(str_replace(array('.', '-'), ' ' , $string)));
  487. }
  488. static public function deflect($string)
  489. {
  490. return strtolower(trim(preg_replace('/([a-z0-9])([A-Z])/', '\1-\2', $string), '-. '));
  491. //return strtolower(trim(preg_replace('/([a-z0-9])([A-Z])/', '\1-\2', preg_replace('/[^A-Za-z0-9-]/', '', $string)), '-. '));
  492. }
  493. /**
  494. * Used to inflect item types to class suffix.
  495. *
  496. * @param string $type
  497. * @param string $module
  498. * @return string
  499. */
  500. static public function typeToClassSuffix($type, $module)
  501. {
  502. $parts = explode('_', $type);
  503. if( count($parts) > 1 && $parts[0] === strtolower($module) )
  504. {
  505. array_shift($parts);
  506. }
  507. $partial = str_replace(' ', '', ucwords(join(' ', $parts)));
  508. return $partial;
  509. }
  510. /**
  511. * Used to inflect item class to type.
  512. *
  513. * @param string $class
  514. * @param string $module
  515. * @return string
  516. * @throws Engine_Api_Exception If given improper arguments
  517. */
  518. static public function classToType($class, $module)
  519. {
  520. list($classModule, $resourceType, $resourceName)
  521. = explode('_', $class, 3);
  522. // Throw stuff
  523. if( strtolower($classModule) != strtolower($module) )
  524. {
  525. throw new Engine_Api_Exception('class and module do not match');
  526. }
  527. else if( $resourceType != 'Model' )
  528. {
  529. throw new Engine_Api_Exception('resource type must be a model');
  530. }
  531. // Parse camel case
  532. preg_match_all('/([A-Z][a-z]+)/', $resourceName, $matches);
  533. if( empty($matches[0]) )
  534. {
  535. throw new Engine_Exception('resource name not useable');
  536. }
  537. $matches = $matches[0];
  538. // Append module name if first not equal
  539. if( strtolower($matches[0]) != strtolower($module) )
  540. {
  541. array_unshift($matches, $module);
  542. }
  543. $type = strtolower(join('_', $matches));
  544. return $type;
  545. }
  546. /**
  547. * Inflects a type to the class name suffix
  548. * @todo Not used?
  549. *
  550. * @param string $type
  551. * @param string $module
  552. * @return string
  553. */
  554. static public function typeToShort($type, $module)
  555. {
  556. $parts = explode('_', $type);
  557. if( count($parts) > 1 && strtolower($parts[0]) == strtolower($module) )
  558. {
  559. array_shift($parts);
  560. }
  561. return strtolower(join('_', $parts));
  562. }
  563. }