Skip to content

Commit b901a19

Browse files
authored
[5.0] Add extensions uninstallation with optional parameter migration on update from 4.4 (#40768)
* Add extensions uninstallation on update * Prepared statement * Pass complete $row as parameter to pre_function * Unlock extension before uninstalling * Change version compare to 5.0.1
1 parent 2dfe0c7 commit b901a19

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

administrator/components/com_admin/script.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ public function update($installer)
9090
// Informational log only
9191
}
9292

93+
// Uninstall extensions before removing their files and folders
94+
$this->uninstallExtensions();
95+
9396
// This needs to stay for 2.5 update compatibility
9497
$this->deleteUnexistingFiles();
9598
$this->updateManifestCaches();
@@ -201,6 +204,85 @@ protected function updateDatabaseMysql()
201204
}
202205
}
203206

207+
/**
208+
* Uninstall extensions and optionally migrate their parameters when
209+
* updating from a version older than 5.0.1.
210+
*
211+
* @return void
212+
*
213+
* @since __DEPLOY_VERSION__
214+
*/
215+
protected function uninstallExtensions()
216+
{
217+
// Don't uninstall extensions when not updating from a version older than 5.0.1
218+
if (empty($this->fromVersion) || version_compare($this->fromVersion, '5.0.1', 'ge')) {
219+
return true;
220+
}
221+
222+
$extensions = [
223+
/**
224+
* Define here the extensions to be uninstalled and optionally migrated on update.
225+
* For each extension, specify an associative array with following elements (key => value):
226+
* 'type' => Field `type` in the `#__extensions` table
227+
* 'element' => Field `element` in the `#__extensions` table
228+
* 'folder' => Field `folder` in the `#__extensions` table
229+
* 'client_id' => Field `client_id` in the `#__extensions` table
230+
* 'pre_function' => Name of an optional migration function to be called before
231+
* uninstalling, `null` if not used.
232+
*/
233+
];
234+
235+
$db = Factory::getDbo();
236+
237+
foreach ($extensions as $extension) {
238+
$row = $db->setQuery(
239+
$db->getQuery(true)
240+
->select($db->quoteName('extension_id'))
241+
->select($db->quoteName('params'))
242+
->from($db->quoteName('#__extensions'))
243+
->where($db->quoteName('type') . ' = ' . $db->quote($extension['type']))
244+
->where($db->quoteName('element') . ' = ' . $db->quote($extension['element']))
245+
->where($db->quoteName('folder') . ' = ' . $db->quote($extension['folder']))
246+
->where($db->quoteName('client_id') . ' = ' . $db->quote($extension['client_id']))
247+
)->loadObject();
248+
249+
// Skip migrating and uninstalling if the extension doesn't exist
250+
if (!$row) {
251+
continue;
252+
}
253+
254+
// If there is a function for migration to be called before uninstalling, call it
255+
if ($extension['pre_function'] && method_exists($this, $extension['pre_function'])) {
256+
$this->{$extension['pre_function']}($row);
257+
}
258+
259+
try {
260+
$db->transactionStart();
261+
262+
// Unlock and unprotect the plugin so we can uninstall it
263+
$db->setQuery(
264+
$db->getQuery(true)
265+
->update($db->quoteName('#__extensions'))
266+
->set($db->quoteName('locked') . ' = 0')
267+
->set($db->quoteName('protected') . ' = 0')
268+
->where($db->quoteName('extension_id') . ' = :extension_id')
269+
->bind(':extension_id', $row->extension_id, ParameterType::INTEGER)
270+
)->execute();
271+
272+
// Uninstall the plugin
273+
$installer = new Installer();
274+
$installer->setDatabase($db);
275+
$installer->uninstall($extension['type'], $row->extension_id);
276+
277+
$db->transactionCommit();
278+
} catch (\Exception $e) {
279+
$db->transactionRollback();
280+
echo Text::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $e->getCode(), $e->getMessage()) . '<br>';
281+
throw $e;
282+
}
283+
}
284+
}
285+
204286
/**
205287
* Update the manifest caches
206288
*

0 commit comments

Comments
 (0)