PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/bower_components/joomla-platform/libraries/legacy/installer/adapters/component.php

https://github.com/dprotopopov/tritumana
PHP | 1881 lines | 1055 code | 322 blank | 504 comment | 167 complexity | 2c1c152b3322eb4345201babe087a2ce MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause, LGPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Installer
  5. *
  6. * @copyright Copyright (C) 2005 - 2013 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. jimport('joomla.filesystem.folder');
  12. /**
  13. * Component installer
  14. *
  15. * @package Joomla.Platform
  16. * @subpackage Installer
  17. * @since 11.1
  18. * @deprecated 13.3
  19. */
  20. class JInstallerComponent extends JAdapterInstance
  21. {
  22. /**
  23. * Copy of the XML manifest file
  24. *
  25. * @var string
  26. * @since 11.1
  27. */
  28. protected $manifest = null;
  29. /**
  30. * Name of the extension
  31. *
  32. * @var string
  33. * @since 11.1
  34. * */
  35. protected $name = null;
  36. /**
  37. * The unique identifier for the extension (e.g. mod_login)
  38. *
  39. * @var string
  40. * @since 11.1
  41. * */
  42. protected $element = null;
  43. /**
  44. * The list of current files fo the Joomla! CMS administrator that are installed and is read
  45. * from the manifest on disk in the update area to handle doing a diff
  46. * and deleting files that are in the old files list and not in the new
  47. * files list.
  48. *
  49. * @var array
  50. * @since 11.1
  51. * */
  52. protected $oldAdminFiles = null;
  53. /**
  54. * The list of current files that are installed and is read
  55. * from the manifest on disk in the update area to handle doing a diff
  56. * and deleting files that are in the old files list and not in the new
  57. * files list.
  58. *
  59. * @var array
  60. * @since 11.1
  61. * */
  62. protected $oldFiles = null;
  63. /**
  64. * A path to the PHP file that the scriptfile declaration in
  65. * the manifest refers to.
  66. *
  67. * @var string
  68. * @since 11.1
  69. * */
  70. protected $manifest_script = null;
  71. /**
  72. * For legacy installations this is a path to the PHP file that the scriptfile declaration in the
  73. * manifest refers to.
  74. *
  75. * @var string
  76. * @since 11.1
  77. * */
  78. protected $install_script = null;
  79. /**
  80. * Custom loadLanguage method
  81. *
  82. * @param string $path The path language files are on.
  83. *
  84. * @return void
  85. *
  86. * @since 11.1
  87. */
  88. public function loadLanguage($path = null)
  89. {
  90. $source = $this->parent->getPath('source');
  91. if (!$source)
  92. {
  93. $this->parent
  94. ->setPath(
  95. 'source',
  96. ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) .
  97. '/components/' . $this->parent->extension->element
  98. );
  99. }
  100. $this->manifest = $this->parent->getManifest();
  101. $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'));
  102. if (substr($name, 0, 4) == 'com_')
  103. {
  104. $extension = $name;
  105. }
  106. else
  107. {
  108. $extension = 'com_' . $name;
  109. }
  110. $lang = JFactory::getLanguage();
  111. $source = $path ? $path : ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/components/' . $extension;
  112. if ($this->manifest->administration->files)
  113. {
  114. $element = $this->manifest->administration->files;
  115. }
  116. elseif ($this->manifest->files)
  117. {
  118. $element = $this->manifest->files;
  119. }
  120. else
  121. {
  122. $element = null;
  123. }
  124. if ($element)
  125. {
  126. $folder = (string) $element->attributes()->folder;
  127. if ($folder && file_exists($path . '/' . $folder))
  128. {
  129. $source = $path . '/' . $folder;
  130. }
  131. }
  132. $lang->load($extension . '.sys', $source, null, false, false) || $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, null, false, false)
  133. || $lang->load($extension . '.sys', $source, $lang->getDefault(), false, false)
  134. || $lang->load($extension . '.sys', JPATH_ADMINISTRATOR, $lang->getDefault(), false, false);
  135. }
  136. /**
  137. * Custom install method for components
  138. *
  139. * @return boolean True on success
  140. *
  141. * @since 11.1
  142. */
  143. public function install()
  144. {
  145. // Get a database connector object
  146. $db = $this->parent->getDbo();
  147. // Get the extension manifest object
  148. $this->manifest = $this->parent->getManifest();
  149. /*
  150. * ---------------------------------------------------------------------------------------------
  151. * Manifest Document Setup Section
  152. * ---------------------------------------------------------------------------------------------
  153. */
  154. // Set the extension's name
  155. $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'));
  156. if (substr($name, 0, 4) == 'com_')
  157. {
  158. $element = $name;
  159. }
  160. else
  161. {
  162. $element = 'com_' . $name;
  163. }
  164. $this->set('name', $name);
  165. $this->set('element', $element);
  166. // Get the component description
  167. $this->parent->set('message', JText::_((string) $this->manifest->description));
  168. // Set the installation target paths
  169. $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $this->get('element')));
  170. $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->get('element')));
  171. // Copy the admin path as it's used as a common base
  172. $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator'));
  173. /*
  174. * ---------------------------------------------------------------------------------------------
  175. * Basic Checks Section
  176. * ---------------------------------------------------------------------------------------------
  177. */
  178. // Make sure that we have an admin element
  179. if (!$this->manifest->administration)
  180. {
  181. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_INSTALL_ADMIN_ELEMENT'), JLog::WARNING, 'jerror');
  182. return false;
  183. }
  184. /*
  185. * ---------------------------------------------------------------------------------------------
  186. * Filesystem Processing Section
  187. * ---------------------------------------------------------------------------------------------
  188. */
  189. /*
  190. * If the component site or admin directory already exists, then we will assume that the component is already
  191. * installed or another component is using that directory.
  192. */
  193. if (file_exists($this->parent->getPath('extension_site')) || file_exists($this->parent->getPath('extension_administrator')))
  194. {
  195. // Look for an update function or update tag
  196. $updateElement = $this->manifest->update;
  197. // Upgrade manually set or update function available or update tag detected
  198. if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update'))
  199. || $updateElement)
  200. {
  201. // Transfer control to the update function
  202. return $this->update();
  203. }
  204. elseif (!$this->parent->isOverwrite())
  205. {
  206. // Overwrite is set.
  207. // We didn't have overwrite set, find an update function or find an update tag so lets call it safe
  208. if (file_exists($this->parent->getPath('extension_site')))
  209. {
  210. // If the site exists say so.
  211. JLog::add(
  212. JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_SITE', $this->parent->getPath('extension_site')),
  213. JLog::WARNING, 'jerror'
  214. );
  215. }
  216. else
  217. {
  218. // If the admin exists say so
  219. JLog::add(
  220. JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_DIR_ADMIN', $this->parent->getPath('extension_administrator')),
  221. JLog::WARNING, 'jerror'
  222. );
  223. }
  224. return false;
  225. }
  226. }
  227. /*
  228. * ---------------------------------------------------------------------------------------------
  229. * Installer Trigger Loading
  230. * ---------------------------------------------------------------------------------------------
  231. */
  232. // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  233. $manifestScript = (string) $this->manifest->scriptfile;
  234. if ($manifestScript)
  235. {
  236. $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript;
  237. if (is_file($manifestScriptFile))
  238. {
  239. // Load the file
  240. include_once $manifestScriptFile;
  241. }
  242. // Set the class name
  243. $classname = $this->get('element') . 'InstallerScript';
  244. if (class_exists($classname))
  245. {
  246. // Create a new instance
  247. $this->parent->manifestClass = new $classname($this);
  248. // And set this so we can copy it later
  249. $this->set('manifest_script', $manifestScript);
  250. }
  251. }
  252. // Run preflight if possible (since we know we're not an update)
  253. ob_start();
  254. ob_implicit_flush(false);
  255. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight'))
  256. {
  257. if ($this->parent->manifestClass->preflight('install', $this) === false)
  258. {
  259. // Install failed, rollback changes
  260. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE'));
  261. return false;
  262. }
  263. }
  264. // Create msg object; first use here
  265. $msg = ob_get_contents();
  266. ob_end_clean();
  267. // If the component directory does not exist, let's create it
  268. $created = false;
  269. if (!file_exists($this->parent->getPath('extension_site')))
  270. {
  271. if (!$created = JFolder::create($this->parent->getPath('extension_site')))
  272. {
  273. JLog::add(
  274. JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_FAILED_TO_CREATE_DIRECTORY_SITE', $this->parent->getPath('extension_site')),
  275. JLog::WARNING, 'jerror'
  276. );
  277. return false;
  278. }
  279. }
  280. /*
  281. * Since we created the component directory and we will want to remove it if we have to roll back
  282. * the installation, let's add it to the installation step stack
  283. */
  284. if ($created)
  285. {
  286. $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_site')));
  287. }
  288. // If the component admin directory does not exist, let's create it
  289. $created = false;
  290. if (!file_exists($this->parent->getPath('extension_administrator')))
  291. {
  292. if (!$created = JFolder::create($this->parent->getPath('extension_administrator')))
  293. {
  294. JLog::add(
  295. JText::sprintf('JLIB_INSTALLER_ERROR_COMP_INSTALL_FAILED_TO_CREATE_DIRECTORY_ADMIN', $this->parent->getPath('extension_administrator')),
  296. JLog::WARNING, 'jerror'
  297. );
  298. // Install failed, rollback any changes
  299. $this->parent->abort();
  300. return false;
  301. }
  302. }
  303. /*
  304. * Since we created the component admin directory and we will want to remove it if we have to roll
  305. * back the installation, let's add it to the installation step stack
  306. */
  307. if ($created)
  308. {
  309. $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_administrator')));
  310. }
  311. // Copy site files
  312. if ($this->manifest->files)
  313. {
  314. if ($this->parent->parseFiles($this->manifest->files) === false)
  315. {
  316. // Install failed, rollback any changes
  317. $this->parent->abort();
  318. return false;
  319. }
  320. }
  321. // Copy admin files
  322. if ($this->manifest->administration->files)
  323. {
  324. if ($this->parent->parseFiles($this->manifest->administration->files, 1) === false)
  325. {
  326. // Install failed, rollback any changes
  327. $this->parent->abort();
  328. return false;
  329. }
  330. }
  331. // Parse optional tags
  332. $this->parent->parseMedia($this->manifest->media);
  333. $this->parent->parseLanguages($this->manifest->languages);
  334. $this->parent->parseLanguages($this->manifest->administration->languages, 1);
  335. // If there is a manifest script, let's copy it.
  336. if ($this->get('manifest_script'))
  337. {
  338. $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script');
  339. $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $this->get('manifest_script');
  340. if (!file_exists($path['dest']) || $this->parent->isOverwrite())
  341. {
  342. if (!$this->parent->copyFiles(array($path)))
  343. {
  344. // Install failed, rollback changes
  345. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_MANIFEST'));
  346. return false;
  347. }
  348. }
  349. }
  350. /*
  351. * ---------------------------------------------------------------------------------------------
  352. * Database Processing Section
  353. * ---------------------------------------------------------------------------------------------
  354. */
  355. // Run the install queries for the component
  356. if (isset($this->manifest->install->sql))
  357. {
  358. $result = $this->parent->parseSQLFiles($this->manifest->install->sql);
  359. if ($result === false)
  360. {
  361. // Install failed, rollback changes
  362. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_SQL_ERROR', $db->stderr(true)));
  363. return false;
  364. }
  365. }
  366. /**
  367. * ---------------------------------------------------------------------------------------------
  368. * Custom Installation Script Section
  369. * ---------------------------------------------------------------------------------------------
  370. */
  371. /*
  372. * If we have an install script, let's include it, execute the custom
  373. * install method, and append the return value from the custom install
  374. * method to the installation message.
  375. */
  376. ob_start();
  377. ob_implicit_flush(false);
  378. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'install'))
  379. {
  380. if ($this->parent->manifestClass->install($this) === false)
  381. {
  382. // Install failed, rollback changes
  383. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE'));
  384. return false;
  385. }
  386. }
  387. // Append messages
  388. $msg .= ob_get_contents();
  389. ob_end_clean();
  390. /**
  391. * ---------------------------------------------------------------------------------------------
  392. * Finalization and Cleanup Section
  393. * ---------------------------------------------------------------------------------------------
  394. */
  395. // Add an entry to the extension table with a whole heap of defaults
  396. $row = JTable::getInstance('extension');
  397. $row->set('name', $this->get('name'));
  398. $row->set('type', 'component');
  399. $row->set('element', $this->get('element'));
  400. // There is no folder for components
  401. $row->set('folder', '');
  402. $row->set('enabled', 1);
  403. $row->set('protected', 0);
  404. $row->set('access', 0);
  405. $row->set('client_id', 1);
  406. $row->set('params', $this->parent->getParams());
  407. $row->set('manifest_cache', $this->parent->generateManifestCache());
  408. if (!$row->store())
  409. {
  410. // Install failed, roll back changes
  411. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true)));
  412. return false;
  413. }
  414. $eid = $row->extension_id;
  415. // Clobber any possible pending updates
  416. $update = JTable::getInstance('update');
  417. $uid = $update->find(array('element' => $this->get('element'), 'type' => 'component', 'client_id' => 1, 'folder' => ''));
  418. if ($uid)
  419. {
  420. $update->delete($uid);
  421. }
  422. // We will copy the manifest file to its appropriate place.
  423. if (!$this->parent->copyManifest())
  424. {
  425. // Install failed, rollback changes
  426. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_COPY_SETUP'));
  427. return false;
  428. }
  429. // Time to build the admin menus
  430. if (!$this->_buildAdminMenus($row->extension_id))
  431. {
  432. JLog::add(JText::_('JLIB_INSTALLER_ABORT_COMP_BUILDADMINMENUS_FAILED'), JLog::WARNING, 'jerror');
  433. // @todo remove code: $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true)));
  434. // @todo remove code: return false;
  435. }
  436. // Set the schema version to be the latest update version
  437. if ($this->manifest->update)
  438. {
  439. $this->parent->setSchemaVersion($this->manifest->update->schemas, $eid);
  440. }
  441. // Register the component container just under root in the assets table.
  442. $asset = JTable::getInstance('Asset');
  443. $asset->name = $row->element;
  444. $asset->parent_id = 1;
  445. $asset->rules = '{}';
  446. $asset->title = $row->name;
  447. $asset->setLocation(1, 'last-child');
  448. if (!$asset->store())
  449. {
  450. // Install failed, roll back changes
  451. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true)));
  452. return false;
  453. }
  454. // And now we run the postflight
  455. ob_start();
  456. ob_implicit_flush(false);
  457. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight'))
  458. {
  459. $this->parent->manifestClass->postflight('install', $this);
  460. }
  461. // Append messages
  462. $msg .= ob_get_contents();
  463. ob_end_clean();
  464. if ($msg != '')
  465. {
  466. $this->parent->set('extension_message', $msg);
  467. }
  468. return $row->extension_id;
  469. }
  470. /**
  471. * Custom update method for components
  472. *
  473. * @return boolean True on success
  474. *
  475. * @since 11.1
  476. */
  477. public function update()
  478. {
  479. // Get a database connector object
  480. $db = $this->parent->getDbo();
  481. // Set the overwrite setting
  482. $this->parent->setOverwrite(true);
  483. // Get the extension manifest object
  484. $this->manifest = $this->parent->getManifest();
  485. /**
  486. * ---------------------------------------------------------------------------------------------
  487. * Manifest Document Setup Section
  488. * ---------------------------------------------------------------------------------------------
  489. */
  490. // Set the extension's name
  491. $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'));
  492. if (substr($name, 0, 4) == 'com_')
  493. {
  494. $element = $name;
  495. }
  496. else
  497. {
  498. $element = 'com_' . $name;
  499. }
  500. $this->set('name', $name);
  501. $this->set('element', $element);
  502. // Get the component description
  503. $description = (string) $this->manifest->description;
  504. if ($description)
  505. {
  506. $this->parent->set('message', JText::_($description));
  507. }
  508. else
  509. {
  510. $this->parent->set('message', '');
  511. }
  512. // Set the installation target paths
  513. $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $this->get('element')));
  514. $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->get('element')));
  515. // Copy the admin path as it's used as a common base
  516. $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator'));
  517. // Hunt for the original XML file
  518. $old_manifest = null;
  519. // Create a new installer because findManifest sets stuff
  520. // Look in the administrator first
  521. $tmpInstaller = new JInstaller;
  522. $tmpInstaller->setPath('source', $this->parent->getPath('extension_administrator'));
  523. if (!$tmpInstaller->findManifest())
  524. {
  525. // Then the site
  526. $tmpInstaller->setPath('source', $this->parent->getPath('extension_site'));
  527. if ($tmpInstaller->findManifest())
  528. {
  529. $old_manifest = $tmpInstaller->getManifest();
  530. }
  531. }
  532. else
  533. {
  534. $old_manifest = $tmpInstaller->getManifest();
  535. }
  536. // Should do this above perhaps?
  537. if ($old_manifest)
  538. {
  539. $this->oldAdminFiles = $old_manifest->administration->files;
  540. $this->oldFiles = $old_manifest->files;
  541. }
  542. else
  543. {
  544. $this->oldAdminFiles = null;
  545. $this->oldFiles = null;
  546. }
  547. /**
  548. * ---------------------------------------------------------------------------------------------
  549. * Basic Checks Section
  550. * ---------------------------------------------------------------------------------------------
  551. */
  552. // Make sure that we have an admin element
  553. if (!$this->manifest->administration)
  554. {
  555. JLog::add(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_ADMIN_ELEMENT'), JLog::WARNING, 'jerror');
  556. return false;
  557. }
  558. /**
  559. * ---------------------------------------------------------------------------------------------
  560. * Installer Trigger Loading
  561. * ---------------------------------------------------------------------------------------------
  562. */
  563. // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  564. $manifestScript = (string) $this->manifest->scriptfile;
  565. if ($manifestScript)
  566. {
  567. $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript;
  568. if (is_file($manifestScriptFile))
  569. {
  570. // Load the file
  571. include_once $manifestScriptFile;
  572. }
  573. // Set the class name
  574. $classname = $element . 'InstallerScript';
  575. if (class_exists($classname))
  576. {
  577. // Create a new instance
  578. $this->parent->manifestClass = new $classname($this);
  579. // And set this so we can copy it later
  580. $this->set('manifest_script', $manifestScript);
  581. }
  582. }
  583. // Run preflight if possible (since we know we're not an update)
  584. ob_start();
  585. ob_implicit_flush(false);
  586. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight'))
  587. {
  588. if ($this->parent->manifestClass->preflight('update', $this) === false)
  589. {
  590. // Install failed, rollback changes
  591. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE'));
  592. return false;
  593. }
  594. }
  595. // Create msg object; first use here
  596. $msg = ob_get_contents();
  597. ob_end_clean();
  598. /**
  599. * ---------------------------------------------------------------------------------------------
  600. * Filesystem Processing Section
  601. * ---------------------------------------------------------------------------------------------
  602. */
  603. // If the component directory does not exist, let's create it
  604. $created = false;
  605. if (!file_exists($this->parent->getPath('extension_site')))
  606. {
  607. if (!$created = JFolder::create($this->parent->getPath('extension_site')))
  608. {
  609. JLog::add(
  610. JText::sprintf('JLIB_INSTALLER_ERROR_COMP_UPDATE_FAILED_TO_CREATE_DIRECTORY_SITE', $this->parent->getPath('extension_site')),
  611. JLog::WARNING, 'jerror'
  612. );
  613. return false;
  614. }
  615. }
  616. /*
  617. * Since we created the component directory and will want to remove it if we have to roll back
  618. * the installation, lets add it to the installation step stack
  619. */
  620. if ($created)
  621. {
  622. $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_site')));
  623. }
  624. // If the component admin directory does not exist, let's create it
  625. $created = false;
  626. if (!file_exists($this->parent->getPath('extension_administrator')))
  627. {
  628. if (!$created = JFolder::create($this->parent->getPath('extension_administrator')))
  629. {
  630. JLog::add(
  631. JText::sprintf('JLIB_INSTALLER_ERROR_COMP_UPDATE_FAILED_TO_CREATE_DIRECTORY_ADMIN', $this->parent->getPath('extension_administrator')),
  632. JLog::WARNING, 'jerror'
  633. );
  634. // Install failed, rollback any changes
  635. $this->parent->abort();
  636. return false;
  637. }
  638. }
  639. /*
  640. * Since we created the component admin directory and we will want to remove it if we have to roll
  641. * back the installation, let's add it to the installation step stack
  642. */
  643. if ($created)
  644. {
  645. $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_administrator')));
  646. }
  647. // Find files to copy
  648. if ($this->manifest->files)
  649. {
  650. if ($this->parent->parseFiles($this->manifest->files, 0, $this->oldFiles) === false)
  651. {
  652. // Install failed, rollback any changes
  653. $this->parent->abort();
  654. return false;
  655. }
  656. }
  657. if ($this->manifest->administration->files)
  658. {
  659. if ($this->parent->parseFiles($this->manifest->administration->files, 1, $this->oldAdminFiles) === false)
  660. {
  661. // Install failed, rollback any changes
  662. $this->parent->abort();
  663. return false;
  664. }
  665. }
  666. // Parse optional tags
  667. $this->parent->parseMedia($this->manifest->media);
  668. $this->parent->parseLanguages($this->manifest->languages);
  669. $this->parent->parseLanguages($this->manifest->administration->languages, 1);
  670. // If there is a manifest script, let's copy it.
  671. if ($this->get('manifest_script'))
  672. {
  673. $path['src'] = $this->parent->getPath('source') . '/' . $this->get('manifest_script');
  674. $path['dest'] = $this->parent->getPath('extension_administrator') . '/' . $this->get('manifest_script');
  675. if (!file_exists($path['dest']) || $this->parent->isOverwrite())
  676. {
  677. if (!$this->parent->copyFiles(array($path)))
  678. {
  679. // Install failed, rollback changes
  680. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_MANIFEST'));
  681. return false;
  682. }
  683. }
  684. }
  685. /**
  686. * ---------------------------------------------------------------------------------------------
  687. * Database Processing Section
  688. * ---------------------------------------------------------------------------------------------
  689. */
  690. // Let's run the update queries for the component
  691. $row = JTable::getInstance('extension');
  692. $eid = $row->find(array('element' => strtolower($this->get('element')), 'type' => 'component'));
  693. if ($this->manifest->update)
  694. {
  695. $result = $this->parent->parseSchemaUpdates($this->manifest->update->schemas, $eid);
  696. if ($result === false)
  697. {
  698. // Install failed, rollback changes
  699. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_UPDATE_SQL_ERROR', $db->stderr(true)));
  700. return false;
  701. }
  702. }
  703. // Time to build the admin menus
  704. if (!$this->_buildAdminMenus($eid))
  705. {
  706. JLog::add(JText::_('JLIB_INSTALLER_ABORT_COMP_BUILDADMINMENUS_FAILED'), JLog::WARNING, 'jerror');
  707. // $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_INSTALL_ROLLBACK', $db->stderr(true)));
  708. // Return false;
  709. }
  710. /**
  711. * ---------------------------------------------------------------------------------------------
  712. * Custom Installation Script Section
  713. * ---------------------------------------------------------------------------------------------
  714. */
  715. /*
  716. * If we have an install script, let's include it, execute the custom
  717. * update method, and append the return value from the custom update
  718. * method to the installation message.
  719. */
  720. ob_start();
  721. ob_implicit_flush(false);
  722. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update'))
  723. {
  724. if ($this->parent->manifestClass->update($this) === false)
  725. {
  726. // Install failed, rollback changes
  727. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE'));
  728. return false;
  729. }
  730. }
  731. // Append messages
  732. $msg .= ob_get_contents();
  733. ob_end_clean();
  734. /**
  735. * ---------------------------------------------------------------------------------------------
  736. * Finalization and Cleanup Section
  737. * ---------------------------------------------------------------------------------------------
  738. */
  739. // Clobber any possible pending updates
  740. $update = JTable::getInstance('update');
  741. $uid = $update->find(array('element' => $this->get('element'), 'type' => 'component', 'client_id' => 1, 'folder' => ''));
  742. if ($uid)
  743. {
  744. $update->delete($uid);
  745. }
  746. // Update an entry to the extension table
  747. if ($eid)
  748. {
  749. $row->load($eid);
  750. }
  751. else
  752. {
  753. // Set the defaults
  754. // There is no folder for components
  755. $row->folder = '';
  756. $row->enabled = 1;
  757. $row->protected = 0;
  758. $row->access = 1;
  759. $row->client_id = 1;
  760. $row->params = $this->parent->getParams();
  761. }
  762. $row->name = $this->get('name');
  763. $row->type = 'component';
  764. $row->element = $this->get('element');
  765. $row->manifest_cache = $this->parent->generateManifestCache();
  766. if (!$row->store())
  767. {
  768. // Install failed, roll back changes
  769. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_COMP_UPDATE_ROLLBACK', $db->stderr(true)));
  770. return false;
  771. }
  772. // We will copy the manifest file to its appropriate place.
  773. if (!$this->parent->copyManifest())
  774. {
  775. // Install failed, rollback changes
  776. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_UPDATE_COPY_SETUP'));
  777. return false;
  778. }
  779. // And now we run the postflight
  780. ob_start();
  781. ob_implicit_flush(false);
  782. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'postflight'))
  783. {
  784. $this->parent->manifestClass->postflight('update', $this);
  785. }
  786. // Append messages
  787. $msg .= ob_get_contents();
  788. ob_end_clean();
  789. if ($msg != '')
  790. {
  791. $this->parent->set('extension_message', $msg);
  792. }
  793. return $row->extension_id;
  794. }
  795. /**
  796. * Custom uninstall method for components
  797. *
  798. * @param integer $id The unique extension id of the component to uninstall
  799. *
  800. * @return mixed Return value for uninstall method in component uninstall file
  801. *
  802. * @since 11.1
  803. */
  804. public function uninstall($id)
  805. {
  806. $db = $this->parent->getDbo();
  807. $row = null;
  808. $retval = true;
  809. // First order of business will be to load the component object table from the database.
  810. // This should give us the necessary information to proceed.
  811. $row = JTable::getInstance('extension');
  812. if (!$row->load((int) $id))
  813. {
  814. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_ERRORUNKOWNEXTENSION'), JLog::WARNING, 'jerror');
  815. return false;
  816. }
  817. // Is the component we are trying to uninstall a core one?
  818. // Because that is not a good idea...
  819. if ($row->protected)
  820. {
  821. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_WARNCORECOMPONENT'), JLog::WARNING, 'jerror');
  822. return false;
  823. }
  824. // Get the admin and site paths for the component
  825. $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $row->element));
  826. $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $row->element));
  827. // Copy the admin path as it's used as a common base
  828. $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator'));
  829. /**
  830. * ---------------------------------------------------------------------------------------------
  831. * Manifest Document Setup Section
  832. * ---------------------------------------------------------------------------------------------
  833. */
  834. // Find and load the XML install file for the component
  835. $this->parent->setPath('source', $this->parent->getPath('extension_administrator'));
  836. // Get the package manifest object
  837. // We do findManifest to avoid problem when uninstalling a list of extension: getManifest cache its manifest file
  838. $this->parent->findManifest();
  839. $this->manifest = $this->parent->getManifest();
  840. if (!$this->manifest)
  841. {
  842. // Make sure we delete the folders if no manifest exists
  843. JFolder::delete($this->parent->getPath('extension_administrator'));
  844. JFolder::delete($this->parent->getPath('extension_site'));
  845. // Remove the menu
  846. $this->_removeAdminMenus($row);
  847. // Raise a warning
  848. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_ERRORREMOVEMANUALLY'), JLog::WARNING, 'jerror');
  849. // Return
  850. return false;
  851. }
  852. // Set the extensions name
  853. $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'));
  854. if (substr($name, 0, 4) == 'com_')
  855. {
  856. $element = $name;
  857. }
  858. else
  859. {
  860. $element = 'com_' . $name;
  861. }
  862. $this->set('name', $name);
  863. $this->set('element', $element);
  864. // Attempt to load the admin language file; might have uninstall strings
  865. $this->loadLanguage(JPATH_ADMINISTRATOR . '/components/' . $element);
  866. /**
  867. * ---------------------------------------------------------------------------------------------
  868. * Installer Trigger Loading and Uninstall
  869. * ---------------------------------------------------------------------------------------------
  870. */
  871. // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  872. $scriptFile = (string) $this->manifest->scriptfile;
  873. if ($scriptFile)
  874. {
  875. $manifestScriptFile = $this->parent->getPath('source') . '/' . $scriptFile;
  876. if (is_file($manifestScriptFile))
  877. {
  878. // Load the file
  879. include_once $manifestScriptFile;
  880. }
  881. // Set the class name
  882. $classname = $row->element . 'InstallerScript';
  883. if (class_exists($classname))
  884. {
  885. // Create a new instance
  886. $this->parent->manifestClass = new $classname($this);
  887. // And set this so we can copy it later
  888. $this->set('manifest_script', $scriptFile);
  889. }
  890. }
  891. ob_start();
  892. ob_implicit_flush(false);
  893. // Run uninstall if possible
  894. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'uninstall'))
  895. {
  896. $this->parent->manifestClass->uninstall($this);
  897. }
  898. $msg = ob_get_contents();
  899. ob_end_clean();
  900. if ($msg != '')
  901. {
  902. $this->parent->set('extension_message', $msg);
  903. }
  904. /**
  905. * ---------------------------------------------------------------------------------------------
  906. * Database Processing Section
  907. * ---------------------------------------------------------------------------------------------
  908. */
  909. // Let's run the uninstall queries for the component
  910. if (isset($this->manifest->uninstall->sql))
  911. {
  912. $result = $this->parent->parseSQLFiles($this->manifest->uninstall->sql);
  913. if ($result === false)
  914. {
  915. // Install failed, rollback changes
  916. JLog::add(JText::sprintf('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_SQL_ERROR', $db->stderr(true)), JLog::WARNING, 'jerror');
  917. $retval = false;
  918. }
  919. }
  920. $this->_removeAdminMenus($row);
  921. /**
  922. * ---------------------------------------------------------------------------------------------
  923. * Filesystem Processing Section
  924. * ---------------------------------------------------------------------------------------------
  925. */
  926. // Let's remove those language files and media in the JROOT/images/ folder that are
  927. // associated with the component we are uninstalling
  928. $this->parent->removeFiles($this->manifest->media);
  929. $this->parent->removeFiles($this->manifest->languages);
  930. $this->parent->removeFiles($this->manifest->administration->languages, 1);
  931. // Remove the schema version
  932. $query = $db->getQuery(true);
  933. $query->delete()->from('#__schemas')->where('extension_id = ' . $id);
  934. $db->setQuery($query);
  935. $db->execute();
  936. // Remove the component container in the assets table.
  937. $asset = JTable::getInstance('Asset');
  938. if ($asset->loadByName($element))
  939. {
  940. $asset->delete();
  941. }
  942. // Remove categories for this component
  943. $query = $db->getQuery(true);
  944. $query->delete()->from('#__categories')->where('extension=' . $db->quote($element), 'OR')
  945. ->where('extension LIKE ' . $db->quote($element . '.%'));
  946. $db->setQuery($query);
  947. $db->execute();
  948. // Clobber any possible pending updates
  949. $update = JTable::getInstance('update');
  950. $uid = $update->find(array('element' => $row->element, 'type' => 'component', 'client_id' => 1, 'folder' => ''));
  951. if ($uid)
  952. {
  953. $update->delete($uid);
  954. }
  955. // Now we need to delete the installation directories. This is the final step in uninstalling the component.
  956. if (trim($row->element))
  957. {
  958. // Delete the component site directory
  959. if (is_dir($this->parent->getPath('extension_site')))
  960. {
  961. if (!JFolder::delete($this->parent->getPath('extension_site')))
  962. {
  963. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_REMOVE_DIRECTORY_SITE'), JLog::WARNING, 'jerror');
  964. $retval = false;
  965. }
  966. }
  967. // Delete the component admin directory
  968. if (is_dir($this->parent->getPath('extension_administrator')))
  969. {
  970. if (!JFolder::delete($this->parent->getPath('extension_administrator')))
  971. {
  972. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_FAILED_REMOVE_DIRECTORY_ADMIN'), JLog::WARNING, 'jerror');
  973. $retval = false;
  974. }
  975. }
  976. // Now we will no longer need the extension object, so let's delete it and free up memory
  977. $row->delete($row->extension_id);
  978. unset($row);
  979. return $retval;
  980. }
  981. else
  982. {
  983. // No component option defined... cannot delete what we don't know about
  984. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_UNINSTALL_NO_OPTION'), JLog::WARNING, 'jerror');
  985. return false;
  986. }
  987. }
  988. /**
  989. * Method to build menu database entries for a component
  990. *
  991. * @return boolean True if successful
  992. *
  993. * @since 11.1
  994. */
  995. protected function _buildAdminMenus()
  996. {
  997. $db = $this->parent->getDbo();
  998. $table = JTable::getInstance('menu');
  999. $option = $this->get('element');
  1000. // If a component exists with this option in the table then we don't need to add menus
  1001. $query = $db->getQuery(true);
  1002. $query->select('m.id, e.extension_id');
  1003. $query->from('#__menu AS m');
  1004. $query->leftJoin('#__extensions AS e ON m.component_id = e.extension_id');
  1005. $query->where('m.parent_id = 1');
  1006. $query->where('m.client_id = 1');
  1007. $query->where('e.element = ' . $db->quote($option));
  1008. $db->setQuery($query);
  1009. $componentrow = $db->loadObject();
  1010. // Check if menu items exist
  1011. if ($componentrow)
  1012. {
  1013. // Don't do anything if overwrite has not been enabled
  1014. if (!$this->parent->isOverwrite())
  1015. {
  1016. return true;
  1017. }
  1018. // Remove existing menu items if overwrite has been enabled
  1019. if ($option)
  1020. {
  1021. // If something goes wrong, there's no way to rollback TODO: Search for better solution
  1022. $this->_removeAdminMenus($componentrow);
  1023. }
  1024. $component_id = $componentrow->extension_id;
  1025. }
  1026. else
  1027. {
  1028. // Lets find the extension id
  1029. $query->clear();
  1030. $query->select('e.extension_id');
  1031. $query->from('#__extensions AS e');
  1032. $query->where('e.element = ' . $db->quote($option));
  1033. $db->setQuery($query);
  1034. // TODO Find Some better way to discover the component_id
  1035. $component_id = $db->loadResult();
  1036. }
  1037. // Ok, now its time to handle the menus. Start with the component root menu, then handle submenus.
  1038. $menuElement = $this->manifest->administration->menu;
  1039. if ($menuElement)
  1040. {
  1041. $data = array();
  1042. $data['menutype'] = 'main';
  1043. $data['client_id'] = 1;
  1044. $data['title'] = (string) trim($menuElement);
  1045. $data['alias'] = (string) $menuElement;
  1046. $data['link'] = 'index.php?option=' . $option;
  1047. $data['type'] = 'component';
  1048. $data['published'] = 0;
  1049. $data['parent_id'] = 1;
  1050. $data['component_id'] = $component_id;
  1051. $data['img'] = ((string) $menuElement->attributes()->img) ? (string) $menuElement->attributes()->img : 'class:component';
  1052. $data['home'] = 0;
  1053. try
  1054. {
  1055. $table->setLocation(1, 'last-child');
  1056. }
  1057. catch (InvalidArgumentException $e)
  1058. {
  1059. JLog::add($e->getMessage(), JLog::WARNING, 'jerror');
  1060. return false;
  1061. }
  1062. if (!$table->bind($data) || !$table->check() || !$table->store())
  1063. {
  1064. // The menu item already exists. Delete it and retry instead of throwing an error.
  1065. $query = $db->getQuery(true);
  1066. $query->select('id');
  1067. $query->from('#__menu');
  1068. $query->where('menutype = ' . $db->quote('main'));
  1069. $query->where('client_id = 1');
  1070. $query->where('link = ' . $db->quote('index.php?option=' . $option));
  1071. $query->where('type = ' . $db->quote('component'));
  1072. $query->where('parent_id = 1');
  1073. $query->where('home = 0');
  1074. $db->setQuery($query);
  1075. $menu_id = $db->loadResult();
  1076. if (!$menu_id)
  1077. {
  1078. // Oops! Could not get the menu ID. Go back and rollback changes.
  1079. JError::raiseWarning(1, $table->getError());
  1080. return false;
  1081. }
  1082. else
  1083. {
  1084. // Remove the old menu item
  1085. $query = $db->getQuery(true);
  1086. $query->delete('#__menu');
  1087. $query->where('id = ' . (int) $menu_id);
  1088. $db->setQuery($query);
  1089. $db->query();
  1090. // Retry creating the menu item
  1091. $table->setLocation(1, 'last-child');
  1092. if (!$table->bind($data) || !$table->check() || !$table->store())
  1093. {
  1094. // Install failed, warn user and rollback changes
  1095. JError::raiseWarning(1, $table->getError());
  1096. return false;
  1097. }
  1098. }
  1099. }
  1100. /*
  1101. * Since we have created a menu item, we add it to the installation step stack
  1102. * so that if we have to rollback the changes we can undo it.
  1103. */
  1104. $this->parent->pushStep(array('type' => 'menu', 'id' => $component_id));
  1105. }
  1106. // No menu element was specified, Let's make a generic menu item
  1107. else
  1108. {
  1109. $data = array();
  1110. $data['menutype'] = 'main';
  1111. $data['client_id'] = 1;
  1112. $data['title'] = $option;
  1113. $data['alias'] = $option;
  1114. $data['link'] = 'index.php?option=' . $option;
  1115. $data['type'] = 'component';
  1116. $data['published'] = 0;
  1117. $data['parent_id'] = 1;
  1118. $data['component_id'] = $component_id;
  1119. $data['img'] = 'class:component';
  1120. $data['home'] = 0;
  1121. try
  1122. {
  1123. $table->setLocation(1, 'last-child');
  1124. }
  1125. catch (InvalidArgumentException $e)
  1126. {
  1127. JLog::add($e->getMessage(), JLog::WARNING, 'jerror');
  1128. return false;
  1129. }
  1130. if (!$table->bind($data) || !$table->check() || !$table->store())
  1131. {
  1132. // Install failed, warn user and rollback changes
  1133. JLog::add($table->getError(), JLog::WARNING, 'jerror');
  1134. return false;
  1135. }
  1136. /*
  1137. * Since we have created a menu item, we add it to the installation step stack
  1138. * so that if we have to rollback the changes we can undo it.
  1139. */
  1140. $this->parent->pushStep(array('type' => 'menu', 'id' => $component_id));
  1141. }
  1142. /*
  1143. * Process SubMenus
  1144. */
  1145. if (!$this->manifest->administration->submenu)
  1146. {
  1147. return true;
  1148. }
  1149. $parent_id = $table->id;
  1150. foreach ($this->manifest->administration->submenu->menu as $child)
  1151. {
  1152. $data = array();
  1153. $data['menutype'] = 'main';
  1154. $data['client_id'] = 1;
  1155. $data['title'] = (string) trim($child);
  1156. $data['alias'] = (string) $child;
  1157. $data['type'] = 'component';
  1158. $data['published'] = 0;
  1159. $data['parent_id'] = $parent_id;
  1160. $data['component_id'] = $component_id;
  1161. $data['img'] = ((string) $child->attributes()->img) ? (string) $child->attributes()->img : 'class:component';
  1162. $data['home'] = 0;
  1163. // Set the sub menu link
  1164. if ((string) $child->attributes()->link)
  1165. {
  1166. $data['link'] = 'index.php?' . $child->attributes()->link;
  1167. }
  1168. else
  1169. {
  1170. $request = array();
  1171. if ((string) $child->attributes()->act)
  1172. {
  1173. $request[] = 'act=' . $child->attributes()->act;
  1174. }
  1175. if ((string) $child->attributes()->task)
  1176. {
  1177. $request[] = 'task=' . $child->attributes()->task;
  1178. }
  1179. if ((string) $child->attributes()->controller)
  1180. {
  1181. $request[] = 'controller=' . $child->attributes()->controller;
  1182. }
  1183. if ((string) $child->attributes()->view)
  1184. {
  1185. $request[] = 'view=' . $child->attributes()->view;
  1186. }
  1187. if ((string) $child->attributes()->layout)
  1188. {
  1189. $request[] = 'layout=' . $child->attributes()->layout;
  1190. }
  1191. if ((string) $child->attributes()->sub)
  1192. {
  1193. $request[] = 'sub=' . $child->attributes()->sub;
  1194. }
  1195. $qstring = (count($request)) ? '&' . implode('&', $request) : '';
  1196. $data['link'] = 'index.php?option=' . $option . $qstring;
  1197. }
  1198. $table = JTable::getInstance('menu');
  1199. try
  1200. {
  1201. $table->setLocation($parent_id, 'last-child');
  1202. }
  1203. catch (InvalidArgumentException $e)
  1204. {
  1205. return false;
  1206. }
  1207. if (!$table->bind($data) || !$table->check() || !$table->store())
  1208. {
  1209. // Install failed, rollback changes
  1210. return false;
  1211. }
  1212. /*
  1213. * Since we have created a menu item, we add it to the installation step stack
  1214. * so that if we have to rollback the changes we can undo it.
  1215. */
  1216. $this->parent->pushStep(array('type' => 'menu', 'id' => $component_id));
  1217. }
  1218. return true;
  1219. }
  1220. /**
  1221. * Method to remove admin menu references to a component
  1222. *
  1223. * @param object &$row Component table object.
  1224. *
  1225. * @return boolean True if successful.
  1226. *
  1227. * @since 11.1
  1228. */
  1229. protected function _removeAdminMenus(&$row)
  1230. {
  1231. $db = $this->parent->getDbo();
  1232. $table = JTable::getInstance('menu');
  1233. $id = $row->extension_id;
  1234. // Get the ids of the menu items
  1235. $query = $db->getQuery(true);
  1236. $query->select('id');
  1237. $query->from('#__menu');
  1238. $query->where($query->qn('client_id') . ' = 1');
  1239. $query->where($query->qn('component_id') . ' = ' . (int) $id);
  1240. $db->setQuery($query);
  1241. $ids = $db->loadColumn();
  1242. // Check for error
  1243. if (!empty($ids))
  1244. {
  1245. // Iterate the items to delete each one.
  1246. foreach ($ids as $menuid)
  1247. {
  1248. if (!$table->delete((int) $menuid))
  1249. {
  1250. $this->setError($table->getError());
  1251. return false;
  1252. }
  1253. }
  1254. // Rebuild the whole tree
  1255. $table->rebuild();
  1256. }
  1257. return true;
  1258. }
  1259. /**
  1260. * Custom rollback method
  1261. * - Roll back the component menu item
  1262. *
  1263. * @param array $step Installation step to rollback.
  1264. *
  1265. * @return boolean True on success
  1266. *
  1267. * @since 11.1
  1268. */
  1269. protected function _rollback_menu($step)
  1270. {
  1271. return $this->_removeAdminMenus((object) array('extension_id' => $step['id']));
  1272. }
  1273. /**
  1274. * Discover unregistered extensions.
  1275. *
  1276. * @return array A list of extensions.
  1277. *
  1278. * @since 11.1
  1279. */
  1280. public function discover()
  1281. {
  1282. $results = array();
  1283. $site_components = JFolder::folders(JPATH_SITE . '/components');
  1284. $admin_components = JFolder::folders(JPATH_ADMINISTRATOR . '/components');
  1285. foreach ($site_components as $component)
  1286. {
  1287. if (file_exists(JPATH_SITE . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml'))
  1288. {
  1289. $manifest_details = JInstaller::parseXMLInstallFile(
  1290. JPATH_SITE . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml'
  1291. );
  1292. $extension = JTable::getInstance('extension');
  1293. $extension->set('type', 'component');
  1294. $extension->set('client_id', 0);
  1295. $extension->set('element', $component);
  1296. $extension->set('folder', '');
  1297. $extension->set('name', $component);
  1298. $extension->set('state', -1);
  1299. $extension->set('manifest_cache', json_encode($manifest_details));
  1300. $extension->set('params', '{}');
  1301. $results[] = $extension;
  1302. }
  1303. }
  1304. foreach ($admin_components as $component)
  1305. {
  1306. if (file_exists(JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml'))
  1307. {
  1308. $manifest_details = JInstaller::parseXMLInstallFile(
  1309. JPATH_ADMINISTRATOR . '/components/' . $component . '/' . str_replace('com_', '', $component) . '.xml'
  1310. );
  1311. $extension = JTable::getInstance('extension');
  1312. $extension->set('type', 'component');
  1313. $extension->set('client_id', 1);
  1314. $extension->set('element', $component);
  1315. $extension->set('folder', '');
  1316. $extension->set('name', $component);
  1317. $extension->set('state', -1);
  1318. $extension->set('manifest_cache', json_encode($manifest_details));
  1319. $extension->set('params', '{}');
  1320. $results[] = $extension;
  1321. }
  1322. }
  1323. return $results;
  1324. }
  1325. /**
  1326. * Install unregistered extensions that have been discovered.
  1327. *
  1328. * @return mixed
  1329. *
  1330. * @since 11.1
  1331. */
  1332. public function discover_install()
  1333. {
  1334. // Need to find to find where the XML file is since we don't store this normally
  1335. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  1336. $short_element = str_replace('com_', '', $this->parent->extension->element);
  1337. $manifestPath = $client->path . '/components/' . $this->parent->extension->element . '/' . $short_element . '.xml';
  1338. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  1339. $this->parent->setPath('manifest', $manifestPath);
  1340. $this->parent->setPath('source', $client->path . '/components/' . $this->parent->extension->element);
  1341. $this->parent->setPath('extension_root', $this->parent->getPath('source'));
  1342. $manifest_details = JInstaller::parseXMLInstallFile($this->parent->getPath('manifest'));
  1343. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  1344. $this->parent->extension->state = 0;
  1345. $this->parent->extension->name = $manifest_details['name'];
  1346. $this->parent->extension->enabled = 1;
  1347. $this->parent->extension->params = $this->parent->getParams();
  1348. try
  1349. {
  1350. $this->parent->extension->store();
  1351. }
  1352. catch (RuntimeException $e)
  1353. {
  1354. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_DISCOVER_STORE_DETAILS'), JLog::WARNING, 'jerror');
  1355. return false;
  1356. }
  1357. // Now we need to run any SQL it has, languages, media or menu stuff
  1358. // Get a database connector object
  1359. $db = $this->parent->getDbo();
  1360. // Get the extension manifest object
  1361. $this->manifest = $this->parent->getManifest();
  1362. /**
  1363. * ---------------------------------------------------------------------------------------------
  1364. * Manifest Document Setup Section
  1365. * ---------------------------------------------------------------------------------------------
  1366. */
  1367. // Set the extensions name
  1368. $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'));
  1369. if (substr($name, 0, 4) == 'com_')
  1370. {
  1371. $element = $name;
  1372. }
  1373. else
  1374. {
  1375. $element = 'com_' . $name;
  1376. }
  1377. $this->set('name', $name);
  1378. $this->set('element', $element);
  1379. // Get the component description
  1380. $description = (string) $this->manifest->description;
  1381. if ($description)
  1382. {
  1383. $this->parent->set('message', JText::_((string) $description));
  1384. }
  1385. else
  1386. {
  1387. $this->parent->set('message', '');
  1388. }
  1389. // Set the installation target paths
  1390. $this->parent->setPath('extension_site', JPath::clean(JPATH_SITE . '/components/' . $this->get('element')));
  1391. $this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR . '/components/' . $this->get('element')));
  1392. // Copy the admin path as it's used as a common base
  1393. $this->parent->setPath('extension_root', $this->parent->getPath('extension_administrator'));
  1394. /**
  1395. * ---------------------------------------------------------------------------------------------
  1396. * Basic Checks Section
  1397. * ---------------------------------------------------------------------------------------------
  1398. */
  1399. // Make sure that we have an admin element
  1400. if (!$this->manifest->administration)
  1401. {
  1402. JLog::add(JText::_('JLIB_INSTALLER_ERROR_COMP_INSTALL_ADMIN_ELEMENT'), JLog::WARNING, 'jerror');
  1403. return false;
  1404. }
  1405. /**
  1406. * ---------------------------------------------------------------------------------------------
  1407. * Installer Trigger Loading
  1408. * ---------------------------------------------------------------------------------------------
  1409. */
  1410. // If there is an manifest class file, lets load it; we'll copy it later (don't have dest yet)
  1411. $manifestScript = (string) $this->manifest->scriptfile;
  1412. if ($manifestScript)
  1413. {
  1414. $manifestScriptFile = $this->parent->getPath('source') . '/' . $manifestScript;
  1415. if (is_file($manifestScriptFile))
  1416. {
  1417. // Load the file
  1418. include_once $manifestScriptFile;
  1419. }
  1420. // Set the class name
  1421. $classname = $element . 'InstallerScript';
  1422. if (class_exists($classname))
  1423. {
  1424. // Create a new instance
  1425. $this->parent->manifestClass = new $classname($this);
  1426. // And set this so we can copy it later
  1427. $this->set('manifest_script', $manifestScript);
  1428. }
  1429. }
  1430. // Run preflight if possible (since we know we're not an update)
  1431. ob_start();
  1432. ob_implicit_flush(false);
  1433. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'preflight'))
  1434. {
  1435. if ($this->parent->manifestClass->preflight('discover_install', $this) === false)
  1436. {
  1437. // Install failed, rollback changes
  1438. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_COMP_INSTALL_CUSTOM_INSTALL_FAILURE'));
  1439. return false;
  1440. }
  1441. }
  1442. // Create msg object; first use here

Large files files are truncated, but you can click here to view the full file