bundle.php 10.7 KB
Newer Older
Taylor Otwell committed
1
<?php namespace Laravel; defined('DS') or die('No direct script access.');
2

Taylor Otwell committed
3
use Laravel\Routing\Router;
4 5
use FilesystemIterator as fIterator;

6 7 8 9 10 11 12
class Bundle {

	/**
	 * All of the application's bundles.
	 *
	 * @var array
	 */
13
	public static $bundles = array();
14 15 16 17 18 19

	/**
	 * A cache of the parsed bundle elements.
	 *
	 * @var array
	 */
20
	public static $elements = array();
21 22 23 24 25 26

	/**
	 * All of the bundles that have been started.
	 *
	 * @var array
	 */
27 28 29
	public static $started = array();

	/**
Taylor Otwell committed
30 31 32 33 34 35 36
	 * All of the bundles that have their routes files loaded.
	 *
	 * @var array
	 */
	public static $routed = array();

	/**
37
	 * Register the bundle for the application.
38
	 *
39 40
	 * @param  string  $bundle
	 * @param  array   $config
41 42
	 * @return void
	 */
43
	public static function register($bundle, $config = array())
44 45
	{
		$defaults = array('handles' => null, 'auto' => false);
Taylor Otwell committed
46

47 48 49 50
		// If the given configuration is actually a string, we will assume it is a
		// location and set the bundle name to match it. This is common for most
		// bundles who simply live in the root bundle directory.
		if (is_string($config))
51
		{
52 53 54
			$bundle = $config;

			$config = array('location' => $bundle);
55 56
		}

Taylor Otwell committed
57
		// If no location is set, we will set the location to match the name of
58 59 60 61 62 63
		// the bundle. This is for bundles who are installed to the root of
		// the bundle directory so a location was not set.
		if ( ! isset($config['location']))
		{
			$config['location'] = $bundle;
		}
64

65
		static::$bundles[$bundle] = array_merge($defaults, $config);
66

asdfgh746@gmail.com committed
67
		// It is possible for the developer to specify auto-loader mappings
68 69
		// directly on the bundle registration. This provides a convenient
		// way to register mappings withuot a bootstrap.
70 71
		if (isset($config['autoloads']))
		{
72
			static::autoloads($bundle, $config);
73
		}
74 75 76
	}

	/**
77 78 79 80 81 82 83 84 85 86 87
	 * Load a bundle by running it's start-up script.
	 *
	 * If the bundle has already been started, no action will be taken.
	 *
	 * @param  string  $bundle
	 * @return void
	 */
	public static function start($bundle)
	{
		if (static::started($bundle)) return;

88
		if ( ! static::exists($bundle))
89 90 91 92
		{
			throw new \Exception("Bundle [$bundle] has not been installed.");
		}

Taylor Otwell committed
93 94
		// Each bundle may have a start script which is responsible for preparing
		// the bundle for use by the application. The start script may register
95 96 97 98 99 100
		// any classes the bundle uses with the auto-loader class, etc.
		if ( ! is_null($starter = static::option($bundle, 'starter')))
		{
			$starter();
		}
		elseif (file_exists($path = static::path($bundle).'start'.EXT))
101
		{
102
			require $path;
103 104 105 106 107 108
		}

		// Each bundle may also have a "routes" file which is responsible for
		// registering the bundle's routes. This is kept separate from the
		// start script for reverse routing efficiency purposes.
		static::routes($bundle);
109

110
		Event::fire("laravel.started: {$bundle}");
111

112
		static::$started[] = strtolower($bundle);
113 114 115 116 117 118 119 120 121 122
	}

	/**
	 * Load the "routes" file for a given bundle.
	 *
	 * @param  string  $bundle
	 * @return void
	 */
	public static function routes($bundle)
	{
Taylor Otwell committed
123 124
		if (static::routed($bundle)) return;

Taylor Otwell committed
125 126
		$path = static::path($bundle).'routes'.EXT;

127 128 129
		// By setting the bundle property on the router the router knows what
		// value to replace the (:bundle) place-holder with when the bundle
		// routes are added, keeping the routes flexible.
Taylor Otwell committed
130
		Router::$bundle = static::option($bundle, 'handles');
131

Taylor Otwell committed
132
		if ( ! static::routed($bundle) and file_exists($path))
133
		{
Taylor Otwell committed
134 135
			static::$routed[] = $bundle;

136
			require $path;
137 138 139 140
		}
	}

