ModuleManager.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. <?php
  2. /**
  3. *
  4. * Cube Framework $Id$ QKN6Rvf+edw/vrqXp1EGojRwRQibhhzdK1RxTFUrfAY=
  5. *
  6. * @link http://codecu.be/framework
  7. * @copyright Copyright (c) 2017 CodeCube SRL
  8. * @license http://codecu.be/framework/license Commercial License
  9. *
  10. * @version 1.10 [rev.1.10.01]
  11. */
  12. /**
  13. * modules manager class
  14. */
  15. namespace Cube;
  16. use Cube\Controller\Request,
  17. Cube\Loader\Autoloader;
  18. class ModuleManager
  19. {
  20. /**
  21. * uri delimiter
  22. */
  23. const URI_DELIMITER = '/';
  24. /**
  25. * name and location of a module config file
  26. */
  27. const MODULE_CONFIG = 'config/*.config.php';
  28. /**
  29. * location of a module's classes
  30. */
  31. const MODULE_FILES = 'src';
  32. /**
  33. *
  34. * location of the application's modules
  35. */
  36. const MODULES_PATH = 'module';
  37. /**
  38. *
  39. * holds an instance of the object
  40. *
  41. * @var \Cube\ModuleManager
  42. */
  43. private static $_instance;
  44. /**
  45. *
  46. * an array that holds the names of the modules defined in the application
  47. *
  48. * @var array
  49. */
  50. protected $_modules = array();
  51. /**
  52. *
  53. * get the paths of the application modules
  54. *
  55. * @var array
  56. */
  57. protected $_paths = array();
  58. /**
  59. *
  60. * holds the route objects that are generated from the modules configs
  61. * the first active route in the stack will give the active module
  62. *
  63. * @var array
  64. */
  65. protected $_routes = array();
  66. /**
  67. *
  68. * the request uri, used for matching route objects and retrieving the active module
  69. *
  70. * @var string
  71. */
  72. protected $_requestUri;
  73. /**
  74. *
  75. * get active module from routing the request
  76. *
  77. * @var string
  78. */
  79. protected $_activeModule;
  80. /**
  81. *
  82. * class to be use for routing
  83. * must implement \Cube\Controller\Router\Route\RouteInterface
  84. *
  85. * @var string
  86. */
  87. protected $_routeClass = '\Cube\Controller\Router\Route\Rewrite';
  88. /**
  89. *
  90. * class constructor
  91. */
  92. protected function __construct()
  93. {
  94. $this->addPath('', self::MODULES_PATH);
  95. }
  96. /**
  97. *
  98. * returns an instance of the object and creates it if it wasnt instantiated yet
  99. *
  100. * @return \Cube\ModuleManager
  101. */
  102. public static function getInstance()
  103. {
  104. if (!self::$_instance instanceof self) {
  105. self::$_instance = new self();
  106. }
  107. return self::$_instance;
  108. }
  109. /**
  110. *
  111. * reset all module properties
  112. *
  113. * @return $this
  114. */
  115. public function resetProperties()
  116. {
  117. $this->_modules = array();
  118. $this->_paths = array();
  119. $this->_routes = array();
  120. $this->_requestUri = '';
  121. $this->_activeModule = '';
  122. return $this;
  123. }
  124. /**
  125. *
  126. * get modules paths
  127. *
  128. * @return array
  129. */
  130. public function getPaths()
  131. {
  132. return $this->_paths;
  133. }
  134. /**
  135. *
  136. * add single module path
  137. *
  138. * @param string $key
  139. * @param string $path
  140. *
  141. * @return $this
  142. */
  143. public function addPath($key, $path)
  144. {
  145. if (!in_array($path, $this->_paths)) {
  146. $this->_paths[$key] = $path;
  147. }
  148. return $this;
  149. }
  150. /**
  151. *
  152. * get the names of the registered modules
  153. *
  154. * @return array
  155. * @throws \DomainException
  156. */
  157. public function getModules()
  158. {
  159. if (empty($this->_modules)) {
  160. throw new \DomainException("No modules have been defined for the application.");
  161. }
  162. return $this->_modules;
  163. }
  164. /**
  165. *
  166. * add multiple modules
  167. *
  168. * @param array $modules
  169. *
  170. * @return $this
  171. */
  172. public function setModules($modules = array())
  173. {
  174. if (!empty($modules)) {
  175. foreach ($modules as $module) {
  176. $this->setModule($module);
  177. }
  178. }
  179. return $this;
  180. }
  181. /**
  182. *
  183. * load module config files
  184. * @1.9: all files that are placed in the config folder and end in .config.php will be included
  185. *
  186. * @param string $module the name of the module
  187. *
  188. * @return array returns the module config array or an empty array if the file doesnt exist
  189. * @throws \OutOfRangeException
  190. */
  191. public function getConfig($module)
  192. {
  193. $result = array();
  194. if (!in_array($module, $this->_modules)) {
  195. throw new \OutOfRangeException(
  196. sprintf("Cannot load the config file for module '%s' because the module was not initialized.", $module));
  197. }
  198. $files = array_merge(
  199. glob(__DIR__
  200. . '/../../'
  201. . self::MODULES_PATH . DIRECTORY_SEPARATOR
  202. . $module . DIRECTORY_SEPARATOR
  203. . self::MODULE_CONFIG),
  204. glob(__DIR__
  205. . '/../../'
  206. . Autoloader::getInstance()->getModsPath() . DIRECTORY_SEPARATOR
  207. . self::MODULES_PATH . DIRECTORY_SEPARATOR
  208. . $module . DIRECTORY_SEPARATOR
  209. . self::MODULE_CONFIG));
  210. foreach ($files as $file) {
  211. if (file_exists($file)) {
  212. $data = (array)include $file;
  213. $result = array_replace_recursive(
  214. array_merge_recursive($result, $data), $data);
  215. }
  216. }
  217. return $result;
  218. }
  219. /**
  220. *
  221. * add a single module to the array, and save its config array as well
  222. *
  223. * @param string $module
  224. *
  225. * @return $this
  226. */
  227. public function setModule($module)
  228. {
  229. if (!in_array($module, $this->_modules) && !empty($module)) {
  230. array_push($this->_modules, $module);
  231. $config = $this->getConfig($module);
  232. if (isset($config['routes'])) {
  233. $this->setRoutes($config['routes'], $module);
  234. }
  235. $this->addPath(
  236. $module,
  237. self::MODULES_PATH . DIRECTORY_SEPARATOR
  238. . $module . DIRECTORY_SEPARATOR
  239. . self::MODULE_FILES);
  240. }
  241. return $this;
  242. }
  243. /**
  244. *
  245. * get the active module based the request uri and the route objects defined
  246. *
  247. * @return string the name of the active module
  248. */
  249. public function getActiveModule()
  250. {
  251. if (!isset($this->_activeModule)) {
  252. foreach ($this->_routes as $route) {
  253. /** @var \Cube\Controller\Router\Route\AbstractRoute $route */
  254. if ($route->match($this->getRequestUri()) !== false) {
  255. $this->_activeModule = $route->getModule();
  256. return $this->_activeModule;
  257. }
  258. }
  259. $split = explode(self::URI_DELIMITER, preg_replace('/^\//', '', $this->getRequestUri()));
  260. $moduleName = ucfirst($split[0]);
  261. $modules = $this->getModules();
  262. if (in_array($moduleName, $modules)) {
  263. $this->_activeModule = $moduleName;
  264. }
  265. else {
  266. // we init a standard request object and get the module variable if available
  267. $request = new Request\Standard();
  268. if ($module = $request->getParam('module')) {
  269. $this->_activeModule = $request->normalize($module);
  270. }
  271. else {
  272. $this->_activeModule = $modules[0];
  273. }
  274. }
  275. }
  276. return $this->_activeModule;
  277. }
  278. /**
  279. *
  280. * override the active module parameter
  281. *
  282. * @param string $module
  283. *
  284. * @return $this
  285. */
  286. public function setActiveModule($module)
  287. {
  288. if (in_array($module, $this->_modules)) {
  289. $this->_activeModule = $module;
  290. }
  291. return $this;
  292. }
  293. /**
  294. *
  295. * clear active module variable
  296. *
  297. * @return $this
  298. */
  299. public function clearActiveModule()
  300. {
  301. $this->_activeModule = null;
  302. return $this;
  303. }
  304. /**
  305. *
  306. * set route class
  307. *
  308. * @param string $routeClass
  309. *
  310. * @return $this
  311. */
  312. public function setRouteClass($routeClass)
  313. {
  314. if (class_exists($routeClass)) {
  315. $this->_routeClass = $routeClass;
  316. }
  317. return $this;
  318. }
  319. /**
  320. *
  321. * get route class
  322. *
  323. * @return string
  324. */
  325. public function getRouteClass()
  326. {
  327. return $this->_routeClass;
  328. }
  329. /**
  330. *
  331. * return the routes array
  332. *
  333. * @return array
  334. */
  335. public function getRoutes()
  336. {
  337. return $this->_routes;
  338. }
  339. /**
  340. *
  341. * create route objects from the arrays defined in the module config files,
  342. * and match routes to the request uri as well
  343. * we get the request uri by creating a new request object
  344. *
  345. * @param array $routes
  346. * @param string $module the name of the module the routes belong to
  347. *
  348. * @return $this
  349. */
  350. public function setRoutes(array $routes, $module)
  351. {
  352. foreach ($routes as $name => $options) {
  353. $path = (isset($options[0])) ? $options[0] : null;
  354. $defaults = (isset($options[1])) ? (array)$options[1] : array();
  355. $conditions = (isset($options[2])) ? (array)$options[2] : array();
  356. /** @var \Cube\Controller\Router\Route\AbstractRoute $route */
  357. $route = new $this->_routeClass($path, $defaults, $conditions);
  358. $route->setName($name)
  359. ->setModule($module);
  360. array_push($this->_routes, $route);
  361. }
  362. return $this;
  363. }
  364. /**
  365. *
  366. * get the formatted request uri, set if its not already set
  367. *
  368. * @return string
  369. */
  370. public function getRequestUri()
  371. {
  372. if (empty($this->_requestUri)) {
  373. $this->setRequestUri();
  374. }
  375. return $this->_requestUri;
  376. }
  377. /**
  378. *
  379. * set the request uri and format it so that it can be used for matching route objects
  380. * (remove the base url of the application from the uri and remove any GET variables as well)
  381. *
  382. * @param string $requestUri
  383. *
  384. * @return $this
  385. */
  386. public function setRequestUri($requestUri = null)
  387. {
  388. if ($requestUri === null) {
  389. $request = new Request();
  390. $requestUri = $request->getRequestUri();
  391. }
  392. $this->_requestUri = $requestUri;
  393. return $this;
  394. }
  395. }