bundle.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. <?php namespace Laravel; defined('DS') or die('No direct script access.');
  2. use Laravel\Routing\Router;
  3. use FilesystemIterator as fIterator;
  4. class Bundle {
  5. /**
  6. * All of the application's bundles.
  7. *
  8. * @var array
  9. */
  10. public static $bundles = array();
  11. /**
  12. * A cache of the parsed bundle elements.
  13. *
  14. * @var array
  15. */
  16. public static $elements = array();
  17. /**
  18. * All of the bundles that have been started.
  19. *
  20. * @var array
  21. */
  22. public static $started = array();
  23. /**
  24. * All of the bundles that have their routes files loaded.
  25. *
  26. * @var array
  27. */
  28. public static $routed = array();
  29. /**
  30. * Register the bundle for the application.
  31. *
  32. * @param string $bundle
  33. * @param array $config
  34. * @return void
  35. */
  36. public static function register($bundle, $config = array())
  37. {
  38. $defaults = array('handles' => null, 'auto' => false);
  39. // If the given configuration is actually a string, we will assume it is a
  40. // location and set the bundle name to match it. This is common for most
  41. // bundles who simply live in the root bundle directory.
  42. if (is_string($config))
  43. {
  44. $bundle = $config;
  45. $config = array('location' => $bundle);
  46. }
  47. // If no location is set, we will set the location to match the name of
  48. // the bundle. This is for bundles who are installed to the root of
  49. // the bundle directory so a location was not set.
  50. if ( ! isset($config['location']))
  51. {
  52. $config['location'] = $bundle;
  53. }
  54. static::$bundles[$bundle] = array_merge($defaults, $config);
  55. // It is possible for the develoepr to specify auto-loader mappings
  56. // directly on the bundle registration. This provides a convenient
  57. // way to register mappings withuot a bootstrap.
  58. if (isset($config['autoloads']))
  59. {
  60. static::autoloads($bundle, $config);
  61. }
  62. }
  63. /**
  64. * Load a bundle by running it's start-up script.
  65. *
  66. * If the bundle has already been started, no action will be taken.
  67. *
  68. * @param string $bundle
  69. * @return void
  70. */
  71. public static function start($bundle)
  72. {
  73. if (static::started($bundle)) return;
  74. if ( ! static::exists($bundle))
  75. {
  76. throw new \Exception("Bundle [$bundle] has not been installed.");
  77. }
  78. // Each bundle may have a start script which is responsible for preparing
  79. // the bundle for use by the application. The start script may register
  80. // any classes the bundle uses with the auto-loader, etc.
  81. if (file_exists($path = static::path($bundle).'start'.EXT))
  82. {
  83. require $path;
  84. }
  85. // Each bundle may also have a "routes" file which is responsible for
  86. // registering the bundle's routes. This is kept separate from the
  87. // start script for reverse routing efficiency purposes.
  88. static::routes($bundle);
  89. Event::fire("laravel.started: {$bundle}");
  90. static::$started[] = strtolower($bundle);
  91. }
  92. /**
  93. * Load the "routes" file for a given bundle.
  94. *
  95. * @param string $bundle
  96. * @return void
  97. */
  98. public static function routes($bundle)
  99. {
  100. if (static::routed($bundle)) return;
  101. $path = static::path($bundle).'routes'.EXT;
  102. // By setting the bundle property on the router the router knows what
  103. // value to replace the (:bundle) place-holder with when the bundle
  104. // routes are added, keeping the routes flexible.
  105. Router::$bundle = static::option($bundle, 'handles');
  106. if ( ! static::routed($bundle) and file_exists($path))
  107. {
  108. static::$routed[] = $bundle;
  109. require $path;
  110. }
  111. }
  112. /**
  113. * Register the auto-loading configuration for a bundle.
  114. *
  115. * @param string $bundle
  116. * @param array $config
  117. * @return void
  118. */
  119. protected static function autoloads($bundle, $config)
  120. {
  121. $path = rtrim(Bundle::path($bundle), DS);
  122. foreach ($config['autoloads'] as $type => $mappings)
  123. {
  124. // When registering each type of mapping we'll replace the (:bundle)
  125. // place-holder with the path to the bundle's root directory, so
  126. // the developer may dryly register the mappings.
  127. $mappings = array_map(function($mapping) use ($path)
  128. {
  129. return str_replace('(:bundle)', $path, $mapping);
  130. }, $mappings);
  131. // Once the mappings are formatted, we will call the Autoloader
  132. // function matching the mapping type and pass in the array of
  133. // mappings so they can be registered and used.
  134. Autoloader::$type($mappings);
  135. }
  136. }
  137. /**
  138. * Disable a bundle for the current request.
  139. *
  140. * @param string $bundle
  141. * @return void
  142. */
  143. public static function disable($bundle)
  144. {
  145. unset(static::$bundles[$bundle]);
  146. }
  147. /**
  148. * Determine which bundle handles the given URI.
  149. *
  150. * The default bundle is returned if no other bundle is assigned.
  151. *
  152. * @param string $uri
  153. * @return string
  154. */
  155. public static function handles($uri)
  156. {
  157. $uri = rtrim($uri, '/').'/';
  158. foreach (static::$bundles as $key => $value)
  159. {
  160. if (isset($value['handles']) and starts_with($uri, $value['handles'].'/'))
  161. {
  162. return $key;
  163. }
  164. }
  165. return DEFAULT_BUNDLE;
  166. }
  167. /**
  168. * Deteremine if a bundle exists within the bundles directory.
  169. *
  170. * @param string $bundle
  171. * @return bool
  172. */
  173. public static function exists($bundle)
  174. {
  175. return $bundle == DEFAULT_BUNDLE or in_array(strtolower($bundle), static::names());
  176. }
  177. /**
  178. * Determine if a given bundle has been started for the request.
  179. *
  180. * @param string $bundle
  181. * @return void
  182. */
  183. public static function started($bundle)
  184. {
  185. return in_array(strtolower($bundle), static::$started);
  186. }
  187. /**
  188. * Determine if a given bundle has its routes file loaded.
  189. *
  190. * @param string $bundle
  191. * @return void
  192. */
  193. public static function routed($bundle)
  194. {
  195. return in_array(strtolower($bundle), static::$routed);
  196. }
  197. /**
  198. * Get the identifier prefix for the bundle.
  199. *
  200. * @param string $bundle
  201. * @return string
  202. */
  203. public static function prefix($bundle)
  204. {
  205. return ($bundle !== DEFAULT_BUNDLE) ? "{$bundle}::" : '';
  206. }
  207. /**
  208. * Get the class prefix for a given bundle.
  209. *
  210. * @param string $bundle
  211. * @return string
  212. */
  213. public static function class_prefix($bundle)
  214. {
  215. return ($bundle !== DEFAULT_BUNDLE) ? Str::classify($bundle).'_' : '';
  216. }
  217. /**
  218. * Return the root bundle path for a given bundle.
  219. *
  220. * <code>
  221. * // Returns the bundle path for the "admin" bundle
  222. * $path = Bundle::path('admin');
  223. *
  224. * // Returns the path('app') constant as the default bundle
  225. * $path = Bundle::path('application');
  226. * </code>
  227. *
  228. * @param string $bundle
  229. * @return string
  230. */
  231. public static function path($bundle)
  232. {
  233. if (is_null($bundle) or $bundle === DEFAULT_BUNDLE)
  234. {
  235. return path('app');
  236. }
  237. else if ($location = array_get(static::$bundles, $bundle.'.location'))
  238. {
  239. return str_finish(path('bundle').$location, DS);
  240. }
  241. }
  242. /**
  243. * Return the root asset path for the given bundle.
  244. *
  245. * @param string $bundle
  246. * @return string
  247. */
  248. public static function assets($bundle)
  249. {
  250. if (is_null($bundle)) return static::assets(DEFAULT_BUNDLE);
  251. return ($bundle != DEFAULT_BUNDLE) ? URL::base()."/bundles/{$bundle}/" : URL::base().'/';
  252. }
  253. /**
  254. * Get the bundle name from a given identifier.
  255. *
  256. * <code>
  257. * // Returns "admin" as the bundle name for the identifier
  258. * $bundle = Bundle::name('admin::home.index');
  259. * </code>
  260. *
  261. * @param string $identifier
  262. * @return string
  263. */
  264. public static function name($identifier)
  265. {
  266. list($bundle, $element) = static::parse($identifier);
  267. return $bundle;
  268. }
  269. /**
  270. * Get the element name from a given identifier.
  271. *
  272. * <code>
  273. * // Returns "home.index" as the element name for the identifier
  274. * $bundle = Bundle::bundle('admin::home.index');
  275. * </code>
  276. *
  277. * @param string $identifier
  278. * @return string
  279. */
  280. public static function element($identifier)
  281. {
  282. list($bundle, $element) = static::parse($identifier);
  283. return $element;
  284. }
  285. /**
  286. * Reconstruct an identifier from a given bundle and element.
  287. *
  288. * <code>
  289. * // Returns "admin::home.index"
  290. * $identifier = Bundle::identifier('admin', 'home.index');
  291. *
  292. * // Returns "home.index"
  293. * $identifier = Bundle::identifier('application', 'home.index');
  294. * </code>
  295. *
  296. * @param string $bundle
  297. * @param string $element
  298. * @return string
  299. */
  300. public static function identifier($bundle, $element)
  301. {
  302. return (is_null($bundle) or $bundle == DEFAULT_BUNDLE) ? $element : $bundle.'::'.$element;
  303. }
  304. /**
  305. * Return the bundle name if it exists, else return the default bundle.
  306. *
  307. * @param string $bundle
  308. * @return string
  309. */
  310. public static function resolve($bundle)
  311. {
  312. return (static::exists($bundle)) ? $bundle : DEFAULT_BUNDLE;
  313. }
  314. /**
  315. * Parse a element identifier and return the bundle name and element.
  316. *
  317. * <code>
  318. * // Returns array(null, 'admin.user')
  319. * $element = Bundle::parse('admin.user');
  320. *
  321. * // Parses "admin::user" and returns array('admin', 'user')
  322. * $element = Bundle::parse('admin::user');
  323. * </code>
  324. *
  325. * @param string $identifier
  326. * @return array
  327. */
  328. public static function parse($identifier)
  329. {
  330. // The parsed elements are cached so we don't have to reparse them on each
  331. // subsequent request for the parsed element. So, if we've already parsed
  332. // the given element, we'll just return the cached copy.
  333. if (isset(static::$elements[$identifier]))
  334. {
  335. return static::$elements[$identifier];
  336. }
  337. if (strpos($identifier, '::') !== false)
  338. {
  339. $element = explode('::', strtolower($identifier));
  340. }
  341. // If no bundle is in the identifier, we will insert the default bundle
  342. // since classes like Config and Lang organize their items by bundle.
  343. // The "application" folder essentially behaves as a bundle.
  344. else
  345. {
  346. $element = array(DEFAULT_BUNDLE, strtolower($identifier));
  347. }
  348. return static::$elements[$identifier] = $element;
  349. }
  350. /**
  351. * Get the information for a given bundle.
  352. *
  353. * @param string $bundle
  354. * @return object
  355. */
  356. public static function get($bundle)
  357. {
  358. return array_get(static::$bundles, $bundle);
  359. }
  360. /**
  361. * Get an option for a given bundle.
  362. *
  363. * @param string $bundle
  364. * @param string $option
  365. * @return mixed
  366. */
  367. public static function option($bundle, $option)
  368. {
  369. $bundle = static::get($bundle);
  370. if ( ! is_null($bundle)) return array_get($bundle, $option);
  371. }
  372. /**
  373. * Get all of the installed bundles for the application.
  374. *
  375. * @return array
  376. */
  377. public static function all()
  378. {
  379. return static::$bundles;
  380. }
  381. /**
  382. * Get all of the installed bundle names.
  383. *
  384. * @return array
  385. */
  386. public static function names()
  387. {
  388. return array_keys(static::$bundles);
  389. }
  390. }