_eventManager) { $this->_eventManager = new CakeEventManager(); $this->_eventManager->attach($this); $this->_attachFilters($this->_eventManager); } return $this->_eventManager; } /** * Returns the list of events this object listents to. * * @return array **/ public function implementedEvents() { return array( 'Dispatcher.before' => array( array('callable' => array($this, 'asset')), array('callable' => array($this, 'cached')), array('callable' => array($this, 'parseParams')), ) ); } /** * Attaches all event listeners for this dispatcher instance. Loads the * dispatcher filters from the configured locations. * * @param CakeEventManager $manager * @return void **/ protected function _attachFilters($manager) { $filters = Configure::read('Dispatcher.filters'); if (empty($filters)) { return; } foreach ($filters as $filter) { if (is_string($filter)) { $filter = array('callable' => $filter); } if (is_string($filter['callable'])) { list($plugin, $callable) = pluginSplit($filter['callable'], true); App::uses($callable, $plugin . 'Routing/Filter'); if (!class_exists($callable)) { throw new MissingDispatcherFilterException($callable); } $manager->attach(new $callable); } else { $on = strtolower($filter['on']); $options = array(); if (isset($filter['priority'])) { $options['priority'] = $filter['priority']; } $manager->attach($filter['callable'], 'Dispatcher.' . $on, $options); } } } /** * Dispatches and invokes given Request, handing over control to the involved controller. If the controller is set * to autoRender, via Controller::$autoRender, then Dispatcher will render the view. * * Actions in CakePHP can be any public method on a controller, that is not declared in Controller. If you * want controller methods to be public and in-accessible by URL, then prefix them with a `_`. * For example `public function _loadPosts() { }` would not be accessible via URL. Private and protected methods * are also not accessible via URL. * * If no controller of given name can be found, invoke() will throw an exception. * If the controller is found, and the action is not found an exception will be thrown. * * @param CakeRequest $request Request object to dispatch. * @param CakeResponse $response Response object to put the results of the dispatch into. * @param array $additionalParams Settings array ("bare", "return") which is melded with the GET and POST params * @return string|void if `$request['return']` is set then it returns response body, null otherwise * @throws MissingControllerException When the controller is missing. */ public function dispatch(CakeRequest $request, CakeResponse $response, $additionalParams = array()) { $beforeEvent = new CakeEvent('Dispatcher.before', $this, compact('request', 'response', 'additionalParams')); $this->getEventManager()->dispatch($beforeEvent); $request = $beforeEvent->data['request']; if ($beforeEvent->result instanceof CakeResponse) { if (isset($request->params['return'])) { return $response->body(); } $response->send(); return; } Router::setRequestInfo($request); $controller = $this->_getController($request, $response); if (!($controller instanceof Controller)) { throw new MissingControllerException(array( 'class' => Inflector::camelize($request->params['controller']) . 'Controller', 'plugin' => empty($request->params['plugin']) ? null : Inflector::camelize($request->params['plugin']) )); } $response = $this->_invoke($controller, $request, $response); if (isset($request->params['return'])) { return $response->body(); } $afterEvent = new CakeEvent('Dispatcher.after', $this, compact('request', 'response')); $this->getEventManager()->dispatch($afterEvent); $afterEvent->data['response']->send(); } /** * Initializes the components and models a controller will be using. * Triggers the controller action, and invokes the rendering if Controller::$autoRender is true and echo's the output. * Otherwise the return value of the controller action are returned. * * @param Controller $controller Controller to invoke * @param CakeRequest $request The request object to invoke the controller for. * @param CakeResponse $response The response object to receive the output * @return CakeResponse te resulting response object */ protected function _invoke(Controller $controller, CakeRequest $request, CakeResponse $response) { $controller->constructClasses(); $controller->startupProcess(); $render = true; $result = $controller->invokeAction($request); if ($result instanceof CakeResponse) { $render = false; $response = $result; } if ($render && $controller->autoRender) { $response = $controller->render(); } elseif ($response->body() === null) { $response->body($result); } $controller->shutdownProcess(); return $response; } /** * Applies Routing and additionalParameters to the request to be dispatched. * If Routes have not been loaded they will be loaded, and app/Config/routes.php will be run. * * @param CakeEvent $event containing the request, response and additional params * @return void */ public function parseParams($event) { $request = $event->data['request']; if (count(Router::$routes) == 0) { $namedExpressions = Router::getNamedExpressions(); extract($namedExpressions); $this->_loadRoutes(); } $params = Router::parse($request->url); $request->addParams($params); if (!empty($event->data['additionalParams'])) { $request->addParams($event->data['additionalParams']); } } /** * Get controller to use, either plugin controller or application controller * * @param CakeRequest $request Request object * @param CakeResponse $response Response for the controller. * @return mixed name of controller if not loaded, or object if loaded */ protected function _getController($request, $response) { $ctrlClass = $this->_loadController($request); if (!$ctrlClass) { return false; } $reflection = new ReflectionClass($ctrlClass); if ($reflection->isAbstract() || $reflection->isInterface()) { return false; } return $reflection->newInstance($request, $response); } /** * Load controller and return controller classname * * @param CakeRequest $request * @return string|bool Name of controller class name */ protected function _loadController($request) { $pluginName = $pluginPath = $controller = null; if (!empty($request->params['plugin'])) { $pluginName = $controller = Inflector::camelize($request->params['plugin']); $pluginPath = $pluginName . '.'; } if (!empty($request->params['controller'])) { $controller = Inflector::camelize($request->params['controller']); } if ($pluginPath . $controller) { $class = $controller . 'Controller'; App::uses('AppController', 'Controller'); App::uses($pluginName . 'AppController', $pluginPath . 'Controller'); App::uses($class, $pluginPath . 'Controller'); if (class_exists($class)) { return $class; } } return false; } /** * Loads route configuration * * @return void */ protected function _loadRoutes() { include APP . 'Config' . DS . 'routes.php'; } /** * Checks whether the response was cached and set the body accordingly. * * @param CakeEvent $event containing the request and response object * @return CakeResponse with cached content if found, null otherwise */ public function cached($event) { $path = $event->data['request']->here(); if (Configure::read('Cache.check') === true) { if ($path == '/') { $path = 'home'; } $path = strtolower(Inflector::slug($path)); $filename = CACHE . 'views' . DS . $path . '.php'; if (!file_exists($filename)) { $filename = CACHE . 'views' . DS . $path . '_index.php'; } if (file_exists($filename)) { $controller = null; $view = new View($controller); $result = $view->renderCache($filename, microtime(true)); if ($result !== false) { $event->data['response']->body($result); return $event->data['response']; } } } } /** * Checks if a requested asset exists and sends it to the browser * * @param CakeEvent $event containing the request and response object * @return CakeResponse if the client is requesting a recognized asset, null otherwise */ public function asset($event) { $url = $event->data['request']->url; $response = $event->data['response']; if (strpos($url, '..') !== false || strpos($url, '.') === false) { return; } $filters = Configure::read('Asset.filter'); $isCss = ( strpos($url, 'ccss/') === 0 || preg_match('#^(theme/([^/]+)/ccss/)|(([^/]+)(?statusCode(404); $event->stopPropagation(); return $response; } elseif ($isCss) { include WWW_ROOT . DS . $filters['css']; $event->stopPropagation(); return $response; } elseif ($isJs) { include WWW_ROOT . DS . $filters['js']; $event->stopPropagation(); return $response; } $pathSegments = explode('.', $url); $ext = array_pop($pathSegments); $parts = explode('/', $url); $assetFile = null; if ($parts[0] === 'theme') { $themeName = $parts[1]; unset($parts[0], $parts[1]); $fileFragment = urldecode(implode(DS, $parts)); $path = App::themePath($themeName) . 'webroot' . DS; if (file_exists($path . $fileFragment)) { $assetFile = $path . $fileFragment; } } else { $plugin = Inflector::camelize($parts[0]); if (CakePlugin::loaded($plugin)) { unset($parts[0]); $fileFragment = urldecode(implode(DS, $parts)); $pluginWebroot = CakePlugin::path($plugin) . 'webroot' . DS; if (file_exists($pluginWebroot . $fileFragment)) { $assetFile = $pluginWebroot . $fileFragment; } } } if ($assetFile !== null) { $event->stopPropagation(); $this->_deliverAsset($response, $assetFile, $ext); return $response; } } /** * Sends an asset file to the client * * @param CakeResponse $response The response object to use. * @param string $assetFile Path to the asset file in the file system * @param string $ext The extension of the file to determine its mime type * @return void */ protected function _deliverAsset(CakeResponse $response, $assetFile, $ext) { ob_start(); $compressionEnabled = Configure::read('Asset.compress') && $response->compress(); if ($response->type($ext) == $ext) { $contentType = 'application/octet-stream'; $agent = env('HTTP_USER_AGENT'); if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent) || preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) { $contentType = 'application/octetstream'; } $response->type($contentType); } if (!$compressionEnabled) { $response->header('Content-Length', filesize($assetFile)); } $response->cache(filemtime($assetFile)); $response->send(); ob_clean(); if ($ext === 'css' || $ext === 'js') { include $assetFile; } else { readfile($assetFile); } if ($compressionEnabled) { ob_end_flush(); } } }