	/**
141 142 143 144 145 146
	 * Register the auto-loading configuration for a bundle.
	 *
	 * @param  string  $bundle
	 * @param  array   $config
	 * @return void
	 */
147
	protected static function autoloads($bundle, $config)
148
	{
149
		$path = rtrim(Bundle::path($bundle), DS);
150

151
		foreach ($config['autoloads'] as $type => $mappings)
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
		{
			// When registering each type of mapping we'll replace the (:bundle)
			// place-holder with the path to the bundle's root directory, so
			// the developer may dryly register the mappings.
			$mappings = array_map(function($mapping) use ($path)
			{
				return str_replace('(:bundle)', $path, $mapping);

			}, $mappings);

			// Once the mappings are formatted, we will call the Autoloader
			// function matching the mapping type and pass in the array of
			// mappings so they can be registered and used.
			Autoloader::$type($mappings);
		}
	}

	/**
170 171 172 173 174 175 176 177 178 179 180
	 * Disable a bundle for the current request.
	 *
	 * @param  string  $bundle
	 * @return void
	 */
	public static function disable($bundle)
	{
		unset(static::$bundles[$bundle]);
	}

	/**
181
	 * Determine which bundle handles the given URI.
182
	 *
Taylor Otwell committed
183
	 * The default bundle is returned if no other bundle is assigned.
184
	 *
Phill Sparks committed
185
	 * @param  string  $uri
186
	 * @return string
187
	 */
188
	public static function handles($uri)
189
	{
190 191
		$uri = rtrim($uri, '/').'/';

192 193
		foreach (static::$bundles as $key => $value)
		{
194 195 196 197
			if (isset($value['handles']) and starts_with($uri, $value['handles'].'/'))
			{
				return $key;
			}
198
		}
199

200
		return DEFAULT_BUNDLE;
201 202 203 204 205 206 207 208 209 210
	}

	/**
	 * Deteremine if a bundle exists within the bundles directory.
	 *
	 * @param  string  $bundle
	 * @return bool
	 */
	public static function exists($bundle)
	{
211
		return $bundle == DEFAULT_BUNDLE or in_array(strtolower($bundle), static::names());
212 213 214 215 216 217 218 219 220 221 222 223 224 225
	}

	/**
	 * Determine if a given bundle has been started for the request.
	 *
	 * @param  string  $bundle
	 * @return void
	 */
	public static function started($bundle)
	{
		return in_array(strtolower($bundle), static::$started);
	}

	/**
Taylor Otwell committed
226 227 228 229 230 231 232 233 234 235 236
	 * Determine if a given bundle has its routes file loaded.
	 *
	 * @param  string  $bundle
	 * @return void
	 */
	public static function routed($bundle)
	{
		return in_array(strtolower($bundle), static::$routed);
	}

	/**
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	 * Get the identifier prefix for the bundle.
	 *
	 * @param  string  $bundle
	 * @return string
	 */
	public static function prefix($bundle)
	{
		return ($bundle !== DEFAULT_BUNDLE) ? "{$bundle}::" : '';
	}

	/**
	 * Get the class prefix for a given bundle.
	 *
	 * @param  string  $bundle
	 * @return string
	 */
	public static function class_prefix($bundle)
	{
		return ($bundle !== DEFAULT_BUNDLE) ? Str::classify($bundle).'_' : '';
	}

	/**
	 * Return the root bundle path for a given bundle.
	 *
	 * <code>
	 *		// Returns the bundle path for the "admin" bundle
	 *		$path = Bundle::path('admin');
	 *
Taylor Otwell committed
265
	 *		// Returns the path('app') constant as the default bundle
266 267 268 269 270 271 272 273
	 *		$path = Bundle::path('application');
	 * </code>
	 *
	 * @param  string  $bundle
	 * @return string
	 */
	public static function path($bundle)
	{
274 275 276 277
		if (is_null($bundle) or $bundle === DEFAULT_BUNDLE)
		{
			return path('app');
		}
278
		elseif ($location = array_get(static::$bundles, $bundle.'.location'))
279
		{
280 281 282 283 284 285 286 287 288 289 290
			// If the bundle location starts with "path: ", we will assume that a raw
			// path has been specified and will simply return it. Otherwise, we'll
			// prepend the bundle directory path onto the location and return.
			if (starts_with($location, 'path: '))
			{
				return str_finish(substr($location, 6), DS);
			}
			else
			{
				return str_finish(path('bundle').$location, DS);
			}
291
		}
292 293 294 295 296 297 298 299 300 301
	}

