-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
[6.0] Fulfill InstallerScriptInterface with a trait #44381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
softforge
merged 20 commits into
joomla:6.0-dev
from
bembelimen:5.3/installation-script-trait
Aug 16, 2025
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
3da350a
Add InstallerScriptTrait
bembelimen ce87cfe
Deprecate InstallerScript
bembelimen dad7575
Fix wrong path call
bembelimen dae0b8e
Remove deprecations
bembelimen 52733b3
Remove deprecation of class
bembelimen b9c79a2
Rename method
bembelimen a277e6d
Merge branch '6.0-dev' into 5.3/installation-script-trait
bembelimen 3bff528
Merge branch '6.0-dev' into 5.3/installation-script-trait
bembelimen 8fe2e77
Add set/getApplication
bembelimen 80406f0
Merge branch '6.0-dev' into 5.3/installation-script-trait
bembelimen 347fff9
Add custom pre/postflight which can be overwritten by the developer
bembelimen 32ec146
Apply suggestions from code review
bembelimen bf9c294
Update libraries/src/Installer/InstallerScriptTrait.php
bembelimen 8c2ccbe
Merge branch '6.0-dev' into 5.3/installation-script-trait
bembelimen 70efcfd
Fix CS
bembelimen 1d8b720
Remove unneded check
bembelimen 2aeae83
Merge branch '6.0-dev' into 5.3/installation-script-trait
bembelimen f5ed7d2
Merge branch '6.0-dev' into 5.3/installation-script-trait
softforge e02ee22
Update libraries/src/Installer/InstallerScriptTrait.php
bembelimen 35a2266
Merge branch '6.0-dev' into 5.3/installation-script-trait
softforge File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
<?php | ||
|
||
/** | ||
* Joomla! Content Management System | ||
* | ||
* @copyright (C) 2025 Open Source Matters, Inc. <https://www.joomla.org> | ||
* @license GNU General Public License version 2 or later; see LICENSE.txt | ||
*/ | ||
|
||
namespace Joomla\CMS\Installer; | ||
|
||
use Joomla\CMS\Application\ApplicationHelper; | ||
use Joomla\CMS\Application\CMSApplicationInterface; | ||
use Joomla\CMS\Language\Text; | ||
use Joomla\CMS\Log\Log; | ||
use Joomla\Filesystem\File; | ||
use Joomla\Filesystem\Folder; | ||
use Joomla\Filesystem\Path; | ||
|
||
trait InstallerScriptTrait | ||
{ | ||
/** | ||
* The extension name. This should be set in the installer script. | ||
* | ||
* @var string | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected string $extension; | ||
|
||
/** | ||
* Minimum PHP version required to install the extension | ||
* | ||
* @var string | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected string $minimumPhp; | ||
|
||
/** | ||
* Minimum Joomla! version required to install the extension | ||
* | ||
* @var string | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected string $minimumJoomla; | ||
|
||
/** | ||
* Allow downgrades of your extension | ||
* | ||
* Use at your own risk as if there is a change in functionality people may wish to downgrade. | ||
* | ||
* @var boolean | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected bool $allowDowngrades = false; | ||
|
||
/** | ||
* A list of files to be deleted | ||
* | ||
* @var array | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected array $deleteFiles = []; | ||
|
||
/** | ||
* A list of folders to be deleted | ||
* | ||
* @var array | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected array $deleteFolders = []; | ||
|
||
/** | ||
* The application object | ||
* | ||
* @var CMSApplicationInterface | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
private CMSApplicationInterface $application; | ||
|
||
/** | ||
* Function called after the extension is installed. | ||
* | ||
* @param InstallerAdapter $adapter The adapter calling this method | ||
* | ||
* @return boolean True on success | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
public function install(InstallerAdapter $adapter): bool | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Function called after the extension is updated. | ||
* | ||
* @param InstallerAdapter $adapter The adapter calling this method | ||
* | ||
* @return boolean True on success | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
public function update(InstallerAdapter $adapter): bool | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Function called after the extension is uninstalled. | ||
* | ||
* @param InstallerAdapter $adapter The adapter calling this method | ||
* | ||
* @return boolean True on success | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
public function uninstall(InstallerAdapter $adapter): bool | ||
{ | ||
return true; | ||
} | ||
|
||
/** | ||
* Function called before extension installation/update/removal procedure commences. | ||
* | ||
* @param string $type The type of change (install or discover_install, update, uninstall) | ||
* @param InstallerAdapter $adapter The adapter calling this method | ||
* | ||
* @return boolean True on success | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
public function preflight(string $type, InstallerAdapter $adapter): bool | ||
{ | ||
$this->extension = $adapter->getName(); | ||
|
||
if (!$this->checkCompatibility($type, $adapter)) { | ||
return false; | ||
} | ||
|
||
if (!$this->checkDowngrade($type, $adapter)) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Function called after extension installation/update/removal procedure commences. | ||
* | ||
* @param string $type The type of change (install or discover_install, update, uninstall) | ||
* @param InstallerAdapter $adapter The adapter calling this method | ||
* | ||
* @return boolean True on success | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
public function postflight(string $type, InstallerAdapter $adapter): bool | ||
{ | ||
$this->removeFiles(); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Check if the extension passes the minimum requirements to be installed | ||
* | ||
* @return boolean True on success | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected function checkCompatibility(string $type, InstallerAdapter $adapter): bool | ||
{ | ||
// Check for the minimum PHP version before continuing | ||
if (!empty($this->minimumPhp) && version_compare(PHP_VERSION, $this->minimumPhp, '<')) { | ||
Log::add(Text::sprintf('JLIB_INSTALLER_MINIMUM_PHP', $this->minimumPhp), Log::WARNING, 'jerror'); | ||
|
||
return false; | ||
} | ||
|
||
// Check for the minimum Joomla version before continuing | ||
if (!empty($this->minimumJoomla) && version_compare(JVERSION, $this->minimumJoomla, '<')) { | ||
Log::add(Text::sprintf('JLIB_INSTALLER_MINIMUM_JOOMLA', $this->minimumJoomla), Log::WARNING, 'jerror'); | ||
|
||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Check if the extension is allowed to be downgraded | ||
* | ||
* @return boolean False when downgrade not allowed and new version is lower than old version otherwise true | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected function checkDowngrade(string $type, InstallerAdapter $adapter): bool | ||
{ | ||
if ($type !== 'update' || $this->allowDowngrades) { | ||
return true; | ||
} | ||
|
||
$oldManifest = $this->getOldManifest($adapter); | ||
|
||
if ($oldManifest !== null && $oldManifest->version && version_compare($oldManifest->version, $adapter->getManifest()->version, '>')) { | ||
Log::add(Text::_('JLIB_INSTALLER_ERROR_DOWNGRADE'), Log::WARNING, 'jerror'); | ||
|
||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Returns the manifest file if it exists or null | ||
* | ||
* @param InstallerAdapter $adapter | ||
* | ||
* @return SimpleXMLElement|null | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected function getOldManifest(InstallerAdapter $adapter): ?\SimpleXMLElement | ||
{ | ||
$client = ApplicationHelper::getClientInfo('administrator', true); | ||
|
||
$pathname = 'extension_' . $client->name; | ||
|
||
$manifestPath = $adapter->getParent()->getPath($pathname) . '/' . $adapter->getParent()->getPath('manifest'); | ||
|
||
return is_file($manifestPath) ? $adapter->getParent()->isManifest($manifestPath) : null; | ||
} | ||
|
||
/** | ||
* Remove the files and folders in the given array from | ||
* | ||
* @return void | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected function removeFiles(): void | ||
{ | ||
if (!empty($this->deleteFiles)) { | ||
foreach ($this->deleteFiles as $file) { | ||
if (is_file(Path::check(JPATH_ROOT . $file)) && !File::delete(JPATH_ROOT . $file)) { | ||
softforge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Log::add(Text::sprintf('JLIB_INSTALLER_ERROR_FILE_FOLDER', $file)); | ||
} | ||
} | ||
} | ||
|
||
if (!empty($this->deleteFolders)) { | ||
foreach ($this->deleteFolders as $folder) { | ||
if (is_dir(Path::check(JPATH_ROOT . $folder)) && !Folder::delete(JPATH_ROOT . $folder)) { | ||
softforge marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Log::add(Text::sprintf('JLIB_INSTALLER_ERROR_FILE_FOLDER', $folder)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Returns the internal application or null when not set. | ||
* | ||
* @return CMSApplicationInterface|null | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected function getApplication(): ?CMSApplicationInterface | ||
{ | ||
return $this->application; | ||
} | ||
|
||
/** | ||
* Sets the application to use. | ||
* | ||
* @param CMSApplicationInterface $application The application | ||
* | ||
* @return void | ||
* | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
public function setApplication(CMSApplicationInterface $application): void | ||
{ | ||
$this->application = $application; | ||
} | ||
|
||
/** | ||
* Creates the dashboard menu module | ||
* | ||
* @param string $dashboard The name of the dashboard | ||
* @param string $preset The name of the menu preset | ||
* | ||
* @return void | ||
* | ||
* @throws \Exception | ||
* @since __DEPLOY_VERSION__ | ||
*/ | ||
protected function addDashboardMenuModule(string $dashboard, string $preset) | ||
{ | ||
$model = $this->getApplication()->bootComponent('com_modules')->getMVCFactory()->createModel('Module', 'Administrator', ['ignore_request' => true]); | ||
$module = [ | ||
'id' => 0, | ||
'asset_id' => 0, | ||
'language' => '*', | ||
'note' => '', | ||
'published' => 1, | ||
'assignment' => 0, | ||
'client_id' => 1, | ||
'showtitle' => 0, | ||
'content' => '', | ||
'module' => 'mod_submenu', | ||
'position' => 'cpanel-' . $dashboard, | ||
]; | ||
|
||
// Try to get a translated module title, otherwise fall back to a fixed string. | ||
$titleKey = strtoupper('COM_' . $this->extension . '_DASHBOARD_' . $dashboard . '_TITLE'); | ||
$title = Text::_($titleKey); | ||
$module['title'] = ($title === $titleKey) ? ucfirst($dashboard) . ' Dashboard' : $title; | ||
|
||
$module['access'] = (int) $this->getApplication()->get('access', 1); | ||
$module['params'] = [ | ||
'menutype' => '*', | ||
'preset' => $preset, | ||
'style' => 'System-none', | ||
]; | ||
|
||
if (!$model->save($module)) { | ||
$this->getApplication()->enqueueMessage(Text::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_FAILED_TO_CREATE_DASHBOARD', $model->getError())); | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.