| Current Path : /home/chauffn/vuzelia/2023/components/com_sppagebuilder/ |
| Current File : /home/chauffn/vuzelia/2023/components/com_sppagebuilder/router.php |
<?php
/**
* @package SP Page Builder
* @author JoomShaper http://www.joomshaper.com
* @copyright Copyright (c) 2010 - 2025 JoomShaper
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPLv2 or later
*/
// No direct access
defined ('_JEXEC') or die ('Restricted access');
if (file_exists(JPATH_ROOT . '/administrator/components/com_sppagebuilder/vendor/autoload.php')) {
require_once JPATH_ROOT . '/administrator/components/com_sppagebuilder/vendor/autoload.php';
}
if (file_exists(JPATH_ROOT . '/administrator/components/com_sppagebuilder/dynamic-content/helper.php')) {
require_once JPATH_ROOT . '/administrator/components/com_sppagebuilder/dynamic-content/helper.php';
}
use Joomla\CMS\Factory;
use Joomla\CMS\Version;
use Joomla\CMS\Filter\OutputFilter;
use JoomShaper\SPPageBuilder\DynamicContent\Constants\FieldTypes;
use JoomShaper\SPPageBuilder\DynamicContent\Models\Collection;
use JoomShaper\SPPageBuilder\DynamicContent\Models\CollectionField;
use JoomShaper\SPPageBuilder\DynamicContent\Models\CollectionItem;
use JoomShaper\SPPageBuilder\DynamicContent\Models\CollectionItemValue;
use JoomShaper\SPPageBuilder\DynamicContent\Models\Page;
use JoomShaper\SPPageBuilder\DynamicContent\Supports\Arr;
use JoomShaper\SPPageBuilder\DynamicContent\Constants\CollectionIds;
class SppagebuilderRouterBase
{
private static $aliasFieldCache = [];
private static $aliasCache = [];
private static $collectionIdCache = [];
public static function buildRoute(&$query)
{
$segments = array();
/** @var CMSApplication */
$app = Factory::getApplication();
$menu = $app->getMenu();
$version = new Version();
$joomlaVersion = (float) $version->getShortVersion();
if ($joomlaVersion >= 6 && isset($query['view']) && $query['view'] === 'form' && isset($query['layout']) && $query['layout'] === 'edit-iframe' && isset($query['lang']))
{
return $segments;
}
// 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 = $menu->getActive();
}
else
{
$menuItem = $menu->getItem($query['Itemid']);
}
$menuItemGiven = !empty($query['Itemid']);
// Check again
if ($menuItemGiven && isset($menuItem) && $menuItem->component !== 'com_sppagebuilder')
{
$menuItemGiven = false;
unset($query['Itemid']);
}
if (isset($query['view']) && $query['view'])
{
$view = $query['view'];
}
else
{
// We need to have a view in the query or it is an invalid URL
return $segments;
}
if (($menuItem instanceof stdClass) && $menuItem->query['view'] === $query['view'] && isset($query['id']) && (int) $menuItem->query['id'] === (int) $query['id'])
{
unset($query['view']);
unset($query['id']);
return $segments;
}
if ($query['view'] === "page")
{
if (!$menuItemGiven) {
$segments[] = $view;
$segments[] = $query['id'] ?? 0;
}
unset($query['view']);
unset($query['id']);
}
if ($view === 'dynamic')
{
$collectionItemId = $query['collection_item_id'] ?? [];
if (!is_array($collectionItemId)) {
$collectionItemId = [$collectionItemId];
}
$collectionType = $query['collection_type'] ?? 'normal-source';
unset($query['collection_item_id']);
unset($query['collection_type']); // Remove collection_type parameter
// Always generate alias for SEF URLs, regardless of menu item
$alias = static::getSlugsByCollectionItemIds($collectionItemId, $collectionType);
if (!empty($alias)) {
$segments = array_merge($segments, $alias);
}
}
if (isset($query['view']) && $query['view'])
{
unset($query['view']);
}
if (isset($query['id']) && $query['id'])
{
$id = $query['id'];
unset($query['id']);
}
if(isset($query['tmpl']) && $query['tmpl'])
{
unset($query['tmpl']);
}
if(isset($query['layout']) && $query['layout'])
{
$segments[] = $query['layout'];
if(isset($id)) {
$segments[] = $id;
}
unset($query['layout']);
}
return $segments;
}
private static function getCollectionTypeFromAlias($alias)
{
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('alias')
->from('#__content')
->where('state = 1')
->where('alias = ' . $db->quote($alias));
$db->setQuery($query);
$result = $db->loadResult();
if ($result) {
return 'articles';
}
return 'normal-source';
}
// Parse
public static function parseRoute(&$segments)
{
/** @var CMSApplication */
$app = Factory::getApplication();
$menu = $app->getMenu();
$item = $menu->getActive();
$vars = array();
if (static::hasRedirect($segments))
{
return $vars;
}
// Page
if (count($segments) === 2 && $segments[0] === 'page')
{
$vars['view'] = $segments[0];
$vars['id'] = (int) $segments[1];
return $vars;
}
// Form
if (count($segments) === 2 && $segments[0] === 'edit')
{
$vars['view'] = 'form';
$vars['id'] = (int) $segments[1];
$vars['tmpl'] = 'component';
$vars['layout'] = 'edit';
return $vars;
}
// determine collection type based on alias
$collectionType = static::getCollectionTypeFromAlias($segments[0]);
$collectionItemIds = static::getCollectionItemIdsFromSlugs($segments);
$isValidCollectionPage = false;
if (isset($collectionItemIds)) {
$collectionArray = Arr::make($collectionItemIds);
$isValidCollectionPage = $collectionArray->every(function ($element) {
return !empty($element);
});
if ($isValidCollectionPage && static::hasConsecutiveSameCollectionItems($collectionItemIds, $collectionType)) {
$isValidCollectionPage = false;
}
}
// Dynamic Content
if (!empty($item) && $item->query['option'] === 'com_sppagebuilder' && $item->query['view'] === 'page' && $isValidCollectionPage) {
$vars['view'] = 'dynamic';
if (!empty($collectionItemIds)) {
foreach ($collectionItemIds as $collectionItemId) {
$vars['collection_item_id'][] = $collectionItemId;
}
}
$vars['collection_type'] = $collectionType;
return $vars;
}
return $vars;
}
private static function hasRedirect(array $segments)
{
$path = trim(implode('/', $segments), '/');
if ($path === '')
{
return false;
}
$db = Factory::getContainer()->get('DatabaseDriver');
$query = $db->getQuery(true)
->select('old_url')
->from('#__redirect_links')
->where('published = 1');
$db->setQuery($query);
$rows = $db->loadColumn();
foreach ($rows as $oldUrl)
{
$normalized = parse_url($oldUrl, PHP_URL_PATH);
if ($normalized === null)
{
$normalized = $oldUrl;
}
$normalized = trim($normalized, '/');
if ($normalized === $path)
{
return true;
}
}
return false;
}
private static function getCollectionItemIdsFromSlugs($slugs)
{
if (empty($slugs)) {
return [];
}
return Arr::make($slugs)->map(function ($slug) {
return static::getCollectionItemIdFromSlug($slug);
})->toArray();
}
/**
* Check if any two consecutive items in the chain belong to the same collection.
* Such URLs (e.g. /blog/blog) are invalid and should result in 404.
*
* @param array $collectionItemIds The collection item IDs from the URL segments.
* @param string $collectionType The collection type (e.g. 'normal-source', 'articles', 'tags').
* @return bool True if consecutive same-collection items exist.
*/
private static function hasConsecutiveSameCollectionItems(array $collectionItemIds, string $collectionType)
{
if (count($collectionItemIds) < 2) {
return false;
}
static::ensureCollectionIdCacheForItemIds($collectionItemIds);
for ($i = 0; $i < count($collectionItemIds) - 1; $i++) {
$collectionId1 = static::getCollectionIdFromItemId($collectionItemIds[$i], $collectionType);
$collectionId2 = static::getCollectionIdFromItemId($collectionItemIds[$i + 1], $collectionType);
if ($collectionId1 !== null && $collectionId2 !== null && $collectionId1 === $collectionId2) {
return true;
}
}
return false;
}
/**
* Preload collection_id for the given item IDs into the cache.
*
* @param array $itemIds The item IDs to cache.
* @return void
*/
private static function ensureCollectionIdCacheForItemIds(array $itemIds)
{
$itemIds = array_filter(array_map('intval', $itemIds));
if (empty($itemIds)) {
return;
}
$missingIds = [];
foreach ($itemIds as $id) {
if (!isset(self::$collectionIdCache[$id])) {
$missingIds[] = $id;
}
}
if (empty($missingIds)) {
return;
}
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('id, collection_id')
->from('#__sppagebuilder_collection_items')
->where('id IN (' . implode(',', array_map('intval', $missingIds)) . ')');
$db->setQuery($query);
$rows = $db->loadObjectList();
foreach ($rows as $row) {
self::$collectionIdCache[$row->id] = $row->collection_id;
}
}
private static function getCollectionItemIdFromSlug($slug)
{
try {
$articleId = self::getArticleIdBySlug($slug);
if ($articleId) {
return $articleId;
}
} catch (\Exception $e) {
}
if (preg_match('/^article-(\d+)$/', $slug, $matches)) {
return (int) $matches[1];
}
$aliasFields = CollectionField::where('type', FieldTypes::ALIAS)->get(['id']);
$aliasFieldIds = Arr::make($aliasFields)->pluck('id')->toArray();
if (!empty($aliasFieldIds)) {
$aliasField = CollectionItemValue::whereIn('field_id', $aliasFieldIds)
->where('value', $slug)
->first(['item_id']);
if (!$aliasField->isEmpty()) {
return $aliasField->item_id ?? null;
}
}
return null;
}
private static function getSlugsByCollectionItemIds($collectionItemIds, $collectionType = 'normal-source')
{
if (empty($collectionItemIds)) {
return [];
}
if (empty(self::$aliasCache)) {
$db = Factory::getDbo();
$aliasFieldIds = $db->setQuery(
$db->getQuery(true)
->select('id')
->from('#__sppagebuilder_collection_fields')
->where('type = ' . $db->quote(FieldTypes::ALIAS))
)->loadColumn();
if (!empty($aliasFieldIds)) {
$query = $db->getQuery(true)
->select('value, field_id, item_id')
->from('#__sppagebuilder_collection_item_values')
->whereIn('field_id', $aliasFieldIds);
$db->setQuery($query);
$aliasItems = $db->loadObjectList();
foreach (Arr::make($aliasItems) as $element) {
$key = $element->item_id . '_' . $element->field_id;
self::$aliasCache[$key] = $element;
}
}
}
if(empty(self::$collectionIdCache)){
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('id, collection_id')
->from('#__sppagebuilder_collection_items');
$db->setQuery($query);
$collectionItems = $db->loadObjectList();
foreach (Arr::make($collectionItems) as $element) {
self::$collectionIdCache[$element->id] = $element->collection_id;
}
}
return Arr::make($collectionItemIds)->map(function ($id) use ($collectionType) {
return static::getItemAliasByCollectionItemId(static::getCollectionIdFromItemId($id, $collectionType), $id);
})->toArray();
}
private static function getCollectionIdFromCache($itemId)
{
if (isset(self::$collectionIdCache[$itemId])) {
return self::$collectionIdCache[$itemId];
}
return null;
}
private static function getCollectionIdFromItemId($itemId, $collectionType = 'normal-source')
{
if ($collectionType === 'articles') {
return CollectionIds::ARTICLES_COLLECTION_ID;
}
if ($collectionType === 'tags') {
return CollectionIds::TAGS_COLLECTION_ID;
}
$collectionId = self::getCollectionIdFromCache($itemId);
if ($collectionId) {
return $collectionId;
}
try {
if (self::articleExists($itemId)) {
return CollectionIds::ARTICLES_COLLECTION_ID;
}
} catch (\Exception $e) {
}
$db = \Joomla\CMS\Factory::getDbo();
$query = $db->getQuery(true)
->select('COUNT(*)')
->from('#__tags')
->where('id = ' . (int) $itemId)
->where('published = 1');
$db->setQuery($query);
$tagCount = $db->loadResult();
if ($tagCount > 0) {
return CollectionIds::TAGS_COLLECTION_ID;
}
return null;
}
private static function getAliasFieldFromCache($collectionId)
{
if (isset(self::$aliasFieldCache[$collectionId])) {
return self::$aliasFieldCache[$collectionId];
}
$aliasField = CollectionField::where('collection_id', $collectionId)
->where('type', FieldTypes::ALIAS)
->first(['id']);
if ($aliasField->isEmpty()) {
self::$aliasFieldCache[$collectionId] = null;
return null;
}
self::$aliasFieldCache[$collectionId] = $aliasField;
return $aliasField;
}
private static function getItemAliasByCollectionItemId($collectionId, $collectionItemId)
{
if (empty($collectionId) || empty($collectionItemId)) {
return null;
}
if ($collectionId === CollectionIds::ARTICLES_COLLECTION_ID) {
if (!\class_exists('SppagebuilderHelperArticles')) {
require_once JPATH_ROOT . '/components/com_sppagebuilder/helpers/articles.php';
}
try {
$article = self::getArticleByCollectionItemId($collectionItemId);
if ($article) {
$alias = !empty($article->alias) ? $article->alias : OutputFilter::stringURLSafe($article->title);
return $alias;
}
} catch (\Exception $e) {
return 'article-' . $collectionItemId;
}
return 'article-' . $collectionItemId;
}
if ($collectionId === CollectionIds::TAGS_COLLECTION_ID) {
try {
$db = \Joomla\CMS\Factory::getDbo();
$query = $db->getQuery(true)
->select('alias, title')
->from('#__tags')
->where('id = ' . (int) $collectionItemId)
->where('published = 1');
$db->setQuery($query);
$tag = $db->loadObject();
if ($tag) {
$alias = !empty($tag->alias) ? $tag->alias : OutputFilter::stringURLSafe($tag->title);
return $alias;
}
} catch (\Exception $e) {
return 'tag-' . $collectionItemId;
}
return 'tag-' . $collectionItemId;
}
$aliasField = self::getAliasFieldFromCache($collectionId);
if ($aliasField->isEmpty()) {
return null;
}
$alias = self::getAliasFromCache($collectionItemId, $aliasField->id);
if (empty($alias)) {
return null;
}
return $alias->value;
}
private static function getAliasFromCache($itemId, $fieldId)
{
$cacheKey = $itemId . '_' . $fieldId;
if (isset(self::$aliasCache[$cacheKey])) {
return self::$aliasCache[$cacheKey];
}
return null;
}
private static function getArticleByCollectionItemId($collectionItemId){
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('alias, title')
->from('#__content')
->where('id = ' . (int) $collectionItemId)
->where('state = 1');
$db->setQuery($query);
return $db->loadObject();
}
private static function getArticleIdBySlug($slug){
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('id')
->from('#__content')
->where('state = 1')
->where('alias = ' . $db->quote($slug));
$db->setQuery($query);
$articleId = $db->loadResult();
if ($articleId) {
return $articleId;
}
$query = $db->getQuery(true)
->select('id, title')
->from('#__content')
->where('state = 1');
$db->setQuery($query);
$articles = $db->loadObjectList();
foreach ($articles as $article) {
if (OutputFilter::stringURLSafe($article->title ?? '') === $slug) {
return $article->id;
}
}
return null;
}
private static function articleExists($articleId){
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('COUNT(*)')
->from('#__content')
->where('id = ' . (int) $articleId)
->where('state = 1');
$db->setQuery($query);
return (bool) $db->loadResult();
}
}
$version = new Version();
$JoomlaVersion = (float) $version->getShortVersion();
if ($JoomlaVersion >= 4)
{
class SppagebuilderRouter extends Joomla\CMS\Component\Router\RouterBase
{
public function build(&$query)
{
$segments = SppagebuilderRouterBase::buildRoute($query);
return $segments;
}
public function parse(&$segments)
{
$vars = SppagebuilderRouterBase::parseRoute($segments);
if (count($vars))
{
$segments = array();
}
return $vars;
}
}
}
/**
* Build the route for the com_banners component
*
* This function is a proxy for the new router interface
* for old SEF extensions.
*
* @param array &$query An array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent URL.
*
* @since 3.3
* @deprecated 4.0 Use Class based routers instead
*/
function SppagebuilderBuildRoute(&$query)
{
$segments = SppagebuilderRouterBase::buildRoute($query);
return $segments;
}
/**
* Parse the segments of a URL.
*
* This function is a proxy for the new router interface
* for old SEF extensions.
*
* @param array $segments The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
*
* @since 3.3
* @deprecated 4.0 Use Class based routers instead
*/
function SppagebuilderParseRoute(&$segments)
{
$vars = SppagebuilderRouterBase::parseRoute($segments);
return $vars;
}