PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/installer/adapters/template.php

http://github.com/joomla/joomla-platform
PHP | 591 lines | 373 code | 88 blank | 130 comment | 47 complexity | c87ad823fc5f91c9f79c7f6dc270f91d MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @package Joomla.Platform
  4. * @subpackage Installer
  5. *
  6. * @copyright Copyright (C) 2005 - 2012 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.installer.extension');
  11. jimport('joomla.base.adapterinstance');
  12. /**
  13. * Template installer
  14. *
  15. * @package Joomla.Platform
  16. * @subpackage Installer
  17. * @since 11.1
  18. */
  19. class JInstallerTemplate extends JAdapterInstance
  20. {
  21. protected $name = null;
  22. protected $element = null;
  23. protected $route = 'install';
  24. /**
  25. * Custom loadLanguage method
  26. *
  27. * @param string $path The path where to find language files.
  28. *
  29. * @return JInstallerTemplate
  30. *
  31. * @since 11.1
  32. */
  33. public function loadLanguage($path = null)
  34. {
  35. $source = $this->parent->getPath('source');
  36. if (!$source)
  37. {
  38. $this->parent
  39. ->setPath(
  40. 'source',
  41. ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/templates/' . $this->parent->extension->element
  42. );
  43. }
  44. $clientId = isset($this->parent->extension) ? $this->parent->extension->client_id : 0;
  45. $this->manifest = $this->parent->getManifest();
  46. $name = strtolower(JFilterInput::getInstance()->clean((string) $this->manifest->name, 'cmd'));
  47. $client = (string) $this->manifest->attributes()->client;
  48. // Load administrator language if not set.
  49. if (!$client)
  50. {
  51. $client = 'ADMINISTRATOR';
  52. }
  53. $extension = "tpl_$name";
  54. $lang = JFactory::getLanguage();
  55. $source = $path ? $path : ($this->parent->extension->client_id ? JPATH_ADMINISTRATOR : JPATH_SITE) . '/templates/' . $name;
  56. $lang->load($extension . '.sys', $source, null, false, false)
  57. || $lang->load($extension . '.sys', constant('JPATH_' . strtoupper($client)), null, false, false)
  58. || $lang->load($extension . '.sys', $source, $lang->getDefault(), false, false)
  59. || $lang->load($extension . '.sys', constant('JPATH_' . strtoupper($client)), $lang->getDefault(), false, false);
  60. }
  61. /**
  62. * Custom install method
  63. *
  64. * @return boolean True on success
  65. *
  66. * @since 11.1
  67. */
  68. public function install()
  69. {
  70. // Get a database connector object
  71. $db = $this->parent->getDbo();
  72. $lang = JFactory::getLanguage();
  73. $xml = $this->parent->getManifest();
  74. // Get the client application target
  75. if ($cname = (string) $xml->attributes()->client)
  76. {
  77. // Attempt to map the client to a base path
  78. $client = JApplicationHelper::getClientInfo($cname, true);
  79. if ($client === false)
  80. {
  81. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_UNKNOWN_CLIENT', $cname));
  82. return false;
  83. }
  84. $basePath = $client->path;
  85. $clientId = $client->id;
  86. }
  87. else
  88. {
  89. // No client attribute was found so we assume the site as the client
  90. $cname = 'site';
  91. $basePath = JPATH_SITE;
  92. $clientId = 0;
  93. }
  94. // Set the extension's name
  95. $name = JFilterInput::getInstance()->clean((string) $xml->name, 'cmd');
  96. $element = strtolower(str_replace(" ", "_", $name));
  97. $this->set('name', $name);
  98. $this->set('element', $element);
  99. // Check to see if a template by the same name is already installed.
  100. $query = $db->getQuery(true);
  101. $query->select($query->qn('extension_id'))->from($query->qn('#__extensions'));
  102. $query->where($query->qn('type') . ' = ' . $query->q('template'));
  103. $query->where($query->qn('element') . ' = ' . $query->q($element));
  104. $db->setQuery($query);
  105. try
  106. {
  107. $id = $db->loadResult();
  108. }
  109. catch (JDatabaseException $e)
  110. {
  111. // Install failed, roll back changes
  112. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ROLLBACK'), $e->getMessage());
  113. return false;
  114. }
  115. // Legacy error handling switch based on the JError::$legacy switch.
  116. // @deprecated 12.1
  117. if (JError::$legacy && $db->getErrorNum())
  118. {
  119. // Install failed, roll back changes
  120. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ROLLBACK', $db->stderr(true)));
  121. return false;
  122. }
  123. // Set the template root path
  124. $this->parent->setPath('extension_root', $basePath . '/templates/' . $element);
  125. // If it's on the fs...
  126. if (file_exists($this->parent->getPath('extension_root')) && (!$this->parent->isOverwrite() || $this->parent->isUpgrade()))
  127. {
  128. $updateElement = $xml->update;
  129. /*
  130. * Upgrade manually set or
  131. * Update function available or
  132. * Update tag detected
  133. */
  134. if ($this->parent->isUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass, 'update'))
  135. || $updateElement)
  136. {
  137. // Force this one
  138. $this->parent->setOverwrite(true);
  139. $this->parent->setUpgrade(true);
  140. if ($id)
  141. {
  142. // If there is a matching extension mark this as an update; semantics really
  143. $this->route = 'update';
  144. }
  145. }
  146. elseif (!$this->parent->isOverwrite())
  147. {
  148. // Overwrite is not set
  149. // If we didn't have overwrite set, find an update function or find an update tag so let's call it safe
  150. $this->parent
  151. ->abort(
  152. JText::sprintf(
  153. 'JLIB_INSTALLER_ABORT_TPL_INSTALL_ANOTHER_TEMPLATE_USING_DIRECTORY', JText::_('JLIB_INSTALLER_' . $this->route),
  154. $this->parent->getPath('extension_root')
  155. )
  156. );
  157. return false;
  158. }
  159. }
  160. /*
  161. * If the template directory already exists, then we will assume that the template is already
  162. * installed or another template is using that directory.
  163. */
  164. if (file_exists($this->parent->getPath('extension_root')) && !$this->parent->isOverwrite())
  165. {
  166. JError::raiseWarning(
  167. 100,
  168. JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ANOTHER_TEMPLATE_USING_DIRECTORY', $this->parent->getPath('extension_root'))
  169. );
  170. return false;
  171. }
  172. // If the template directory does not exist, let's create it
  173. $created = false;
  174. if (!file_exists($this->parent->getPath('extension_root')))
  175. {
  176. if (!$created = JFolder::create($this->parent->getPath('extension_root')))
  177. {
  178. $this->parent
  179. ->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_FAILED_CREATE_DIRECTORY', $this->parent->getPath('extension_root')));
  180. return false;
  181. }
  182. }
  183. // If we created the template directory and will want to remove it if we have to roll back
  184. // the installation, let's add it to the installation step stack
  185. if ($created)
  186. {
  187. $this->parent->pushStep(array('type' => 'folder', 'path' => $this->parent->getPath('extension_root')));
  188. }
  189. // Copy all the necessary files
  190. if ($this->parent->parseFiles($xml->files, -1) === false)
  191. {
  192. // Install failed, rollback changes
  193. $this->parent->abort();
  194. return false;
  195. }
  196. if ($this->parent->parseFiles($xml->images, -1) === false)
  197. {
  198. // Install failed, rollback changes
  199. $this->parent->abort();
  200. return false;
  201. }
  202. if ($this->parent->parseFiles($xml->css, -1) === false)
  203. {
  204. // Install failed, rollback changes
  205. $this->parent->abort();
  206. return false;
  207. }
  208. // Parse optional tags
  209. $this->parent->parseMedia($xml->media);
  210. $this->parent->parseLanguages($xml->languages, $clientId);
  211. // Get the template description
  212. $this->parent->set('message', JText::_((string) $xml->description));
  213. // Lastly, we will copy the manifest file to its appropriate place.
  214. if (!$this->parent->copyManifest(-1))
  215. {
  216. // Install failed, rollback changes
  217. $this->parent->abort(JText::_('JLIB_INSTALLER_ABORT_TPL_INSTALL_COPY_SETUP'));
  218. return false;
  219. }
  220. // Extension Registration
  221. $row = JTable::getInstance('extension');
  222. if ($this->route == 'update' && $id)
  223. {
  224. $row->load($id);
  225. }
  226. else
  227. {
  228. $row->type = 'template';
  229. $row->element = $this->get('element');
  230. // There is no folder for templates
  231. $row->folder = '';
  232. $row->enabled = 1;
  233. $row->protected = 0;
  234. $row->access = 1;
  235. $row->client_id = $clientId;
  236. $row->params = $this->parent->getParams();
  237. // Custom data
  238. $row->custom_data = '';
  239. }
  240. // Name might change in an update
  241. $row->name = $this->get('name');
  242. $row->manifest_cache = $this->parent->generateManifestCache();
  243. if (!$row->store())
  244. {
  245. // Install failed, roll back changes
  246. $this->parent->abort(JText::sprintf('JLIB_INSTALLER_ABORT_TPL_INSTALL_ROLLBACK', $db->stderr(true)));
  247. return false;
  248. }
  249. if ($this->route == 'install')
  250. {
  251. // Insert record in #__template_styles
  252. $query = $db->getQuery(true);
  253. $query->insert('#__template_styles');
  254. $query->set('template=' . $db->Quote($row->element));
  255. $query->set('client_id=' . $db->Quote($clientId));
  256. $query->set('home=0');
  257. $debug = $lang->setDebug(false);
  258. $query->set('title=' . $db->Quote(JText::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', JText::_($this->get('name')))));
  259. $lang->setDebug($debug);
  260. $query->set('params=' . $db->Quote($row->params));
  261. $db->setQuery($query);
  262. // There is a chance this could fail but we don't care...
  263. $db->query();
  264. }
  265. return $row->get('extension_id');
  266. }
  267. /**
  268. * Custom update method for components
  269. *
  270. * @return boolean True on success
  271. *
  272. * @since 11.1
  273. */
  274. public function update()
  275. {
  276. return $this->install();
  277. }
  278. /**
  279. * Custom uninstall method
  280. *
  281. * @param integer $id The extension ID
  282. *
  283. * @return boolean True on success
  284. *
  285. * @since 11.1
  286. */
  287. public function uninstall($id)
  288. {
  289. // Initialise variables.
  290. $retval = true;
  291. // First order of business will be to load the template object table from the database.
  292. // This should give us the necessary information to proceed.
  293. $row = JTable::getInstance('extension');
  294. if (!$row->load((int) $id) || !strlen($row->element))
  295. {
  296. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_ERRORUNKOWNEXTENSION'));
  297. return false;
  298. }
  299. // Is the template we are trying to uninstall a core one?
  300. // Because that is not a good idea...
  301. if ($row->protected)
  302. {
  303. JError::raiseWarning(100, JText::sprintf('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_WARNCORETEMPLATE', $row->name));
  304. return false;
  305. }
  306. $name = $row->element;
  307. $clientId = $row->client_id;
  308. // For a template the id will be the template name which represents the subfolder of the templates folder that the template resides in.
  309. if (!$name)
  310. {
  311. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_ID_EMPTY'));
  312. return false;
  313. }
  314. // Deny remove default template
  315. $db = $this->parent->getDbo();
  316. $query = 'SELECT COUNT(*) FROM #__template_styles' . ' WHERE home = 1 AND template = ' . $db->Quote($name);
  317. $db->setQuery($query);
  318. if ($db->loadResult() != 0)
  319. {
  320. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DEFAULT'));
  321. return false;
  322. }
  323. // Get the template root path
  324. $client = JApplicationHelper::getClientInfo($clientId);
  325. if (!$client)
  326. {
  327. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_CLIENT'));
  328. return false;
  329. }
  330. $this->parent->setPath('extension_root', $client->path . '/templates/' . strtolower($name));
  331. $this->parent->setPath('source', $this->parent->getPath('extension_root'));
  332. // We do findManifest to avoid problem when uninstalling a list of extensions: getManifest cache its manifest file
  333. $this->parent->findManifest();
  334. $manifest = $this->parent->getManifest();
  335. if (!($manifest instanceof JXMLElement))
  336. {
  337. // Kill the extension entry
  338. $row->delete($row->extension_id);
  339. unset($row);
  340. // Make sure we delete the folders
  341. JFolder::delete($this->parent->getPath('extension_root'));
  342. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_INVALID_NOTFOUND_MANIFEST'));
  343. return false;
  344. }
  345. // Remove files
  346. $this->parent->removeFiles($manifest->media);
  347. $this->parent->removeFiles($manifest->languages, $clientId);
  348. // Delete the template directory
  349. if (JFolder::exists($this->parent->getPath('extension_root')))
  350. {
  351. $retval = JFolder::delete($this->parent->getPath('extension_root'));
  352. }
  353. else
  354. {
  355. JError::raiseWarning(100, JText::_('JLIB_INSTALLER_ERROR_TPL_UNINSTALL_TEMPLATE_DIRECTORY'));
  356. $retval = false;
  357. }
  358. // Set menu that assigned to the template back to default template
  359. $query = 'UPDATE #__menu INNER JOIN #__template_styles' . ' ON #__template_styles.id = #__menu.template_style_id'
  360. . ' SET #__menu.template_style_id = 0' . ' WHERE #__template_styles.template = ' . $db->Quote(strtolower($name))
  361. . ' AND #__template_styles.client_id = ' . $db->Quote($clientId);
  362. $db->setQuery($query);
  363. $db->Query();
  364. $query = 'DELETE FROM #__template_styles' . ' WHERE template = ' . $db->Quote($name) . ' AND client_id = ' . $db->Quote($clientId);
  365. $db->setQuery($query);
  366. $db->Query();
  367. $row->delete($row->extension_id);
  368. unset($row);
  369. return $retval;
  370. }
  371. /**
  372. * Discover existing but uninstalled templates
  373. *
  374. * @return array JExtensionTable list
  375. */
  376. public function discover()
  377. {
  378. $results = array();
  379. $site_list = JFolder::folders(JPATH_SITE . '/templates');
  380. $admin_list = JFolder::folders(JPATH_ADMINISTRATOR . '/templates');
  381. $site_info = JApplicationHelper::getClientInfo('site', true);
  382. $admin_info = JApplicationHelper::getClientInfo('administrator', true);
  383. foreach ($site_list as $template)
  384. {
  385. if ($template == 'system')
  386. {
  387. continue;
  388. // Ignore special system template
  389. }
  390. $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_SITE . "/templates/$template/templateDetails.xml");
  391. $extension = JTable::getInstance('extension');
  392. $extension->set('type', 'template');
  393. $extension->set('client_id', $site_info->id);
  394. $extension->set('element', $template);
  395. $extension->set('name', $template);
  396. $extension->set('state', -1);
  397. $extension->set('manifest_cache', json_encode($manifest_details));
  398. $results[] = $extension;
  399. }
  400. foreach ($admin_list as $template)
  401. {
  402. if ($template == 'system')
  403. {
  404. continue;
  405. // Ignore special system template
  406. }
  407. $manifest_details = JApplicationHelper::parseXMLInstallFile(JPATH_ADMINISTRATOR . "/templates/$template/templateDetails.xml");
  408. $extension = JTable::getInstance('extension');
  409. $extension->set('type', 'template');
  410. $extension->set('client_id', $admin_info->id);
  411. $extension->set('element', $template);
  412. $extension->set('name', $template);
  413. $extension->set('state', -1);
  414. $extension->set('manifest_cache', json_encode($manifest_details));
  415. $results[] = $extension;
  416. }
  417. return $results;
  418. }
  419. /**
  420. * Discover_install
  421. * Perform an install for a discovered extension
  422. *
  423. * @return boolean
  424. *
  425. * @since 11.1
  426. */
  427. public function discover_install()
  428. {
  429. // Templates are one of the easiest
  430. // If its not in the extensions table we just add it
  431. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  432. $manifestPath = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml';
  433. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  434. $description = (string) $this->parent->manifest->description;
  435. if ($description)
  436. {
  437. $this->parent->set('message', JText::_($description));
  438. }
  439. else
  440. {
  441. $this->parent->set('message', '');
  442. }
  443. $this->parent->setPath('manifest', $manifestPath);
  444. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  445. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  446. $this->parent->extension->state = 0;
  447. $this->parent->extension->name = $manifest_details['name'];
  448. $this->parent->extension->enabled = 1;
  449. $data = new JObject;
  450. foreach ($manifest_details as $key => $value)
  451. {
  452. $data->set($key, $value);
  453. }
  454. $this->parent->extension->params = $this->parent->getParams();
  455. if ($this->parent->extension->store())
  456. {
  457. // Insert record in #__template_styles
  458. $db = $this->parent->getDbo();
  459. $query = $db->getQuery(true);
  460. $query->insert('#__template_styles');
  461. $query->set('template=' . $db->Quote($this->parent->extension->element));
  462. $query->set('client_id=' . $db->Quote($this->parent->extension->client_id));
  463. $query->set('home=0');
  464. $query->set('title=' . $db->Quote(JText::sprintf('JLIB_INSTALLER_DEFAULT_STYLE', $this->parent->extension->name)));
  465. $query->set('params=' . $db->Quote($this->parent->extension->params));
  466. $db->setQuery($query);
  467. $db->query();
  468. return $this->parent->extension->get('extension_id');
  469. }
  470. else
  471. {
  472. JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_TPL_DISCOVER_STORE_DETAILS'));
  473. return false;
  474. }
  475. }
  476. /**
  477. * Refreshes the extension table cache
  478. *
  479. * @return boolean Result of operation, true if updated, false on failure
  480. *
  481. * @since 11.1
  482. */
  483. public function refreshManifestCache()
  484. {
  485. // Need to find to find where the XML file is since we don't store this normally.
  486. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  487. $manifestPath = $client->path . '/templates/' . $this->parent->extension->element . '/templateDetails.xml';
  488. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  489. $this->parent->setPath('manifest', $manifestPath);
  490. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  491. $this->parent->extension->manifest_cache = json_encode($manifest_details);
  492. $this->parent->extension->name = $manifest_details['name'];
  493. try
  494. {
  495. return $this->parent->extension->store();
  496. }
  497. catch (JException $e)
  498. {
  499. JError::raiseWarning(101, JText::_('JLIB_INSTALLER_ERROR_TPL_REFRESH_MANIFEST_CACHE'));
  500. return false;
  501. }
  502. }
  503. }