Skip to content

Instantly share code, notes, and snippets.

@cave2006
Forked from Septdir/README-ru-RU.md
Created October 18, 2023 04:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cave2006/85dc95e7a28d32417c1787aa01620ab4 to your computer and use it in GitHub Desktop.
Save cave2006/85dc95e7a28d32417c1787aa01620ab4 to your computer and use it in GitHub Desktop.
Joomla Install Script

Установочный скрипт для Joomla

Пример установочного скрипта для Joomla

Joomla Install Script

Joomla Install Script Example

; @package Joomla Install Script
; @version __DEPLOY_VERSION__
; @author Septdir Workshop - septdir.com
; @copyright Copyright (c) 2018 - 2021 Septdir Workshop. All rights reserved.
; @license GNU/GPL license: https://www.gnu.org/copyleft/gpl.html
; @link https://www.septdir.com/
; Note : All ini files need to be saved as UTF-8
TYPE_NAME = "Joomla Install Script"
TYPE_NAME_DESCRIPTION = "Joomla Install Script Example"
TYPE_NAME_ERROR_COMPATIBLE_PHP = "This version is compatible only with PHP %s and later"
TYPE_NAME_ERROR_COMPATIBLE_JOOMLA = "This version is compatible only with Joomla %s and later"
TYPE_NAME_ERROR_COMPATIBLE_DATABASE = "This version is compatible only with MySQL %s or MariaDB %s and later"
; @package Joomla Install Script
; @version __DEPLOY_VERSION__
; @author Septdir Workshop - septdir.com
; @copyright Copyright (c) 2018 - 2021 Septdir Workshop. All rights reserved.
; @license GNU/GPL license: https://www.gnu.org/copyleft/gpl.html
; @link https://www.septdir.com/
; Note : All ini files need to be saved as UTF-8
TYPE_NAME = "Установочный скрипт для Joomla"
TYPE_NAME_DESCRIPTION = "Пример установочного скрипта для Joomla"
TYPE_NAME_ERROR_COMPATIBLE_PHP = "Данная версия совместима только с PHP %s и более поздними версиями"
TYPE_NAME_ERROR_COMPATIBLE_JOOMLA = "Данная версия совместима только с Joomla %s и более поздними версиями"
TYPE_NAME_ERROR_COMPATIBLE_DATABASE = "Данная версия совместима только с MySQL %s или MariaDB %s и более поздними версиями"
<?php
/*
* @package Joomla Install Script
* @version __DEPLOY_VERSION__
* @author Septdir Workshop - septdir.com
* @copyright Copyright (c) 2018 - 2021 Septdir Workshop. All rights reserved.
* @license GNU/GPL license: https://www.gnu.org/copyleft/gpl.html
* @link https://www.septdir.com/
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Filesystem\Path;
use Joomla\CMS\Installer\Adapter\PackageAdapter;
use Joomla\CMS\Installer\Installer;
use Joomla\CMS\Installer\InstallerAdapter;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Version;
use Joomla\Registry\Registry;
class type_nameInstallerScript
{
/**
* Minimum PHP version required to install the extension.
*
* @var string
*
* @since __DEPLOY_VERSION__
*/
protected $minimumPhp = '7.0';
/**
* Minimum Joomla version required to install the extension.
*
* @var string
*
* @since __DEPLOY_VERSION__
*/
protected $minimumJoomla = '3.9.0';
/**
* Minimum MySQL version required to install the extension.
*
* @var string
*
* @since __DEPLOY_VERSION__
*/
protected $minimumMySQL = '8.0';
/**
* Minimum MariaDb version required to install the extension.
*
* @var string
*
* @since __DEPLOY_VERSION__
*/
protected $minimumMariaDb = '10.4.1';
/**
* Extension params for check.
*
* @var array
*
* @since __DEPLOY_VERSION__
*/
protected $extensionParams = array(
'param' => 'value',
);
/**
* Runs right before any installation action.
*
* @param string $type Type of PostFlight action.
* @param InstallerAdapter|PackageAdapter $parent Parent object calling object.
*
* @throws Exception
*
* @return boolean True on success, false on failure.
*
* @since __DEPLOY_VERSION__
*/
function preflight($type, $parent)
{
// Check compatible
if (!$this->checkCompatible('TYPE_NAME_')) return false;
return true;
}
/**
* Method to check compatible.
*
* @param string $prefix Language constants prefix.
*
* @throws Exception
*
* @return boolean True on success, false on failure.
*
* @since __DEPLOY_VERSION__
*/
protected function checkCompatible($prefix = null)
{
// Check old Joomla
if (!class_exists('Joomla\CMS\Version'))
{
JFactory::getApplication()->enqueueMessage(JText::sprintf($prefix . 'ERROR_COMPATIBLE_JOOMLA',
$this->minimumJoomla), 'error');
return false;
}
$app = Factory::getApplication();
// Check PHP
if (!(version_compare(PHP_VERSION, $this->minimumPhp) >= 0))
{
$app->enqueueMessage(Text::sprintf($prefix . 'ERROR_COMPATIBLE_PHP', $this->minimumPhp),
'error');
return false;
}
// Check joomla version
if (!(new Version())->isCompatible($this->minimumJoomla))
{
$app->enqueueMessage(Text::sprintf($prefix . 'ERROR_COMPATIBLE_JOOMLA', $this->minimumJoomla),
'error');
return false;
}
// Check database version
$db = Factory::getDbo();
$serverType = $db->getServerType();
$serverVersion = $db->getVersion();
if ($serverType == 'mysql' && stripos($serverVersion, 'mariadb') !== false)
{
$serverVersion = preg_replace('/^5\.5\.5-/', '', $serverVersion);
if (!(version_compare($serverVersion, $this->minimumMariaDb) >= 0))
{
$app->enqueueMessage(Text::sprintf($prefix . 'ERROR_COMPATIBLE_DATABASE',
$this->minimumMySQL, $this->minimumMariaDb), 'error');
return false;
}
}
elseif ($serverType == 'mysql' && !(version_compare($serverVersion, $this->minimumMySQL) >= 0))
{
$app->enqueueMessage(Text::sprintf($prefix . 'ERROR_COMPATIBLE_DATABASE',
$this->minimumMySQL, $this->minimumMariaDb), 'error');
return false;
}
return true;
}
/**
* Runs right after any installation action.
*
* @param string $type Type of PostFlight action. Possible values are:
* @param InstallerAdapter $parent Parent object calling object.
*
* @throws Exception
*
* @return boolean True on success, false on failure.
*
* @since __DEPLOY_VERSION__
*/
function postflight($type, $parent)
{
// Enable plugin
if ($type == 'install') $this->enablePlugin($parent);
// Parse layouts
$this->parseLayouts($parent->getParent()->getManifest()->layouts, $parent->getParent());
// Parse cli
$this->parseCLI($parent->getParent()->getManifest()->cli, $parent->getParent());
// Check databases
$this->checkTables($parent);
// Check root category
$this->checkRootRecord('#__categories_table');
// Check extension params
$this->checkExtensionParams($parent);
// Refresh media
if ($type === 'update') (new Version())->refreshMediaVersion();
return true;
}
/**
* Enable plugin after installation.
*
* @param InstallerAdapter $parent Parent object calling object.
*
* @since __DEPLOY_VERSION__
*/
protected function enablePlugin($parent)
{
// Prepare plugin object
$plugin = new stdClass();
$plugin->type = 'plugin';
$plugin->element = $parent->getElement();
$plugin->folder = (string) $parent->getParent()->manifest->attributes()['group'];
$plugin->enabled = 1;
// Update record
Factory::getDbo()->updateObject('#__extensions', $plugin, array('type', 'element', 'folder'));
}
/**
* Method to parse through a layout element of the installation manifest and take appropriate action.
*
* @param SimpleXMLElement $element The XML node to process.
* @param Installer $installer Installer calling object.
*
* @return boolean True on success.
*
* @since __DEPLOY_VERSION__
*/
public function parseLayouts(SimpleXMLElement $element, $installer)
{
if (!$element || !count($element->children())) return false;
// Get destination
$folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null;
$destination = Path::clean(JPATH_ROOT . '/layouts' . $folder);
// Get source
$folder = (string) $element->attributes()->folder;
$source = ($folder && file_exists($installer->getPath('source') . '/' . $folder)) ?
$installer->getPath('source') . '/' . $folder : $installer->getPath('source');
// Prepare files
$copyFiles = array();
foreach ($element->children() as $file)
{
$path['src'] = Path::clean($source . '/' . $file);
$path['dest'] = Path::clean($destination . '/' . $file);
// Is this path a file or folder?
$path['type'] = $file->getName() === 'folder' ? 'folder' : 'file';
if (basename($path['dest']) !== $path['dest'])
{
$newdir = dirname($path['dest']);
if (!Folder::create($newdir))
{
Log::add(Text::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir), Log::WARNING, 'jerror');
return false;
}
}
$copyFiles[] = $path;
}
return $installer->copyFiles($copyFiles, true);
}
/**
* Method to parse through a cli element of the installation manifest and take appropriate action.
*
* @param SimpleXMLElement $element The XML node to process.
* @param Installer $installer Installer calling object.
*
* @return boolean True on success.
*
* @since __DEPLOY_VERSION__
*/
public function parseCLI(SimpleXMLElement $element, $installer)
{
if (!$element || !count($element->children())) return false;
// Get destination
$folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null;
$destination = Path::clean(JPATH_ROOT . '/cli' . $folder);
// Get source
$folder = (string) $element->attributes()->folder;
$source = ($folder && file_exists($installer->getPath('source') . '/' . $folder)) ?
$installer->getPath('source') . '/' . $folder : $installer->getPath('source');
// Prepare files
$copyFiles = array();
foreach ($element->children() as $file)
{
$path['src'] = Path::clean($source . '/' . $file);
$path['dest'] = Path::clean($destination . '/' . $file);
// Is this path a file or folder?
$path['type'] = $file->getName() === 'folder' ? 'folder' : 'file';
if (basename($path['dest']) !== $path['dest'])
{
$newdir = dirname($path['dest']);
if (!Folder::create($newdir))
{
Log::add(Text::sprintf('JLIB_INSTALLER_ERROR_CREATE_DIRECTORY', $newdir), Log::WARNING, 'jerror');
return false;
}
}
$copyFiles[] = $path;
}
return $installer->copyFiles($copyFiles, true);
}
/**
* Method to create database tables in not exist.
*
* @param InstallerAdapter $parent Parent object calling object.
*
* @since __DEPLOY_VERSION__
*/
protected function checkTables($parent)
{
if ($sql = file_get_contents($parent->getParent()->getPath('extension_administrator')
. '/sql/install.mysql.utf8.sql'))
{
$db = Factory::getDbo();
foreach ($db->splitSql($sql) as $query)
{
$db->setQuery($db->convertUtf8mb4QueryToUtf8($query));
try
{
$db->execute();
}
catch (JDataBaseExceptionExecuting $e)
{
Log::add(Text::sprintf('JLIB_INSTALLER_ERROR_SQL_ERROR', $e->getMessage()), Log::WARNING, 'jerror');
}
}
}
}
/**
* Method to create root record if don't exist.
*
* @param string $table Table name.
*
* @since __DEPLOY_VERSION__
*/
protected function checkRootRecord($table = null)
{
$db = Factory::getDbo();
// Get base categories
$query = $db->getQuery(true)
->select('id')
->from($table)
->where('id = 1');
$db->setQuery($query);
// Add root in not found
if (empty($db->loadResult()))
{
$root = new stdClass();
$root->id = 1;
$root->parent_id = 0;
$root->lft = 0;
$root->rgt = 1;
$root->level = 0;
$root->path = '';
$root->alias = 'root';
$root->state = 1;
$db->insertObject($table, $root);
}
}
/**
* Method to check extension params and set if need.
*
* @param InstallerAdapter $parent Parent object calling object.
*
* @since __DEPLOY_VERSION__
*/
protected function checkExtensionParams($parent)
{
if (!empty($this->extensionParams))
{
$element = $parent->getElement();
$folder = (string) $parent->getParent()->manifest->attributes()['group'];
// Get extension
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select(array('extension_id', 'params'))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('element') . ' = ' . $db->quote($element));
if (!empty($folder)) $query->where($db->quoteName('folder') . ' = ' . $db->quote($folder));
if ($extension = $db->setQuery($query)->loadObject())
{
$extension->params = new Registry($extension->params);
// Check params
$needUpdate = false;
foreach ($this->extensionParams as $path => $value)
{
if (!$extension->params->exists($path))
{
$needUpdate = true;
$extension->params->set($path, $value);
}
}
// Update
if ($needUpdate)
{
$extension->params = (string) $extension->params;
$db->updateObject('#__extensions', $extension, 'extension_id');
}
}
}
}
/**
* This method is called after extension is uninstalled.
*
* @param InstallerAdapter $parent Parent object calling object.
*
* @since __DEPLOY_VERSION__
*/
public function uninstall($parent)
{
// Remove layouts
$this->removeLayouts($parent->getParent()->getManifest()->layouts);
// Remove cli
$this->removeCLI($parent->getParent()->getManifest()->cli);
}
/**
* Method to parse through a layouts element of the installation manifest and remove the files that were installed.
*
* @param SimpleXMLElement $element The XML node to process.
*
* @return boolean True on success.
*
* @since __DEPLOY_VERSION__
*/
protected function removeLayouts(SimpleXMLElement $element)
{
if (!$element || !count($element->children())) return false;
// Get the array of file nodes to process
$files = $element->children();
// Get source
$folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null;
$source = Path::clean(JPATH_ROOT . '/layouts' . $folder);
// Process each file in the $files array (children of $tagName).
foreach ($files as $file)
{
$path = Path::clean($source . '/' . $file);
// Actually delete the files/folders
if (is_dir($path)) $val = Folder::delete($path);
else $val = File::delete($path);
if ($val === false)
{
Log::add('Failed to delete ' . $path, Log::WARNING, 'jerror');
return false;
}
}
if (!empty($folder)) Folder::delete($source);
return true;
}
/**
* Method to parse through a cli element of the installation manifest and remove the files that were installed.
*
* @param SimpleXMLElement $element The XML node to process.
*
* @return boolean True on success.
*
* @since __DEPLOY_VERSION__
*/
protected function removeCLI(SimpleXMLElement $element)
{
if (!$element || !count($element->children())) return false;
// Get the array of file nodes to process
$files = $element->children();
// Get source
$folder = ((string) $element->attributes()->destination) ? '/' . $element->attributes()->destination : null;
$source = Path::clean(JPATH_ROOT . '/cli' . $folder);
// Process each file in the $files array (children of $tagName).
foreach ($files as $file)
{
$path = Path::clean($source . '/' . $file);
// Actually delete the files/folders
if (is_dir($path)) $val = Folder::delete($path);
else $val = File::delete($path);
if ($val === false)
{
Log::add('Failed to delete ' . $path, Log::WARNING, 'jerror');
return false;
}
}
if (!empty($folder)) Folder::delete($source);
return true;
}
}
<?xml version="1.0" encoding="utf-8"?>
<extension version="3.9" type="type" method="upgrade">
<name>TYPE_NAME</name>
<description>TYPE_NAME_DESCRIPTION</description>
<scriptfile>script.php</scriptfile>
<languages folder="language">
<language tag="en-GB">en-GB/en-GB.type_name.sys.ini</language>
<language tag="ru-RU">ru-RU/ru-RU.type_name.sys.ini</language>
</languages>
<layouts destination="type/name" folder="layouts">
<folder>folder_name</folder>
<filename>filename.php</filename>
</layouts>
<cli destination="" folder="cli">
<folder>folder_name</folder>
<filename>filename.php</filename>
</cli>
</extension>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment