Current File : /home/pacjaorg/public_html/km/libraries/src/Installer/Adapter/TemplateAdapter.php |
<?php
/**
* Joomla! Content Management System
*
* @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\CMS\Installer\Adapter;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Installer\Installer;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Table\Table;
use Joomla\CMS\Table\Update;
use Joomla\Database\ParameterType;
// phpcs:disable PSR1.Files.SideEffects
\defined('JPATH_PLATFORM') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Template installer
*
* @since 3.1
*/
class TemplateAdapter extends InstallerAdapter
{
/**
* The install client ID
*
* @var integer
* @since 3.4
*/
protected $clientId;
/**
* Method to check if the extension is already present in the database
*
* @return void
*
* @since 3.4
* @throws \RuntimeException
*/
protected function checkExistingExtension()
{
try {
$this->currentExtensionId = $this->extension->find(
[
'element' => $this->element,
'type' => $this->type,
'client_id' => $this->clientId,
]
);
} catch (\RuntimeException $e) {
// Install failed, roll back changes
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_ROLLBACK',
Text::_('JLIB_INSTALLER_' . $this->route),
$e->getMessage()
),
$e->getCode(),
$e
);
}
}
/**
* Method to copy the extension's base files from the `<files>` tag(s) and the manifest file
*
* @return void
*
* @since 3.4
* @throws \RuntimeException
*/
protected function copyBaseFiles()
{
// Copy all the necessary files
if ($this->parent->parseFiles($this->getManifest()->files, -1) === false) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES',
'files'
)
);
}
if ($this->parent->parseFiles($this->getManifest()->images, -1) === false) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES',
'images'
)
);
}
if ($this->parent->parseFiles($this->getManifest()->css, -1) === false) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_FILES',
'css'
)
);
}
// If there is a manifest script, let's copy it.
if ($this->manifest_script) {
$path = [];
$path['src'] = $this->parent->getPath('source') . '/' . $this->manifest_script;
$path['dest'] = $this->parent->getPath('extension_root') . '/' . $this->manifest_script;
if ($this->parent->isOverwrite() || !file_exists($path['dest'])) {
if (!$this->parent->copyFiles([$path])) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_MANIFEST',
Text::_('JLIB_INSTALLER_' . strtoupper($this->getRoute()))
)
);
}
}
}
}
/**
* Method to finalise the installation processing
*
* @return void
*
* @since 3.1
* @throws \RuntimeException
*/
protected function finaliseInstall()
{
// Clobber any possible pending updates
/** @var Update $update */
$update = Table::getInstance('update');
$uid = $update->find(
[
'element' => $this->element,
'type' => $this->type,
'client_id' => $this->clientId,
]
);
if ($uid) {
$update->delete($uid);
}
// Lastly, we will copy the manifest file to its appropriate place.
if ($this->route !== 'discover_install') {
if (!$this->parent->copyManifest(-1)) {
// Install failed, rollback changes
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_COPY_SETUP',
Text::_('JLIB_INSTALLER_' . strtoupper($this->route))
)
);
}
}
}
/**
* Method to finalise the uninstallation processing
*
* @return boolean
*
* @since 4.0.0
* @throws \RuntimeException
*/
protected function finaliseUninstall(): bool
{
$db = $this->getDatabase();
$query = $db->getQuery(true);
$element = $this->extension->element;
$clientId = $this->extension->client_id;
$extensionId = $this->extension->extension_id;
// Set menu that assigned to the template back to default template
$subQuery = $db->getQuery(true)
->select($db->quoteName('s.id'))
->from($db->quoteName('#__template_styles', 's'))
->where(
[
$db->quoteName('s.template') . ' = :element',
$db->quoteName('s.client_id') . ' = :clientId',
]
);
$query->bind(':element', $element)
->bind(':clientId', $clientId, ParameterType::INTEGER);
$query->update($db->quoteName('#__menu'))
->set($db->quoteName('template_style_id') . ' = 0')
->where($db->quoteName('template_style_id') . ' IN (' . (string) $subQuery . ')');
$db->setQuery($query);
$db->execute();
// Remove the template's styles
$query = $db->getQuery(true)
->delete($db->quoteName('#__template_styles'))
->where(
[
$db->quoteName('template') . ' = :template',
$db->quoteName('client_id') . ' = :client_id',
]
)
->bind(':template', $element)
->bind(':client_id', $clientId, ParameterType::INTEGER);
$db->setQuery($query);
$db->execute();
// Remove the schema version
$query = $db->getQuery(true)
->delete($db->quoteName('#__schemas'))
->where($db->quoteName('extension_id') . ' = :extension_id')
->bind(':extension_id', $extensionId, ParameterType::INTEGER);
$db->setQuery($query);
$db->execute();
// Remove any overrides
$query = $db->getQuery(true)
->delete($db->quoteName('#__template_overrides'))
->where($db->quoteName('template') . ' = :template')
->bind(':template', $element);
$db->setQuery($query);
$db->execute();
// Clobber any possible pending updates
$update = Table::getInstance('update');
$uid = $update->find(
[
'element' => $this->extension->element,
'type' => $this->type,
'client_id' => $this->extension->client_id,
]
);
if ($uid) {
$update->delete($uid);
}
$this->extension->delete();
return true;
}
/**
* Custom loadLanguage method
*
* @param string $path The path where to find language files.
*
* @return void
*
* @since 3.1
*/
public function loadLanguage($path = null)
{
$source = $this->parent->getPath('source');
$basePath = $this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE;
if (!$source) {
$this->parent->setPath('source', $basePath . '/templates/' . $this->parent->extension->element);
}
$this->setManifest($this->parent->getManifest());
$client = (string) $this->getManifest()->attributes()->client;
// Load administrator language if not set.
if (!$client) {
$client = 'ADMINISTRATOR';
}
$base = \constant('JPATH_' . strtoupper($client));
$extension = 'tpl_' . $this->getName();
$source = $path ?: $base . '/templates/' . $this->getName();
$this->doLoadLanguage($extension, $source, $base);
}
/**
* Method to parse optional tags in the manifest
*
* @return void
*
* @since 3.4
*/
protected function parseOptionalTags()
{
$this->parent->parseMedia($this->getManifest()->media);
$this->parent->parseLanguages($this->getManifest()->languages, $this->clientId);
}
/**
* Overloaded method to parse queries for template installations
*
* @return void
*
* @since 3.4
* @throws \RuntimeException
*/
protected function parseQueries()
{
if (\in_array($this->route, ['install', 'discover_install'])) {
$db = $this->getDatabase();
$query = $db->getQuery(true);
$lang = Factory::getLanguage();
$debug = $lang->setDebug(false);
$columns = [
$db->quoteName('template'),
$db->quoteName('client_id'),
$db->quoteName('home'),
$db->quoteName('title'),
$db->quoteName('params'),
$db->quoteName('inheritable'),
$db->quoteName('parent'),
];
$values = $query->bindArray(
[
$this->extension->element,
$this->extension->client_id,
'0',
Text::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', Text::_($this->extension->name)),
$this->extension->params,
(int) $this->manifest->inheritable,
(string) $this->manifest->parent ?: '',
],
[
ParameterType::STRING,
ParameterType::INTEGER,
ParameterType::STRING,
ParameterType::STRING,
ParameterType::STRING,
ParameterType::INTEGER,
ParameterType::STRING,
]
);
$lang->setDebug($debug);
// Insert record in #__template_styles
$query->insert($db->quoteName('#__template_styles'))
->columns($columns)
->values(implode(',', $values));
// There is a chance this could fail but we don't care...
$db->setQuery($query)->execute();
}
}
/**
* Prepares the adapter for a discover_install task
*
* @return void
*
* @since 3.4
*/
public function prepareDiscoverInstall()
{
$client = ApplicationHelper::getClientInfo($this->extension->client_id);
$manifestPath = $client->path . '/templates/' . $this->extension->element . '/templateDetails.xml';
$this->parent->manifest = $this->parent->isManifest($manifestPath);
$this->parent->setPath('manifest', $manifestPath);
$this->setManifest($this->parent->getManifest());
}
/**
* Removes this extension's files
*
* @return void
*
* @since 4.0.0
* @throws \RuntimeException
*/
protected function removeExtensionFiles()
{
// Remove files
$this->parent->removeFiles($this->getManifest()->media);
$this->parent->removeFiles($this->getManifest()->languages, $this->extension->client_id);
// Delete the template directory
if (Folder::exists($this->parent->getPath('extension_root'))) {
Folder::delete($this->parent->getPath('extension_root'));
} else {
Log::add(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY'), Log::WARNING, 'jerror');
}
}
/**
* Method to do any prechecks and setup the install paths for the extension
*
* @return void
*
* @since 3.4
* @throws \RuntimeException
*/
protected function setupInstallPaths()
{
// Get the client application target
$cname = (string) $this->getManifest()->attributes()->client;
if ($cname) {
// Attempt to map the client to a base path
$client = ApplicationHelper::getClientInfo($cname, true);
if ($client === false) {
throw new \RuntimeException(Text::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_UNKNOWN_CLIENT', $cname));
}
$basePath = $client->path;
$this->clientId = $client->id;
} else {
// No client attribute was found so we assume the site as the client
$basePath = JPATH_SITE;
$this->clientId = 0;
}
// Set the template root path
if (empty($this->element)) {
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE',
Text::_('JLIB_INSTALLER_' . strtoupper($this->route))
)
);
}
$this->parent->setPath('extension_root', $basePath . '/templates/' . $this->element);
}
/**
* Method to do any prechecks and setup the uninstall job
*
* @return void
*
* @since 4.0.0
*/
protected function setupUninstall()
{
$this->parent->extension = $this->extension;
$db = $this->getDatabase();
$name = $this->extension->element;
$clientId = $this->extension->client_id;
// For a template the id will be the template name which represents the subfolder of the templates folder that the template resides in.
if (!$name) {
throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY'));
}
// Deny removing a parent template if there are children
$query = $db->getQuery(true)
->select('COUNT(*)')
->from($db->quoteName('#__template_styles'))
->where(
[
$db->quoteName('parent') . ' = :template',
$db->quoteName('client_id') . ' = :client_id',
]
)
->bind(':template', $name)
->bind(':client_id', $clientId);
$db->setQuery($query);
if ($db->loadResult() != 0) {
throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_PARENT_TEMPLATE'));
}
// Deny remove default template
$query = $db->getQuery(true)
->select('COUNT(*)')
->from($db->quoteName('#__template_styles'))
->where(
[
$db->quoteName('home') . ' = ' . $db->quote('1'),
$db->quoteName('template') . ' = :template',
$db->quoteName('client_id') . ' = :client_id',
]
)
->bind(':template', $name)
->bind(':client_id', $clientId);
$db->setQuery($query);
if ($db->loadResult() != 0) {
throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DEFAULT'));
}
// Get the template root path
$client = ApplicationHelper::getClientInfo($clientId);
if (!$client) {
throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_CLIENT'));
}
$this->parent->setPath('extension_root', $client->path . '/templates/' . strtolower($name));
$this->parent->setPath('source', $this->parent->getPath('extension_root'));
// We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file
$this->parent->findManifest();
$manifest = $this->parent->getManifest();
if (!($manifest instanceof \SimpleXMLElement)) {
// Kill the extension entry
$this->extension->delete($this->extension->extension_id);
// Make sure we delete the folders
Folder::delete($this->parent->getPath('extension_root'));
throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_NOTFOUND_MANIFEST'));
}
// Attempt to load the language file; might have uninstall strings
$this->loadLanguage();
}
/**
* Method to store the extension to the database
*
* @return void
*
* @since 3.4
* @throws \RuntimeException
*/
protected function storeExtension()
{
// Discover installs are stored a little differently
if ($this->route === 'discover_install') {
$manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest'));
$this->extension->manifest_cache = json_encode($manifest_details);
$this->extension->state = 0;
$this->extension->name = $manifest_details['name'];
$this->extension->enabled = 1;
$this->extension->params = $this->parent->getParams();
$this->extension->changelogurl = (string) $this->manifest->changelogurl;
if (!$this->extension->store()) {
// Install failed, roll back changes
throw new \RuntimeException(Text::_('JLIB_INSTALLER_ERROR_TPL_DISCOVER_STORE_DETAILS'));
}
return;
}
// Was there a template already installed with the same name?
if ($this->currentExtensionId) {
if (!$this->parent->isOverwrite()) {
// Install failed, roll back changes
throw new \RuntimeException(
Text::_('JLIB_INSTALLER_ABORT_TPL_INSTALL_ALREADY_INSTALLED')
);
}
// Load the entry and update the manifest_cache
$this->extension->load($this->currentExtensionId);
} else {
$this->extension->type = 'template';
$this->extension->element = $this->element;
// There is no folder for templates
$this->extension->folder = '';
$this->extension->enabled = 1;
$this->extension->protected = 0;
$this->extension->access = 1;
$this->extension->client_id = $this->clientId;
$this->extension->params = $this->parent->getParams();
$this->extension->changelogurl = $this->changelogurl;
}
// Name might change in an update
$this->extension->name = $this->name;
// Update the manifest cache for the entry
$this->extension->manifest_cache = $this->parent->generateManifestCache();
$this->extension->changelogurl = $this->changelogurl;
if (!$this->extension->store()) {
// Install failed, roll back changes
throw new \RuntimeException(
Text::sprintf(
'JLIB_INSTALLER_ABORT_ROLLBACK',
Text::_('JLIB_INSTALLER_' . strtoupper($this->route)),
$this->extension->getError()
)
);
}
}
/**
* Discover existing but uninstalled templates
*
* @return array Extension list
*/
public function discover()
{
$results = [];
$site_list = Folder::folders(JPATH_SITE . '/templates');
$admin_list = Folder::folders(JPATH_ADMINISTRATOR . '/templates');
$site_info = ApplicationHelper::getClientInfo('site', true);
$admin_info = ApplicationHelper::getClientInfo('administrator', true);
foreach ($site_list as $template) {
if (file_exists(JPATH_SITE . "/templates/$template/templateDetails.xml")) {
if ($template === 'system') {
// Ignore special system template
continue;
}
$manifest_details = Installer::parseXMLInstallFile(JPATH_SITE . "/templates/$template/templateDetails.xml");
$extension = Table::getInstance('extension');
$extension->set('type', 'template');
$extension->set('client_id', $site_info->id);
$extension->set('element', $template);
$extension->set('folder', '');
$extension->set('name', $template);
$extension->set('state', -1);
$extension->set('manifest_cache', json_encode($manifest_details));
$extension->set('params', '{}');
$results[] = $extension;
}
}
foreach ($admin_list as $template) {
if (file_exists(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml")) {
if ($template === 'system') {
// Ignore special system template
continue;
}
$manifest_details = Installer::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml");
$extension = Table::getInstance('extension');
$extension->set('type', 'template');
$extension->set('client_id', $admin_info->id);
$extension->set('element', $template);
$extension->set('folder', '');
$extension->set('name', $template);
$extension->set('state', -1);
$extension->set('manifest_cache', json_encode($manifest_details));
$extension->set('params', '{}');
$results[] = $extension;
}
}
return $results;
}
/**
* Refreshes the extension table cache
*
* @return boolean Result of operation, true if updated, false on failure
*
* @since 3.1
*/
public function refreshManifestCache()
{
// Need to find to find where the XML file is since we don't store this normally.
$client = ApplicationHelper::getClientInfo($this->parent->extension->client_id);
$manifestPath = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml';
$this->parent->manifest = $this->parent->isManifest($manifestPath);
$this->parent->setPath('manifest', $manifestPath);
$manifest_details = Installer::parseXMLInstallFile($this->parent->getPath('manifest'));
$this->parent->extension->manifest_cache = json_encode($manifest_details);
$this->parent->extension->name = $manifest_details['name'];
try {
return $this->parent->extension->store();
} catch (\RuntimeException $e) {
Log::add(Text::_('JLIB_INSTALLER_ERROR_TPL_REFRESH_MANIFEST_CACHE'), Log::WARNING, 'jerror');
return false;
}
}
}