PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/installer/adapters/module.php

https://bitbucket.org/ankursaxena_2/joomla-platform
PHP | 813 lines | 480 code | 131 blank | 202 comment | 77 complexity | f4a23f5bd5ed97317b3e1828a492c88c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Installer
  5. *
  6. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  7. * @license GNU General Public License version 2 or later; see LICENSE
  8. */
  9. defined('JPATH_PLATFORM') or die;
  10. jimport('joomla.base.adapterinstance');
  11. /**
  12. * Module installer
  13. *
  14. * @package Joomla.Platform
  15. * @subpackage Installer
  16. * @since 11.1
  17. */
  18. class JInstallerModule extends JAdapterInstance
  19. {
  20. /**
  21. * @var string install function routing
  22. */
  23. protected $route = 'Install';
  24. protected $manifest = null;
  25. protected $manifest_script = null;
  26. protected $name = null;
  27. protected $element = null;
  28. protected $scriptElement = null;
  29. /**
  30. * Custom loadLanguage method
  31. *
  32. * @param string $path the path where to find language files
  33. *
  34. * @since 11.1
  35. */
  36. public function loadLanguage($path=null)
  37. {
  38. $source = $this->parent->getPath('source');
  39. if (!$source) {
  40. $this->parent->setPath('source', ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/'.$this->parent->extension->element);
  41. }
  42. $this->manifest = $this->parent->getManifest();
  43. if ($this->manifest->files) {
  44. $element = $this->manifest->files;
  45. $extension = '';
  46. if (count($element->children())) {
  47. foreach ($element->children() as $file)
  48. {
  49. if ((string)$file->attributes()->module) {
  50. $extension = strtolower((string)$file->attributes()->module);
  51. break;
  52. }
  53. }
  54. }
  55. if ($extension) {
  56. $lang = JFactory::getLanguage();
  57. $source = $path ? $path : ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/'.$extension ;
  58. $folder = (string)$element->attributes()->folder;
  59. if ($folder && file_exists("$path/$folder")) {
  60. $source = "$path/$folder";
  61. }
  62. $client = (string)$this->manifest->attributes()->client;
  63. $lang->load($extension . '.sys', $source, null, false, false)
  64. || $lang->load($extension . '.sys', constant('JPATH_' . strtoupper($client)), null, false, false)
  65. || $lang->load($extension . '.sys', $source, $lang->getDefault(), false, false)
  66. || $lang->load($extension . '.sys', constant('JPATH_' . strtoupper($client)), $lang->getDefault(), false, false);
  67. }
  68. }
  69. }
  70. /**
  71. * Custom install method
  72. *
  73. * @return boolean True on success
  74. *
  75. * @since 11.1
  76. */
  77. public function install()
  78. {
  79. // Get a database connector object
  80. $db = $this->parent->getDbo();
  81. // Get the extension manifest object
  82. $this->manifest = $this->parent->getManifest();
  83. // Manifest Document Setup Section
  84. // Set the extensions name
  85. $name = (string)$this->manifest->name;
  86. $name = JFilterInput::getInstance()->clean($name, 'string');
  87. $this->set('name', $name);
  88. // Get the component description
  89. $description = (string)$this->manifest->description;
  90. if ($description) {
  91. $this->parent->set('message', JText::_($description));
  92. }
  93. else {
  94. $this->parent->set('message', '');
  95. }
  96. // Target Application Section
  97. // Get the target application
  98. if ($cname = (string)$this->manifest->attributes()->client) {
  99. // Attempt to map the client to a base path
  100. jimport('joomla.application.helper');
  101. $client = JApplicationHelper::getClientInfo($cname, true);
  102. if ($client === false) {
  103. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_UNKNOWN_CLIENT', JText::_('JLIB_INSTALLER_'.$this->route), $client->name));
  104. return false;
  105. }
  106. $basePath = $client->path;
  107. $clientId = $client->id;
  108. }
  109. else {
  110. // No client attribute was found so we assume the site as the client
  111. $cname = 'site';
  112. $basePath = JPATH_SITE;
  113. $clientId = 0;
  114. }
  115. // Set the installation path
  116. $element = '';
  117. if (count($this->manifest->files->children())) {
  118. foreach ($this->manifest->files->children() as $file)
  119. {
  120. if ((string)$file->attributes()->module) {
  121. $element = (string)$file->attributes()->module;
  122. $this->set('element',$element);
  123. break;
  124. }
  125. }
  126. }
  127. if (!empty ($element)) {
  128. $this->parent->setPath('extension_root', $basePath.DS.'modules'.DS.$element);
  129. }
  130. else {
  131. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_INSTALL_NOFILE', JText::_('JLIB_INSTALLER_'.$this->route)));
  132. return false;
  133. }
  134. // Check to see if a module by the same name is already installed
  135. // If it is, then update the table because if the files aren't there
  136. // we can assume that it was (badly) uninstalled
  137. // If it isn't, add an entry to extensions
  138. $query = 'SELECT `extension_id`' .
  139. ' FROM `#__extensions` ' .
  140. ' WHERE element = '.$db->Quote($element) .
  141. ' AND client_id = '.(int)$clientId;
  142. $db->setQuery($query);
  143. try
  144. {
  145. $db->Query();
  146. }
  147. catch(JException $e)
  148. {
  149. // Install failed, roll back changes
  150. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_ROLLBACK', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
  151. return false;
  152. }
  153. $id = $db->loadResult();
  154. // If the module directory already exists, then we will assume that the
  155. // module is already installed or another module is using that
  156. // directory.
  157. // Check that this is either an issue where its not overwriting or it is
  158. // set to upgrade anyway
  159. if (file_exists($this->parent->getPath('extension_root')) && (!$this->parent->getOverwrite() || $this->parent->getUpgrade())) {
  160. // Look for an update function or update tag
  161. $updateElement = $this->manifest->update;
  162. // Upgrade manually set or
  163. // Update function available or
  164. // Update tag detected
  165. if ($this->parent->getUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'update')) || is_a($updateElement, 'JXMLElement')) {
  166. // Force this one
  167. $this->parent->setOverwrite(true);
  168. $this->parent->setUpgrade(true);
  169. if ($id) {
  170. // If there is a matching extension mark this as an update; semantics really
  171. $this->route = 'Update';
  172. }
  173. }
  174. else if (!$this->parent->getOverwrite()) {
  175. // Overwrite is set
  176. // We didn't have overwrite set, find an udpate function or find an update tag so lets call it safe
  177. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_INSTALL_DIRECTORY', JText::_('JLIB_INSTALLER_'.$this->route), $this->parent->getPath('extension_root')));
  178. return false;
  179. }
  180. }
  181. // Installer Trigger Loading
  182. // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  183. $this->scriptElement = $this->manifest->scriptfile;
  184. $manifestScript = (string)$this->manifest->scriptfile;
  185. if ($manifestScript) {
  186. $manifestScriptFile = $this->parent->getPath('source').DS.$manifestScript;
  187. if (is_file($manifestScriptFile)) {
  188. // Load the file
  189. include_once $manifestScriptFile;
  190. }
  191. // Set the class name
  192. $classname = $element.'InstallerScript';
  193. if (class_exists($classname)) {
  194. // Create a new instance
  195. $this->parent->manifestClass = new $classname($this);
  196. // and set this so we can copy it later
  197. $this->set('manifest_script', $manifestScript);
  198. // Note: if we don't find the class, don't bother to copy the file
  199. }
  200. }
  201. // run preflight if possible (since we know we're not an update)
  202. ob_start();
  203. ob_implicit_flush(false);
  204. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'preflight')) {
  205. if ($this->parent->manifestClass->preflight($this->route, $this) === false) {
  206. // Install failed, rollback changes
  207. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_CUSTOM_INSTALL_FAILURE'));
  208. return false;
  209. }
  210. }
  211. // Create msg object; first use here
  212. $msg = ob_get_contents();
  213. ob_end_clean();
  214. // Filesystem Processing Section
  215. // If the module directory does not exist, lets create it
  216. $created = false;
  217. if (!file_exists($this->parent->getPath('extension_root'))) {
  218. if (!$created = JFolder::create($this->parent->getPath('extension_root'))) {
  219. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_INSTALL_CREATE_DIRECTORY', JText::_('JLIB_INSTALLER_'.$this->route), $this->parent->getPath('extension_root')));
  220. return false;
  221. }
  222. }
  223. // Since we created the module directory and will want to remove it if
  224. // we have to roll back the installation, lets add it to the
  225. // installation step stack
  226. if ($created) {
  227. $this->parent->pushStep(array ('type' => 'folder', 'path' => $this->parent->getPath('extension_root')));
  228. }
  229. // Copy all necessary files
  230. if ($this->parent->parseFiles($this->manifest->files, -1) === false) {
  231. // Install failed, roll back changes
  232. $this->parent->abort();
  233. return false;
  234. }
  235. // Parse optional tags
  236. $this->parent->parseMedia($this->manifest->media, $clientId);
  237. $this->parent->parseLanguages($this->manifest->languages, $clientId);
  238. // Parse deprecated tags
  239. $this->parent->parseFiles($this->manifest->images, -1);
  240. // Database Processing Section
  241. $row = JTable::getInstance('extension');
  242. // Was there a module already installed with the same name?
  243. if ($id) {
  244. // Load the entry and update the manifest_cache
  245. $row->load($id);
  246. $row->name = $this->get('name'); // update name
  247. $row->manifest_cache = $this->parent->generateManifestCache(); // update manifest
  248. if (!$row->store()) {
  249. // Install failed, roll back changes
  250. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_ROLLBACK', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
  251. return false;
  252. }
  253. }
  254. else {
  255. $row->set('name', $this->get('name'));
  256. $row->set('type', 'module');
  257. $row->set('element', $this->get('element'));
  258. $row->set('folder', ''); // There is no folder for modules
  259. $row->set('enabled', 1);
  260. $row->set('protected', 0);
  261. $row->set('access', $clientId == 1 ? 2 : 0);
  262. $row->set('client_id', $clientId);
  263. $row->set('params', $this->parent->getParams());
  264. $row->set('custom_data', ''); // custom data
  265. $row->set('manifest_cache', $this->parent->generateManifestCache());
  266. if (!$row->store()) {
  267. // Install failed, roll back changes
  268. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_ROLLBACK', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
  269. return false;
  270. }
  271. // Set the insert id
  272. $row->extension_id = $db->insertid();
  273. // Since we have created a module item, we add it to the installation step stack
  274. // so that if we have to rollback the changes we can undo it.
  275. $this->parent->pushStep(array ('type' => 'extension', 'extension_id' => $row->extension_id));
  276. // Create unpublished module in jos_modules
  277. $module = JTable::getInstance('module');
  278. $module->set('title', $this->get('name'));
  279. $module->set('module', $this->get('element'));
  280. $module->set('access', '1');
  281. $module->set('showtitle', '1');
  282. $module->set('client_id', $clientId);
  283. $module->set('language', '*');
  284. $module->store();
  285. }
  286. // Let's run the queries for the module
  287. // If Joomla 1.5 compatible, with discreet sql files - execute appropriate
  288. // file for utf-8 support or non-utf-8 support
  289. // Try for Joomla 1.5 type queries
  290. // Second argument is the utf compatible version attribute
  291. if (strtolower($this->route) == 'install') {
  292. $utfresult = $this->parent->parseSQLFiles($this->manifest->install->sql);
  293. if ($utfresult === false) {
  294. // Install failed, rollback changes
  295. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_INSTALL_SQL_ERROR', JText::_('JLIB_INSTALLER_'.$this->route), $db->stderr(true)));
  296. return false;
  297. }
  298. // Set the schema version to be the latest update version
  299. if ($this->manifest->update) {
  300. $this->parent->setSchemaVersion($this->manifest->update->schemas, $row->extension_id);
  301. }
  302. }
  303. else if (strtolower($this->route) == 'update') {
  304. if ($this->manifest->update) {
  305. $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $row->extension_id);
  306. if ($result === false) {
  307. // Install failed, rollback changes
  308. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_MOD_UPDATE_SQL_ERROR', $db->stderr(true)));
  309. return false;
  310. }
  311. }
  312. }
  313. // Start Joomla! 1.6
  314. ob_start();
  315. ob_implicit_flush(false);
  316. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,$this->route)) {
  317. if ($this->parent->manifestClass->{$this->route}($this) === false) {
  318. // Install failed, rollback changes
  319. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_CUSTOM_INSTALL_FAILURE'));
  320. return false;
  321. }
  322. }
  323. // Append messages
  324. $msg .= ob_get_contents();
  325. ob_end_clean();
  326. // Finalization and Cleanup Section
  327. // Lastly, we will copy the manifest file to its appropriate place.
  328. if (!$this->parent->copyManifest(-1)) {
  329. // Install failed, rollback changes
  330. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_MOD_INSTALL_COPY_SETUP'));
  331. return false;
  332. }
  333. // And now we run the postflight
  334. ob_start();
  335. ob_implicit_flush(false);
  336. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'postflight')) {
  337. $this->parent->manifestClass->postflight($this->route, $this);
  338. }
  339. // Append messages
  340. $msg .= ob_get_contents();
  341. ob_end_clean();
  342. if ($msg != '') {
  343. $this->parent->set('extension_message', $msg);
  344. }
  345. return $row->get('extension_id');
  346. }
  347. /**
  348. * Custom update method
  349. * This is really a shell for the install system
  350. *
  351. * @return boolean True on success
  352. * @since 11.1
  353. */
  354. function update()
  355. {
  356. // Set the overwrite setting
  357. $this->parent->setOverwrite(true);
  358. $this->parent->setUpgrade(true);
  359. // Set the route for the install
  360. $this->route = 'Update';
  361. // Go to install which handles updates properly
  362. return $this->install();
  363. }
  364. /**
  365. * Custom discover method
  366. *
  367. * @return array JExtension list of extensions available
  368. * @since 11.1
  369. */
  370. public function discover()
  371. {
  372. $results = Array();
  373. $site_list = JFolder::folders(JPATH_SITE.DS.'modules');
  374. $admin_list = JFolder::folders(JPATH_ADMINISTRATOR.DS.'modules');
  375. $site_info = JApplicationHelper::getClientInfo('site', true);
  376. $admin_info = JApplicationHelper::getClientInfo('administrator', true);
  377. foreach ($site_list as $module) {
  378. $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE."/modules/$module/$module.xml");
  379. $extension = JTable::getInstance('extension');
  380. $extension->set('type', 'module');
  381. $extension->set('client_id', $site_info->id);
  382. $extension->set('element', $module);
  383. $extension->set('name', $module);
  384. $extension->set('state', -1);
  385. $extension->set('manifest_cache', json_encode($manifest_details));
  386. $results[] = clone $extension;
  387. }
  388. foreach ($admin_list as $module) {
  389. $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_ADMINISTRATOR."/modules/$module/$module.xml");
  390. $extension = JTable::getInstance('extension');
  391. $extension->set('type', 'module');
  392. $extension->set('client_id', $admin_info->id);
  393. $extension->set('element', $module);
  394. $extension->set('name', $module);
  395. $extension->set('state', -1);
  396. $extension->set('manifest_cache', json_encode($manifest_details));
  397. $results[] = clone $extension;
  398. }
  399. return $results;
  400. }
  401. /**
  402. * Custom discover_install method
  403. *
  404. * @param int $id The id of the extension to install
  405. *
  406. * @return void
  407. * @since 11.1
  408. */
  409. function discover_install()
  410. {
  411. // Modules are like templates, and are one of the easiest
  412. // If its not in the extensions table we just add it
  413. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  414. $manifestPath = $client->path . DS . 'modules'. DS . $this->parent->extension->element . DS . $this->parent->extension->element . '.xml';
  415. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  416. $description = (string)$this->parent->manifest->description;
  417. if ($description) {
  418. $this->parent->set('message', JText::_($description));
  419. }
  420. else {
  421. $this->parent->set('message', '');
  422. }
  423. $this->parent->setPath('manifest', $manifestPath);
  424. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  425. // TODO: Re-evaluate this; should we run installation triggers? postflight perhaps?
  426. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  427. $this->parent->extension->state = 0;
  428. $this->parent->extension->name = $manifest_details['name'];
  429. $this->parent->extension->enabled = 1;
  430. $this->parent->extension->params = $this->parent->getParams();
  431. if ($this->parent->extension->store()) {
  432. return $this->parent->extension->get('extension_id');
  433. }
  434. else {
  435. JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_MOD_DISCOVER_STORE_DETAILS'));
  436. return false;
  437. }
  438. }
  439. /**
  440. * Refreshes the extension table cache
  441. * @return boolean result of operation, true if updated, false on failure
  442. * @since 11.1
  443. */
  444. public function refreshManifestCache()
  445. {
  446. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  447. $manifestPath = $client->path . DS . 'modules'. DS . $this->parent->extension->element . DS . $this->parent->extension->element . '.xml';
  448. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  449. $this->parent->setPath('manifest', $manifestPath);
  450. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  451. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  452. $this->parent->extension->name = $manifest_details['name'];
  453. if ($this->parent->extension->store()) {
  454. return true;
  455. }
  456. else {
  457. JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_MOD_REFRESH_MANIFEST_CACHE'));
  458. return false;
  459. }
  460. }
  461. /**
  462. * Custom uninstall method
  463. *
  464. * @param int $id The id of the module to uninstall
  465. *
  466. * @return boolean True on success
  467. * @since 11.1
  468. */
  469. public function uninstall($id)
  470. {
  471. // Initialise variables.
  472. $row = null;
  473. $retval = true;
  474. $db = $this->parent->getDbo();
  475. // First order of business will be to load the module object table from the database.
  476. // This should give us the necessary information to proceed.
  477. $row = JTable::getInstance('extension');
  478. if (!$row->load((int) $id) || !strlen($row->element)) {
  479. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_ERRORUNKOWNEXTENSION'));
  480. return false;
  481. }
  482. // Is the module we are trying to uninstall a core one?
  483. // Because that is not a good idea...
  484. if ($row->protected) {
  485. JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_WARNCOREMODULE', $row->name));
  486. return false;
  487. }
  488. // Get the extension root path
  489. jimport('joomla.application.helper');
  490. $element = $row->element;
  491. $client = JApplicationHelper::getClientInfo($row->client_id);
  492. if ($client === false) {
  493. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_UNKNOWN_CLIENT', $row->client_id));
  494. return false;
  495. }
  496. $this->parent->setPath('extension_root', $client->path.DS.'modules'.DS.$element);
  497. $this->parent->setPath('source', $this->parent->getPath('extension_root'));
  498. // Get the package manifest objecct
  499. // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file
  500. $this->parent->findManifest();
  501. $this->manifest = $this->parent->getManifest();
  502. // Attempt to load the language file; might have uninstall strings
  503. $this->loadLanguage(($row->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/modules/'.$element);
  504. // If there is an manifest class file, let's load it
  505. $this->scriptElement = $this->manifest->scriptfile;
  506. $manifestScript = (string)$this->manifest->scriptfile;
  507. if ($manifestScript) {
  508. $manifestScriptFile = $this->parent->getPath('extension_root').DS.$manifestScript;
  509. if (is_file($manifestScriptFile)) {
  510. // Load the file
  511. include_once $manifestScriptFile;
  512. }
  513. // Set the class name
  514. $classname = $element.'InstallerScript';
  515. if (class_exists($classname)) {
  516. // Create a new instance
  517. $this->parent->manifestClass = new $classname($this);
  518. // And set this so we can copy it later
  519. $this->set('manifest_script', $manifestScript);
  520. // Note: if we don't find the class, don't bother to copy the file
  521. }
  522. }
  523. ob_start();
  524. ob_implicit_flush(false);
  525. // Run uninstall if possible
  526. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'uninstall')) {
  527. $this->parent->manifestClass->uninstall($this);
  528. }
  529. $msg = ob_get_contents();
  530. ob_end_clean();
  531. if (!($this->manifest instanceof JXMLElement)) {
  532. // Make sure we delete the folders
  533. JFolder::delete($this->parent->getPath('extension_root'));
  534. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_INVALID_NOTFOUND_MANIFEST'));
  535. return false;
  536. }
  537. /*
  538. * Let's run the uninstall queries for the component
  539. * If Joomla 1.5 compatible, with discreet sql files - execute appropriate
  540. * file for utf-8 support or non-utf support
  541. */
  542. // Try for Joomla 1.5 type queries
  543. // Second argument is the utf compatible version attribute
  544. $utfresult = $this->parent->parseSQLFiles($this->manifest->uninstall->sql);
  545. if ($utfresult === false) {
  546. // Install failed, rollback changes
  547. JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_SQL_ERROR', $db->stderr(true)));
  548. $retval = false;
  549. }
  550. // Remove the schema version
  551. $query = $db->getQuery(true);
  552. $query->delete()->from('#__schemas')->where('extension_id = '. $row->extension_id);
  553. $db->setQuery($query);
  554. $db->Query();
  555. // Remove other files
  556. $this->parent->removeFiles($this->manifest->media);
  557. $this->parent->removeFiles($this->manifest->languages, $row->client_id);
  558. // Let's delete all the module copies for the type we are uninstalling
  559. $query = 'SELECT `id`' .
  560. ' FROM `#__modules`' .
  561. ' WHERE module = '.$db->Quote($row->element) .
  562. ' AND client_id = '.(int)$row->client_id;
  563. $db->setQuery($query);
  564. try
  565. {
  566. $modules = $db->loadResultArray();
  567. }
  568. catch(JException $e)
  569. {
  570. $modules = array();
  571. }
  572. // Do we have any module copies?
  573. if (count($modules))
  574. {
  575. // Ensure the list is sane
  576. JArrayHelper::toInteger($modules);
  577. $modID = implode(',', $modules);
  578. // Wipe out any items assigned to menus
  579. $query = 'DELETE' .
  580. ' FROM #__modules_menu' .
  581. ' WHERE moduleid IN ('.$modID.')';
  582. $db->setQuery($query);
  583. try
  584. {
  585. $db->query();
  586. }
  587. catch(JException $e)
  588. {
  589. JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $db->stderr(true)));
  590. $retval = false;
  591. }
  592. // Wipe out any instances in the modules table
  593. $query = 'DELETE' .
  594. ' FROM #__modules' .
  595. ' WHERE id IN ('.$modID.')';
  596. $db->setQuery($query);
  597. try
  598. {
  599. $db->query();
  600. }
  601. catch (JException $e)
  602. {
  603. JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_MOD_UNINSTALL_EXCEPTION', $db->stderr(true)));
  604. $retval = false;
  605. }
  606. }
  607. // Now we will no longer need the module object, so lets delete it and free up memory
  608. $row->delete($row->extension_id);
  609. $query = 'DELETE FROM `#__modules` WHERE module = '.$db->Quote($row->element) . ' AND client_id = ' . $row->client_id;
  610. $db->setQuery($query);
  611. try
  612. {
  613. // clean up any other ones that might exist as well
  614. $db->Query();
  615. }
  616. catch(JException $e)
  617. {
  618. //Ignore the error...
  619. }
  620. unset ($row);
  621. // Remove the installation folder
  622. if (!JFolder::delete($this->parent->getPath('extension_root'))) {
  623. // JFolder should raise an error
  624. $retval = false;
  625. }
  626. return $retval;
  627. }
  628. /**
  629. * Custom rollback method
  630. * - Roll back the menu item
  631. *
  632. * @param array $arg Installation step to rollback
  633. *
  634. * @return boolean True on success
  635. * @since 11.1
  636. */
  637. protected function _rollback_menu($arg)
  638. {
  639. // Get database connector object
  640. $db = $this->parent->getDbo();
  641. // Remove the entry from the #__modules_menu table
  642. $query = 'DELETE' .
  643. ' FROM `#__modules_menu`' .
  644. ' WHERE moduleid='.(int)$arg['id'];
  645. $db->setQuery($query);
  646. try
  647. {
  648. return $db->query();
  649. }
  650. catch(JException $e)
  651. {
  652. return false;
  653. }
  654. }
  655. /**
  656. * Custom rollback method
  657. * - Roll back the module item
  658. *
  659. * @param array $arg Installation step to rollback
  660. *
  661. * @return boolean True on success
  662. * @since 11.1
  663. */
  664. protected function _rollback_module($arg)
  665. {
  666. // Get database connector object
  667. $db = $this->parent->getDbo();
  668. // Remove the entry from the #__modules table
  669. $query = 'DELETE' .
  670. ' FROM `#__modules`' .
  671. ' WHERE id='.(int)$arg['id'];
  672. $db->setQuery($query);
  673. try
  674. {
  675. return $db->query();
  676. }
  677. catch(JException $e)
  678. {
  679. return false;
  680. }
  681. }
  682. }