Completed
Pull Request — master (#7)
by Markus
06:25
created

Dispatcher::moduleExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
// +---------------------------------------------------------------------------+
4
// | This file is part of the Agavi package.                                   |
5
// | Copyright (c) 2005-2011 the Agavi Project.                                |
6
// | Based on the Mojavi3 MVC Framework, Copyright (c) 2003-2005 Sean Kerr.    |
7
// |                                                                           |
8
// | For the full copyright and license information, please view the LICENSE   |
9
// | file that was distributed with this source code. You can also view the    |
10
// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
11
// |   vi: set noexpandtab:                                                    |
12
// |   Local Variables:                                                        |
13
// |   indent-tabs-mode: t                                                     |
14
// |   End:                                                                    |
15
// +---------------------------------------------------------------------------+
16
17
namespace Agavi\Dispatcher;
18
19
use Agavi\Controller\Controller;
20
use Agavi\Config\Config;
21
use Agavi\Config\ConfigCache;
22
use Agavi\Exception\AgaviException;
23
use Agavi\Exception\ClassNotFoundException;
24
use Agavi\Exception\FileNotFoundException;
25
use Agavi\Filter\FilterChain;
26
use Agavi\Filter\Filter;
27
use Agavi\Request\RequestDataHolder;
28
use Agavi\Response\Response;
29
use Agavi\Util\ParameterHolder;
30
use Agavi\Exception\DispatcherException;
31
use Agavi\Core\Context;
32
use Agavi\Exception\DisabledModuleException;
33
use Agavi\Util\Toolkit;
34
use Agavi\View\View;
35
36
/**
37
 * Dispatcher directs application flow.
38
 *
39
 * @package    agavi
40
 * @subpackage Dispatcher
41
 *
42
 * @author     Sean Kerr <[email protected]>
43
 * @author     David Zülke <[email protected]>
44
 * @copyright  Authors
45
 * @copyright  The Agavi Project
46
 *
47
 * @since      0.9.0
48
 *
49
 * @version    $Id$
50
 */
51
class Dispatcher extends ParameterHolder
52
{
53
	/**
54
	 * @var        int The number of execution containers run so far.
55
	 */
56
	protected $numExecutions = 0;
57
	
58
	/**
59
	 * @var        Context An Context instance.
60
	 */
61
	protected $context = null;
62
	
63
	/**
64
	 * @var        Response The global response.
65
	 */
66
	protected $response = null;
67
	
68
	/**
69
	 * @var        FilterChain The global filter chain.
70
	 */
71
	protected $filterChain = null;
72
	
73
	/**
74
	 * @var        array An array of filter instances for reuse.
75
	 */
76
	protected $filters = array(
77
		'global' => array(),
78
		'controller' => array(
79
			'*' => null
80
		),
81
		'dispatch' => null,
82
		'execution' => null,
83
		'security' => null
84
	);
85
	
86
	/**
87
	 * @var        string The default Output Type.
88
	 */
89
	protected $defaultOutputType = null;
90
	
91
	/**
92
	 * @var        array An array of registered Output Types.
93
	 */
94
	protected $outputTypes = array();
95
	
96
	/**
97
	 * @var        array Ref to the request data object from the request.
98
	 */
99
	private $requestData = null;
100
	
101
	/**
102
	 * Increment the execution counter.
103
	 * Will throw an exception if the maximum amount of runs is exceeded.
104
	 *
105
	 * @throws     DispatcherException If too many execution runs were made.
106
	 *
107
	 * @author     David Zülke <[email protected]>
108
	 * @since      0.11.0
109
	 */
110
	public function countExecution()
111
	{
112
		$maxExecutions = $this->getParameter('max_executions');
113
		
114
		if(++$this->numExecutions > $maxExecutions && $maxExecutions > 0) {
115
			throw new DispatcherException('Too many execution runs have been detected for this Context.');
116
		}
117
	}
118
	
119
	/**
120
	 * Create and initialize new execution container instance.
121
	 *
122
	 * @param      string                 $moduleName    The name of the module.
123
	 * @param      string                 $controllerName    The name of the controller.
124
	 * @param      RequestDataHolder      $arguments     A RequestDataHolder with additional
125
	 *                                    request arguments.
126
	 * @param      string                 $outputType    Optional name of an initial output type
127
	 *                                    to set.
128
	 * @param      string                 $requestMethod Optional name of the request method to
129
	 *                                    be used in this container.
130
	 *
131
	 * @return     ExecutionContainer A new execution container instance,
132
	 *                                     fully initialized.
133
	 *
134
	 * @author     David Zülke <[email protected]>
135
	 * @since      0.11.0
136
	 */
137
	public function createExecutionContainer($moduleName = null, $controllerName = null, RequestDataHolder $arguments = null, $outputType = null, $requestMethod = null)
138
	{
139
		// create a new execution container
140
        /** @var ExecutionContainer $container */
141
		$container = $this->context->createInstanceFor('execution_container');
142
		$container->setModuleName($moduleName);
143
		$container->setControllerName($controllerName);
144
		$container->setRequestData($this->requestData);
0 ignored issues
show
Documentation introduced by
$this->requestData is of type array, but the function expects a object<Agavi\Request\RequestDataHolder>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
145
		if($arguments !== null) {
146
			$container->setArguments($arguments);
147
		}
148
		$container->setOutputType($this->context->getDispatcher()->getOutputType($outputType));
149
		if($requestMethod === null) {
150
			$requestMethod = $this->context->getRequest()->getMethod();
151
		}
152
		$container->setRequestMethod($requestMethod);
153
		return $container;
154
	}
155
	
156
	/**
157
	 * Initialize a module and load its autoload, module config etc.
158
	 *
159
	 * @param      string $moduleName The name of the module to initialize.
160
	 *
161
	 * @author     Felix Gilcher <[email protected]>
162
	 * @since      1.0.0
163
	 */
164
	public function initializeModule($moduleName)
165
	{
166
		$lowerModuleName = strtolower($moduleName);
167
		
168
		if(null === Config::get('modules.' . $lowerModuleName . '.enabled')) {
169
			// set some defaults first
170
			Config::fromArray(array(
171
				'modules.' . $lowerModuleName . '.agavi.controller.path' => '%core.module_dir%/${moduleName}/controllers/${controllerName}Controller.class.php',
172
				'modules.' . $lowerModuleName . '.agavi.cache.path' => '%core.module_dir%/${moduleName}/cache/${controllerName}.xml',
173
				'modules.' . $lowerModuleName . '.agavi.template.directory' => '%core.module_dir%/${module}/templates',
174
				'modules.' . $lowerModuleName . '.agavi.validate.path' => '%core.module_dir%/${moduleName}/validate/${controllerName}.xml',
175
				'modules.' . $lowerModuleName . '.agavi.view.path' => '%core.module_dir%/${moduleName}/views/${viewName}View.class.php',
176
				'modules.' . $lowerModuleName . '.agavi.view.name' => '${controllerName}${viewName}',
177
			));
178
			// include the module configuration
179
			// loaded only once due to the way load() (former import()) works
180
			if(is_readable(Config::get('core.module_dir') . '/' . $moduleName . '/config/module.xml')) {
181
				include_once(ConfigCache::checkConfig(Config::get('core.module_dir') . '/' . $moduleName . '/config/module.xml'));
182
			} else {
183
				Config::set('modules.' . $lowerModuleName . '.enabled', true);
184
			}
185
			
186
			$moduleAutoload = Config::get('core.module_dir') . '/' . $moduleName . '/config/autoload.xml';
187
			if(is_readable($moduleAutoload)) {
188
				ConfigCache::load($moduleAutoload);
189
			}
190
			
191
			if(Config::get('modules.' . $lowerModuleName . '.enabled')) {
192
				$moduleConfigHandlers = Config::get('core.module_dir') . '/' . $moduleName . '/config/config_handlers.xml';
193
				if(is_readable($moduleConfigHandlers)) {
194
					ConfigCache::addConfigHandlersFile($moduleConfigHandlers);
195
				}
196
			}
197
		}
198
		
199
		if(!Config::get('modules.' . $lowerModuleName . '.enabled')) {
200
			throw new DisabledModuleException(sprintf('The module "%1$s" is disabled.', $moduleName));
201
		}
202
		
203
		// check for a module config.php
204
		$moduleConfig = Config::get('core.module_dir') . '/' . $moduleName . '/config.php';
205
		if(is_readable($moduleConfig)) {
206
			require_once($moduleConfig);
207
		}
208
	}
209
	
210
	/**
211
	 * Dispatch a request
212
	 *
213
	 * @param      RequestDataHolder  $arguments An optional request data holder object
214
	 *                                with additional request data.
215
	 * @param      ExecutionContainer $container An optional execution container that,
216
	 *                                if given, will be executed right away,
217
	 *                                skipping routing execution.
218
	 *
219
	 * @return     Response The response produced during this dispatch call.
220
	 *
221
	 * @author     David Zülke <[email protected]>
222
	 * @since      0.9.0
223
	 */
224
	public function dispatch(RequestDataHolder $arguments = null, ExecutionContainer $container = null)
225
	{
226
		try {
227
			
228
			$rq = $this->context->getRequest();
229
			$rd = $rq->getRequestData();
230
			
231
			if($container === null) {
232
				// match routes and assign returned initial execution container
233
				$container = $this->context->getRouting()->execute();
234
			}
235
			
236
			if($container instanceof ExecutionContainer) {
237
				// merge in any arguments given. they need to have precedence over what the routing found
238
				if($arguments !== null) {
239
					$rd->merge($arguments);
240
				}
241
				
242
				// next, we have to see if the routing did anything useful, i.e. whether or not it was enabled.
243
				$moduleName = $container->getModuleName();
244
				$controllerName = $container->getControllerName();
245
				if(!$moduleName) {
246
					// no module has been specified; that means the routing did not run, as it would otherwise have the 404 controller's module name
247
					
248
					// lets see if our request data has values for module and controller
249
					$ma = $rq->getParameter('module_accessor');
250
					$aa = $rq->getParameter('controller_accessor');
251
					if($rd->hasParameter($ma) && $rd->hasParameter($aa)) {
252
						// yup. grab those
253
						$moduleName = $rd->getParameter($ma);
254
						$controllerName = $rd->getParameter($aa);
255
					} else {
256
						// nope. then its time for the default controller
257
						$moduleName = Config::get('controllers.default_module');
258
						$controllerName = Config::get('controllers.default_controller');
259
					}
260
					
261
                    // so by now we hopefully have something reasonable for module and controller names - let's set them on the container
262
					$container->setModuleName($moduleName);
263
					$container->setControllerName($controllerName);
264
				}
265
				
266
				if(!Config::get('core.available', false)) {
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
267
					$container = $container->createSystemControllerForwardContainer('unavailable');
268
				}
269
				
270
				// create a new filter chain
271
				/** @var FilterChain $filterChain */
272
				$filterChain = $this->getFilterChain();
273
				
274
				$this->loadFilters($filterChain, 'global');
275
				
276
				// register the dispatch filter
277
				$filterChain->register($this->filters['dispatch'], 'agavi_dispatch_filter');
278
				
279
				// go, go, go!
280
				$filterChain->execute($container);
281
				
282
				$response = $container->getResponse();
283
			} elseif($container instanceof Response) {
284
				// the routing returned a response!
285
				$response = $container;
286
				// set $container to null so Exception::render() won't think it is a container if an exception happens later!
287
				$container = null;
288
			} else {
289
				throw new AgaviException('AgaviRouting::execute() returned neither ExecutionContainer nor Response object.');
290
			}
291
			$response->merge($this->response);
292
			
293
			if($this->getParameter('send_response')) {
294
				$response->send();
295
			}
296
			
297
			return $response;
298
			
299
		} catch(\Exception $e) {
300
			AgaviException::render($e, $this->context, $container);
0 ignored issues
show
Bug introduced by
It seems like $container defined by $this->context->getRouting()->execute() on line 233 can also be of type object<Agavi\Response\Response>; however, Agavi\Exception\AgaviException::render() does only seem to accept null|object<Agavi\Dispatcher\ExecutionContainer>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
301
		}
302
	}
303
	
304
	/**
305
	 * Get the global response instance.
306
	 *
307
	 * @return     Response The global response.
308
	 *
309
	 * @author     David Zülke <[email protected]>
310
	 * @since      0.11.0
311
	 */
312
	public function getGlobalResponse()
313
	{
314
		return $this->response;
315
	}
316
	
317
	
318
	/**
319
	 * Indicates whether or not a module has a specific controller file.
320
	 * 
321
	 * Please note that this is only a cursory check and does not 
322
	 * check whether the file actually contains the proper class
323
	 *
324
	 * @param      string $moduleName A module name.
325
	 * @param      string $controllerName An controller name.
326
	 *
327
	 * @return     mixed  the path to the controller file if the controller file
328
	 *                    exists and is readable, false in any other case
329
	 *
330
	 * @author     Felix Gilcher <[email protected]>
331
	 * @since      1.0.0
332
	 */
333 View Code Duplication
	public function checkControllerFile($moduleName, $controllerName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
334
	{
335
		$this->initializeModule($moduleName);
336
		
337
		$controllerName = Toolkit::canonicalName($controllerName);
338
		$file = Toolkit::evaluateModuleDirective(
339
			$moduleName,
340
			'agavi.controller.path',
341
			array(
342
				'moduleName' => $moduleName,
343
				'controllerName' => $controllerName,
344
			)
345
		);
346
		
347
		if(is_readable($file) && substr($controllerName, 0, 1) !== '/') {
348
			return $file;
349
		}
350
		
351
		return false;
352
	}
353
	
354
	/**
355
	 * Retrieve an Controller implementation instance.
356
	 *
357
	 * @param      string $moduleName A module name.
358
	 * @param      string $controllerName An controller name.
359
	 *
360
	 * @return     Controller An Controller implementation instance
361
	 *
362
	 * @throws     FileNotFoundException|ClassNotFoundException if the controller could not be found.
363
	 *
364
	 * @author     Sean Kerr <[email protected]>
365
	 * @author     Mike Vincent <[email protected]>
366
	 * @author     David Zülke <[email protected]>
367
	 * @since      0.9.0
368
	 */
369
	public function createControllerInstance($moduleName, $controllerName)
370
	{
371
		$this->initializeModule($moduleName);
372
		
373
		$controllerName = Toolkit::canonicalName($controllerName);
374
		$longControllerName = str_replace('/', '_', $controllerName);
375
		
376
		$class = $moduleName . '_' . $longControllerName . 'Controller';
377
		
378 View Code Duplication
		if(!class_exists($class)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
			if(false !== ($file = $this->checkControllerFile($moduleName, $controllerName))) {
380
				require($file);
381
			} else {
382
				throw new FileNotFoundException(sprintf('Could not find file for Controller "%s" in Module "%s".', $controllerName, $moduleName));
383
			}
384
			
385
			if(!class_exists($class, false)) {
386
				throw new ClassNotFoundException(sprintf('Failed to instantiate Controller "%s" in Module "%s" because file "%s" does not contain class "%s".', $controllerName, $moduleName, $file, $class));
387
			}
388
		} 
389
		
390
		return new $class();
391
	}
392
393
	/**
394
	 * Retrieve the current application context.
395
	 *
396
	 * @return     Context An Context instance.
397
	 *
398
	 * @author     Sean Kerr <[email protected]>
399
	 * @since      0.9.0
400
	 */
401
	public final function getContext()
0 ignored issues
show
Coding Style introduced by
As per PSR2, final should precede the visibility keyword.
Loading history...
402
	{
403
		return $this->context;
404
	}
405
406
407
	
408
	/**
409
	 * Indicates whether or not a module has a specific view file.
410
	 * 
411
	 * Please note that this is only a cursory check and does not 
412
	 * check whether the file actually contains the proper class
413
	 *
414
	 * @param      string $moduleName A module name.
415
	 * @param      string $viewName A view name.
416
	 *
417
	 * @return     mixed  the path to the view file if the view file 
418
	 *                    exists and is readable, false in any other case
419
	 * 
420
	 * @author     Felix Gilcher <[email protected]>
421
	 * @since      1.0.0
422
	 */
423 View Code Duplication
	public function checkViewFile($moduleName, $viewName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
424
	{
425
		$this->initializeModule($moduleName);
426
		
427
		$viewName = Toolkit::canonicalName($viewName);
428
		$file = Toolkit::evaluateModuleDirective(
429
			$moduleName,
430
			'agavi.view.path',
431
			array(
432
				'moduleName' => $moduleName,
433
				'viewName' => $viewName,
434
			)
435
		);
436
		
437
		if(is_readable($file) && substr($viewName, 0, 1) !== '/') {
438
			return $file;
439
		}
440
		
441
		return false;
442
	}
443
	
444
	/**
445
	 * Retrieve a View implementation instance.
446
	 *
447
	 * @param      string $moduleName A module name.
448
	 * @param      string $viewName A view name.
449
	 *
450
	 * @return     View A View implementation instance,
451
	 *
452
	 * @throws     AgaviException if the view could not be found.
453
	 *
454
	 * @author     Sean Kerr <[email protected]>
455
	 * @author     Mike Vincent <[email protected]>
456
	 * @author     David Zülke <[email protected]>
457
	 * @since      0.9.0
458
	 */
459
	public function createViewInstance($moduleName, $viewName)
460
	{
461
		try {
462
			$this->initializeModule($moduleName);
463
		} catch(DisabledModuleException $e) {
464
			// views from disabled modules should be usable by definition
465
			// swallow
466
		}
467
		
468
		$viewName = Toolkit::canonicalName($viewName);
469
		$longViewName = str_replace('/', '_', $viewName);
470
		
471
		$class = $moduleName . '_' . $longViewName . 'View';
472
		
473 View Code Duplication
		if(!class_exists($class)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
474
			
475
			if(false !== ($file = $this->checkViewFile($moduleName, $viewName))) {
476
				require($file);
477
			} else {
478
				throw new FileNotFoundException(sprintf('Could not find file for View "%s" in Module "%s".', $viewName, $moduleName));
479
			}
480
			
481
			if(!class_exists($class, false)) {
482
				throw new ClassNotFoundException(sprintf('Failed to instantiate View "%s" in Module "%s" because file "%s" does not contain class "%s".', $viewName, $moduleName, $file, $class));
483
			}
484
		} 
485
		
486
		return new $class();
487
	}
488
489
	/**
490
	 * Constructor.
491
	 *
492
	 * @author     David Zülke <[email protected]>
493
	 * @since      0.11.0
494
	 */
495
	public function __construct()
496
	{
497
		parent::__construct();
498
		$this->setParameters(array(
499
			'max_executions' => 20,
500
			'send_response' => true,
501
		));
502
	}
503
	
504
	/**
505
	 * Initialize this Dispatcher.
506
	 *
507
	 * @param      Context $context A Context instance.
508
	 * @param      array   $parameters An array of initialization parameters.
509
	 *
510
	 * @author     David Zülke <[email protected]>
511
	 * @since      0.9.0
512
	 */
513
	public function initialize(Context $context, array $parameters = array())
514
	{
515
		$this->context = $context;
516
		
517
		$this->setParameters($parameters);
518
		
519
		$this->response = $this->context->createInstanceFor('response');
520
		
521
		$cfg = Config::get('core.config_dir') . '/output_types.xml';
522
		require(ConfigCache::checkConfig($cfg, $this->context->getName()));
523
		
524
		if(Config::get('core.use_security', false)) {
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
525
			$this->filters['security'] = $this->context->createInstanceFor('security_filter');
526
		}
527
		
528
		$this->filters['dispatch'] = $this->context->createInstanceFor('dispatch_filter');
529
		
530
		$this->filters['execution'] = $this->context->createInstanceFor('execution_filter');
531
	}
532
	
533
	/**
534
	 * Get a filter.
535
	 *
536
	 * @param      string $which The name of the filter list section.
537
	 *
538
	 * @return     Filter A filter instance, or null.
539
	 *
540
	 * @author     David Zülke <[email protected]>
541
	 * @since      0.11.0
542
	 */
543
	public function getFilter($which)
544
	{
545
		return (isset($this->filters[$which]) ? $this->filters[$which] : null);
546
	}
547
	
548
	/**
549
	 * Get the global filter chain.
550
	 *
551
	 * @return     FilterChain The global filter chain.
552
	 *
553
	 * @author     David Zülke <[email protected]>
554
	 * @since      1.1.0
555
	 */
556 View Code Duplication
	public function getFilterChain()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
557
	{
558
		if($this->filterChain === null) {
559
			$this->filterChain = $this->context->createInstanceFor('filter_chain');
560
			$this->filterChain->setType(FilterChain::TYPE_GLOBAL);
561
		}
562
		
563
		return $this->filterChain;
564
	}
565
	
566
	/**
567
	 * Load filters.
568
	 *
569
	 * @param      FilterChain $filterChain A FilterChain instance.
570
	 * @param      string      $which "global" or "controller".
571
	 * @param      string      $module A module name, or "*" for the generic config.
572
	 *
573
	 * @author     David Zülke <[email protected]>
574
	 * @since      0.11.0
575
	 */
576
	public function loadFilters(FilterChain $filterChain, $which = 'global', $module = null)
577
	{
578
		if($module === null) {
579
			$module = '*';
580
		}
581
		
582
		if(($which != 'global' && !isset($this->filters[$which][$module])) || $which == 'global' && $this->filters[$which] == null) {
583
			if($which == 'global') {
584
				$this->filters[$which] = array();
585
				$filters =& $this->filters[$which];
586 View Code Duplication
			} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
587
				$this->filters[$which][$module] = array();
588
				$filters =& $this->filters[$which][$module];
589
			}
590
			$config = ($module == '*' ? Config::get('core.config_dir') : Config::get('core.module_dir') . '/' . $module . '/config') . '/' . $which . '_filters.xml';
591
			if(is_readable($config)) {
592
				require(ConfigCache::checkConfig($config, $this->context->getName()));
593
			}
594 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
595
			if($which == 'global') {
596
				$filters =& $this->filters[$which];
597
			} else {
598
				$filters =& $this->filters[$which][$module];
599
			}
600
		}
601
		
602
		foreach($filters as $name => $filter) {
603
			$filterChain->register($filter, $name);
604
		}
605
	}
606
607
	/**
608
	 * Indicates whether or not a module has a specific model.
609
	 *
610
	 * @param      string $moduleName A module name.
611
	 * @param      string $modelName A model name.
612
	 *
613
	 * @return     bool true, if the model exists, otherwise false.
614
	 *
615
	 * @author     Sean Kerr <[email protected]>
616
	 * @since      0.9.0
617
	 */
618
	public function modelExists($moduleName, $modelName)
619
	{
620
		$modelName = Toolkit::canonicalName($modelName);
621
		$file = Config::get('core.module_dir') . '/' . $moduleName . '/models/' . $modelName .	'Model.class.php';
622
		return is_readable($file);
623
	}
624
625
	/**
626
	 * Indicates whether or not a module exists.
627
	 *
628
	 * @param      string $moduleName A module name.
629
	 *
630
	 * @return     bool true, if the module exists, otherwise false.
631
	 *
632
	 * @author     Sean Kerr <[email protected]>
633
	 * @since      0.9.0
634
	 */
635
	public function moduleExists($moduleName)
636
	{
637
		$file = Config::get('core.module_dir') . '/' . $moduleName . '/config/module.xml';
638
		return is_readable($file);
639
	}
640
641
	/**
642
	 * Do any necessary startup work after initialization.
643
	 *
644
	 * This method is not called directly after initialize().
645
	 *
646
	 * @author     David Zülke <[email protected]>
647
	 * @since      0.11.0
648
	 */
649
	public function startup()
650
	{
651
		// grab a pointer to the request data
652
		$this->requestData = $this->context->getRequest()->getRequestData();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->context->getRequest()->getRequestData() of type object<Agavi\Request\RequestDataHolder> is incompatible with the declared type array of property $requestData.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
653
	}
654
655
	/**
656
	 * Execute the shutdown procedure for this Dispatcher.
657
	 *
658
	 * @author     Sean Kerr <[email protected]>
659
	 * @since      0.9.0
660
	 */
661
	public function shutdown()
662
	{
663
	}
664
665
	/**
666
	 * Indicates whether or not a module has a specific controller.
667
	 *
668
	 * @param      string $moduleName A module name.
669
	 * @param      string $controllerName A view name.
670
	 *
671
	 * @return     bool true, if the controller exists, otherwise false.
672
	 *
673
	 * @author     David Zülke <[email protected]>
674
	 * @since      1.0.1
675
	 */
676
	public function controllerExists($moduleName, $controllerName)
677
	{
678
		return $this->checkControllerFile($moduleName, $controllerName) !== false;
679
	}
680
681
	/**
682
	 * Indicates whether or not a module has a specific view.
683
	 *
684
	 * @param      string $moduleName A module name.
685
	 * @param      string $viewName A view name.
686
	 *
687
	 * @return     bool true, if the view exists, otherwise false.
688
	 *
689
	 * @author     Sean Kerr <[email protected]>
690
	 * @since      0.9.0
691
	 */
692
	public function viewExists($moduleName, $viewName)
693
	{
694
		return $this->checkViewFile($moduleName, $viewName) !== false;
695
	}
696
	
697
	/**
698
	 * Retrieve an Output Type object
699
	 *
700
	 * @param      string $name The optional output type name.
701
	 *
702
	 * @return     OutputType An Output Type object.
703
	 *
704
	 * @author     David Zülke <[email protected]>
705
	 * @since      0.11.0
706
	 */
707 View Code Duplication
	public function getOutputType($name = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
708
	{
709
		if($name === null) {
710
			$name = $this->defaultOutputType;
711
		}
712
		if(isset($this->outputTypes[$name])) {
713
			return $this->outputTypes[$name];
714
		} else {
715
			throw new AgaviException('Output Type "' . $name . '" has not been configured.');
716
		}
717
	}
718
}
719
720
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...