/** * Receives events generated in the models and dispatches them to a events-manager if available * Notify the behaviors that are listening in the model * * @param string $eventName * @param \Phalcon\Mvc\CollectionInterface $model * @return mixed * @throws Exception */ public function notifyEvent($eventName, $model) { if (is_string($eventName) === false || is_object($model) === false || $model instanceof CollectionInterface === false) { throw new Exception('Invalid parameter type.'); } //Dispatch events to the global events manager if (is_object($this->_eventsManager) === true) { $status = $this->_eventsManager->fire('collection:' . $eventName, $model); if ($status === false) { return false; } } //A model can have a specific events manager if (is_array($this->_customEventsManager) === true) { $entityName = strtolower(get_class($model)); if (isset($this->_customEventsManager[$entityName]) === true) { $status = $this->_customEventsManager[$entityName]->fire('collection:' . $eventName, $model); } } return $status; }
/** * Dispatch a event to the listeners and behaviors * This method expects that the endpoint listeners/behaviors returns true * meaning that a least one is implemented * * @param \Phalcon\Mvc\ModelInterface $model * @param string $eventName * @param array $data * @return mixed * @throws Exception */ public function missingMethod($model, $eventName, $data) { if (is_object($model) === false || $model instanceof ModelInterface === false || is_string($eventName) === false || is_array($data) === false) { throw new Exception('Invalid parameter type.'); } if (is_array($this->_behaviors) === true) { $entityName = strtolower(get_class($model)); if (isset($this->_behaviors[$entityName]) === true) { //Notify all the events on the behavior foreach ($this->_behaviors[$entityName] as $behavior) { $result = $behavior->missingMethod($model, $eventName, $data); if (is_null($result) === false) { return $result; } } } } //Dispatch events to the global events manager if (is_object($this->_eventsManager) === true) { return $this->_eventsManager->fire('model:' . $eventName, $model, $data); } return null; }
/** * Handle the command-line arguments. * * * <code> * $arguments = array( * 'task' => 'taskname', * 'action' => 'action', * 'params' => array('parameter1', 'parameter2') * ); * $console->handle($arguments); * </code> * * @param array $arguments * @return mixed * @throws Exception */ public function handle($arguments = null) { /* Type check */ if (is_null($arguments) === true) { $arguments = array(); } elseif (is_array($arguments) === false) { throw new Exception('Invalid parameter type.'); } if (is_object($this->_dependencyInjector) === false) { throw new Exception('A dependency injection object is required to access internal services'); } $router = $this->_dependencyInjector->getShared('router'); $router->handle($arguments); $moduleName = $router->getModuleName(); if (isset($moduleName) === true) { //Event: console:beforeStartModule if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('console:beforeStartModule', $this, $moduleName) === false) { return false; } } //Validate module structure if (is_array($this->_modules) === false || isset($this->_modules[$moduleName]) === false) { throw new Exception('Module \'' . $moduleName . '\' isn\'t registered in the console container'); } if (is_array($this->_modules[$moduleName]) === false) { throw new Exception('Invalid module definition path'); } //Require ['path'] if (isset($this->_modules[$moduleName]['path']) === true) { if (file_exists($this->_modules[$moduleName]['path']) === true) { require $this->_modules[$moduleName]['path']; } else { throw new Exception('Module definition path \'' . $this->_modules[$moduleName]['path'] . '" doesn\'t exist'); } } //Get class name if (isset($this->_modules[$moduleName]['className']) === true) { $className = $this->_modules[$moduleName]['className']; } else { $className = 'Module'; } //Prepare $moduleObject $moduleObject = $this->_dependencyInjector->get($className); $moduleObject->registerAutoloaders(); $moduleObject->registerServices($this->_dependencyInjector); //Event: console:afterStartModule if (is_object($this->_eventsManager) === true) { $this->_moduleObject = $moduleObject; if ($this->_eventsManager->fire('console:afterStartModule', $this, $moduleName) === false) { return false; } } } //Get route $taskName = $router->getTaskName(); $actionName = $router->getActionName(); $params = $router->getParams(); //Get dispatcher $dispatcher = $this->_dependencyInjector->getShared('dispatcher'); if (is_object($dispatcher) === false || $dispatcher instanceof DispatcherInterface === false) { throw new Exception('Dispatcher service is not available.'); } //Set route $dispatcher->setTaskName($taskName); $dispatcher->setActionName($actionName); $dispatcher->setParams($params); //Event: console:beforeHandleTask if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('console:beforeHandleTask', $this, $dispatcher) === false) { return false; } } //Dispatch $task = $dispatcher->dispatch(); if (is_object($this->_eventsManager) === true) { $this->_eventsManager->fire('console:afterHandleTask', $this, $task); } return $task; }
/** * Dispatches a handle action taking into account the routing parameters * * @return object|boolean */ public function dispatch() { if (is_object($this->_dependencyInjector) === false) { $this->_throwDispatchException('A dependency injection container is required to access related dispatching services', self::EXCEPTION_NO_DI); return false; } if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('dispatch:beforeDispatchLoop', $this) === false) { return false; } } $numberDispatches = 0; $this->_finished = false; $handler = null; while (true) { //Loop until finished is false if ($this->_finished === true) { break; } ++$numberDispatches; //Throw an exception after 256 consecutive forwards if ($numberDispatches >= 256) { $this->_throwDispatchException('Dispatcher has detected a cyclic routing causing stability problems', self::EXCEPTION_CYCLIC_ROUTING); break; } $this->_finished = true; //If the current namespace is null we use the set in $this->_defaultNamespace if (is_null($this->_namespaceName) === true) { $this->_namespaceName = $this->_defaultNamespace; } //If the handler is null we use the set in $this->_defaultHandler if (is_null($this->_handlerName) === true) { $this->_handlerName = $this->_defaultHandler; } //If the action is null we use the set in $this->_defaultAction if (is_null($this->_actionName) === true) { $this->_actionName = $this->_defaultAction; } //Calling beforeDispatch if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('dispatch:beforeDispatch', $this) === false) { continue; } //Check if the user made a forward in the listener if ($this->_finished === false) { continue; } } //We don't camelize the classes if they are in namespaces $p = strpos($this->_handlerName, '\\'); if ($p === false) { $camelizedClass = Text::camelize($this->_handlerName); } elseif ($p === 0) { //@note this only handles one leading slash $camelizedClass = substr($this->_handlerName, strlen($this->_handlerName) + 1); } else { $camelizedClass = $this->_handlerName; } //Create the complete controller class name prepending the namespace if (is_null($this->_namespaceName) === false) { if (strrpos($this->_namespaceName, '\\') === strlen($this->_namespaceName) - 1) { $handlerClass = $this->_namespaceName . $camelizedClass . $this->_handlerSuffix; } else { $handlerClass = $this->_namespaceName . '\\' . $camelizedClass . $this->_handlerSuffix; } } else { $handlerClass = $camelizedClass . $this->_handlerSuffix; } //Handlers are retrieved as shared instances from the Service Container if ($this->_dependencyInjector->has($handlerClass) === false) { //Check using autoloading if (class_exists($handlerClass) === false) { if ($this->_throwDispatchException($handlerClass . ' handler class cannot be loaded', self::EXCEPTION_HANDLER_NOT_FOUND) === false) { if ($this->_finished === false) { continue; } } break; } } //Handlers must be only objects $handler = $this->_dependencyInjector->getShared($handlerClass); if (is_object($handler) === false) { if ($this->_throwDispatchException('Invalid handler returned from the services container', self::EXCEPTION_INVALID_HANDLER) === false) { if ($this->_finished === false) { continue; } } break; } //If the object was recently created in the DI we initialize it $wasFresh = $this->_dependencyInjector->wasFreshInstance(); $this->_activeHandler = $handler; //Check if the method exists in the handler $actionMethod = $this->_actionName . $this->_actionSuffix; if (method_exists($handler, $actionMethod) === false) { //Call beforeNotFoundAction if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('dispatch:beforeNotFoundAction', $this) === false) { continue; } if ($this->_finished === false) { continue; } } if ($this->_throwDispatchException('Action \'' . $this->_actionName . '\' was not found on handler \'' . $this->_handlerName . '\'', self::EXCEPTION_ACTION_NOT_FOUND) === false) { if ($this->_finished === false) { continue; } } break; } //Calling beforeExecuteRoute if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('dispatch:beforeExecuteRoute', $this) === false) { continue; } //Check if the user made a forward in the listener if ($this->_finished === false) { continue; } } //Calling beforeExecuteRoute as callback and event if (method_exists($handler, 'beforeExecuteRoute') === true) { if ($handler->beforeExecuteRoute($this) === false) { continue; } //Check if the user made a forward in the listener if ($this->_finished === false) { continue; } } //Check if params is an array if (is_array($this->_params) === false) { if ($this->_throwDispatchException('Action parameters must be an Array', self::EXCEPTION_INVALID_PARAMS) === false) { if ($this->_finished === false) { continue; } } break; } //Call the 'initialize' method just once per request if ($wasFresh === true) { if (method_exists($handler, 'initialize') === true) { $handler->initialize(); } } //Call the method with/without exceptions if an events manager is present if (is_object($this->_eventsManager) === true) { try { //Call the method allowing exceptions $m = new ReflectionMethod($handler, $actionMethod); $value = $m->invokeArgs($handler, $this->_params); } catch (\Exception $exception) { //Copy the exception to rethrow it later if needed //Try to handle the exception if ($this->_handleException($exception) === false) { if ($this->_finished === false) { continue; } } else { //Exception wasn't handled, rethrow it throw new Exception($exception); } } //Update the latest value produced by the latest handler $this->_returnedValue = $value; } else { //Call the method handling exceptions as normal $this->_returnedValue = call_user_func_array(array($handler, $actionMethod), $this->_params); } $this->_lastHandler = $handler; //Calling afterExecuteRoute if (is_object($this->_eventsManager) === true) { if ($this->_eventsManager->fire('dispatch:afterExecuteRoute', $this) === false) { continue; } if ($this->_finished === false) { continue; } //Calling afetDispatch $this->_eventsManager->fire('dispatch:afterDispatch', $this); } //Calling afterExecuteRoute as callback and event if (method_exists($handler, 'afterExecuteRoute') === true) { if ($handler->afterExecuteRoute($this, $this->_returnedValue) === false) { continue; } if ($this->_finished === false) { continue; } } } //Call afterDispatchLoop if (is_object($this->_eventsManager) === true) { $this->_eventsManager->fire('dispatch:afterDispatchLoop', $this); } return $handler; }