<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2024 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
use Joomla\CMS\Component\Router\RouterViewConfiguration;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Rule to prepare the query and add missing information
*
* This rule adds the alias to an ID query parameter and the
* category ID if either of them is missing. This requires that
* the db table contains an alias column.
* This fixes sloppy URLs in the code, but doesn't mean you can
* simply drop the alias from the &id= in the future. Cleaning up
* every request with this would mean a significant performance impact
*
* @since 5.3.0
*/
class PreprocessRules implements RulesInterface
{
use DatabaseAwareTrait;
/**
* View to prepare
*
* @var RouterViewConfiguration
* @since 5.3.0
*/
protected $view;
/**
* DB Table to read the information from
*
* @var string
* @since 5.3.0
*/
protected $table;
/**
* ID column in the table to read the information from
*
* @var string
* @since 5.3.0
*/
protected $key;
/**
* Parent ID column in the table to read the information from
*
* @var string
* @since 5.3.0
*/
protected $parent_key;
/**
* Class constructor.
*
* @param RouterViewConfiguration $view View to act on
* @param string $table Table name for the views information
* @param string $key Key in the table to get the information
* @param string $parent_key Column name of the parent key
*
* @since 5.3.0
*/
public function __construct(RouterViewConfiguration $view, $table, $key, $parent_key = null)
{
$this->view = $view;
$this->table = $table;
$this->key = $key;
$this->parent_key = $parent_key;
}
/**
* Finds the correct Itemid for this query
*
* @param array &$query The query array to process
*
* @return void
*
* @since 5.3.0
*/
public function preprocess(&$query)
{
// We only work for URLs with the view we have been setup for
if (!isset($query['view']) || $query['view'] != $this->view->name) {
return;
}
$key = $this->view->key;
$parent_key = $this->view->parent_key;
// We have to have at least the ID or something to repair
if (!isset($query[$key]) || (strpos($query[$key], ':') && isset($query[$parent_key]))) {
return;
}
$dbquery = $this->getDatabase()->getQuery(true);
$id = (int) $query[$key];
$dbquery->select($dbquery->quoteName('alias'))
->from($this->table)
->where($dbquery->quoteName($this->key) . ' = :key')
->bind(':key', $id, ParameterType::INTEGER);
// Do we have a parent key?
if ($parent_key && $this->parent_key) {
$dbquery->select($dbquery->quoteName($this->parent_key));
}
$obj = $this->getDatabase()->setQuery($dbquery)->loadObject();
// We haven't found the item in the database. Abort.
if (!$obj) {
return;
}
// Lets fix the slug (id:alias)
if (!strpos($query[$key], ':')) {
$query[$key] .= ':' . $obj->alias;
}
// If we have a parent key and it is missing, lets add it
if ($parent_key && $this->parent_key && !isset($query[$parent_key])) {
$query[$parent_key] = $obj->{$this->parent_key};
}
}
/**
* Dummy method to fulfil the interface requirements
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 5.3.0
* @codeCoverageIgnore
*/
public function parse(&$segments, &$vars)
{
}
/**
* Dummy method to fulfil the interface requirements
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 5.3.0
* @codeCoverageIgnore
*/
public function build(&$query, &$segments)
{
}
}