	/**
	 * Return the root asset path for the given bundle.
	 *
	 * @param  string  $bundle
	 * @return string
	 */
	public static function assets($bundle)
	{
Taylor Otwell committed
302 303
		if (is_null($bundle)) return static::assets(DEFAULT_BUNDLE);

Colin Viebrock committed
304
		return ($bundle != DEFAULT_BUNDLE) ? "/bundles/{$bundle}/" : '/';
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	}

	/**
	 * Get the bundle name from a given identifier.
	 *
	 * <code>
	 *		// Returns "admin" as the bundle name for the identifier
	 *		$bundle = Bundle::name('admin::home.index');
	 * </code>
	 *
	 * @param  string  $identifier
	 * @return string
	 */
	public static function name($identifier)
	{
		list($bundle, $element) = static::parse($identifier);

		return $bundle;
	}

	/**
	 * Get the element name from a given identifier.
	 *
	 * <code>
	 *		// Returns "home.index" as the element name for the identifier
	 *		$bundle = Bundle::bundle('admin::home.index');
	 * </code>
	 *
	 * @param  string  $identifier
	 * @return string
	 */
	public static function element($identifier)
	{
		list($bundle, $element) = static::parse($identifier);

		return $element;
	}

	/**
	 * Reconstruct an identifier from a given bundle and element.
	 *
	 * <code>
	 *		// Returns "admin::home.index"
	 *		$identifier = Bundle::identifier('admin', 'home.index');
	 *
	 *		// Returns "home.index"
	 *		$identifier = Bundle::identifier('application', 'home.index');
	 * </code>
	 *
	 * @param  string  $bundle
	 * @param  string  $element
	 * @return string
	 */
	public static function identifier($bundle, $element)
	{
		return (is_null($bundle) or $bundle == DEFAULT_BUNDLE) ? $element : $bundle.'::'.$element;
	}

	/**
	 * Return the bundle name if it exists, else return the default bundle.
	 *
	 * @param  string  $bundle
	 * @return string
	 */
	public static function resolve($bundle)
	{
		return (static::exists($bundle)) ? $bundle : DEFAULT_BUNDLE;
	}

	/**
	 * Parse a element identifier and return the bundle name and element.
	 *
	 * <code>
	 *		// Returns array(null, 'admin.user')
	 *		$element = Bundle::parse('admin.user');
	 *
	 *		// Parses "admin::user" and returns array('admin', 'user')
	 *		$element = Bundle::parse('admin::user');
	 * </code>
	 *
	 * @param  string  $identifier
	 * @return array
	 */
	public static function parse($identifier)
	{
		// The parsed elements are cached so we don't have to reparse them on each
391 392
		// subsequent request for the parsed element. So if we've already parsed
		// the given element, we'll just return the cached copy as the value.
393 394 395 396 397 398 399 400 401 402 403
		if (isset(static::$elements[$identifier]))
		{
			return static::$elements[$identifier];
		}

		if (strpos($identifier, '::') !== false)
		{
			$element = explode('::', strtolower($identifier));
		}
		// If no bundle is in the identifier, we will insert the default bundle
		// since classes like Config and Lang organize their items by bundle.
404
		// The application folder essentially behaves as a default bundle.
405 406 407 408 409 410 411 412 413
		else
		{
			$element = array(DEFAULT_BUNDLE, strtolower($identifier));
		}

		return static::$elements[$identifier] = $element;
	}

	/**
414 415 416
	 * Get the information for a given bundle.
	 *
	 * @param  string  $bundle
417
	 * @return object
418 419 420
	 */
	public static function get($bundle)
	{
421
		return array_get(static::$bundles, $bundle);
422 423 424
	}

	/**
Taylor Otwell committed
425 426 427 428
	 * Get an option for a given bundle.
	 *
	 * @param  string  $bundle
	 * @param  string  $option
429
	 * @param  mixed   $default
Taylor Otwell committed
430 431
	 * @return mixed
	 */
432
	public static function option($bundle, $option, $default = null)
Taylor Otwell committed
433 434 435
	{
		$bundle = static::get($bundle);

436 437 438 439 440 441
		if (is_null($bundle))
		{
			return value($default);
		}

		return array_get($bundle, $option, $default);
Taylor Otwell committed
442 443 444
	}

	/**
Taylor Otwell committed
445
	 * Get all of the installed bundles for the application.
446 447 448 449 450
	 *
	 * @return array
	 */
	public static function all()
	{
Taylor Otwell committed
451 452 453 454 455 456 457 458 459 460
		return static::$bundles;
	}

	/**
	 * Get all of the installed bundle names.
	 *
	 * @return array
	 */
	public static function names()
	{
461
		return array_keys(static::$bundles);
462 463 464
	}

}