* @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Tags\Site\Service; use Joomla\CMS\Application\SiteApplication; use Joomla\CMS\Categories\CategoryFactoryInterface; use Joomla\CMS\Component\Router\RouterBase; use Joomla\CMS\Menu\AbstractMenu; use Joomla\Database\DatabaseInterface; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Routing class from com_tags * * @since 3.3 */ class Router extends RouterBase { /** * The db * * @var DatabaseInterface * * @since 4.0.0 */ private $db; /** * Tags Component router constructor * * @param SiteApplication $app The application object * @param AbstractMenu $menu The menu object to work with * @param CategoryFactoryInterface $categoryFactory The category object * @param DatabaseInterface $db The database object * * @since 4.0.0 */ public function __construct(SiteApplication $app, AbstractMenu $menu, ?CategoryFactoryInterface $categoryFactory, DatabaseInterface $db) { $this->db = $db; parent::__construct($app, $menu); } /** * Build the route for the com_tags component * * @param array &$query An array of URL arguments * * @return array The URL arguments to use to assemble the subsequent URL. * * @since 3.3 */ public function build(&$query) { $segments = array(); // Get a menu item based on Itemid or currently active // We need a menu item. Either the one specified in the query, or the current active one if none specified if (empty($query['Itemid'])) { $menuItem = $this->menu->getActive(); } else { $menuItem = $this->menu->getItem($query['Itemid']); } $mView = empty($menuItem->query['view']) ? null : $menuItem->query['view']; $mId = empty($menuItem->query['id']) ? null : $menuItem->query['id']; if (is_array($mId)) { $mId = ArrayHelper::toInteger($mId); } $view = ''; if (isset($query['view'])) { $view = $query['view']; if (empty($query['Itemid'])) { $segments[] = $view; } unset($query['view']); } // Are we dealing with a tag that is attached to a menu item? if ($mView == $view && isset($query['id']) && $mId == $query['id']) { unset($query['id']); return $segments; } if ($view === 'tag') { $notActiveTag = is_array($mId) ? (count($mId) > 1 || $mId[0] != (int) $query['id']) : ($mId != (int) $query['id']); if ($notActiveTag || $mView != $view) { // ID in com_tags can be either an integer, a string or an array of IDs $id = is_array($query['id']) ? implode(',', $query['id']) : $query['id']; $segments[] = $id; } unset($query['id']); } if (isset($query['layout'])) { if ( (!empty($query['Itemid']) && isset($menuItem->query['layout']) && $query['layout'] == $menuItem->query['layout']) || $query['layout'] === 'default' ) { unset($query['layout']); } } $total = count($segments); for ($i = 0; $i < $total; $i++) { $segments[$i] = str_replace(':', '-', $segments[$i]); $position = strpos($segments[$i], '-'); if ($position) { // Remove id from segment $segments[$i] = substr($segments[$i], $position + 1); } } return $segments; } /** * Parse the segments of a URL. * * @param array &$segments The segments of the URL to parse. * * @return array The URL attributes to be used by the application. * * @since 3.3 */ public function parse(&$segments) { $total = count($segments); $vars = array(); for ($i = 0; $i < $total; $i++) { $segments[$i] = preg_replace('/-/', ':', $segments[$i], 1); } // Get the active menu item. $item = $this->menu->getActive(); // Count route segments $count = count($segments); // Standard routing for tags. if (!isset($item)) { $vars['view'] = $segments[0]; $vars['id'] = $this->fixSegment($segments[$count - 1]); unset($segments[0]); unset($segments[$count - 1]); return $vars; } $vars['id'] = $this->fixSegment($segments[0]); $vars['view'] = 'tag'; unset($segments[0]); return $vars; } /** * Try to add missing id to segment * * @param string $segment One piece of segment of the URL to parse * * @return string The segment with founded id * * @since 3.7 */ protected function fixSegment($segment) { // Try to find tag id $alias = str_replace(':', '-', $segment); $query = $this->db->getQuery(true) ->select($this->db->quoteName('id')) ->from($this->db->quoteName('#__tags')) ->where($this->db->quoteName('alias') . ' = :alias') ->bind(':alias', $alias); $id = $this->db->setQuery($query)->loadResult(); if ($id) { $segment = "$id:$alias"; } return $segment; } }