primo commit
This commit is contained in:
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2021-2024 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Button;
|
||||
|
||||
use Joomla\CMS\Button\ActionButton;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class DefaultButton extends ActionButton
|
||||
{
|
||||
protected function preprocess()
|
||||
{
|
||||
$this->addState(
|
||||
0,
|
||||
'sitemap.setAsDefault',
|
||||
'icon-unfeatured',
|
||||
Text::_('COM_OSMAP_SITEMAP_IS_DEFAULT_LABEL'),
|
||||
['tip_title' => Text::_('COM_OSMAP_SITEMAP_IS_DEFAULT_DESC')]
|
||||
);
|
||||
$this->addState(
|
||||
1,
|
||||
'sitemap.setAsDefault',
|
||||
'icon-color-featured icon-star',
|
||||
Text::_('COM_OSMAP_SITEMAP_IS_DEFAULT_LABEL')
|
||||
);
|
||||
|
||||
parent::preprocess();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Component;
|
||||
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
|
||||
abstract class Helper extends ComponentHelper
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getParams($option = 'com_osmap', $strict = false)
|
||||
{
|
||||
return parent::getParams($option, $strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public static function getComponent($option = 'com_osmap', $strict = false)
|
||||
{
|
||||
return parent::getComponent($option, $strict);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
/**
|
||||
* A simple class for handling layered variables
|
||||
*
|
||||
* Class AbstractConfiguration
|
||||
*
|
||||
* @package OSMap
|
||||
*/
|
||||
class Configuration
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $settings = null;
|
||||
|
||||
public function __construct(array $settings = [])
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that the current configuration is valid
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate dot notation into array keys
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name, $default = null)
|
||||
{
|
||||
if (strpos($name, '.') === false) {
|
||||
return $this->settings[$name] ?? $default;
|
||||
}
|
||||
$levels = explode('.', $name);
|
||||
|
||||
$value = &$this->settings;
|
||||
for ($i = 0; $i < count($levels) - 1; $i++) {
|
||||
$key = $levels[$i];
|
||||
if (is_array($value) && isset($value[$key])) {
|
||||
$value = &$value[$key];
|
||||
} elseif (is_object($value) && isset($value->{$key})) {
|
||||
$value = $value->{$key};
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
$key = $levels[$i];
|
||||
if (isset($value[$key])) {
|
||||
return $value[$key];
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a dot notation key to the setting array
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $newValue
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function set($name, $newValue)
|
||||
{
|
||||
$oldValue = $this->get($name);
|
||||
|
||||
if (strpos($name, '.') === false) {
|
||||
$this->settings[$name] = $newValue;
|
||||
} else {
|
||||
$keys = explode('.', $name);
|
||||
$tree = &$this->settings;
|
||||
for ($i = 0; $i < count($keys) - 1; $i++) {
|
||||
$key = $keys[$i];
|
||||
if (empty($tree[$key]) || !is_array($tree[$key])) {
|
||||
$tree[$key] = [];
|
||||
}
|
||||
$tree = &$tree[$key];
|
||||
}
|
||||
|
||||
$final = array_pop($keys);
|
||||
if ($newValue === null) {
|
||||
unset($tree[$final]);
|
||||
} else {
|
||||
$tree[$final] = $newValue;
|
||||
}
|
||||
}
|
||||
return $oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as Configuration class
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return Configuration
|
||||
*/
|
||||
public function toConfig($key = null)
|
||||
{
|
||||
if ($key) {
|
||||
return new static($this->get($key, []));
|
||||
}
|
||||
|
||||
return clone $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as JSON string
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toString($key = null)
|
||||
{
|
||||
$value = $key ? $this->get($key) : $this->settings;
|
||||
return json_encode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as stdClass
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function toObject($key = null)
|
||||
{
|
||||
$value = $key ? $this->get($key) : $this->settings;
|
||||
return json_decode(json_encode($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as array
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($key = null)
|
||||
{
|
||||
$value = $key ? $this->get($key) : $this->settings;
|
||||
return json_decode(json_encode($value), true);
|
||||
}
|
||||
|
||||
/*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toString();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap;
|
||||
|
||||
use Alledia\Framework\Profiler;
|
||||
use Alledia\OSMap\Helper\Images;
|
||||
use JDatabaseDriver;
|
||||
use Joomla\CMS\Application\WebApplication;
|
||||
use Joomla\CMS\Language\Language;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\CMS\User\User;
|
||||
use Joomla\Input\Input;
|
||||
use ReflectionClass;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
/**
|
||||
* Class Container
|
||||
*
|
||||
* @package OSMap
|
||||
*
|
||||
* @property WebApplication $app
|
||||
* @property JDatabaseDriver $db
|
||||
* @property Input $input
|
||||
* @property User $user
|
||||
* @property Language $language
|
||||
* @property Profiler $profiler
|
||||
* @property Router $router
|
||||
* @property Uri $uri
|
||||
* @property Images $imagesHelper
|
||||
*
|
||||
* @method WebApplication getApp()
|
||||
* @method JDatabaseDriver getDb()
|
||||
* @method Input getInput()
|
||||
* @method User getUser()
|
||||
* @method Language getLanguage()
|
||||
* @method Profiler getProfiler()
|
||||
* @method Router getRouter()
|
||||
* @method Uri getUri()
|
||||
*
|
||||
*/
|
||||
class Container extends \Pimple\Container
|
||||
{
|
||||
public function __get($name)
|
||||
{
|
||||
if (isset($this[$name])) {
|
||||
return $this[$name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __call($name, $args)
|
||||
{
|
||||
if (strpos($name, 'get') === 0 && !$args) {
|
||||
$key = strtolower(substr($name, 3));
|
||||
if (isset($this[$key])) {
|
||||
return $this[$key];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instance of a class using parameter autodetect
|
||||
*
|
||||
* @param string $className
|
||||
*
|
||||
* @return object
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getInstance($className)
|
||||
{
|
||||
$class = new ReflectionClass($className);
|
||||
if ($instance = $this->getServiceEntry($class)) {
|
||||
return $instance;
|
||||
}
|
||||
|
||||
$dependencies = [];
|
||||
if (!is_null($class->getConstructor())) {
|
||||
$params = $class->getConstructor()->getParameters();
|
||||
foreach ($params as $param) {
|
||||
$dependentClass = $param->getClass();
|
||||
if ($dependentClass) {
|
||||
$dependentClassName = $dependentClass->name;
|
||||
$dependentReflection = new ReflectionClass($dependentClassName);
|
||||
if ($dependentReflection->isInstantiable()) {
|
||||
//use recursion to get dependencies
|
||||
$dependencies[] = $this->getInstance($dependentClassName);
|
||||
} elseif ($dependentReflection->isInterface()) {
|
||||
// Interfaces need to be pre-registered in the container
|
||||
if ($concrete = $this->getServiceEntry($dependentReflection, true)) {
|
||||
$dependencies[] = $concrete;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $class->newInstanceArgs($dependencies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a service in the container based on class name
|
||||
* Classes can be registered either through their short name
|
||||
* or full class name. Short name take precedence.
|
||||
*
|
||||
* @param ReflectionClass $class
|
||||
* @param bool $require
|
||||
*
|
||||
* @return object|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getServiceEntry(ReflectionClass $class, $require = false)
|
||||
{
|
||||
$key = strtolower($class->getShortName());
|
||||
if (isset($this[$key])) {
|
||||
return $this[$key];
|
||||
}
|
||||
|
||||
$name = $class->getName();
|
||||
if (isset($this[$name])) {
|
||||
return $this[$name];
|
||||
}
|
||||
|
||||
if ($require) {
|
||||
throw new \Exception($class->getName() . ' - is not registered in the container');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Controller;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\AdminController;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
abstract class Admin extends AdminController
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function execute($task)
|
||||
{
|
||||
$this->task = $task;
|
||||
|
||||
$task = strtolower($task);
|
||||
|
||||
PluginHelper::importPlugin('osmap');
|
||||
|
||||
$controllerName = strtolower(str_replace('OSMapController', '', get_class($this)));
|
||||
$eventParams = [$controllerName, $task];
|
||||
$results = Factory::getApplication()->triggerEvent('osmapOnBeforeExecuteTask', $eventParams);
|
||||
|
||||
// Check if any of the plugins returned the exit signal
|
||||
if (is_array($results) && in_array('exit', $results, true)) {
|
||||
Factory::getApplication()->enqueueMessage('COM_OSMAP_MSG_TASK_STOPPED_BY_PLUGIN', 'warning');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($this->taskMap[$task])) {
|
||||
$doTask = $this->taskMap[$task];
|
||||
|
||||
} elseif (isset($this->taskMap['__default'])) {
|
||||
$doTask = $this->taskMap['__default'];
|
||||
|
||||
} else {
|
||||
throw new Exception(Text::sprintf('JLIB_APPLICATION_ERROR_TASK_NOT_FOUND', $task), 404);
|
||||
}
|
||||
|
||||
// Record the actual task being fired
|
||||
$this->doTask = $doTask;
|
||||
|
||||
$result = $this->$doTask();
|
||||
|
||||
// Runs the event after the task was executed
|
||||
$eventParams[] = &$result;
|
||||
Factory::getApplication()->triggerEvent('osmapOnAfterExecuteTask', $eventParams);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function checkToken($method = 'post', $redirect = true)
|
||||
{
|
||||
if (is_callable([parent::class, 'checkToken'])) {
|
||||
return parent::checkToken($method, $redirect);
|
||||
}
|
||||
|
||||
Session::checkToken() or jexit(Text::_('JINVALID_TOKEN'));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Controller;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\BaseController;
|
||||
use Joomla\CMS\Session\Session;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class Base extends BaseController
|
||||
{
|
||||
public function checkToken($method = 'post', $redirect = true)
|
||||
{
|
||||
$valid = Session::checkToken();
|
||||
if (!$valid && $redirect) {
|
||||
$home = Factory::getApplication()->getMenu()->getDefault();
|
||||
$container = Factory::getPimpleContainer();
|
||||
|
||||
$app = Factory::getApplication();
|
||||
|
||||
$app->enqueueMessage(Text::_('JINVALID_TOKEN'), 'error');
|
||||
$app->redirect($container->router->routeURL('index.php?Itemid=' . $home->id));
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Controller;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\MVC\Controller\FormController;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
abstract class Form extends FormController
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function execute($task)
|
||||
{
|
||||
$this->task = $task;
|
||||
|
||||
$task = strtolower($task);
|
||||
|
||||
PluginHelper::importPlugin('osmap');
|
||||
|
||||
$controllerName = strtolower(str_replace('OSMapController', '', get_class($this)));
|
||||
$eventParams = [
|
||||
$controllerName,
|
||||
$task
|
||||
];
|
||||
$results = Factory::getApplication()->triggerEvent('osmapOnBeforeExecuteTask', $eventParams);
|
||||
|
||||
// Check if any of the plugins returned the exit signal
|
||||
if (is_array($results) && in_array('exit', $results, true)) {
|
||||
Factory::getApplication()->enqueueMessage('COM_OSMAP_MSG_TASK_STOPPED_BY_PLUGIN', 'warning');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($this->taskMap[$task])) {
|
||||
$doTask = $this->taskMap[$task];
|
||||
} elseif (isset($this->taskMap['__default'])) {
|
||||
$doTask = $this->taskMap['__default'];
|
||||
} else {
|
||||
throw new \Exception(Text::sprintf('JLIB_APPLICATION_ERROR_TASK_NOT_FOUND', $task), 404);
|
||||
}
|
||||
|
||||
// Record the actual task being fired
|
||||
$this->doTask = $doTask;
|
||||
|
||||
$result = $this->$doTask();
|
||||
|
||||
// Runs the event after the task was executed
|
||||
$eventParams[] = &$result;
|
||||
Factory::getApplication()->triggerEvent('osmapOnAfterExecuteTask', $eventParams);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Controller;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class Json extends \JControllerLegacy
|
||||
{
|
||||
/**
|
||||
* @param string $method
|
||||
* @param bool $redirect
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function checkToken($method = 'post', $redirect = true)
|
||||
{
|
||||
if (!\JSession::checkToken()) {
|
||||
throw new \Exception(Text::_('JINVALID_TOKEN'), 403);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap;
|
||||
|
||||
use Alledia\OSMap\Sitemap\SitemapInterface;
|
||||
use Joomla\CMS\Table\Table;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
|
||||
/**
|
||||
* OSMap Factory
|
||||
*/
|
||||
class Factory extends \Alledia\Framework\Factory
|
||||
{
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
protected static $pimpleContainer;
|
||||
|
||||
/**
|
||||
* Get a OSMap container class
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
public static function getPimpleContainer(): Container
|
||||
{
|
||||
if (empty(static::$pimpleContainer)) {
|
||||
$config = [];
|
||||
|
||||
$container = new Container(['configuration' => new Configuration($config)]);
|
||||
|
||||
// Load the Service class according to the current license
|
||||
$serviceClass = '\\Alledia\\OSMap\\Services\\' . ucfirst(OSMAP_LICENSE);
|
||||
|
||||
$container->register(new $serviceClass());
|
||||
|
||||
static::$pimpleContainer = $container;
|
||||
}
|
||||
|
||||
return static::$pimpleContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the Sitemap class according to the given id and
|
||||
* sitemap type.
|
||||
*
|
||||
* @param ?int $id
|
||||
* @param string $type
|
||||
*
|
||||
* @return SitemapInterface
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getSitemap(?int $id, string $type = 'standard'): ?SitemapInterface
|
||||
{
|
||||
if ($id > 0) {
|
||||
switch ($type) {
|
||||
case 'standard':
|
||||
return new Sitemap\Standard($id);
|
||||
|
||||
case 'images':
|
||||
return new Sitemap\Images($id);
|
||||
|
||||
case 'news':
|
||||
return new Sitemap\News($id);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a table. If no prefix is set, we use OSMap's table
|
||||
* prefix as default.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param ?string $prefix
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public static function getTable(string $tableName, ?string $prefix = 'OSMapTable'): ?Table
|
||||
{
|
||||
return Table::getInstance($tableName, $prefix);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,403 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Helper;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\HTML\Helpers\Sidebar;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Version;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
abstract class General
|
||||
{
|
||||
protected static $plugins = [];
|
||||
|
||||
/**
|
||||
* Build the submenu in admin if needed. Triggers the
|
||||
* onAdminSubmenu event for component addons to attach
|
||||
* their own admin screens.
|
||||
*
|
||||
* The expected response must be an array
|
||||
* [
|
||||
* "text" => Static language string,
|
||||
* "link" => Link to the screen
|
||||
* "view" => unique view name
|
||||
* ]
|
||||
*
|
||||
* @param string $viewName
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function addSubmenu(string $viewName)
|
||||
{
|
||||
if (Version::MAJOR_VERSION > 3) {
|
||||
// Not needed for Joomla 4+
|
||||
return;
|
||||
}
|
||||
|
||||
$submenus = [
|
||||
[
|
||||
'text' => 'COM_OSMAP_SUBMENU_SITEMAPS',
|
||||
'link' => 'index.php?option=com_osmap&view=sitemaps',
|
||||
'view' => 'sitemaps'
|
||||
],
|
||||
[
|
||||
'text' => 'COM_OSMAP_SUBMENU_EXTENSIONS',
|
||||
'link' => 'index.php?option=com_plugins&view=plugins&filter_folder=osmap',
|
||||
'view' => 'extensions'
|
||||
]
|
||||
];
|
||||
|
||||
Factory::getApplication()->triggerEvent('onOSMapAddAdminSubmenu', [&$submenus]);
|
||||
|
||||
if (!empty($submenus)) {
|
||||
foreach ($submenus as $submenu) {
|
||||
if (is_array($submenu)) {
|
||||
Sidebar::addEntry(
|
||||
Text::_($submenu['text']),
|
||||
$submenu['link'],
|
||||
$viewName == $submenu['view']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sitemap type checking the input.
|
||||
* The expected types:
|
||||
* - standard
|
||||
* - images
|
||||
* - news
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getSitemapTypeFromInput(): string
|
||||
{
|
||||
$input = Factory::getPimpleContainer()->input;
|
||||
|
||||
if ($input->getBool('images', false)) {
|
||||
return 'images';
|
||||
|
||||
} elseif ($input->getBool('news', false)) {
|
||||
return 'news';
|
||||
|
||||
} else {
|
||||
return 'standard';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of plugins from the database. Legacy plugins from XMap
|
||||
* will be returned first, then OSMap plugins. Always respecting the
|
||||
* ordering.
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public static function getPluginsFromDatabase(): array
|
||||
{
|
||||
$db = Factory::getPimpleContainer()->db;
|
||||
|
||||
// Get all the OSMap and XMap plugins. Get XMap plugins first
|
||||
// then OSMap. Always respecting the ordering.
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'folder',
|
||||
'params',
|
||||
'element'
|
||||
])
|
||||
->from('#__extensions')
|
||||
->where('type = ' . $db->quote('plugin'))
|
||||
->where(
|
||||
sprintf(
|
||||
'folder IN (%s)',
|
||||
join(',', $db->quote(['osmap', 'xmap']))
|
||||
)
|
||||
)
|
||||
->where('enabled = 1')
|
||||
->order('folder DESC, ordering');
|
||||
|
||||
return $db->setQuery($query)->loadObjectList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the plugin is compatible with the given option
|
||||
*
|
||||
* @param object $plugin
|
||||
* @param ?string $option
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function checkPluginCompatibilityWithOption(object $plugin, ?string $option): bool
|
||||
{
|
||||
if (empty($option)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$path = JPATH_PLUGINS . '/' . $plugin->folder . '/' . $plugin->element . '/' . $plugin->element . '.php';
|
||||
$compatible = false;
|
||||
|
||||
if (File::exists($path)) {
|
||||
/*
|
||||
* Legacy plugins have element == option.
|
||||
* But may still not be compatible with
|
||||
* the current content/option
|
||||
*/
|
||||
$isLegacy = $plugin->element === $option;
|
||||
|
||||
$className = $isLegacy
|
||||
? ($plugin->folder . '_' . $option)
|
||||
: ('Plg' . ucfirst($plugin->folder) . ucfirst($plugin->element));
|
||||
|
||||
if (!class_exists($className)) {
|
||||
require_once $path;
|
||||
}
|
||||
|
||||
// Instantiate the plugin if the class exists
|
||||
if (class_exists($className)) {
|
||||
$dispatcher = Factory::getDispatcher();
|
||||
$instance = method_exists($className, 'getInstance') ?
|
||||
$className::getInstance() : new $className($dispatcher);
|
||||
|
||||
// If is legacy, we know it is compatible since the element and option were already validated
|
||||
$compatible = $isLegacy
|
||||
|| (
|
||||
method_exists($instance, 'getComponentElement')
|
||||
&& $instance->getComponentElement() === $option
|
||||
);
|
||||
|
||||
if ($compatible) {
|
||||
$plugin->instance = $instance;
|
||||
$plugin->className = $className;
|
||||
$plugin->isLegacy = $isLegacy;
|
||||
$plugin->params = new Registry($plugin->params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $compatible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plugins according to the given option/component
|
||||
*
|
||||
* @param ?string $option
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public static function getPluginsForComponent(?string $option): array
|
||||
{
|
||||
// Check if there is a cached list of plugins for this option
|
||||
if ($option && empty(static::$plugins[$option])) {
|
||||
$compatiblePlugins = [];
|
||||
|
||||
$plugins = static::getPluginsFromDatabase();
|
||||
|
||||
if ($plugins) {
|
||||
foreach ($plugins as $plugin) {
|
||||
if (static::checkPluginCompatibilityWithOption($plugin, $option)) {
|
||||
$compatiblePlugins[] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static::$plugins[$option] = $compatiblePlugins;
|
||||
}
|
||||
|
||||
return static::$plugins[$option] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts pagebreaks from the given text. Returns a list of subnodes
|
||||
* related to each pagebreak.
|
||||
*
|
||||
* @param string $text
|
||||
* @param string $baseLink
|
||||
* @param ?string $uid
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public static function getPagebreaks(string $text, string $baseLink, ?string $uid = ''): array
|
||||
{
|
||||
$matches = $subNodes = [];
|
||||
|
||||
if (preg_match_all(
|
||||
'/<hr\s*[^>]*?(?:(?:\s*alt="(?P<alt>[^"]+)")|(?:\s*title="(?P<title>[^"]+)"))+[^>]*>/i',
|
||||
$text,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
)) {
|
||||
$i = 2;
|
||||
foreach ($matches as $match) {
|
||||
if (strpos($match[0], 'class="system-pagebreak"') !== false) {
|
||||
$link = $baseLink . '&limitstart=' . ($i - 1);
|
||||
|
||||
$subNode = (object)[
|
||||
'name' => $match['alt'] ?? $match['title'] ?? Text::sprintf('Page #', $i),
|
||||
'uid' => $uid . '.' . ($i - 1),
|
||||
'expandible' => false,
|
||||
'link' => $link,
|
||||
];
|
||||
|
||||
$subNodes[] = $subNode;
|
||||
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $subNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given date is empty, considering not only as string,
|
||||
* but integer, boolean or date.
|
||||
*
|
||||
* @param mixed $date
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isEmptyDate($date): bool
|
||||
{
|
||||
$db = Factory::getPimpleContainer()->db;
|
||||
|
||||
$invalidDates = [
|
||||
'',
|
||||
null,
|
||||
false,
|
||||
0,
|
||||
'0',
|
||||
-1,
|
||||
'-1',
|
||||
$db->getNullDate(),
|
||||
'0000-00-00'
|
||||
];
|
||||
|
||||
return in_array($date, $invalidDates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array or string with the authorised view levels for public or
|
||||
* guest users. If the param $asString is true, it returns a string as CSV.
|
||||
* If false, an array. If the current view was called by the admin to edit
|
||||
* the sitemap links, we return all access levels to give access for everything.
|
||||
*
|
||||
* @param bool $asString
|
||||
*
|
||||
* @return string|string[]
|
||||
*/
|
||||
public static function getAuthorisedViewLevels(bool $asString = true)
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
$levels = [];
|
||||
|
||||
// Check if we need to return all levels, if it was called from the admin to edit the link list
|
||||
if ($container->input->get('view') === 'adminsitemapitems') {
|
||||
$db = $container->db;
|
||||
|
||||
// Get all access levels
|
||||
$query = $db->getQuery(true)
|
||||
->select('id')
|
||||
->from($db->quoteName('#__viewlevels'));
|
||||
$rows = $db->setQuery($query)->loadRowList();
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$levels[] = $row[0];
|
||||
}
|
||||
|
||||
} else {
|
||||
// Only shows returns the level for the current user
|
||||
$levels = Factory::getUser()->getAuthorisedViewLevels();
|
||||
}
|
||||
|
||||
if ($asString) {
|
||||
$levels = implode(',', $levels);
|
||||
}
|
||||
|
||||
return $levels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the appropriate component language files are loaded
|
||||
*
|
||||
* @param string $option
|
||||
* @param string $adminPath
|
||||
* @param string $sitePath
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function loadOptionLanguage(
|
||||
string $option = 'com_osmap',
|
||||
string $adminPath = OSMAP_ADMIN_PATH,
|
||||
string $sitePath = OSMAP_SITE_PATH
|
||||
) {
|
||||
$app = Factory::getApplication();
|
||||
|
||||
switch ($app->getName()) {
|
||||
case 'administrator':
|
||||
Factory::getLanguage()->load($option, $adminPath);
|
||||
break;
|
||||
|
||||
case 'site':
|
||||
Factory::getLanguage()->load($option, $sitePath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the needed method is static or not and call it in the proper
|
||||
* way, avoiding Strict warnings in 3rd party plugins. It returns the
|
||||
* result of the called method.
|
||||
*
|
||||
* @param string $class
|
||||
* @param object $instance
|
||||
* @param string $method
|
||||
* @param array $params
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function callUserFunc(string $class, object $instance, string $method, array $params = [])
|
||||
{
|
||||
try {
|
||||
$reflection = new \ReflectionMethod($class, $method);
|
||||
|
||||
return $reflection->isStatic()
|
||||
? call_user_func_array([$class, $method], $params)
|
||||
: call_user_func_array([$instance, $method], $params);
|
||||
|
||||
} catch (\Exception $error) {
|
||||
// Just ignore this?
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Helper;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Exception;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
defined('_JEXEC') or die();
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
|
||||
|
||||
|
||||
class Images
|
||||
{
|
||||
/**
|
||||
* Extracts images from the given text.
|
||||
*
|
||||
* @param string $text
|
||||
* @param ?int $max
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getImagesFromText(string $text, int $max = 0): array
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
$images = [];
|
||||
|
||||
// Look for <img> tags
|
||||
preg_match_all(
|
||||
'/<img[^>](?=.*(?:src="(?P<src>[^"]*)"))?(?=.*(title="(?P<title>[^"]*)"))?(?=.*(alt="(?P<alt>[^"]*)"))?.[^>]*>/i',
|
||||
$text,
|
||||
$matches1,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
// Look for <a> tags with href to images
|
||||
preg_match_all(
|
||||
'/<a[^>](?=.*(?:href="(?P<src>[^"]+\.(gif|png|jpg|jpeg))"))(?=.*(title="(?P<title>[^"]*)"))?.[^>]*>/i',
|
||||
$text,
|
||||
$matches2,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
|
||||
$matches = array_merge($matches1, $matches2);
|
||||
|
||||
if (count($matches)) {
|
||||
if ($max > 0) {
|
||||
$matches = array_slice($matches, 0, $max);
|
||||
}
|
||||
|
||||
foreach ($matches as $match) {
|
||||
if (
|
||||
($src = trim($match['src'] ?? ''))
|
||||
&& $container->router->isInternalURL($src)
|
||||
) {
|
||||
if ($container->router->isRelativeUri($src)) {
|
||||
$src = $container->router->convertRelativeUriToFullUri($src);
|
||||
}
|
||||
|
||||
$title = trim($match['title'] ?? '');
|
||||
$alt = trim($match['alt'] ?? '');
|
||||
|
||||
$images[] = (object)[
|
||||
'src' => $src,
|
||||
'title' => $title ?: ($alt ?: '')
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of images from the content image params.
|
||||
*
|
||||
* @param object $item
|
||||
*
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getImagesFromParams($item)
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
$imagesParam = json_decode($item->images);
|
||||
$images = [];
|
||||
|
||||
if (isset($imagesParam->image_intro) && !empty($imagesParam->image_intro)) {
|
||||
$ignoreAlt = $imagesParam->image_intro_alt_empty ?? false;
|
||||
|
||||
$images[] = (object)[
|
||||
'src' => $container->router->convertRelativeUriToFullUri($imagesParam->image_intro),
|
||||
'title' => $imagesParam->image_intro_caption
|
||||
?: ($ignoreAlt ? null : $imagesParam->image_intro_alt)
|
||||
];
|
||||
}
|
||||
|
||||
if (isset($imagesParam->image_fulltext) && !empty($imagesParam->image_fulltext)) {
|
||||
$ignoreAlt = $imagesParam->image_fulltext_alt_empty ?? true;
|
||||
$images[] = (object)[
|
||||
'src' => $container->router->convertRelativeUriToFullUri($imagesParam->image_fulltext),
|
||||
'title' => $imagesParam->image_fulltext_caption
|
||||
?: ($ignoreAlt ? null : $imagesParam->image_fulltext_all)
|
||||
];
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Helper;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
abstract class Legacy
|
||||
{
|
||||
/**
|
||||
* Method to return a list of language home page menu items.
|
||||
* Added here to keep compatibility with Joomla 3.4.x.
|
||||
*
|
||||
* @return array of menu objects.
|
||||
*/
|
||||
public static function getSiteHomePages()
|
||||
{
|
||||
// To avoid doing duplicate database queries.
|
||||
static $multilangSiteHomePages = null;
|
||||
|
||||
if (!isset($multilangSiteHomePages)) {
|
||||
// Check for Home pages languages.
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select('language')
|
||||
->select('id')
|
||||
->from($db->quoteName('#__menu'))
|
||||
->where('home = 1')
|
||||
->where('published = 1')
|
||||
->where('client_id = 0');
|
||||
$db->setQuery($query);
|
||||
|
||||
$multilangSiteHomePages = $db->loadObjectList('language');
|
||||
}
|
||||
|
||||
return $multilangSiteHomePages;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Plugin;
|
||||
|
||||
use Alledia\Framework\Exception;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Plugin\CMSPlugin;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
abstract class Base extends CMSPlugin
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected static $memoryLimit = null;
|
||||
|
||||
/**
|
||||
* Minimum memory in MB required to continue on sites with limited memory
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $memoryMinimum = 4;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct(&$subject, $config = [])
|
||||
{
|
||||
require_once JPATH_ADMINISTRATOR . '/components/com_osmap/include.php';
|
||||
|
||||
parent::__construct($subject, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set memory limit to unlimited. If unable to do so,
|
||||
* we'll want to check that we have enough memory left to continue,
|
||||
* so we can fail gracefully
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function fixMemoryLimit()
|
||||
{
|
||||
if (static::$memoryLimit === null) {
|
||||
$limit = @ini_set('memory_limit', -1);
|
||||
|
||||
if (empty($limit)) {
|
||||
$mags = [
|
||||
'K' => 1024,
|
||||
'M' => 1024 * 1024,
|
||||
'G' => 1024 * 1024 * 1024
|
||||
];
|
||||
$limit = ini_get('memory_limit');
|
||||
$regex = sprintf('/(\d*)([%s])/', join(array_keys($mags)));
|
||||
if (preg_match($regex, $limit, $match)) {
|
||||
$limit = $match[1] * $mags[$match[2]];
|
||||
}
|
||||
|
||||
static::$memoryLimit = $limit;
|
||||
static::$memoryMinimum *= $mags['M'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if we're about to run out of memory. If things get too tight
|
||||
* all we can do is throw an informative message or redirect somewhere else
|
||||
* that isn't an OSMap page
|
||||
*
|
||||
* @TODO: Decide whether to implement the redirect option
|
||||
*
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected static function checkMemory()
|
||||
{
|
||||
if (static::$memoryLimit === null) {
|
||||
static::fixMemoryLimit();
|
||||
}
|
||||
|
||||
if (static::$memoryLimit && (static::$memoryLimit - memory_get_usage(true) < static::$memoryMinimum)) {
|
||||
$message = Text::sprintf('COM_OSMAP_WARNING_OOM', get_called_class());
|
||||
throw new Exception($message, 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getViewFromUrl(string $url): string
|
||||
{
|
||||
$linkUrl = parse_url($url);
|
||||
if (isset($linkUrl['query'])) {
|
||||
parse_str($linkUrl['query'], $linkQuery);
|
||||
|
||||
if (isset($linkQuery['view'])) {
|
||||
return $linkQuery['view'];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Plugin;
|
||||
|
||||
use Alledia\OSMap\Sitemap\Collector;
|
||||
use Alledia\OSMap\Sitemap\Item;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
|
||||
interface ContentInterface
|
||||
{
|
||||
/**
|
||||
* Returns the unique instance of the plugin
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function getInstance();
|
||||
|
||||
/**
|
||||
* Returns the element of the component which this plugin supports.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getComponentElement();
|
||||
|
||||
/**
|
||||
* This function is called before a menu item is used. We use it to set the
|
||||
* proper uniqueid for the item
|
||||
*
|
||||
* @param Item $node Menu item to be "prepared"
|
||||
* @param Registry $params The extension params
|
||||
*
|
||||
* @return void
|
||||
* @since 1.2
|
||||
*/
|
||||
public static function prepareMenuItem($node, $params);
|
||||
|
||||
/**
|
||||
* Expands a com_content menu item
|
||||
*
|
||||
* @param Collector $collector
|
||||
* @param Item $parent
|
||||
* @param Registry $params
|
||||
*
|
||||
* @return void
|
||||
* @since 1.0
|
||||
*/
|
||||
public static function getTree($collector, $parent, $params);
|
||||
}
|
||||
@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap;
|
||||
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\CMS\Version;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
|
||||
class Router
|
||||
{
|
||||
/**
|
||||
* Route the given URL using the site application. If in admin, the result
|
||||
* needs to be the same as the frontend.
|
||||
*
|
||||
* @param string $url
|
||||
* @param bool $absolute
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function routeURL(string $url, bool $absolute = false): string
|
||||
{
|
||||
if ((strpos($url, '&') !== 0) && (strpos($url, 'index.php') !== 0)) {
|
||||
// Not a routable URL
|
||||
return $url;
|
||||
}
|
||||
|
||||
if ($absolute) {
|
||||
return Route::link('site', $url, true, Route::TLS_IGNORE, true);
|
||||
}
|
||||
|
||||
return Route::link('site', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the supplied URL is internal
|
||||
*
|
||||
* @param ?string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInternalURL(?string $url): bool
|
||||
{
|
||||
$uri = Uri::getInstance($url);
|
||||
$base = $uri->toString(['scheme', 'host', 'port', 'path']);
|
||||
$host = $uri->toString(['scheme', 'host', 'port']);
|
||||
$path = $uri->toString(['path']);
|
||||
$baseHost = Uri::getInstance($uri::root())->toString(['host']);
|
||||
|
||||
if ($path === $url) {
|
||||
return true;
|
||||
|
||||
} elseif (
|
||||
empty($host)
|
||||
&& strpos($path, 'index.php') === 0
|
||||
|| empty($host) == false && preg_match('#' . preg_quote($uri::root(), '#') . '#', $base)
|
||||
|| empty($host) == false && $host === $baseHost && strpos($path, 'index.php') !== false
|
||||
|| empty($host) == false && $base === $host
|
||||
&& preg_match('#' . preg_quote($base, '#') . '#', $uri::root())
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given URL is a relative URI. Returns true, if affirmative.
|
||||
*
|
||||
* @param ?string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRelativeUri(?string $url): bool
|
||||
{
|
||||
if ($url) {
|
||||
$urlPath = (new Uri($url))->toString(['path']);
|
||||
|
||||
return $urlPath === $url;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an internal relative URI into a full link.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convertRelativeUriToFullUri(string $path): string
|
||||
{
|
||||
if (
|
||||
Version::MAJOR_VERSION > 3
|
||||
&& strpos($path, '#joomlaImage:') !== false
|
||||
) {
|
||||
$media = HTMLHelper::_('cleanImageURL', $path);
|
||||
$path = $media->url;
|
||||
}
|
||||
|
||||
if ($path[0] == '/') {
|
||||
$scheme = ['scheme', 'user', 'pass', 'host', 'port'];
|
||||
$path = Uri::getInstance()->toString($scheme) . $path;
|
||||
|
||||
} elseif ($this->isRelativeUri($path)) {
|
||||
$path = Uri::root() . $path;
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sanitized URL, removing double slashes and trailing slash.
|
||||
*
|
||||
* @param ?string $url
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function sanitizeURL(?string $url): ?string
|
||||
{
|
||||
if ($url) {
|
||||
return preg_replace('#([^:])(/{2,})#', '$1/', $url);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a URL without the hash
|
||||
*
|
||||
* @param ?string $url
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function removeHashFromURL(?string $url): ?string
|
||||
{
|
||||
if ($url) {
|
||||
// Check if the URL has a hash to remove it (XML sitemap shouldn't have hash on the URL)
|
||||
$hashPos = strpos($url, '#');
|
||||
|
||||
if ($hashPos !== false) {
|
||||
// Remove the hash
|
||||
$url = substr($url, 0, $hashPos);
|
||||
}
|
||||
|
||||
return trim($url);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a consistent url hash regardless of scheme or site root.
|
||||
*
|
||||
* @param ?string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createUrlHash(?string $url): string
|
||||
{
|
||||
return md5(str_replace(Uri::root(), '', (string)$url));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Services;
|
||||
|
||||
use Alledia\Framework\Profiler;
|
||||
use Alledia\OSMap\Factory;
|
||||
use Alledia\OSMap\Helper\Images;
|
||||
use Alledia\OSMap\Router;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Pimple\Container as Pimple;
|
||||
use Pimple\ServiceProviderInterface;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
/**
|
||||
* Class Services
|
||||
*
|
||||
* Pimple services for OSMap. The container must be instantiated with
|
||||
* at least the following values:
|
||||
*
|
||||
* new \OSMap\Container(
|
||||
* array(
|
||||
* 'configuration' => new Configuration($config)
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @package OSMap
|
||||
*/
|
||||
class Free implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Registers services on the given container.
|
||||
*
|
||||
* This method should only be used to configure services and parameters.
|
||||
* It should not get services.
|
||||
*
|
||||
* @param Pimple $pimple
|
||||
*/
|
||||
public function register(Pimple $pimple)
|
||||
{
|
||||
$pimple['app'] = function () {
|
||||
return Factory::getApplication();
|
||||
};
|
||||
|
||||
$pimple['db'] = function () {
|
||||
return Factory::getDbo();
|
||||
};
|
||||
|
||||
$pimple['input'] = function () {
|
||||
return Factory::getApplication()->input;
|
||||
};
|
||||
|
||||
$pimple['user'] = function () {
|
||||
return Factory::getUser();
|
||||
};
|
||||
|
||||
$pimple['language'] = function () {
|
||||
return Factory::getLanguage();
|
||||
};
|
||||
|
||||
$pimple['profiler'] = function () {
|
||||
return new Profiler();
|
||||
};
|
||||
|
||||
$pimple['router'] = function () {
|
||||
return new Router();
|
||||
};
|
||||
|
||||
$pimple['uri'] = function () {
|
||||
return new Uri();
|
||||
};
|
||||
|
||||
$this->registerHelper($pimple);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Pimple $pimple
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerHelper(Pimple $pimple)
|
||||
{
|
||||
$pimple['imagesHelper'] = function () {
|
||||
return new Images();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,794 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Alledia\OSMap\Helper\General;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
/**
|
||||
* Sitemap items collector
|
||||
*/
|
||||
class Collector
|
||||
{
|
||||
/**
|
||||
* @var SitemapInterface
|
||||
*/
|
||||
protected $sitemap;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $uidList = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $urlHashList = [];
|
||||
|
||||
/**
|
||||
* Callback used to trigger the desired action while fetching items.
|
||||
* This is only used in the legacy method printNode, which is called by
|
||||
* the osmap plugins to process the additional items.
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $printNodeCallback;
|
||||
|
||||
/**
|
||||
* The current view: xml or html. Kept for backward compatibility with
|
||||
* the legacy plugins. It is always XML since the collector is generic now
|
||||
* and needs to have the information about the item's level even for the
|
||||
* XML view in the Pro version
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $view = 'xml';
|
||||
|
||||
/**
|
||||
* Legacy property used by some plugins. True if we are collecting news.
|
||||
*
|
||||
* @var string
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public $isNews = false;
|
||||
|
||||
/**
|
||||
* The items counter.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $counter = 0;
|
||||
|
||||
/**
|
||||
* The custom settings for items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $itemsSettings = null;
|
||||
|
||||
/**
|
||||
* The legacy custom settings for items. Which will be upgraded
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $legacyItemsSettings = null;
|
||||
|
||||
/**
|
||||
* If false, say that any next sub-level should be unpublished
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $unpublishLevel = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tmpItemDefaultSettings = [
|
||||
'changefreq' => 'weekly',
|
||||
'priority' => '0.5'
|
||||
];
|
||||
|
||||
/**
|
||||
* The current items level
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $currentLevel = 0;
|
||||
|
||||
/**
|
||||
* The reference for the instance of the current menu for item and its
|
||||
* subitems.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $currentMenu;
|
||||
|
||||
/**
|
||||
* The ID of the current menu item for nodes
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $currentMenuItemId = null;
|
||||
|
||||
/**
|
||||
* The component's params
|
||||
*
|
||||
* @var Registry
|
||||
*/
|
||||
public $params;
|
||||
|
||||
/**
|
||||
* Collector constructor.
|
||||
*
|
||||
* @param SitemapInterface $sitemap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(SitemapInterface $sitemap)
|
||||
{
|
||||
$this->sitemap = $sitemap;
|
||||
$this->params = ComponentHelper::getParams('com_osmap');
|
||||
|
||||
/*
|
||||
* Try to detect the current view. This is just for backward compatibility
|
||||
* for legacy plugins. New plugins doesn't need to know what is the view.
|
||||
* They always calculate the visibility for both views and the view is
|
||||
* the one who decides to whow or not. If not equals HTML, is always XML.
|
||||
*/
|
||||
$inputView = Factory::getPimpleContainer()->input->get('view', 'xml');
|
||||
if ($inputView === 'html') {
|
||||
$this->view = 'html';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects sitemap items based on the selected menus. This is the main
|
||||
* method of this class. For each found item, it will call the given
|
||||
* callback, so it can manipulate the data in many ways. It returns the
|
||||
* total of found items.
|
||||
*
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function fetch(callable $callback): int
|
||||
{
|
||||
$menus = $this->getSitemapMenus();
|
||||
|
||||
$this->counter = 0;
|
||||
if ($menus) {
|
||||
$this->getLegacyItemsSettings();
|
||||
$this->getItemsSettings();
|
||||
|
||||
foreach ($menus as $menu) {
|
||||
$this->currentMenu = &$menu;
|
||||
|
||||
$items = $this->getMenuItems($menu);
|
||||
foreach ($items as $item) {
|
||||
if ($this->itemIsBlackListed($item)) {
|
||||
$item = null;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store the current menu item id. Added to use it while defining the node's settings hash, so same
|
||||
// items, but from different menus can have individual settings
|
||||
$this->currentMenuItemId = $item['id'];
|
||||
|
||||
// Set the menu item UID. The UID can be changed by 3rd party plugins, according to the content
|
||||
$item['uid'] = 'menuitem.' . $item['id'];
|
||||
|
||||
// Store the menu settings to use in the submitItemToCallback called by callbacks
|
||||
$this->tmpItemDefaultSettings['changefreq'] = $menu->changefreq;
|
||||
$this->tmpItemDefaultSettings['priority'] = $menu->priority;
|
||||
|
||||
// Check the level of menu
|
||||
$level = (int)$item['level'] - 1;
|
||||
if ($level !== $this->currentLevel) {
|
||||
$this->changeLevel($level - $this->currentLevel);
|
||||
}
|
||||
|
||||
// Submit the item and prepare it calling the plugins
|
||||
$this->submitItemToCallback($item, $callback, true);
|
||||
|
||||
// Internal links can trigger plugins to grab more items
|
||||
// The child items are not displayed if the parent item is ignored
|
||||
if ($item->isInternal && !$item->ignore) {
|
||||
// Call the plugin to get additional items related to it
|
||||
$this->callPluginsGetItemTree($item, $callback);
|
||||
}
|
||||
|
||||
// Make sure the memory is cleaned up
|
||||
$item = null;
|
||||
}
|
||||
$items = [];
|
||||
unset($items);
|
||||
}
|
||||
|
||||
$menu = null;
|
||||
}
|
||||
|
||||
$this->currentMenu = null;
|
||||
$this->tmpItemDefaultSettings = [];
|
||||
|
||||
return $this->counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the item to the callback, checking duplicity and incrementing
|
||||
* the counter. It can receive an array or object and returns true or false
|
||||
* according to the result of the callback.
|
||||
*
|
||||
* @param array|object $item
|
||||
* @param callable $callback
|
||||
* @param bool $prepareItem
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function submitItemToCallback(&$item, callable $callback, bool $prepareItem = false): bool
|
||||
{
|
||||
$currentMenuItemId = $this->getCurrentMenuItemId();
|
||||
|
||||
$item = (object)$item;
|
||||
|
||||
// Add the menu information
|
||||
$item->menuItemId = $this->currentMenu->id;
|
||||
$item->menuItemTitle = $this->currentMenu->name;
|
||||
$item->menuItemType = $this->currentMenu->menutype;
|
||||
|
||||
|
||||
// Converts to an Item instance, setting internal attributes
|
||||
$item = new Item($item, $currentMenuItemId);
|
||||
|
||||
if ($prepareItem) {
|
||||
// Call the plugins to prepare the item
|
||||
$this->callPluginsPreparingTheItem($item);
|
||||
}
|
||||
|
||||
// Make sure to have the correct date format (UTC)
|
||||
$item->setModificationDate();
|
||||
|
||||
$item->setAdapter();
|
||||
$item->visibleForRobots = $item->adapter->checkVisibilityForRobots();
|
||||
|
||||
// Set the current level to the item
|
||||
$item->level = $this->currentLevel;
|
||||
|
||||
$this->setItemCustomSettings($item);
|
||||
$this->checkParentIsUnpublished($item);
|
||||
$this->checkDuplicatedUIDToIgnore($item);
|
||||
|
||||
// Verify if the item can be displayed to count as unique for the XML sitemap
|
||||
if (
|
||||
!$item->ignore
|
||||
&& $item->published
|
||||
&& $item->visibleForRobots
|
||||
&& (!$item->duplicate || !$this->params->get('ignore_duplicated_uids', 1))
|
||||
) {
|
||||
// Check if the URL is not duplicated (specially for the XML sitemap)
|
||||
$this->checkDuplicatedURLToIgnore($item);
|
||||
|
||||
if (!$item->duplicate || !$this->params->get('ignore_duplicated_uids', 1)) {
|
||||
++$this->counter;
|
||||
}
|
||||
}
|
||||
|
||||
return (bool)call_user_func_array($callback, [&$item]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of selected menus for the sitemap.
|
||||
* It returns a list of objects with the attributes:
|
||||
* - name
|
||||
* - menutype
|
||||
* - priority
|
||||
* - changefrq
|
||||
* - ordering
|
||||
*
|
||||
* @return object[];
|
||||
*/
|
||||
protected function getSitemapMenus(): array
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'mt.id',
|
||||
'mt.title AS ' . $db->quoteName('name'),
|
||||
'mt.menutype',
|
||||
'osm.changefreq',
|
||||
'osm.priority',
|
||||
'osm.ordering'
|
||||
])
|
||||
->from('#__osmap_sitemap_menus AS osm')
|
||||
->join('LEFT', '#__menu_types AS mt ON (osm.menutype_id = mt.id)')
|
||||
->where('osm.sitemap_id = ' . $db->quote($this->sitemap->id))
|
||||
->order('osm.ordering');
|
||||
|
||||
return $db->setQuery($query)->loadObjectList('menutype');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the menu items as a tree
|
||||
*
|
||||
* @param object $menu
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getMenuItems(object $menu): array
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
$db = $container->db;
|
||||
$app = $container->app;
|
||||
$lang = $container->language;
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'm.id',
|
||||
'm.title AS ' . $db->quoteName('name'),
|
||||
'm.alias',
|
||||
'm.path',
|
||||
'm.level',
|
||||
'm.type',
|
||||
'm.home',
|
||||
'm.params',
|
||||
'm.parent_id',
|
||||
'm.browserNav',
|
||||
'm.link',
|
||||
'1 AS ' . $db->quoteName('isMenuItem'), // Say that the menu came from a menu
|
||||
'0 AS ' . $db->quoteName('ignore') // Flag that allows child classes choose to ignore items
|
||||
])
|
||||
->from('#__menu AS m')
|
||||
->join('INNER', '#__menu AS p ON (p.lft = 0)')
|
||||
->where([
|
||||
'm.menutype = ' . $db->quote($menu->menutype),
|
||||
'm.published = 1',
|
||||
sprintf('m.access IN (%s)', General::getAuthorisedViewLevels()),
|
||||
'm.lft > p.lft',
|
||||
'm.lft < p.rgt'
|
||||
])
|
||||
->order('m.lft');
|
||||
|
||||
if ($app->isClient('site')) {
|
||||
if ($app->getLanguageFilter()) {
|
||||
$languageTags = array_map([$db, 'quote'], [$lang->getTag(), '*']);
|
||||
|
||||
$query->where(sprintf('m.language IN (%s)', join(',', $languageTags)));
|
||||
}
|
||||
}
|
||||
|
||||
$items = $db->setQuery($query)->loadAssocList();
|
||||
|
||||
if ($this->params->get('ignore_hidden_menus', false)) {
|
||||
$items = array_filter(
|
||||
$items,
|
||||
function ($menu) {
|
||||
$params = json_decode($menu['params']);
|
||||
if (isset($params->menu_show) && $params->menu_show == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item's uid was already registered. If positive, set the
|
||||
* item to be ignored and return true. If negative, register the item and
|
||||
* return false.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkDuplicatedUIDToIgnore(Item $item): bool
|
||||
{
|
||||
// If is already set, interrupt the flux and ignore the item
|
||||
if (isset($this->uidList[$item->uid])) {
|
||||
$item->duplicate = true;
|
||||
|
||||
if ($this->params->get('ignore_duplicated_uids', 1)) {
|
||||
$item->addAdminNote('COM_OSMAP_ADMIN_NOTE_DUPLICATED_IGNORED');
|
||||
} else {
|
||||
$item->addAdminNote('COM_OSMAP_ADMIN_NOTE_DUPLICATED');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not set and published, so let's register
|
||||
if ($item->published && $item->visibleForRobots && !$item->ignore) {
|
||||
$this->uidList[$item->uid] = 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item's full link was already registered. If positive,
|
||||
* set the item to be ignored and return true. If negative, register the item and return false
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkDuplicatedURLToIgnore(Item $item): bool
|
||||
{
|
||||
if (!empty($item->fullLink)) {
|
||||
$container = Factory::getPimpleContainer();
|
||||
|
||||
// We need to make sure to have a URL free of hash chars
|
||||
$url = $container->router->removeHashFromURL($item->fullLink);
|
||||
$hash = $container->router->createUrlHash($url);
|
||||
|
||||
if (isset($this->urlHashList[$hash])) {
|
||||
$item->duplicate = true;
|
||||
$item->addAdminNote('COM_OSMAP_ADMIN_NOTE_DUPLICATED_URL_IGNORED');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not set and published, so let's register
|
||||
if ($item->published && $item->visibleForRobots && !$item->ignore) {
|
||||
$this->urlHashList[$hash] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the respective OSMap and XMap plugin, according to the item's
|
||||
* component/option. If the plugin's method returns false, it will set
|
||||
* the item's ignore attribute to true.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function callPluginsPreparingTheItem(Item $item)
|
||||
{
|
||||
$plugins = General::getPluginsForComponent($item->component);
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
$className = '\\' . $plugin->className;
|
||||
|
||||
if (method_exists($className, 'prepareMenuItem')) {
|
||||
if ($plugin->isLegacy) {
|
||||
$params = $plugin->params->toArray();
|
||||
} else {
|
||||
$params =& $plugin->params;
|
||||
}
|
||||
|
||||
$arguments = [
|
||||
&$item,
|
||||
&$params
|
||||
];
|
||||
|
||||
// If a legacy plugin doesn't specify this method as static, fix the plugin to avoid warnings
|
||||
$result = General::callUserFunc(
|
||||
$className,
|
||||
$plugin->instance,
|
||||
'prepareMenuItem',
|
||||
$arguments
|
||||
);
|
||||
|
||||
// If a plugin doesn't return true we ignore the item and break
|
||||
if ($result === false) {
|
||||
$item->set('ignore', true);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$plugin = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the respective OSMap and XMap plugin, according to the item's
|
||||
* component/option. Get additional items and send to the callback.
|
||||
*
|
||||
* @param Item $item
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function callPluginsGetItemTree(Item $item, callable $callback)
|
||||
{
|
||||
$this->printNodeCallback = $callback;
|
||||
|
||||
// Call the OSMap and XMap legacy plugins
|
||||
$plugins = General::getPluginsForComponent($item->component);
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
$className = '\\' . $plugin->className;
|
||||
if (method_exists($className, 'getTree')) {
|
||||
if ($plugin->isLegacy) {
|
||||
$params = $plugin->params->toArray();
|
||||
} else {
|
||||
$params = $plugin->params;
|
||||
}
|
||||
|
||||
$arguments = [
|
||||
&$this,
|
||||
&$item,
|
||||
&$params
|
||||
];
|
||||
|
||||
General::callUserFunc(
|
||||
$className,
|
||||
$plugin->instance,
|
||||
'getTree',
|
||||
$arguments
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the link of the item is in the blacklist array.
|
||||
*
|
||||
* @param array $item
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function itemIsBlackListed(array $item): bool
|
||||
{
|
||||
$blackList = [
|
||||
'administrator' => 1
|
||||
];
|
||||
|
||||
$link = $item['link'];
|
||||
|
||||
return isset($blackList[$link]);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used for backward compatibility. The plugins will call
|
||||
* it. In the legacy XMap, its behavior depends on the sitemap view type,
|
||||
* only changing the level in the HTML view. OSMap will always consider the
|
||||
* level of the item, even for XML view. XML will just ignore that.
|
||||
*
|
||||
* @param int $step
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeLevel(int $step)
|
||||
{
|
||||
$this->currentLevel += $step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called by legacy plugins, which will pass the new item to the
|
||||
* callback. Returns the result of the callback converted to boolean.
|
||||
*
|
||||
* @param array|object $node
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function printNode($node): bool
|
||||
{
|
||||
return $this->submitItemToCallback($node, $this->printNodeCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the settings for all items which have custom settings.
|
||||
*
|
||||
* @return array;
|
||||
*/
|
||||
protected function getItemsSettings(): array
|
||||
{
|
||||
if (empty($this->itemsSettings)) {
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'*',
|
||||
sprintf(
|
||||
'IF (IFNULL(settings_hash, %1$s) = %1$s, uid, CONCAT(uid, %2$s, settings_hash)) AS %3$s',
|
||||
$db->quote(''),
|
||||
$db->quote(':'),
|
||||
$db->quoteName('key')
|
||||
)
|
||||
])
|
||||
->from('#__osmap_items_settings')
|
||||
->where('sitemap_id = ' . $db->quote($this->sitemap->id))
|
||||
->where($db->quoteName('format') . ' = 2');
|
||||
|
||||
$this->itemsSettings = $db->setQuery($query)->loadAssocList('key');
|
||||
}
|
||||
|
||||
return $this->itemsSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item custom settings if set. If not set, returns false.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return ?array[]
|
||||
*/
|
||||
public function getItemCustomSettings(string $key): ?array
|
||||
{
|
||||
if (isset($this->itemsSettings[$key])) {
|
||||
return $this->itemsSettings[$key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method gets the legacy settings for all items to be loaded avoiding
|
||||
* lost the custom settings for items after the migration to v4.2.1.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getLegacyItemsSettings(): array
|
||||
{
|
||||
if ($this->legacyItemsSettings === null) {
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('*')
|
||||
->from('#__osmap_items_settings')
|
||||
->where('sitemap_id = ' . $db->quote($this->sitemap->id))
|
||||
->where($db->quoteName('format') . ' IS NULL');
|
||||
|
||||
$this->legacyItemsSettings = $db->setQuery($query)->loadAssocList('uid');
|
||||
}
|
||||
|
||||
return $this->legacyItemsSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the settings based on the UID only. Used when we have legacy
|
||||
* settings on the database.
|
||||
*
|
||||
* @param string $uid
|
||||
*
|
||||
* @return ?array[]
|
||||
*/
|
||||
protected function getLegacyItemCustomSettings(string $uid): ?array
|
||||
{
|
||||
if (isset($this->legacyItemsSettings[$uid])) {
|
||||
return $this->legacyItemsSettings[$uid];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item's custom settings if exists. If no custom settings are
|
||||
* found and is a menu item, use the menu's settings. If is s subitem
|
||||
* (from plugins), we consider it already set the respective settings. But
|
||||
* if there is a custom setting for the item, we use that overriding what
|
||||
* was set in the plugin.
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setItemCustomSettings(Item $item)
|
||||
{
|
||||
// Check if the menu item has custom settings. If not, use the values from the menu
|
||||
// Check if there is a custom settings specific for this URL. Sometimes the same page has different URLs.
|
||||
// We can have different settings for items with the same UID, but different URLs
|
||||
$key = $item->uid . ':' . $item->settingsHash;
|
||||
$settings = $this->getItemCustomSettings($key);
|
||||
|
||||
// Check if there is a custom settings for all links with that UID (happens right after a migration from
|
||||
// versions before 4.0.0 or before 4.2.1)
|
||||
if (empty($settings)) {
|
||||
$settings = $this->getLegacyItemCustomSettings($item->uid);
|
||||
|
||||
// The Joomla plugin changed the UID
|
||||
// from joomla.archive => joomla.archive.[id] and joomla.featured => joomla.featured[id]
|
||||
// So we need to try getting the settings from the old UID
|
||||
if ($settings === null) {
|
||||
if (preg_match('/^joomla.(archive|featured)/', $item->uid, $matches)) {
|
||||
$settings = $this->getLegacyItemCustomSettings('joomla.' . $matches[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($settings)) {
|
||||
// No custom settings, so let's use the menu's settings
|
||||
if ($item->isMenuItem) {
|
||||
$item->changefreq = $this->tmpItemDefaultSettings['changefreq'];
|
||||
$item->priority = $this->tmpItemDefaultSettings['priority'];
|
||||
}
|
||||
|
||||
} else {
|
||||
// Apply the custom settings
|
||||
$item->changefreq = $settings['changefreq'] ?? 'weekly';
|
||||
$item->priority = (float)$settings['priority'] ?? .5;
|
||||
$item->published = (bool)$settings['published'] ?? true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the parent is unpublished or ignored and makes sure to ignore any item on it's sublevel
|
||||
*
|
||||
* @param Item $item
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function checkParentIsUnpublished(Item $item)
|
||||
{
|
||||
// Check if this item belongs to a sub-level which needs to be unpublished
|
||||
if ($this->unpublishLevel !== false && $item->level > $this->unpublishLevel) {
|
||||
$item->set('published', false);
|
||||
$item->addAdminNote('COM_OSMAP_ADMIN_NOTE_PARENT_UNPUBLISHED');
|
||||
}
|
||||
|
||||
// If the item is unpublished and the 'ignore' level is false, mark the level to ignore sub-items
|
||||
$displayable = $item->published
|
||||
&& !$item->ignore
|
||||
&& (!$item->duplicate || !$this->params->get('ignore_duplicated_uids', 1));
|
||||
if (!$displayable && $this->unpublishLevel === false) {
|
||||
$this->unpublishLevel = $item->level;
|
||||
}
|
||||
|
||||
// If the item won't be ignored, make sure to reset the 'ignore' level
|
||||
if (
|
||||
$item->published
|
||||
&& !$item->ignore
|
||||
&& (!$item->duplicate || !$this->params->get('ignore_duplicated_uids', 1))
|
||||
) {
|
||||
$this->unpublishLevel = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current menu item id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCurrentMenuItemId(): int
|
||||
{
|
||||
return (int)$this->currentMenuItemId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes circular reference
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
$this->sitemap = null;
|
||||
$this->printNodeCallback = null;
|
||||
$this->params = null;
|
||||
$this->currentMenu = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap;
|
||||
|
||||
use Alledia\OSMap;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class Images extends Standard
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'images';
|
||||
}
|
||||
@ -0,0 +1,609 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Alledia\OSMap\Helper\General;
|
||||
use Joomla\CMS\Date\Date;
|
||||
use Joomla\CMS\Language\Multilanguage;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Object\CMSObject;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
/**
|
||||
* Sitemap item
|
||||
*/
|
||||
class Item extends CMSObject
|
||||
{
|
||||
/**
|
||||
* @var int;
|
||||
*/
|
||||
public $id = null;
|
||||
|
||||
/**
|
||||
* @var string;
|
||||
*/
|
||||
public $uid = null;
|
||||
|
||||
/**
|
||||
* Item's link, which can be relative or un-routed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $link = null;
|
||||
|
||||
/**
|
||||
* Routed full link, sanitized and without any hash segment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $fullLink = null;
|
||||
|
||||
/**
|
||||
* Routed full link, sanitized but can contain a hash segment
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $rawLink = null;
|
||||
|
||||
/**
|
||||
* @var Registry
|
||||
*/
|
||||
public $params = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $priority = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $changefreq = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $created = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $modified = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $publishUp = null;
|
||||
|
||||
/**
|
||||
* The component associated to the option URL param
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $ignore = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $duplicate = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $browserNav = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $isInternal = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $home = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $type = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $expandible = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $secure = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $isMenuItem = 0;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $published = 1;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $images = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $settingsHash = null;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $level = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $adapterName = 'Generic';
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
public $adapter = null;
|
||||
|
||||
/**
|
||||
* If true, says the item is visible for robots
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $visibleForRobots = true;
|
||||
|
||||
/**
|
||||
* If true, says the item's parent is visible for robots
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $parentIsVisibleForRobots = true;
|
||||
|
||||
/**
|
||||
* Stores a list of notes generated by the collector to display in the admin
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $adminNotes = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $visibleForXML = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $visibleForHTML = true;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $menuItemId = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $menuItemName = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $menuItemType = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $subnodes = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $slug = null;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct($itemData, $currentMenuItemId)
|
||||
{
|
||||
parent::__construct($itemData);
|
||||
|
||||
if (class_exists('\\Alledia\\OSMap\\Sitemap\\ItemAdapter\\GenericPro')) {
|
||||
$this->adapterName = 'GenericPro';
|
||||
}
|
||||
|
||||
$this->published = (bool)$this->published;
|
||||
$this->isMenuItem = (bool)$this->isMenuItem;
|
||||
$this->params = new Registry($this->params);
|
||||
|
||||
// Check if the link is an internal link
|
||||
$this->isInternal = $this->checkLinkIsInternal();
|
||||
|
||||
$this->prepareDate('created');
|
||||
$this->prepareDate('modified');
|
||||
|
||||
$defaultDate = is_null($this->created) ? $this->modified : $this->created;
|
||||
$this->prepareDate('publishUp', $defaultDate);
|
||||
|
||||
$this->setLink();
|
||||
$this->extractComponentFromLink();
|
||||
$this->setFullLink();
|
||||
|
||||
// Sanitize internal links
|
||||
if ($this->isInternal) {
|
||||
$this->sanitizeFullLink();
|
||||
}
|
||||
|
||||
$this->rawLink = $this->fullLink;
|
||||
|
||||
// Removes the hash segment from the Full link, if exists
|
||||
$container = Factory::getPimpleContainer();
|
||||
$this->fullLink = $container->router->removeHashFromURL($this->fullLink);
|
||||
|
||||
// Make sure to have a unique hash for the settings
|
||||
$this->settingsHash = $container->router->createUrlHash($this->fullLink . $currentMenuItemId);
|
||||
|
||||
/*
|
||||
* Do not use a "prepare" method because we need to make sure it will
|
||||
* be calculated after the link is set.
|
||||
*/
|
||||
$this->calculateUID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the note to the admin note attribute and initialize the variable
|
||||
* if needed
|
||||
*
|
||||
* @param string $note
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addAdminNote(string $note)
|
||||
{
|
||||
if (!is_array($this->adminNotes)) {
|
||||
$this->adminNotes = [];
|
||||
}
|
||||
|
||||
$this->adminNotes[] = Text::_($note);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkLinkIsInternal(): bool
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
|
||||
return $container->router->isInternalURL($this->link)
|
||||
|| in_array(
|
||||
$this->type,
|
||||
[
|
||||
'separator',
|
||||
'heading',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the correct date for the attribute
|
||||
*
|
||||
* @param string $attributeName
|
||||
* @param ?string $default
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareDate(string $attributeName, ?string $default = null)
|
||||
{
|
||||
if ($default !== null && empty($this->{$attributeName})) {
|
||||
$this->{$attributeName} = $default;
|
||||
}
|
||||
|
||||
if (General::isEmptyDate($this->{$attributeName})) {
|
||||
$this->{$attributeName} = null;
|
||||
}
|
||||
|
||||
if (!General::isEmptyDate($this->{$attributeName})) {
|
||||
if (!is_numeric($this->{$attributeName})) {
|
||||
$date = new Date($this->{$attributeName});
|
||||
$this->{$attributeName} = $date->toUnix();
|
||||
}
|
||||
|
||||
// Convert dates from UTC
|
||||
if (intval($this->{$attributeName})) {
|
||||
if ($this->{$attributeName} < 0) {
|
||||
$this->{$attributeName} = null;
|
||||
} else {
|
||||
$date = new Date($this->{$attributeName});
|
||||
$this->{$attributeName} = $date->toISO8601();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasCompatibleLanguage(): bool
|
||||
{
|
||||
// Check the language
|
||||
if (Multilanguage::isEnabled() && isset($this->language)) {
|
||||
if ($this->language === '*' || $this->language === Factory::getLanguage()->getTag()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash based on the link, to avoid duplicated links. It will
|
||||
* set the new UID to the item.
|
||||
*
|
||||
* @param bool $force
|
||||
* @param string $prefix
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function calculateUID(bool $force = false, string $prefix = '')
|
||||
{
|
||||
if (empty($this->uid) || $force) {
|
||||
$this->uid = $prefix . md5($this->fullLink);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the link in special cases, like alias, where the link doesn't have
|
||||
* the correct related menu id.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setLink()
|
||||
{
|
||||
// If is an alias, use the Itemid stored in the parameters to get the correct url
|
||||
if ($this->type === 'alias') {
|
||||
// Get the related menu item's link
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('link')
|
||||
->from('#__menu')
|
||||
->where('id = ' . $db->quote($this->params->get('aliasoptions')));
|
||||
|
||||
$this->link = $db->setQuery($query)->loadResult();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the link removing double slashes and trailing slash
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function sanitizeFullLink()
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
|
||||
$this->fullLink = $container->router->sanitizeURL($this->fullLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current link to a full URL, including the base URI.
|
||||
* If the item is the home menu, will return the base URI. If internal,
|
||||
* will return a routed full URL (SEF, if enabled). If it is an external
|
||||
* URL, won't change the link.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setFullLink()
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
|
||||
if ($this->home) {
|
||||
// Correct the URL for the home page.
|
||||
// Check if multi-language is enabled to use the proper route
|
||||
if (Multilanguage::isEnabled()) {
|
||||
$lang = Factory::getLanguage();
|
||||
$tag = $lang->getTag();
|
||||
$lang = null;
|
||||
|
||||
$homes = Multilanguage::getSiteHomePages();
|
||||
|
||||
$home = $homes[$tag] ?? $homes['*'];
|
||||
|
||||
$this->fullLink = $container->router->routeURL('index.php?Itemid=' . $home->id, true);
|
||||
|
||||
} else {
|
||||
$this->fullLink = $container->uri::root();
|
||||
}
|
||||
|
||||
$this->fullLink = $container->router->sanitizeURL($this->fullLink);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->type === 'separator' || $this->type === 'heading') {
|
||||
// Not a url so disable browser nav
|
||||
$this->browserNav = 3;
|
||||
$this->uid = $this->type . '.' . md5($this->name . $this->id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->type === 'url') {
|
||||
$this->link = trim($this->link);
|
||||
// Check if it is a single Hash char, the user doesn't want to point to any URL
|
||||
if ($this->link === '#' || empty($this->link)) {
|
||||
$this->fullLink = '';
|
||||
$this->visibleForXML = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it is a relative URI
|
||||
if ($container->router->isRelativeUri($this->link)) {
|
||||
$this->fullLink = $container->router->sanitizeURL(
|
||||
$container->router->convertRelativeUriToFullUri($this->link)
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->fullLink = $this->link;
|
||||
|
||||
if (!$this->isInternal) {
|
||||
// External URLS have UID as a hash as part of its url
|
||||
$this->calculateUID(true, 'external.');
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->type === 'alias') {
|
||||
// Use the destination itemid, instead of the alias' item id.
|
||||
// This will make sure we have the correct routed url.
|
||||
$this->fullLink = 'index.php?Itemid=' . $this->params->get('aliasoptions');
|
||||
}
|
||||
|
||||
// If is a menu item but not an alias, force to use the current menu's item id
|
||||
if ($this->isMenuItem && $this->type !== 'alias' && $this->type !== 'url') {
|
||||
$this->fullLink = 'index.php?Itemid=' . $this->id;
|
||||
}
|
||||
|
||||
// If is not a menu item, use as base for the fullLink, the item link
|
||||
if (!$this->isMenuItem) {
|
||||
$this->fullLink = $this->link;
|
||||
}
|
||||
|
||||
if ($this->isInternal) {
|
||||
$this->fullLink = $container->router->routeURL($this->fullLink, true);
|
||||
}
|
||||
|
||||
$this->fullLink = $container->router->sanitizeURL($this->fullLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the item adapter according to the type of content. The adapter can
|
||||
* extract custom params from the item like params and metadata.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setAdapter()
|
||||
{
|
||||
// Check if there is class for the option
|
||||
$adapterClass = '\\Alledia\\OSMap\\Sitemap\\ItemAdapter\\' . $this->adapterName;
|
||||
if (class_exists($adapterClass)) {
|
||||
$this->adapter = new $adapterClass($this);
|
||||
} else {
|
||||
$this->adapter = new ItemAdapter\Generic($this);
|
||||
}
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->adapter->cleanup();
|
||||
|
||||
$this->adapter = null;
|
||||
$this->params = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the option from the link, to identify the component called by
|
||||
* the link.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function extractComponentFromLink()
|
||||
{
|
||||
$this->component = null;
|
||||
|
||||
if (preg_match('#^/?index.php.*option=(com_[^&]+)#', $this->link, $matches)) {
|
||||
$this->component = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the admin notes as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAdminNotesString(): string
|
||||
{
|
||||
if (is_array($this->adminNotes)) {
|
||||
return implode("\n", $this->adminNotes);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the correct modification date.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setModificationDate()
|
||||
{
|
||||
if (General::isEmptyDate($this->modified)) {
|
||||
$this->modified = null;
|
||||
}
|
||||
|
||||
if (!General::isEmptyDate($this->modified)) {
|
||||
if (!is_numeric($this->modified)) {
|
||||
$date = new Date($this->modified);
|
||||
$this->modified = $date->toUnix();
|
||||
}
|
||||
|
||||
// Convert dates from UTC
|
||||
if (intval($this->modified)) {
|
||||
if ($this->modified < 0) {
|
||||
$this->modified = null;
|
||||
} else {
|
||||
$date = new \JDate($this->modified);
|
||||
$this->modified = $date->toISO8601();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap\ItemAdapter;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
interface AdapterInterface
|
||||
{
|
||||
/**
|
||||
* Gets the visible state for robots. Each adapter will check specific params. Returns
|
||||
* true if the item is visible.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkVisibilityForRobots();
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap\ItemAdapter;
|
||||
|
||||
use Alledia\OSMap\Sitemap\Item;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class Generic implements AdapterInterface
|
||||
{
|
||||
/**
|
||||
* @var Item
|
||||
*/
|
||||
protected $item;
|
||||
|
||||
/**
|
||||
* @param Item $item
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Item $item)
|
||||
{
|
||||
$this->item = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function checkVisibilityForRobots()
|
||||
{
|
||||
// Always visible for the Free version
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap;
|
||||
|
||||
use Alledia\OSMap;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class News extends Standard
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'news';
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
interface SitemapInterface
|
||||
{
|
||||
/**
|
||||
* Traverse the sitemap items recursively and call the given callback,
|
||||
* passing each node as parameter.
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param bool $triggerEvents
|
||||
* @param bool $updateCount
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function traverse(callable $callback, bool $triggerEvents = true, bool $updateCount = false);
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\Sitemap;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class Standard implements SitemapInterface
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var Registry
|
||||
*/
|
||||
public $params;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $isDefault = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $isPublished = true;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $createdOn;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $linksCount = 0;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'standard';
|
||||
|
||||
/**
|
||||
* @var Collector
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* Limit in days for news sitemap items
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $newsDateLimit = 2;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(int $id)
|
||||
{
|
||||
/** @var \OSMapTableSitemap $sitemap */
|
||||
$sitemap = Factory::getTable('Sitemap');
|
||||
$sitemap->load($id);
|
||||
|
||||
if (empty($sitemap) || !$sitemap->id) {
|
||||
throw new \Exception(Text::_('COM_OSMAP_SITEMAP_NOT_FOUND'), 404);
|
||||
}
|
||||
|
||||
$this->id = $sitemap->id;
|
||||
$this->name = $sitemap->name;
|
||||
$this->isDefault = $sitemap->is_default == 1;
|
||||
$this->isPublished = $sitemap->published == 1;
|
||||
$this->createdOn = $sitemap->created_on;
|
||||
$this->linksCount = (int)$sitemap->links_count;
|
||||
$this->params = new Registry($sitemap->params);
|
||||
|
||||
$this->initCollector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to initialize the items collector
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function initCollector()
|
||||
{
|
||||
$this->collector = new Collector($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function traverse(callable $callback, $triggerEvents = true, $updateCount = false)
|
||||
{
|
||||
if ($triggerEvents) {
|
||||
// Call the plugins, allowing to interact or override the collector
|
||||
PluginHelper::importPlugin('osmap');
|
||||
|
||||
$eventParams = [$this, $callback];
|
||||
$results = Factory::getApplication()->triggerEvent('osmapOnBeforeCollectItems', $eventParams);
|
||||
|
||||
// A plugin asked to stop the traverse
|
||||
if (in_array(true, $results)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$results = null;
|
||||
}
|
||||
|
||||
// Fetch the sitemap items
|
||||
$count = $this->collector->fetch($callback);
|
||||
|
||||
if ($updateCount) {
|
||||
// Update the links count in the sitemap
|
||||
$this->updateLinksCount($count);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
$this->collector->cleanup();
|
||||
$this->collector = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the count of links in the database
|
||||
*
|
||||
* @param int $count
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function updateLinksCount(int $count)
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$updateObject = (object)[
|
||||
'id' => $this->id,
|
||||
'links_count' => $count
|
||||
];
|
||||
|
||||
$db->updateObject('#__osmap_sitemaps', $updateObject, ['id']);
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->collector = null;
|
||||
$this->params = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2021-2024 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\View\Admin;
|
||||
|
||||
use Alledia\OSMap\Controller\Form;
|
||||
use Alledia\OSMap\View\TraitOSMapView;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class AbstractForm extends \Alledia\Framework\Joomla\View\Admin\AbstractForm
|
||||
{
|
||||
use TraitOSMapView;
|
||||
|
||||
/**
|
||||
* Render a form fieldset with the ability to compact two fields
|
||||
* into a single line
|
||||
*
|
||||
* @param string $fieldSet
|
||||
* @param array $sameLine
|
||||
* @param bool $tabbed
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function renderFieldset(string $fieldSet, array $sameLine = [], ?bool $tabbed = false): string
|
||||
{
|
||||
$html = [];
|
||||
if ($this->form && $this->form instanceof Form) {
|
||||
$fieldSets = $this->form->getFieldsets();
|
||||
|
||||
if ($fieldSets[$fieldSet]) {
|
||||
$name = $fieldSets[$fieldSet]->name;
|
||||
$label = $fieldSets[$fieldSet]->label;
|
||||
|
||||
$html = [];
|
||||
|
||||
if ($tabbed) {
|
||||
$html[] = HTMLHelper::_('bootstrap.addTab', 'myTab', $name, Text::_($label));
|
||||
}
|
||||
|
||||
$html[] = '<div class="row-fluid">';
|
||||
$html[] = '<fieldset class="adminform">';
|
||||
|
||||
foreach ($this->form->getFieldset($name) as $field) {
|
||||
if (in_array($field->fieldname, $sameLine)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fieldHtml = [
|
||||
'<div class="control-group">',
|
||||
'<div class="control-label">',
|
||||
$field->label,
|
||||
'</div>',
|
||||
'<div class="controls">',
|
||||
$field->input
|
||||
];
|
||||
$html = array_merge($html, $fieldHtml);
|
||||
|
||||
if (isset($sameLine[$field->fieldname])) {
|
||||
$html[] = ' ' . $this->form->getField($sameLine[$field->fieldname])->input;
|
||||
}
|
||||
|
||||
$html[] = '</div>';
|
||||
$html[] = '</div>';
|
||||
}
|
||||
$html[] = '</fieldset>';
|
||||
$html[] = '</div>';
|
||||
if ($tabbed) {
|
||||
$html[] = HTMLHelper::_('bootstrap.endTab');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return join('', $html);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\View\Admin;
|
||||
|
||||
use Alledia\OSMap\Controller\Form;
|
||||
use Alledia\OSMap\Factory;
|
||||
use Alledia\OSMap\View\TraitOSMapView;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class AbstractList extends \Alledia\Framework\Joomla\View\Admin\AbstractList
|
||||
{
|
||||
use TraitOSMapView;
|
||||
}
|
||||
@ -0,0 +1,375 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\View\Site;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Alledia\OSMap\Sitemap\Standard;
|
||||
use Joomla\CMS\Application\ApplicationHelper;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
|
||||
class AbstractList extends \Alledia\Framework\Joomla\View\Site\AbstractList
|
||||
{
|
||||
/**
|
||||
* @var Standard
|
||||
*/
|
||||
protected $sitemap = null;
|
||||
|
||||
/**
|
||||
* @var Registry
|
||||
*/
|
||||
protected $osmapParams = null;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $debug = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $showExternalLinks = 0;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $showMenuTitles = 1;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $generalCounter = 0;
|
||||
|
||||
/**
|
||||
* List of found items to render the sitemap
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $menus = [];
|
||||
|
||||
/**
|
||||
* A list of last items per level. Used to identify the parent items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $lastItemsPerLevel = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($config = [])
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
$this->params = Factory::getApplication()->getParams();
|
||||
$this->debug = (bool)$this->params->get('debug', 0);
|
||||
$this->osmapParams = ComponentHelper::getParams('com_osmap');
|
||||
$this->showExternalLinks = (int)$this->osmapParams->get('show_external_links', 0);
|
||||
$this->showMenuTitles = (int)$this->params->get('show_menu_titles', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The display method
|
||||
*
|
||||
* @param string $tpl
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function display($tpl = null)
|
||||
{
|
||||
$container = Factory::getPimpleContainer();
|
||||
|
||||
$id = $container->input->getInt('id');
|
||||
|
||||
$this->osmapParams = ComponentHelper::getParams('com_osmap');
|
||||
|
||||
$this->sitemap = Factory::getSitemap($id);
|
||||
|
||||
if (!$this->sitemap->isPublished) {
|
||||
throw new \Exception(Text::_('COM_OSMAP_MSG_SITEMAP_IS_UNPUBLISHED'), 404);
|
||||
}
|
||||
|
||||
$app = Factory::getApplication();
|
||||
if ($title = $this->params->def('page_title')) {
|
||||
if ($app->get('sitename_pagetitles', 0) == 1) {
|
||||
$title = Text::sprintf('JPAGETITLE', $app->get('sitename'), $title);
|
||||
|
||||
} elseif ($app->get('sitename_pagetitles', 0) == 2) {
|
||||
$title = Text::sprintf('JPAGETITLE', $title, $app->get('sitename'));
|
||||
}
|
||||
$this->document->setTitle($title);
|
||||
}
|
||||
|
||||
if ($description = $this->params->get('menu-meta_description')) {
|
||||
$this->document->setDescription($description);
|
||||
}
|
||||
|
||||
if ($keywords = $this->params->get('menu-meta_keywords')) {
|
||||
$this->document->setMetaData('keywords', $keywords);
|
||||
}
|
||||
|
||||
if ($robots = $this->params->get('robots')) {
|
||||
$this->document->setMetaData('robots', $robots);
|
||||
}
|
||||
|
||||
parent::display($tpl);
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback called to print each node. Returns true if it was
|
||||
* able to print. False, if not.
|
||||
*
|
||||
* @param object $node
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function registerNodeIntoList(object $node): bool
|
||||
{
|
||||
$ignoreDuplicatedUIDs = (int)$this->osmapParams->get('ignore_duplicated_uids', 1);
|
||||
|
||||
$display = !$node->ignore
|
||||
&& $node->published
|
||||
&& (!$node->duplicate || !$ignoreDuplicatedUIDs)
|
||||
&& $node->visibleForHTML;
|
||||
|
||||
if ($display && !$node->isInternal) {
|
||||
// Show external links if so configured
|
||||
$display = $this->showExternalLinks > 0;
|
||||
}
|
||||
|
||||
if (!$node->hasCompatibleLanguage()) {
|
||||
$display = false;
|
||||
}
|
||||
|
||||
if (!$display) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the menu was already registered and register if needed
|
||||
if ($node->level === 0 && !isset($this->menus[$node->menuItemType])) {
|
||||
$queueItem = (object)[
|
||||
'menuItemId' => $node->menuItemId,
|
||||
'menuItemTitle' => $node->menuItemTitle,
|
||||
'menuItemType' => $node->menuItemType,
|
||||
'level' => -1,
|
||||
'children' => []
|
||||
];
|
||||
|
||||
// Add the menu to the main list of items
|
||||
$this->menus[$node->menuItemType] = $queueItem;
|
||||
|
||||
// Add this menu as the last one on the list of menus
|
||||
$this->lastItemsPerLevel[-1] = $queueItem;
|
||||
}
|
||||
|
||||
// Instantiate the current item
|
||||
$queueItem = (object)[];
|
||||
$queueItem->rawLink = $node->rawLink;
|
||||
$queueItem->type = $node->type;
|
||||
$queueItem->level = $node->level;
|
||||
$queueItem->name = $node->name;
|
||||
$queueItem->uid = $node->uid;
|
||||
$queueItem->children = [];
|
||||
|
||||
// Add debug information, if debug is enabled
|
||||
if ($this->debug) {
|
||||
$queueItem->fullLink = $node->fullLink;
|
||||
$queueItem->link = $node->link;
|
||||
$queueItem->modified = $node->modified;
|
||||
$queueItem->duplicate = $node->duplicate;
|
||||
$queueItem->visibleForRobots = $node->visibleForRobots;
|
||||
$queueItem->adapter = get_class($node->adapter);
|
||||
$queueItem->menuItemType = $node->menuItemType;
|
||||
}
|
||||
|
||||
// Add this item to its parent children list
|
||||
$this->lastItemsPerLevel[$queueItem->level - 1]->children[] = $queueItem;
|
||||
|
||||
// Add this item as the last one on the level
|
||||
$this->lastItemsPerLevel[$queueItem->level] = $queueItem;
|
||||
|
||||
unset($node);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print debug info for a note
|
||||
*
|
||||
* @param object $node
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function printDebugInfo($node)
|
||||
{
|
||||
$debugRow = '<div><span>%s:</span> %s</div>';
|
||||
echo '<div class="osmap-debug-box">'
|
||||
. sprintf('<div><span>#:</span> %s</div>', $this->generalCounter)
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_UID'), $node->uid)
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_FULL_LINK'), htmlspecialchars($node->fullLink))
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_RAW_LINK'), htmlspecialchars($node->rawLink))
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_LINK'), htmlspecialchars($node->link))
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_MODIFIED'), htmlspecialchars($node->modified))
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_LEVEL'), $node->level)
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_DUPLICATE'), Text::_($node->duplicate ? 'JYES' : 'JNO'))
|
||||
. sprintf(
|
||||
$debugRow,
|
||||
Text::_('COM_OSMAP_VISIBLE_FOR_ROBOTS'),
|
||||
Text::_($node->visibleForRobots ? 'JYES' : 'JNO')
|
||||
)
|
||||
. sprintf($debugRow, Text::_('COM_OSMAP_ADAPTER_CLASS'), $node->adapter);
|
||||
|
||||
if (method_exists($node, 'getAdminNotesString')) {
|
||||
if ($adminNotes = $node->getAdminNotesString()) {
|
||||
echo sprintf($debugRow, Text::_('COM_OSMAP_ADMIN_NOTES'), nl2br($adminNotes));
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an item
|
||||
*
|
||||
* @param object $item
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function printItem(object $item)
|
||||
{
|
||||
$this->generalCounter++;
|
||||
|
||||
$liClass = $this->debug ? 'osmap-debug-item' : '';
|
||||
$liClass .= $this->generalCounter % 2 == 0 ? ' even' : '';
|
||||
|
||||
if (empty($item->children) == false) {
|
||||
$liClass .= ' osmap-has-children';
|
||||
}
|
||||
|
||||
$sanitizedUID = ApplicationHelper::stringURLSafe($item->uid);
|
||||
|
||||
echo sprintf('<li class="%s" id="osmap-li-uid-%s">', $liClass, $sanitizedUID);
|
||||
|
||||
// Some items are just separator, without a link. Do not print as link then
|
||||
if (trim($item->rawLink ?? '') === '') {
|
||||
$type = $item->type ?? 'separator';
|
||||
echo sprintf('<span class="osmap-item-%s">%s</span>', $type, htmlspecialchars($item->name));
|
||||
|
||||
} else {
|
||||
echo sprintf(
|
||||
'<a href="%s" target="_self" class="osmap-link">%s</a>',
|
||||
$item->rawLink,
|
||||
htmlspecialchars($item->name)
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->debug) {
|
||||
$this->printDebugInfo($item);
|
||||
}
|
||||
|
||||
if (empty($item->children) == false) {
|
||||
$this->printMenu($item);
|
||||
}
|
||||
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders html sitemap
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function renderSitemap()
|
||||
{
|
||||
if (!empty($this->menus)) {
|
||||
$columns = max((int)$this->params->get('columns', 1), 1);
|
||||
|
||||
foreach ($this->menus as $menuType => $menu) {
|
||||
if (
|
||||
isset($menu->menuItemTitle)
|
||||
&& $this->showMenuTitles
|
||||
&& empty($menu->children) == false
|
||||
) {
|
||||
if ($this->debug) {
|
||||
$debug = sprintf(
|
||||
'<div><span>%s:</span> %s: %s</div>',
|
||||
Text::_('COM_OSMAP_MENUTYPE'),
|
||||
$menu->menuItemId,
|
||||
$menu->menuItemType
|
||||
);
|
||||
}
|
||||
|
||||
echo sprintf(
|
||||
'<h2 id="osmap-menu-uid-%s">%s%s</h2>',
|
||||
ApplicationHelper::stringURLSafe($menu->menuItemType),
|
||||
$menu->menuItemTitle,
|
||||
empty($debug) ? '' : $debug
|
||||
);
|
||||
}
|
||||
|
||||
$this->printMenu($menu, $columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the menu item and its children items
|
||||
*
|
||||
* @param object $menu
|
||||
* @param ?int $columns
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function printMenu(object $menu, ?int $columns = null)
|
||||
{
|
||||
if (isset($menu->menuItemType)) {
|
||||
$sanitizedUID = ApplicationHelper::stringURLSafe($menu->menuItemType);
|
||||
} else {
|
||||
$sanitizedUID = ApplicationHelper::stringURLSafe($menu->uid);
|
||||
}
|
||||
|
||||
$class = ['level_' . ($menu->level + 1)];
|
||||
if ($columns && $columns > 1) {
|
||||
$class[] = 'columns_' . $columns;
|
||||
}
|
||||
|
||||
echo sprintf(
|
||||
'<ul class="%s" id="osmap-ul-uid-%s">',
|
||||
join(' ', $class),
|
||||
$sanitizedUID
|
||||
);
|
||||
|
||||
foreach ($menu->children as $item) {
|
||||
$this->printItem($item);
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2021-2024 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\OSMap\View;
|
||||
|
||||
use Alledia\OSMap\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Plugin\PluginHelper;
|
||||
use Joomla\CMS\Toolbar\ToolbarHelper;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
trait TraitOSMapView
|
||||
{
|
||||
/**
|
||||
* Default admin screen title
|
||||
*
|
||||
* @param ?string $sub
|
||||
* @param string $icon
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function setTitle(?string $sub = null, string $icon = 'osmap')
|
||||
{
|
||||
$title = Text::_('COM_OSMAP');
|
||||
if ($sub) {
|
||||
$title .= ': ' . Text::_($sub);
|
||||
}
|
||||
|
||||
ToolbarHelper::title($title, $icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the admin screen toolbar buttons
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function setToolBar()
|
||||
{
|
||||
$user = Factory::getUser();
|
||||
if ($user->authorise('core.admin', 'com_osmap')) {
|
||||
ToolbarHelper::preferences('com_osmap');
|
||||
}
|
||||
|
||||
PluginHelper::importPlugin('osmap');
|
||||
|
||||
Factory::getApplication()->triggerEvent(
|
||||
'osmapOnAfterSetToolBar',
|
||||
[
|
||||
strtolower(str_replace('OSMapView', '', $this->getName()))
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ShackInstaller
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2016-2023 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of ShackInstaller.
|
||||
*
|
||||
* ShackInstaller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ShackInstaller is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\Installer;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class AutoLoader
|
||||
{
|
||||
/**
|
||||
* Associative array where the key is a namespace prefix and the value
|
||||
* is an array of base directories for classes in that namespace.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $prefixes = [];
|
||||
|
||||
/**
|
||||
* Associative array of prefixes for loading specialized camelCase classes
|
||||
* where Uppercase letters in the class name indicate directory structure
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $camelPrefixes = [];
|
||||
|
||||
/**
|
||||
* @var AutoLoader
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
*/
|
||||
protected static function registerLoader($method)
|
||||
{
|
||||
if (static::$instance === null) {
|
||||
static::$instance = new static();
|
||||
}
|
||||
|
||||
spl_autoload_register([static::$instance, $method]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a psr4 namespace
|
||||
*
|
||||
* @param string $prefix The namespace prefix.
|
||||
* @param string $baseDir A base directory for class files in the
|
||||
* namespace.
|
||||
* @param ?bool $prepend If true, prepend the base directory to the stack
|
||||
* instead of appending it; this causes it to be searched first rather
|
||||
* than last.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function register(string $prefix, string $baseDir, ?bool $prepend = false)
|
||||
{
|
||||
if (count(self::$prefixes) == 0) {
|
||||
static::registerLoader('loadClass');
|
||||
}
|
||||
|
||||
// normalize namespace prefix
|
||||
$prefix = trim($prefix, '\\') . '\\';
|
||||
|
||||
// normalize the base directory with a trailing separator
|
||||
$baseDir = rtrim($baseDir, '\\/') . '/';
|
||||
|
||||
// initialise the namespace prefix array
|
||||
if (empty(self::$prefixes[$prefix])) {
|
||||
self::$prefixes[$prefix] = [];
|
||||
}
|
||||
|
||||
// retain the base directory for the namespace prefix
|
||||
if ($prepend) {
|
||||
array_unshift(self::$prefixes[$prefix], $baseDir);
|
||||
} else {
|
||||
array_push(self::$prefixes[$prefix], $baseDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the class file for a given class name.
|
||||
*
|
||||
* @param string $class The fully-qualified class name.
|
||||
*
|
||||
* @return ?string The mapped file name on success
|
||||
*/
|
||||
protected function loadClass(string $class): ?string
|
||||
{
|
||||
$prefixes = explode('\\', $class);
|
||||
$className = '';
|
||||
while ($prefixes) {
|
||||
$className = array_pop($prefixes) . $className;
|
||||
$prefix = join('\\', $prefixes) . '\\';
|
||||
|
||||
if ($filePath = $this->loadMappedFile($prefix, $className)) {
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
$className = '\\' . $className;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the mapped file for a namespace prefix and class.
|
||||
*
|
||||
* @param string $prefix The namespace prefix.
|
||||
* @param string $className The relative class name.
|
||||
*
|
||||
* @return ?string path that was loaded
|
||||
*/
|
||||
protected function loadMappedFile(string $prefix, string $className): ?string
|
||||
{
|
||||
// are there any base directories for this namespace prefix?
|
||||
if (isset(self::$prefixes[$prefix]) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// look through base directories for this namespace prefix
|
||||
foreach (self::$prefixes[$prefix] as $baseDir) {
|
||||
$path = $baseDir . str_replace('\\', '/', $className) . '.php';
|
||||
|
||||
if (is_file($path)) {
|
||||
require_once $path;
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a base directory for classes organized using camelCase.
|
||||
* Class names beginning with the prefix will be automatically loaded
|
||||
* if there is a matching file in the directory tree starting with $baseDir.
|
||||
* File names and directory names are all expected to be lower case.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* $prefix = 'Simplerenew'
|
||||
* $baseDir = '/library/joomla'
|
||||
*
|
||||
* A class name of: SimplerenewViewAdmin
|
||||
* Would be in : /library/joomla/view/admin.php
|
||||
*
|
||||
* This system is intended for situations where full name spacing is either
|
||||
* unavailable or impractical due to integration with other systems.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @param string $baseDir
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function registerCamelBase(string $prefix, string $baseDir)
|
||||
{
|
||||
if (!is_dir($baseDir)) {
|
||||
throw new \Exception("Cannot register '{$prefix}'. The requested base directory does not exist!'");
|
||||
}
|
||||
|
||||
if (count(self::$camelPrefixes) == 0) {
|
||||
// Register function on first call
|
||||
static::registerLoader('loadCamelClass');
|
||||
}
|
||||
|
||||
if (empty(self::$camelPrefixes[$prefix])) {
|
||||
self::$camelPrefixes[$prefix] = $baseDir;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Autoload a class using the camelCase structure
|
||||
*
|
||||
* @param string $class
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function loadCamelClass(string $class): ?string
|
||||
{
|
||||
if (!class_exists($class)) {
|
||||
foreach (self::$camelPrefixes as $prefix => $baseDir) {
|
||||
if (strpos($class, $prefix) === 0) {
|
||||
$parts = preg_split('/(?<=[a-z])(?=[A-Z])/x', substr($class, strlen($prefix)));
|
||||
|
||||
$file = strtolower(join('/', $parts));
|
||||
$filePath = $baseDir . '/' . $file . '.php';
|
||||
|
||||
if (is_file($filePath)) {
|
||||
require_once $filePath;
|
||||
|
||||
return $filePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,435 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ShackInstaller
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2016-2023 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of ShackInstaller.
|
||||
*
|
||||
* ShackInstaller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ShackInstaller is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\Installer\Extension;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
/**
|
||||
* Generic extension class
|
||||
*/
|
||||
class Generic
|
||||
{
|
||||
/**
|
||||
* The extension namespace
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = null;
|
||||
|
||||
/**
|
||||
* The extension type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = null;
|
||||
|
||||
/**
|
||||
* The extension id
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $id = null;
|
||||
|
||||
/**
|
||||
* The extension name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = null;
|
||||
|
||||
/**
|
||||
* The extension params
|
||||
*
|
||||
* @var Registry
|
||||
*/
|
||||
public $params = null;
|
||||
|
||||
/**
|
||||
* The extension enable state
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $enabled = null;
|
||||
|
||||
/**
|
||||
* The element of the extension
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $element = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $folder = null;
|
||||
|
||||
/**
|
||||
* Base path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePath = null;
|
||||
|
||||
/**
|
||||
* The manifest information
|
||||
*
|
||||
* @var \SimpleXMLElement
|
||||
*/
|
||||
public $manifest = null;
|
||||
|
||||
/**
|
||||
* The config.xml information
|
||||
*
|
||||
* @var \SimpleXMLElement
|
||||
*/
|
||||
public $config = null;
|
||||
|
||||
/**
|
||||
* Class constructor, set the extension type.
|
||||
*
|
||||
* @param string $namespace The element of the extension
|
||||
* @param string $type The type of extension
|
||||
* @param ?string $folder The folder for plugins (only)
|
||||
* @param string $basePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $namespace, string $type, ?string $folder = '', string $basePath = JPATH_SITE)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->element = strtolower($namespace);
|
||||
$this->folder = $folder;
|
||||
$this->basePath = $basePath;
|
||||
$this->namespace = $namespace;
|
||||
|
||||
$this->getManifest();
|
||||
|
||||
$this->getDataFromDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about this extension from the database
|
||||
* NOTE: This is duplicated code from the corresponding class in
|
||||
* \Alledia\Framework\Joomla\Extension\Generic
|
||||
*/
|
||||
protected function getDataFromDatabase()
|
||||
{
|
||||
$element = $this->getElementToDb();
|
||||
|
||||
// Load the extension info from database
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
$db->quoteName('extension_id'),
|
||||
$db->quoteName('name'),
|
||||
$db->quoteName('enabled'),
|
||||
$db->quoteName('params')
|
||||
])
|
||||
->from('#__extensions')
|
||||
->where($db->quoteName('type') . ' = ' . $db->quote($this->type))
|
||||
->where($db->quoteName('element') . ' = ' . $db->quote($element));
|
||||
|
||||
if ($this->type === 'plugin') {
|
||||
$query->where($db->quoteName('folder') . ' = ' . $db->quote($this->folder));
|
||||
}
|
||||
|
||||
$db->setQuery($query);
|
||||
$row = $db->loadObject();
|
||||
|
||||
if (is_object($row)) {
|
||||
$this->id = $row->extension_id;
|
||||
$this->name = $row->name;
|
||||
$this->enabled = (bool)$row->enabled;
|
||||
$this->params = new Registry($row->params);
|
||||
|
||||
} else {
|
||||
$this->id = null;
|
||||
$this->name = null;
|
||||
$this->enabled = false;
|
||||
$this->params = new Registry();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the extension is enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return (bool)$this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path for the extension
|
||||
*
|
||||
* @return string The path
|
||||
*/
|
||||
public function getExtensionPath(): string
|
||||
{
|
||||
$folders = [
|
||||
'component' => 'administrator/components/',
|
||||
'plugin' => 'plugins/',
|
||||
'template' => 'templates/',
|
||||
'library' => 'libraries/',
|
||||
'cli' => 'cli/',
|
||||
'module' => 'modules/'
|
||||
];
|
||||
|
||||
$basePath = $this->basePath . '/' . $folders[$this->type];
|
||||
|
||||
switch ($this->type) {
|
||||
case 'plugin':
|
||||
$basePath .= $this->folder . '/';
|
||||
break;
|
||||
|
||||
case 'module':
|
||||
if (!preg_match('/^mod_/', $this->element)) {
|
||||
$basePath .= 'mod_';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'component':
|
||||
if (!preg_match('/^com_/', $this->element)) {
|
||||
$basePath .= 'com_';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$basePath .= $this->element;
|
||||
|
||||
return $basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFullElement(): string
|
||||
{
|
||||
$prefixes = [
|
||||
'component' => 'com',
|
||||
'plugin' => 'plg',
|
||||
'template' => 'tpl',
|
||||
'library' => 'lib',
|
||||
'cli' => 'cli',
|
||||
'module' => 'mod'
|
||||
];
|
||||
|
||||
$fullElement = $prefixes[$this->type];
|
||||
|
||||
if ($this->type === 'plugin') {
|
||||
$fullElement .= '_' . $this->folder;
|
||||
}
|
||||
|
||||
$fullElement .= '_' . $this->element;
|
||||
|
||||
return $fullElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element to match the database records.
|
||||
* Only components and modules have the prefix.
|
||||
*
|
||||
* @return string The element
|
||||
*/
|
||||
public function getElementToDb(): string
|
||||
{
|
||||
$prefixes = [
|
||||
'component' => 'com_',
|
||||
'module' => 'mod_'
|
||||
];
|
||||
|
||||
$fullElement = '';
|
||||
if (array_key_exists($this->type, $prefixes)) {
|
||||
if (!preg_match('/^' . $prefixes[$this->type] . '/', $this->element)) {
|
||||
$fullElement = $prefixes[$this->type];
|
||||
}
|
||||
}
|
||||
|
||||
$fullElement .= $this->element;
|
||||
|
||||
return $fullElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get manifest path for this extension
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getManifestPath(): string
|
||||
{
|
||||
$extensionPath = $this->getExtensionPath();
|
||||
|
||||
switch ($this->type) {
|
||||
case 'template':
|
||||
$fileName = 'templateDetails.xml';
|
||||
break;
|
||||
|
||||
case 'library':
|
||||
$fileName = $this->element . '.xml';
|
||||
if (!is_file($extensionPath . '/' . $fileName)) {
|
||||
$extensionPath = JPATH_MANIFESTS . '/libraries';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'module':
|
||||
$fileName = 'mod_' . $this->element . '.xml';
|
||||
break;
|
||||
|
||||
case 'pkg':
|
||||
$extensionPath = JPATH_MANIFESTS . '/packages';
|
||||
$fileName = 'pkg_' . $this->element . '.xml';
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
$extensionPath = JPATH_MANIFESTS . '/files';
|
||||
$fileName = 'file_' . $this->element . '.xml';
|
||||
break;
|
||||
|
||||
default:
|
||||
$fileName = $this->element . '.xml';
|
||||
break;
|
||||
}
|
||||
|
||||
return $extensionPath . '/' . $fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extension information
|
||||
*
|
||||
* @param bool $force If true, force to load the manifest, ignoring the cached one
|
||||
*
|
||||
* @return ?\SimpleXMLElement
|
||||
*/
|
||||
public function getManifest(bool $force = false): ?\SimpleXMLElement
|
||||
{
|
||||
if ($this->manifest === null || $force) {
|
||||
$this->manifest = false;
|
||||
|
||||
$path = $this->getManifestPath();
|
||||
if (is_file($path)) {
|
||||
$this->manifest = simplexml_load_file($path);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->manifest ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extension config file
|
||||
*
|
||||
* @param bool $force Force to reload the config file
|
||||
*
|
||||
* @return \SimpleXMLElement
|
||||
*/
|
||||
public function getConfig(bool $force = false)
|
||||
{
|
||||
if ($this->config === null || $force) {
|
||||
$path = $this->getExtensionPath() . '/config.xml';
|
||||
|
||||
$this->config = is_file($path) ? simplexml_load_file($path) : false;
|
||||
}
|
||||
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the update URL from database
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUpdateURL(): string
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$query = $db->getQuery(true)
|
||||
->select('sites.location')
|
||||
->from('#__update_sites AS sites')
|
||||
->leftJoin('#__update_sites_extensions AS extensions ON (sites.update_site_id = extensions.update_site_id)')
|
||||
->where('extensions.extension_id = ' . $this->id);
|
||||
|
||||
return $db->setQuery($query)->loadResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the update URL
|
||||
*
|
||||
* @param string $url
|
||||
*/
|
||||
public function setUpdateURL(string $url)
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
// Get the update site id
|
||||
$join = $db->quoteName('#__update_sites_extensions') . ' AS extensions '
|
||||
. 'ON (sites.update_site_id = extensions.update_site_id)';
|
||||
$query = $db->getQuery(true)
|
||||
->select('sites.update_site_id')
|
||||
->from($db->quoteName('#__update_sites') . ' AS sites')
|
||||
->leftJoin($join)
|
||||
->where('extensions.extension_id = ' . $this->id);
|
||||
$db->setQuery($query);
|
||||
$siteId = (int)$db->loadResult();
|
||||
|
||||
if (!empty($siteId)) {
|
||||
$query = $db->getQuery(true)
|
||||
->update($db->quoteName('#__update_sites'))
|
||||
->set($db->quoteName('location') . ' = ' . $db->quote($url))
|
||||
->where($db->quoteName('update_site_id') . ' = ' . $siteId);
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the params on the database
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function storeParams()
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
$params = $db->quote($this->params->toString());
|
||||
$id = $db->quote($this->id);
|
||||
|
||||
$query = "UPDATE `#__extensions` SET params = {$params} WHERE extension_id = {$id}";
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get extension name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ShackInstaller
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2016-2023 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of ShackInstaller.
|
||||
*
|
||||
* ShackInstaller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ShackInstaller is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\Installer\Extension;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
use Alledia\Installer\AutoLoader;
|
||||
|
||||
/**
|
||||
* Licensed class, for extensions with Free and Pro versions
|
||||
*/
|
||||
class Licensed extends Generic
|
||||
{
|
||||
/**
|
||||
* License type: free or pro
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $license = null;
|
||||
|
||||
/**
|
||||
* The path for the pro library
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $proLibraryPath = null;
|
||||
|
||||
/**
|
||||
* The path for the free library
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $libraryPath = null;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct(string $namespace, string $type, ?string $folder = '', string $basePath = JPATH_SITE)
|
||||
{
|
||||
parent::__construct($namespace, $type, $folder, $basePath);
|
||||
|
||||
$this->license = $this->manifest ? strtolower($this->manifest->alledia->license) : 'free';
|
||||
|
||||
$this->getLibraryPath();
|
||||
$this->getProLibraryPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the license is pro
|
||||
*
|
||||
* @return bool True for pro license
|
||||
*/
|
||||
public function isPro(): bool
|
||||
{
|
||||
return $this->license === 'pro';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the license is free
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFree(): bool
|
||||
{
|
||||
return !$this->isPro();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path for the free library, based on the extension type
|
||||
*
|
||||
* @return string The path for pro
|
||||
*/
|
||||
public function getLibraryPath(): string
|
||||
{
|
||||
if (empty($this->libraryPath)) {
|
||||
$basePath = $this->getExtensionPath();
|
||||
|
||||
$this->libraryPath = $basePath . '/library';
|
||||
}
|
||||
|
||||
return $this->libraryPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path for the pro library, based on the extension type
|
||||
*
|
||||
* @return string The path for pro
|
||||
*/
|
||||
public function getProLibraryPath(): string
|
||||
{
|
||||
if ($this->proLibraryPath === null) {
|
||||
$basePath = $this->getLibraryPath();
|
||||
|
||||
$this->proLibraryPath = $basePath . '/Pro';
|
||||
}
|
||||
|
||||
return $this->proLibraryPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the library, if existent (including the Pro Library)
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function loadLibrary(): bool
|
||||
{
|
||||
$libraryPath = $this->getLibraryPath();
|
||||
|
||||
// If we have a library path, lets load it
|
||||
if (is_dir($libraryPath)) {
|
||||
if ($this->isPro()) {
|
||||
// Check if the pro library exists
|
||||
if (!is_dir($this->getProLibraryPath())) {
|
||||
throw new \Exception("Pro library not found: {$this->type}, {$this->element}");
|
||||
}
|
||||
}
|
||||
|
||||
AutoLoader::register('Alledia\\' . $this->namespace, $libraryPath);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
101
administrator/components/com_osmap/library/Installer/Loader.php
Normal file
101
administrator/components/com_osmap/library/Installer/Loader.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ShackInstaller
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2016-2023 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of ShackInstaller.
|
||||
*
|
||||
* ShackInstaller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ShackInstaller is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\Installer;
|
||||
|
||||
use Alledia\Framework\Factory;
|
||||
use Joomla\CMS\Log\Log;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
abstract class Loader
|
||||
{
|
||||
protected static $logRegistered = false;
|
||||
|
||||
/**
|
||||
* Safely include a PHP file, making sure it exists before import.
|
||||
*
|
||||
* This method will register a log message and display a warning for admins
|
||||
* in case the file is missed.
|
||||
*
|
||||
* @param string $path The file path you want to include
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function includeFile(string $path): bool
|
||||
{
|
||||
if (!static::$logRegistered) {
|
||||
Log::addLogger(
|
||||
['text_file' => 'shackframework.loader.errors.php'],
|
||||
Log::ALL,
|
||||
['allediaframework']
|
||||
);
|
||||
|
||||
static::$logRegistered = true;
|
||||
}
|
||||
|
||||
// Check if the file doesn't exist
|
||||
if (!is_file($path)) {
|
||||
$logMsg = 'Required file is missed: ' . $path;
|
||||
|
||||
// Generate a backtrace to know from where the request cames
|
||||
if (version_compare(phpversion(), '5.4', '<')) {
|
||||
$backtrace = debug_backtrace();
|
||||
} else {
|
||||
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
}
|
||||
|
||||
if (!empty($backtrace)) {
|
||||
$logMsg .= sprintf(
|
||||
' (%s:%s)',
|
||||
$backtrace[0]['file'],
|
||||
$backtrace[0]['line']
|
||||
);
|
||||
}
|
||||
|
||||
// Register the log
|
||||
Log::add($logMsg, Log::ERROR, 'allediaframework');
|
||||
|
||||
// Warn admin users
|
||||
$app = Factory::getApplication();
|
||||
if ($app->getName() == 'administrator') {
|
||||
$app->enqueueMessage(
|
||||
'ShackInstaller Loader detected that a required file was not found! Please, check the logs.',
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
// Stand up a flag to warn a required file is missed
|
||||
if (!defined('SHACK_INSTALLER_MISSED_FILE')) {
|
||||
define('SHACK_INSTALLER_MISSED_FILE', true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
include_once $path;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,536 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\Installer\OSMap\Free;
|
||||
|
||||
use Alledia\Installer\OSMap\XmapConverter;
|
||||
use Joomla\CMS\Application\SiteApplication;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Installer\InstallerAdapter;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Table\Table;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
// phpcs:enable PSR1.Files.SideEffects
|
||||
|
||||
class AbstractScript extends \Alledia\Installer\AbstractScript
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $isXmapDataFound = false;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function customPostFlight(string $type, InstallerAdapter $parent): void
|
||||
{
|
||||
if ($type == 'uninstall') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if XMap is installed, to start a migration
|
||||
$xmapConverter = new XmapConverter();
|
||||
|
||||
// This attribute will be used by the custom template to display the option to migrate legacy sitemaps
|
||||
$this->isXmapDataFound = $this->findTable('#__xmap_sitemap') && $xmapConverter->checkXmapDataExists();
|
||||
|
||||
// If Xmap plugins are still available, and we don't have the OSMap plugins yet,
|
||||
// save Xmap plugins params to re-apply after install OSMap plugins
|
||||
$xmapConverter->saveXmapPluginParamsIfExists();
|
||||
|
||||
// Load Alledia Framework
|
||||
require_once JPATH_ADMINISTRATOR . '/components/com_osmap/include.php';
|
||||
|
||||
switch ($type) {
|
||||
case 'install':
|
||||
case 'discover_install':
|
||||
$this->createDefaultSitemap();
|
||||
|
||||
$link = HTMLHelper::_(
|
||||
'link',
|
||||
'index.php?option=com_plugins&view=plugins&filter.search=OSMap',
|
||||
Text::_('COM_OSMAP_INSTALLER_PLUGINS_PAGE')
|
||||
);
|
||||
$this->sendMessage(Text::sprintf('COM_OSMAP_INSTALLER_GOTOPLUGINS', $link), 'warning');
|
||||
break;
|
||||
|
||||
case 'update':
|
||||
$this->checkDatabase();
|
||||
$this->fixXMLMenus();
|
||||
$this->clearLanguageFiles();
|
||||
break;
|
||||
}
|
||||
|
||||
$xmapConverter->moveXmapPluginsParamsToOSMapPlugins();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default sitemap if no one is found.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createDefaultSitemap(): void
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
// Check if we have any sitemaps, otherwise let's create a default one
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__osmap_sitemaps');
|
||||
$noSitemaps = ((int)$db->setQuery($query)->loadResult()) === 0;
|
||||
|
||||
if ($noSitemaps) {
|
||||
// Get all menus
|
||||
|
||||
// Search for home menu and language if exists
|
||||
$subQuery = $db->getQuery(true)
|
||||
->select('b.menutype, b.home, b.language, l.image, l.sef, l.title_native')
|
||||
->from('#__menu AS b')
|
||||
->leftJoin('#__languages AS l ON l.lang_code = b.language')
|
||||
->where('b.home != 0')
|
||||
->where('(b.client_id = 0 OR b.client_id IS NULL)');
|
||||
|
||||
// Get all menu types with optional home menu and language
|
||||
$query = $db->getQuery(true)
|
||||
->select('a.id, a.asset_id, a.menutype, a.title, a.description, a.client_id')
|
||||
->select('c.home, c.language, c.image, c.sef, c.title_native')
|
||||
->from('#__menu_types AS a')
|
||||
->leftJoin('(' . $subQuery . ') c ON c.menutype = a.menutype')
|
||||
->order('a.id');
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
$menus = $db->loadObjectList();
|
||||
|
||||
if (!empty($menus)) {
|
||||
$data = [
|
||||
'name' => 'Default Sitemap',
|
||||
'is_default' => 1,
|
||||
'published' => 1,
|
||||
];
|
||||
|
||||
// Create the sitemap
|
||||
Table::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_osmap/tables');
|
||||
$row = Table::getInstance('Sitemap', 'OSMapTable');
|
||||
$row->save($data);
|
||||
|
||||
$i = 0;
|
||||
foreach ($menus as $menu) {
|
||||
$menuTypeId = $this->getMenuTypeId($menu->menutype);
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->set('sitemap_id = ' . $db->quote($row->id))
|
||||
->set('menutype_id = ' . $db->quote($menuTypeId))
|
||||
->set('priority = ' . $db->quote('0.5'))
|
||||
->set('changefreq = ' . $db->quote('weekly'))
|
||||
->set('ordering = ' . $db->quote($i++))
|
||||
->insert('#__osmap_sitemap_menus');
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are sitemaps in the old table. After migrate, remove
|
||||
* the table.
|
||||
*
|
||||
* On updates, verify current schema
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function checkDatabase(): void
|
||||
{
|
||||
$this->sendDebugMessage(__METHOD__);
|
||||
|
||||
if ($this->findTable('#__osmap_sitemap')) {
|
||||
$this->migrateLegacyDatabase();
|
||||
|
||||
} else {
|
||||
$this->checkDatabaseSchema();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function migrateLegacyDatabase(): void
|
||||
{
|
||||
$this->sendDebugMessage('Migrating legacy database');
|
||||
|
||||
try {
|
||||
$db = $this->dbo;
|
||||
|
||||
$db->transactionStart();
|
||||
|
||||
// For the migration, as we only have new tables, make sure to have a clean start
|
||||
$db->setQuery('DELETE FROM ' . $db->quoteName('#__osmap_items_settings'))->execute();
|
||||
$db->setQuery('DELETE FROM ' . $db->quoteName('#__osmap_sitemap_menus'))->execute();
|
||||
$db->setQuery('DELETE FROM ' . $db->quoteName('#__osmap_sitemaps'))->execute();
|
||||
|
||||
// Get legacy sitemaps
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'id',
|
||||
'title',
|
||||
'is_default',
|
||||
'state',
|
||||
'created',
|
||||
'selections',
|
||||
'excluded_items',
|
||||
])
|
||||
->from('#__osmap_sitemap');
|
||||
$sitemaps = $db->setQuery($query)->loadObjectList();
|
||||
|
||||
// Move the legacy sitemaps to the new table
|
||||
if ($sitemaps) {
|
||||
foreach ($sitemaps as $sitemap) {
|
||||
if ($sitemap->created === $db->getNullDate()) {
|
||||
$sitemap->created = Factory::getDate()->toSql();
|
||||
}
|
||||
|
||||
$insertObject = (object)[
|
||||
'id' => $sitemap->id,
|
||||
'name' => $sitemap->title,
|
||||
'is_default' => $sitemap->is_default,
|
||||
'published' => $sitemap->state,
|
||||
'created_on' => $sitemap->created,
|
||||
];
|
||||
$db->insertObject('#__osmap_sitemaps', $insertObject);
|
||||
|
||||
// Add the selected menus
|
||||
$menus = json_decode($sitemap->selections, true);
|
||||
if (is_array($menus)) {
|
||||
foreach ($menus as $menuType => $menu) {
|
||||
$menuTypeId = $this->getMenuTypeId($menuType);
|
||||
|
||||
if ($menuTypeId) {
|
||||
// Menu type still exists
|
||||
$insertObject = (object)[
|
||||
'sitemap_id' => $sitemap->id,
|
||||
'menutype_id' => $menuTypeId,
|
||||
'priority' => $menu['priority'],
|
||||
'changefreq' => $menu['changefreq'],
|
||||
'ordering' => $menu['ordering'],
|
||||
];
|
||||
$db->insertObject('#__osmap_sitemap_menus', $insertObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$excludedItems = json_decode($sitemap->excluded_items ?? '', true);
|
||||
if (is_array($excludedItems)) {
|
||||
// Convert settings for excluded items
|
||||
foreach ($excludedItems as $item) {
|
||||
$uid = $this->convertItemUID($item[0]);
|
||||
|
||||
// Check if the item was already registered
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__osmap_items_settings')
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($uid),
|
||||
]);
|
||||
$count = $db->setQuery($query)->loadResult();
|
||||
|
||||
if ($count == 0) {
|
||||
$insertObject = (object)[
|
||||
'sitemap_id' => $sitemap->id,
|
||||
'uid' => $uid,
|
||||
'published' => 0,
|
||||
'changefreq' => 'weekly',
|
||||
'priority' => '0.5',
|
||||
];
|
||||
$db->insertObject('#__osmap_items_settings', $insertObject);
|
||||
|
||||
} else {
|
||||
// Update the setting
|
||||
$query = $db->getQuery(true)
|
||||
->update('#__osmap_items_settings')
|
||||
->set('published = 0')
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($uid),
|
||||
]);
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert custom settings for items
|
||||
if ($this->findTable('#__osmap_items')) {
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'uid',
|
||||
'properties',
|
||||
])
|
||||
->from('#__osmap_items')
|
||||
->where('sitemap_id = ' . $db->quote($sitemap->id))
|
||||
->where('view = ' . $db->quote('xml'));
|
||||
$modifiedItems = $db->setQuery($query)->loadObjectList();
|
||||
|
||||
if ($modifiedItems) {
|
||||
foreach ($modifiedItems as $item) {
|
||||
$item->properties = str_replace(';', '&', $item->properties);
|
||||
parse_str($item->properties, $properties);
|
||||
|
||||
$item->uid = $this->convertItemUID($item->uid);
|
||||
|
||||
// Check if the item already exists to update, or insert
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__osmap_items_settings')
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($item->uid),
|
||||
]);
|
||||
$exists = (bool)$db->setQuery($query)->loadResult();
|
||||
|
||||
if ($exists) {
|
||||
$fields = [];
|
||||
|
||||
// Check if the changefreq is set and set to update
|
||||
if (isset($properties['changefreq'])) {
|
||||
$fields = 'changefreq = ' . $db->quote($properties['changefreq']);
|
||||
}
|
||||
|
||||
// Check if the priority is set and set to update
|
||||
if (isset($properties['priority'])) {
|
||||
$fields = 'priority = ' . $db->quote($properties['priority']);
|
||||
}
|
||||
|
||||
// Update the item
|
||||
$query = $db->getQuery(true)
|
||||
->update('#__osmap_items_settings')
|
||||
->set($fields)
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($item->uid),
|
||||
]);
|
||||
$db->setQuery($query)->execute();
|
||||
|
||||
} else {
|
||||
$insertObject = (object)[
|
||||
'sitemap_id' => $sitemap->id,
|
||||
'uid' => $item->uid,
|
||||
'published' => 1,
|
||||
'changefreq' => $properties['changefreq'] ?? 'weekly',
|
||||
'priority' => $properties['priority'] ?? '0.5',
|
||||
];
|
||||
|
||||
$db->insertObject('#__osmap_items_settings', $insertObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the old table
|
||||
$query = 'DROP TABLE IF EXISTS ' . $db->quoteName('#__osmap_items');
|
||||
$db->setQuery($query)->execute();
|
||||
|
||||
// Remove the old table
|
||||
$query = 'DROP TABLE IF EXISTS ' . $db->quoteName('#__osmap_sitemap');
|
||||
$db->setQuery($query)->execute();
|
||||
|
||||
$db->transactionCommit();
|
||||
|
||||
} catch (\Throwable $error) {
|
||||
$this->sendErrorMessage($error);
|
||||
$db->transactionRollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the menutype.
|
||||
*
|
||||
* @param string $menuType
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getMenuTypeId(string $menuType): int
|
||||
{
|
||||
$db = $this->dbo;
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('id')
|
||||
->from('#__menu_types')
|
||||
->where('menutype = ' . $db->quote($menuType));
|
||||
|
||||
return (int)$db->setQuery($query)->loadResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a legacy UID to the new pattern. Instead of "com_contenta25",
|
||||
* "joomla.article.25". Returns the new UID
|
||||
*
|
||||
* @param string $uid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function convertItemUID(string $uid): string
|
||||
{
|
||||
// Joomla articles in categories
|
||||
if (preg_match('#com_contentc[0-9]+a([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.article.' . $matches[1];
|
||||
}
|
||||
|
||||
// Joomla categories
|
||||
if (preg_match('#com_contentc([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.category.' . $matches[1];
|
||||
}
|
||||
|
||||
// Joomla articles
|
||||
if (preg_match('#com_contenta([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.article.' . $matches[1];
|
||||
}
|
||||
|
||||
// Joomla featured
|
||||
if (preg_match('#com_contentfeatureda([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.featured.' . $matches[1];
|
||||
}
|
||||
|
||||
// Menu items
|
||||
if (preg_match('#itemid([0-9]*)#', $uid, $matches)) {
|
||||
return 'menuitem.' . $matches[1];
|
||||
}
|
||||
|
||||
return $uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function checkDatabaseSchema(): void
|
||||
{
|
||||
if (version_compare($this->schemaVersion, '5', 'ge')) {
|
||||
$this->sendDebugMessage('No DB Schema updates');
|
||||
return;
|
||||
}
|
||||
|
||||
$db = $this->dbo;
|
||||
|
||||
$this->sendDebugMessage('Checking database schema updates: v' . $this->schemaVersion);
|
||||
|
||||
if ($this->findColumn('#__osmap_items_settings.format')) {
|
||||
$this->sendDebugMessage('UPDATE: items_settings.format');
|
||||
|
||||
$db->setQuery(join(' ', [
|
||||
'ALTER TABLE `#__osmap_items_settings`',
|
||||
"MODIFY `format` TINYINT(1) UNSIGNED NULL DEFAULT '2'",
|
||||
"COMMENT 'Format of the setting: 1) Legacy Mode - UID Only; 2) Based on menu ID and UID'",
|
||||
]))
|
||||
->execute();
|
||||
}
|
||||
|
||||
if ($this->findColumn('#__osmap_items_settings.url_hash')) {
|
||||
$this->sendDebugMessage('UPDATE: items_settings.url_hash');
|
||||
|
||||
$db->setQuery(
|
||||
sprintf(
|
||||
'ALTER TABLE %s CHANGE %s %s CHAR(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT %s',
|
||||
$db->quoteName('#__osmap_items_settings'),
|
||||
$db->quoteName('url_hash'),
|
||||
$db->quoteName('settings_hash'),
|
||||
$db->quote('')
|
||||
)
|
||||
)
|
||||
->execute();
|
||||
}
|
||||
|
||||
$this->dropConstraints([
|
||||
'#__osmap_sitemap_menus.fk_sitemaps',
|
||||
'#__osmap_sitemap_menus.fk_sitemaps_menus',
|
||||
]);
|
||||
|
||||
$this->addIndexes([
|
||||
'#__osmap_sitemaps.idx_default' => ['is_default ASC', 'id ASC'],
|
||||
'#__osmap_items_settings.idx_sitemap_id' => ['sitemap_id ASC'],
|
||||
'#__osmap_sitemap_menus.idx_menutype_id' => ['menutype_id ASC'],
|
||||
'#__osmap_sitemap_menus.idx_sitemaps_id' => ['sitemap_id ASC'],
|
||||
]);
|
||||
|
||||
$this->dropIndexes([
|
||||
'#__osmap_sitemaps.default_idx',
|
||||
'#__osmap_sitemap_menus.idx_sitemap_menus',
|
||||
'#__osmap_sitemap_menus.fk_sitemaps_idx',
|
||||
'#__osmap_sitemap_menus.ordering_idx',
|
||||
'#__osmap_sitemap_menus.idx_ordering',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new format=xml to existing xml menus
|
||||
*
|
||||
* @since v4.2.25
|
||||
*/
|
||||
protected function fixXMLMenus()
|
||||
{
|
||||
$db = $this->dbo;
|
||||
$siteApp = SiteApplication::getInstance('site');
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('id, link')
|
||||
->from('#__menu')
|
||||
->where([
|
||||
'client_id = ' . $siteApp->getClientId(),
|
||||
sprintf('link LIKE %s', $db->quote('%com_osmap%')),
|
||||
sprintf('link LIKE %s', $db->quote('%view=xml%')),
|
||||
sprintf('link NOT LIKE %s', $db->quote('%format=xml%')),
|
||||
]);
|
||||
|
||||
$menus = $db->setQuery($query)->loadObjectList();
|
||||
foreach ($menus as $menu) {
|
||||
$menu->link .= '&format=xml';
|
||||
$db->updateObject('#__menu', $menu, ['id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear localized language files from core folders
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function clearLanguageFiles()
|
||||
{
|
||||
$files = array_merge(
|
||||
Folder::files(JPATH_ADMINISTRATOR . '/language', '_osmap', true, true),
|
||||
Folder::files(JPATH_SITE . '/language', '_osmap', true, true)
|
||||
);
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (is_file($file)) {
|
||||
File::delete($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,513 @@
|
||||
<?php
|
||||
/**
|
||||
* @package OSMap
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2007-2014 XMap - Joomla! Vargas - Guillermo Vargas. All rights reserved.
|
||||
* @copyright 2016-2024 Joomlashack.com. All rights reserved.
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of OSMap.
|
||||
*
|
||||
* OSMap is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* OSMap is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with OSMap. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Alledia\Installer\OSMap;
|
||||
|
||||
use Alledia\Framework\Joomla\Extension\Generic;
|
||||
use Joomla\CMS\Factory;
|
||||
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
class XmapConverter
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $xmapPluginsParams = [];
|
||||
|
||||
/**
|
||||
* List of refactored Xmap plugins to migrate the settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $refactoredXmapPlugins = ['com_content' => 'joomla'];
|
||||
|
||||
/**
|
||||
* Look for the Xmap data to suggest a data migration
|
||||
*
|
||||
* @return bool True if Xmap data was found
|
||||
*/
|
||||
public function checkXmapDataExists(): bool
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
// Do we have any Xmap sitemap?
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__xmap_sitemap');
|
||||
|
||||
$total = (int)$db->setQuery($query)->loadResult();
|
||||
|
||||
return $total > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the Xmap plugins params into the new plugins. Receives a list of
|
||||
* plugin names to look for params.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function saveXmapPluginParamsIfExists()
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'element',
|
||||
'params'
|
||||
])
|
||||
->from('#__extensions')
|
||||
->where([
|
||||
'type = "plugin"',
|
||||
'folder = "xmap"',
|
||||
'element IN ("' . implode('","', array_keys($this->refactoredXmapPlugins)) . '")'
|
||||
]);
|
||||
$legacyPlugins = $db->setQuery($query)->loadObjectList();
|
||||
|
||||
// Check if the respective OSMap plugin is already installed. If so, do not save its params to not override.
|
||||
if ($legacyPlugins) {
|
||||
foreach ($legacyPlugins as $plugin) {
|
||||
$query = $db->getQuery(true)
|
||||
->select('extension_id')
|
||||
->from('#__extensions')
|
||||
->where([
|
||||
'type = "plugin"',
|
||||
'folder = "osmap"',
|
||||
'element = "' . $plugin->element . '"'
|
||||
]);
|
||||
$osmapPluginID = $db->setQuery($query)->loadResult();
|
||||
|
||||
if (empty($osmapPluginID)) {
|
||||
$this->xmapPluginsParams[] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method move the Xmap plugins' params to the OSMap plugins.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function moveXmapPluginsParamsToOSMapPlugins()
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
if (!empty($this->xmapPluginsParams)) {
|
||||
foreach ($this->xmapPluginsParams as $plugin) {
|
||||
// Look for the OSMap plugin
|
||||
$query = $db->getQuery(true)
|
||||
->select('extension_id')
|
||||
->from('#__extensions')
|
||||
->where([
|
||||
'type = "plugin"',
|
||||
'folder = "osmap"',
|
||||
'element = ' . $db->quote($this->refactoredXmapPlugins[$plugin->element] ?? '')
|
||||
]);
|
||||
$osmapPluginID = $db->setQuery($query)->loadResult();
|
||||
|
||||
if (!empty($osmapPluginID)) {
|
||||
$query = $db->getQuery(true)
|
||||
->update('#__extensions')
|
||||
->set('params = ' . $db->quote(addslashes($plugin->params)))
|
||||
->where('extension_id = ' . $osmapPluginID);
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates data from Xmap to OSMap.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function migrateData()
|
||||
{
|
||||
$result = (object)[
|
||||
'success' => false
|
||||
];
|
||||
|
||||
$db = Factory::getDbo();
|
||||
$db->transactionStart();
|
||||
|
||||
try {
|
||||
// Do we have any Xmap sitemap?
|
||||
$sitemapFailedIds = [];
|
||||
$itemFailedIds = [];
|
||||
$query = $db->getQuery(true)
|
||||
->select('*')
|
||||
->from('#__xmap_sitemap');
|
||||
$sitemaps = $db->setQuery($query)->loadObjectList();
|
||||
|
||||
if ($sitemaps) {
|
||||
// Cleanup the db tables
|
||||
$tables = [
|
||||
'#__osmap_items_settings',
|
||||
'#__osmap_sitemap_menus',
|
||||
'#__osmap_sitemaps'
|
||||
];
|
||||
foreach ($tables as $table) {
|
||||
$db->setQuery(
|
||||
$db->getQuery(true)->delete($db->quoteName($table))
|
||||
)->execute();
|
||||
}
|
||||
|
||||
// Import the sitemaps
|
||||
foreach ($sitemaps as $sitemap) {
|
||||
$query = $db->getQuery(true)
|
||||
->set([
|
||||
$db->quoteName('id') . '=' . $db->quote($sitemap->id),
|
||||
$db->quoteName('name') . '=' . $db->quote($sitemap->title),
|
||||
$db->quoteName('is_default') . '=' . $db->quote($sitemap->is_default),
|
||||
$db->quoteName('published') . '=' . $db->quote($sitemap->state),
|
||||
$db->quoteName('created_on') . '=' . $db->quote($sitemap->created)
|
||||
])
|
||||
->insert('#__osmap_sitemaps');
|
||||
|
||||
if ($db->setQuery($query)->execute()) {
|
||||
// Add the selected menus to the correct table
|
||||
if ($menus = json_decode($sitemap->selections, true)) {
|
||||
foreach ($menus as $menuType => $menu) {
|
||||
if ($menuTypeId = $this->getMenuTypeId($menuType)) {
|
||||
// Convert the selection of menus into a row
|
||||
$query = $db->getQuery(true)
|
||||
->insert('#__osmap_sitemap_menus')
|
||||
->columns([
|
||||
'sitemap_id',
|
||||
'menutype_id',
|
||||
'priority',
|
||||
'changefreq',
|
||||
'ordering'
|
||||
])
|
||||
->values(
|
||||
implode(
|
||||
',',
|
||||
[
|
||||
$db->quote($sitemap->id),
|
||||
$db->quote($menuTypeId),
|
||||
$db->quote($menu['priority']),
|
||||
$db->quote($menu['changefreq']),
|
||||
$db->quote($menu['ordering'])
|
||||
]
|
||||
)
|
||||
);
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert settings about excluded items
|
||||
if ($sitemap->excluded_items ?? null) {
|
||||
if ($excludedItems = json_decode($sitemap->excluded_items, true)) {
|
||||
foreach ($excludedItems as $item) {
|
||||
$uid = $this->convertItemUID($item[0]);
|
||||
|
||||
// Check if the item was already registered
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__osmap_items_settings')
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($uid)
|
||||
]);
|
||||
$count = $db->setQuery($query)->loadResult();
|
||||
|
||||
if ($count == 0) {
|
||||
// Insert the settings
|
||||
$query = $db->getQuery(true)
|
||||
->insert('#__osmap_items_settings')
|
||||
->columns([
|
||||
'sitemap_id',
|
||||
'uid',
|
||||
'published',
|
||||
'changefreq',
|
||||
'priority'
|
||||
])
|
||||
->values(
|
||||
implode(
|
||||
',',
|
||||
[
|
||||
$sitemap->id,
|
||||
$db->quote($uid),
|
||||
0,
|
||||
$db->quote('weekly'),
|
||||
$db->quote('0.5')
|
||||
]
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// Update the setting
|
||||
$query = $db->getQuery(true)
|
||||
->update('#__osmap_items_settings')
|
||||
->set('published = 0')
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($uid)
|
||||
]);
|
||||
}
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert custom settings for items
|
||||
$query = $db->getQuery(true)
|
||||
->select([
|
||||
'uid',
|
||||
'properties'
|
||||
])
|
||||
->from('#__xmap_items')
|
||||
->where('sitemap_id = ' . $db->quote($sitemap->id))
|
||||
->where('view = ' . $db->quote('xml'));
|
||||
|
||||
if ($modifiedItems = $db->setQuery($query)->loadObjectList()) {
|
||||
foreach ($modifiedItems as $item) {
|
||||
$item->properties = str_replace(';', '&', $item->properties);
|
||||
parse_str($item->properties, $properties);
|
||||
|
||||
$item->uid = $this->convertItemUID($item->uid);
|
||||
|
||||
// Check if the item already exists to update, or insert
|
||||
$query = $db->getQuery(true)
|
||||
->select('COUNT(*)')
|
||||
->from('#__osmap_items_settings')
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($item->uid)
|
||||
]);
|
||||
|
||||
$exists = (bool)$db->setQuery($query)->loadResult();
|
||||
if ($exists) {
|
||||
$fields = [];
|
||||
|
||||
// Check if the changefreq is set and set to update
|
||||
if (isset($properties['changefreq'])) {
|
||||
$fields = 'changefreq = ' . $db->quote($properties['changefreq']);
|
||||
}
|
||||
|
||||
// Check if the priority is set and set to update
|
||||
if (isset($properties['priority'])) {
|
||||
$fields = 'priority = ' . $db->quote($properties['priority']);
|
||||
}
|
||||
|
||||
// Update the item
|
||||
$query = $db->getQuery(true)
|
||||
->update('#__osmap_items_settings')
|
||||
->set($fields)
|
||||
->where([
|
||||
'sitemap_id = ' . $db->quote($sitemap->id),
|
||||
'uid = ' . $db->quote($item->uid)
|
||||
]);
|
||||
|
||||
} else {
|
||||
$columns = [
|
||||
'sitemap_id',
|
||||
'uid',
|
||||
'published'
|
||||
];
|
||||
|
||||
$values = [
|
||||
$db->quote($sitemap->id),
|
||||
$db->quote($item->uid),
|
||||
1
|
||||
];
|
||||
|
||||
// Check if the changefreq is set and set to update
|
||||
if (isset($properties['changefreq'])) {
|
||||
$columns[] = 'changefreq';
|
||||
$values[] = 'changefreq = ' . $db->quote($properties['changefreq']);
|
||||
}
|
||||
|
||||
// Check if the priority is set and set to update
|
||||
if (isset($properties['priority'])) {
|
||||
$columns[] = 'priority';
|
||||
$values[] = 'priority = ' . $db->quote($properties['priority']);
|
||||
}
|
||||
|
||||
// Insert a new item
|
||||
$query = $db->getQuery(true)
|
||||
->insert('#__osmap_items_settings')
|
||||
->columns($columns)
|
||||
->values(implode(',', $values));
|
||||
}
|
||||
$db->setQuery($query)->execute();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$sitemapFailedIds = $sitemap->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($sitemapFailedIds || $itemFailedIds) {
|
||||
throw new \Exception('Failed the sitemap or item migration');
|
||||
}
|
||||
|
||||
/*
|
||||
* Menu Migration
|
||||
*/
|
||||
$xmap = new Generic('Xmap', 'component');
|
||||
$osmap = new Generic('OSMap', 'component');
|
||||
|
||||
// Remove OSMap menus
|
||||
$query = $db->getQuery(true)
|
||||
->delete('#__menu')
|
||||
->where('type = ' . $db->quote('component'))
|
||||
->where('component_id = ' . $db->quote($osmap->getId()));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
// Get the Xmap menus
|
||||
$query = $db->getQuery(true)
|
||||
->select('*')
|
||||
->from('#__menu')
|
||||
->where('type = ' . $db->quote('component'))
|
||||
->where('component_id = ' . $db->quote($xmap->getId()));
|
||||
$db->setQuery($query);
|
||||
$xmapMenus = $db->loadObjectList();
|
||||
|
||||
if (!empty($xmapMenus)) {
|
||||
// Convert each menu to OSMap
|
||||
foreach ($xmapMenus as $menu) {
|
||||
$query = $db->getQuery(true)
|
||||
->set('title = ' . $db->quote($this->replaceXmapByOSMap($menu->title)))
|
||||
->set('alias = ' . $db->quote($this->replaceXmapByOSMap($menu->alias)))
|
||||
->set('path = ' . $db->quote($this->replaceXmapByOSMap($menu->path)))
|
||||
->set('link = ' . $db->quote($this->replaceXmapByOSMap($menu->link)))
|
||||
->set('img = ' . $db->quote($this->replaceXmapByOSMap($menu->img)))
|
||||
->set('component_id = ' . $db->quote($osmap->getId()))
|
||||
->update('#__menu')
|
||||
->where('id = ' . $db->quote($menu->id));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
}
|
||||
}
|
||||
|
||||
// Disable Xmap
|
||||
$query = $db->getQuery(true)
|
||||
->set('enabled = 0')
|
||||
->update('#__extensions')
|
||||
->where('extension_id = ' . $db->quote($xmap->getId()));
|
||||
$db->setQuery($query);
|
||||
$db->execute();
|
||||
|
||||
// Clean up Xmap db tables
|
||||
$db->setQuery('DELETE FROM ' . $db->quoteName('#__xmap_sitemap'));
|
||||
$db->execute();
|
||||
|
||||
$db->setQuery('DELETE FROM ' . $db->quoteName('#__xmap_items'));
|
||||
$db->execute();
|
||||
|
||||
$db->transactionCommit();
|
||||
|
||||
$result->success = true;
|
||||
} catch (\Exception $e) {
|
||||
$db->transactionRollback();
|
||||
var_dump($e);
|
||||
}
|
||||
|
||||
echo json_encode($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the Xmap strings in multiple formats, changing to OSMap.
|
||||
*
|
||||
* @param string $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function replaceXmapByOSMap(string $str): string
|
||||
{
|
||||
$replacements = [
|
||||
'XMAP' => 'OSMAP',
|
||||
'XMap' => 'OSMap',
|
||||
'xMap' => 'OSMap',
|
||||
'xmap' => 'osmap',
|
||||
];
|
||||
|
||||
return str_replace(
|
||||
array_keys($replacements),
|
||||
$replacements,
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the menutype.
|
||||
*
|
||||
* @param string $menuType
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getMenuTypeId(string $menuType): int
|
||||
{
|
||||
$db = Factory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true)
|
||||
->select('id')
|
||||
->from('#__menu_types')
|
||||
->where('menutype = ' . $db->quote($menuType));
|
||||
|
||||
return (int)$db->setQuery($query)->loadResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a legacy UID to the new pattern. Instead of "com_contenta25",
|
||||
* "joomla.article.25". Returns the new UID
|
||||
*
|
||||
* @param string $uid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function convertItemUID(string $uid): string
|
||||
{
|
||||
// Joomla articles in categories
|
||||
if (preg_match('#com_contentc[0-9]+a([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.article.' . $matches[1];
|
||||
}
|
||||
|
||||
// Joomla categories
|
||||
if (preg_match('#com_contentc([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.category.' . $matches[1];
|
||||
}
|
||||
|
||||
// Joomla articles
|
||||
if (preg_match('#com_contenta([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.article.' . $matches[1];
|
||||
}
|
||||
|
||||
// Joomla featured
|
||||
if (preg_match('#com_contentfeatureda([0-9]+)#', $uid, $matches)) {
|
||||
return 'joomla.featured.' . $matches[1];
|
||||
}
|
||||
|
||||
// Menu items
|
||||
if (preg_match('#itemid([0-9]*)#', $uid, $matches)) {
|
||||
return 'menuitem.' . $matches[1];
|
||||
}
|
||||
|
||||
return $uid;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ShackInstaller
|
||||
* @contact www.joomlashack.com, help@joomlashack.com
|
||||
* @copyright 2016-2023 Joomlashack.com. All rights reserved
|
||||
* @license https://www.gnu.org/licenses/gpl.html GNU/GPL
|
||||
*
|
||||
* This file is part of ShackInstaller.
|
||||
*
|
||||
* ShackInstaller is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* ShackInstaller is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with ShackInstaller. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use Alledia\Installer\AutoLoader;
|
||||
use Joomla\CMS\Version;
|
||||
|
||||
// phpcs:disable PSR1.Files.SideEffects
|
||||
defined('_JEXEC') or die();
|
||||
|
||||
if (defined('SHACK_INSTALLER_BASE') == false) {
|
||||
define('SHACK_INSTALLER_BASE', __DIR__);
|
||||
|
||||
require_once SHACK_INSTALLER_BASE . '/AutoLoader.php';
|
||||
}
|
||||
|
||||
AutoLoader::register('Alledia\\Installer', __DIR__, true);
|
||||
|
||||
if (defined('SHACK_INSTALLER_VERSION') == false) {
|
||||
define('SHACK_INSTALLER_VERSION', '2.4.4');
|
||||
define('SHACK_INSTALLER_COMPATIBLE', '2.4.0');
|
||||
|
||||
if (isset($reportErrors) == false) {
|
||||
$reportErrors = E_ALL ^ E_DEPRECATED ^ E_USER_DEPRECATED;
|
||||
if (Version::MAJOR_VERSION == 4) {
|
||||
// There is a bad line of code in Joomla 4 that runs during extension install/update
|
||||
$reportErrors = $reportErrors ^ E_NOTICE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($reportErrors) {
|
||||
set_error_handler('\\Alledia\\Installer\\AbstractScript::errorHandler', $reportErrors);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user