PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/cms/installer/adapter/component.php

https://github.com/kochen/joomla-rtl
PHP | 1900 lines | 1062 code | 325 blank | 513 comment | 166 complexity | 7ba7e60322ad6eb2f3f5fe9e70208695 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause, Apache-2.0

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

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

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