From 2e1eec050b6067ca43428bec3bab80ca6615d14f Mon Sep 17 00:00:00 2001 From: Mohamed Karam Date: Tue, 18 Jul 2017 00:02:46 +0300 Subject: [PATCH] Lib api (#20) * Added route function * Added ApiRouter class * Fixing phpcs errors * Fixed coding standard issues, wrong namespace * Added service provider for ApiRouter * Changed the name of getRouter to getApiRouter * Fixed some phpcs issues * Codestyle * Code style part 2 * Changed the delimiter of controller function * Modified parseRoute method to parse the controller to be an array of class and method * Fixed code standard issues * Code style * Added dispatch function, Edited parseRoute function * Added request method to the route parsing function, removed some unnecessary code and called dispatch function in doExecute function * Code style * Added request variables to the input object * Type safe comparison * Removed the API component path constant * Update ApiApplication.php --- .../src/CMS/Application/ApiApplication.php | 74 ++++++++++++++++++- .../src/CMS/Component/ComponentHelper.php | 13 ++-- libraries/src/CMS/Router/ApiRouter.php | 57 ++++++++++++-- 3 files changed, 130 insertions(+), 14 deletions(-) diff --git a/libraries/src/CMS/Application/ApiApplication.php b/libraries/src/CMS/Application/ApiApplication.php index 4e108c3980ff3..06fc7ee210406 100644 --- a/libraries/src/CMS/Application/ApiApplication.php +++ b/libraries/src/CMS/Application/ApiApplication.php @@ -11,6 +11,7 @@ defined('JPATH_PLATFORM') or die; use Joomla\Application\Web\WebClient; +use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Router\ApiRouter; use Joomla\DI\Container; use Joomla\Registry\Registry; @@ -71,6 +72,20 @@ protected function doExecute() // Initialise the application $this->initialiseApp(); + // Mark afterInitialise in the profiler. + JDEBUG ? $this->profiler->mark('afterInitialise') : null; + + // Route the application + $this->route(); + + // Mark afterApiRoute in the profiler. + JDEBUG ? $this->profiler->mark('afterApiRoute') : null; + + // Dispatch the application + $this->dispatch(); + + // Mark afterDispatch in the profiler. + JDEBUG ? $this->profiler->mark('afterDispatch') : null; } /** @@ -148,11 +163,32 @@ public function getTemplate($params = false) protected function route() { $uri = \JUri::getInstance(); - $router = static::getRouter(); + $router = $this->getApiRouter(); // Trigger the onBeforeApiRoute event. PluginHelper::importPlugin('webservices'); $this->triggerEvent('onBeforeApiRoute', &$router); + + $route = $router->parseRoute($uri::current(), $this->input->getMethod()); + + $this->input->set('option', $route['vars']['component']); + $this->input->set('controller', $route['controller']); + $this->input->set('task', $route['task']); + + foreach ($route['vars'] as $key => $value) + { + if ($key !== 'component') + { + if ($this->input->getMethod() === 'POST') + { + $this->input->post->set($key, $value); + } + else + { + $this->input->set($key, $value); + } + } + } } /** @@ -166,4 +202,40 @@ public function getApiRouter() { return JFactory::getContainer()->get('ApiRouter'); } + + /** + * Dispatch the application + * + * @param string $component The component which is being rendered. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function dispatch($component = null) + { + $app = \JFactory::getApplication(); + + // Get the component if not set. + if (!$component) + { + $component = $this->input->get('option', null); + } + + // Load the document to the API + $this->loadDocument(); + + // Set up the params + $document = \JFactory::getDocument(); + + // Register the document object with \JFactory + \JFactory::$document = $document; + + $contents = ComponentHelper::renderComponent($component); + $document->setBuffer($contents, 'component'); + + // Trigger the onAfterDispatch event. + PluginHelper::importPlugin('system'); + $this->triggerEvent('onAfterDispatch'); + } } diff --git a/libraries/src/CMS/Component/ComponentHelper.php b/libraries/src/CMS/Component/ComponentHelper.php index 08685145cb413..de03654363c60 100644 --- a/libraries/src/CMS/Component/ComponentHelper.php +++ b/libraries/src/CMS/Component/ComponentHelper.php @@ -313,11 +313,14 @@ public static function renderComponent($option, $params = array()) { $app = \JFactory::getApplication(); - // Load template language files. - $template = $app->getTemplate(true)->template; - $lang = \JFactory::getLanguage(); - $lang->load('tpl_' . $template, JPATH_BASE, null, false, true) - || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, true); + if (!$app->isClient('api')) + { + // Load template language files. + $template = $app->getTemplate(true)->template; + $lang = \JFactory::getLanguage(); + $lang->load('tpl_' . $template, JPATH_BASE, null, false, true) + || $lang->load('tpl_' . $template, JPATH_THEMES . "/$template", null, false, true); + } if (empty($option)) { diff --git a/libraries/src/CMS/Router/ApiRouter.php b/libraries/src/CMS/Router/ApiRouter.php index 447011ca23882..02bb04ad1a8cb 100644 --- a/libraries/src/CMS/Router/ApiRouter.php +++ b/libraries/src/CMS/Router/ApiRouter.php @@ -16,14 +16,6 @@ */ class ApiRouter extends Router { - /** - * Router instances container. - * - * @var array - * @since __DEPLOY_VERSION__ - */ - protected static $instances = array(); - /** * Creates routes map for CRUD * @@ -87,4 +79,53 @@ public function createCRUDRoutes($baseName, $controller, $defaults = array()) ); $this->addRoutes($routes); } + + /** + * Parse the given route and return the name of a controller mapped to the given route. + * + * @param string $route The route string for which to find and execute a controller. + * @param string $method Request method to match. One of GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE or PATCH + * + * @return array An array containing the controller and the matched variables. + * + * @since __DEPLOY_VERSION__ + * @throws \InvalidArgumentException + */ + public function parseRoute($route, $method = 'GET') + { + $method = strtoupper($method); + + if (!array_key_exists($method, $this->routes)) + { + throw new \InvalidArgumentException(sprintf('%s is not a valid HTTP method.', $method)); + } + + // Get the path from the route and remove and leading or trailing slash. + $route = trim(parse_url($route, PHP_URL_PATH), ' /'); + + // Iterate through all of the known routes looking for a match. + foreach ($this->routes[$method] as $rule) + { + if (preg_match($rule['regex'], $route, $matches)) + { + // If we have gotten this far then we have a positive match. + $vars = $rule['defaults']; + + foreach ($rule['vars'] as $i => $var) + { + $vars[$var] = $matches[$i + 1]; + } + + $controller = preg_split("/[.]+/", $rule['controller']); + + return [ + 'controller' => $controller[0], + 'task' => $controller[0], + 'vars' => $vars + ]; + } + } + + throw new \InvalidArgumentException(sprintf('Unable to handle request for route `%s`.', $route), 404); + } }