PageRenderTime 41ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/installer/adapters/language.php

https://github.com/joebushi/joomla
PHP | 506 lines | 337 code | 53 blank | 116 comment | 52 complexity | f02b3cd06ea08310691ac8779aee97bc MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. <?php
  2. /**
  3. * @version $Id$
  4. * @copyright Copyright (C) 2005 - 2010 Open Source Matters, Inc. All rights reserved.
  5. * @license GNU General Public License version 2 or later; see LICENSE.txt
  6. */
  7. // No direct access
  8. defined('JPATH_BASE') or die;
  9. jimport('joomla.base.adapterinstance');
  10. /**
  11. * Language installer
  12. *
  13. * @package Joomla.Framework
  14. * @subpackage Installer
  15. * @since 1.5
  16. */
  17. class JInstallerLanguage extends JAdapterInstance
  18. {
  19. /**
  20. * Core language pack flag
  21. * @access private
  22. * @var boolean
  23. */
  24. protected $_core = false;
  25. /**
  26. * Custom install method
  27. * Note: This behaves badly due to hacks made in the middle of 1.5.x to add
  28. * the ability to install multiple distinct packs in one install. The
  29. * preferred method is to use a package to install multiple language packs.
  30. *
  31. * @access public
  32. * @return boolean True on success
  33. * @since 1.5
  34. */
  35. public function install()
  36. {
  37. $this->manifest = $this->parent->getManifest();
  38. $root = &$manifest->document;
  39. // Get the client application target
  40. if ((string)$this->manifest->attributes()->client == 'both')
  41. {
  42. JError::raiseWarning(42, JText::_('Instr_Error_Deprecated_format'));
  43. $element = $this->manifest->site->files;
  44. if (!$this->_install('site', JPATH_SITE, 0, $element)) {
  45. return false;
  46. }
  47. $element = $this->manifest->administration->files;
  48. if (!$this->_install('administrator', JPATH_ADMINISTRATOR, 1, $element)) {
  49. return false;
  50. }
  51. // This causes an issue because we have two eid's, *sigh* nasty hacks!
  52. return true;
  53. }
  54. elseif ($cname = (string)$this->manifest->attributes()->client)
  55. {
  56. // Attempt to map the client to a base path
  57. jimport('joomla.application.helper');
  58. $client = &JApplicationHelper::getClientInfo($cname, true);
  59. if ($client === null) {
  60. $this->parent->abort(JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_Unknown_client_type', $cname)));
  61. return false;
  62. }
  63. $basePath = $client->path;
  64. $clientId = $client->id;
  65. $element = $this->manifest->files;
  66. return $this->_install($cname, $basePath, $clientId, $element);
  67. }
  68. else
  69. {
  70. // No client attribute was found so we assume the site as the client
  71. $cname = 'site';
  72. $basePath = JPATH_SITE;
  73. $clientId = 0;
  74. $element = $this->manifest->files;
  75. return $this->_install($cname, $basePath, $clientId, $element);
  76. }
  77. }
  78. /**
  79. * Install function that is designed to handle individual clients
  80. */
  81. protected function _install($cname, $basePath, $clientId, &$element)
  82. {
  83. $this->manifest = $this->parent->getManifest();
  84. // Get the language name
  85. // Set the extensions name
  86. $name = JFilterInput::getInstance()->clean((string)$this->manifest->name, 'cmd');
  87. $this->set('name', $name);
  88. // Get the Language tag [ISO tag, eg. en-GB]
  89. $tag = (string)$this->manifest->tag;
  90. // Check if we found the tag - if we didn't, we may be trying to install from an older language package
  91. if ( ! $tag)
  92. {
  93. $this->parent->abort(JText::sprintf('Instr_Abort', JText::_('Instr_Error_No_Language_Tag')));
  94. return false;
  95. }
  96. $this->set('tag', $tag);
  97. // Set the language installation path
  98. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.$tag);
  99. // Do we have a meta file in the file list? In other words... is this a core language pack?
  100. if ($element INSTANCEOF JXMLElement && count($element->children()))
  101. {
  102. $files = $element->children();
  103. foreach ($files as $file) {
  104. if ((string)$file->attributes()->file == 'meta') {
  105. $this->_core = true;
  106. break;
  107. }
  108. }
  109. }
  110. // Either we are installing a core pack or a core pack must exist for the language we are installing.
  111. if (!$this->_core)
  112. {
  113. if (!JFile::exists($this->parent->getPath('extension_site').DS.$this->get('tag').'.xml')) {
  114. $this->parent->abort(JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_No_core_language', $this->get('tag'))));
  115. return false;
  116. }
  117. }
  118. // If the language directory does not exist, lets create it
  119. $created = false;
  120. if (!file_exists($this->parent->getPath('extension_site')))
  121. {
  122. if (!$created = JFolder::create($this->parent->getPath('extension_site')))
  123. {
  124. $this->parent->abort(JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_Create_folder_failed', $this->parent->getPath('extension_site'))));
  125. return false;
  126. }
  127. }
  128. else
  129. {
  130. // look for an update function or update tag
  131. $updateElement = $this->manifest->update;
  132. // upgrade manually set
  133. // update function available
  134. // update tag detected
  135. if ($this->parent->getUpgrade() || ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'update')) || is_a($updateElement, 'JXMLElement')) {
  136. return $this->update(); // transfer control to the update function
  137. }
  138. else if (!$this->parent->getOverwrite())
  139. {
  140. // overwrite is set
  141. // we didn't have overwrite set, find an update function or find an update tag so lets call it safe
  142. if (file_exists($this->parent->getPath('extension_site'))) { // if the site exists say that
  143. JError::raiseWarning(1, JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_Folder_in_use', $this->parent->getPath('extension_site'))));
  144. }
  145. else { // if the admin exists say that
  146. JError::raiseWarning(1, JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_Folder_in_use', $this->parent->getPath('extension_administrator'))));
  147. }
  148. return false;
  149. }
  150. }
  151. /*
  152. * If we created the language directory and will want to remove it if we
  153. * have to roll back the installation, lets add it to the installation
  154. * step stack
  155. */
  156. if ($created) {
  157. $this->parent->pushStep(array ('type' => 'folder', 'path' => $this->parent->getPath('extension_site')));
  158. }
  159. // Copy all the necessary files
  160. if ($this->parent->parseFiles($element) === false)
  161. {
  162. // Install failed, rollback changes
  163. $this->parent->abort();
  164. return false;
  165. }
  166. // Copy all the necessary font files to the common pdf_fonts directory
  167. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.'pdf_fonts');
  168. $overwrite = $this->parent->setOverwrite(true);
  169. if ($this->parent->parseFiles($this->manifest->fonts) === false)
  170. {
  171. // Install failed, rollback changes
  172. $this->parent->abort();
  173. return false;
  174. }
  175. $this->parent->setOverwrite($overwrite);
  176. // Get the language description
  177. $description = (string)$this->manifest->description;
  178. if ($description) {
  179. $this->parent->set('message', JText::_($description));
  180. }
  181. else {
  182. $this->parent->set('message', '');
  183. }
  184. // Add an entry to the extension table with a whole heap of defaults
  185. $row = & JTable::getInstance('extension');
  186. $row->set('name', $this->get('name'));
  187. $row->set('type', 'language');
  188. $row->set('element', $this->get('tag'));
  189. $row->set('folder', ''); // There is no folder for languages
  190. $row->set('enabled', 1);
  191. $row->set('protected', 0);
  192. $row->set('access', 0);
  193. $row->set('client_id', $clientId);
  194. $row->set('params', $this->parent->getParams());
  195. $row->set('manifest_cache', $this->parent->generateManifestCache());
  196. if (!$row->store())
  197. {
  198. // Install failed, roll back changes
  199. $this->parent->abort(JText::sprintf('Instr_Abort', $db->getErrorMsg()));
  200. return false;
  201. }
  202. // Clobber any possible pending updates
  203. $update = &JTable::getInstance('update');
  204. $uid = $update->find(Array('element'=>$this->get('tag'),
  205. 'type'=>'language',
  206. 'client_id'=>'',
  207. 'folder'=>''));
  208. if ($uid) {
  209. $update->delete($uid);
  210. }
  211. return $row->get('extension_id');
  212. }
  213. /**
  214. * Custom update method
  215. *
  216. * @return boolean True on success, false on failure
  217. * @since 1.6
  218. */
  219. public function update()
  220. {
  221. $xml = &$this->parent->getManifest();
  222. $this->manifest = $xml;
  223. $cname = $xml->attributes()->client;
  224. // Attempt to map the client to a base path
  225. jimport('joomla.application.helper');
  226. $client = &JApplicationHelper::getClientInfo($cname, true);
  227. if ($client === null || (empty($cname) && $cname !== 0))
  228. {
  229. $this->parent->abort(JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_Unknown_client_type', $cname)));
  230. return false;
  231. }
  232. $basePath = $client->path;
  233. $clientId = $client->id;
  234. // Get the language name
  235. // Set the extensions name
  236. $name = (string)$this->manifest->name;
  237. $name = JFilterInput::getInstance()->clean($name, 'cmd');
  238. $this->set('name', $name);
  239. // Get the Language tag [ISO tag, eg. en-GB]
  240. $tag = (string)$xml->tag;
  241. // Check if we found the tag - if we didn't, we may be trying to install from an older language package
  242. if (!$tag)
  243. {
  244. $this->parent->abort(JText::sprintf('Instr_Abort', JText::_('Instr_Error_No_Language_Tag')));
  245. return false;
  246. }
  247. $this->set('tag', $tag);
  248. $folder = $tag;
  249. // Set the language installation path
  250. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.$this->get('tag'));
  251. // Do we have a meta file in the file list? In other words... is this a core language pack?
  252. if (count($xml->files->children()))
  253. {
  254. foreach ($xml->files->children() as $file)
  255. {
  256. if ((string)$file->attributes()->file == 'meta')
  257. {
  258. $this->_core = true;
  259. break;
  260. }
  261. }
  262. }
  263. // Either we are installing a core pack or a core pack must exist for the language we are installing.
  264. if (!$this->_core)
  265. {
  266. if (!JFile::exists($this->parent->getPath('extension_site').DS.$this->get('tag').'.xml'))
  267. {
  268. $this->parent->abort(JText::sprintf('Instr_Abort', JText::sprintf('Instr_Error_No_core_language', $this->get('tag'))));
  269. return false;
  270. }
  271. }
  272. // Copy all the necessary files
  273. if ($this->parent->parseFiles($element) === false)
  274. {
  275. // Install failed, rollback changes
  276. $this->parent->abort();
  277. return false;
  278. }
  279. // Copy all the necessary font files to the common pdf_fonts directory
  280. $this->parent->setPath('extension_site', $basePath.DS.'language'.DS.'pdf_fonts');
  281. $overwrite = $this->parent->setOverwrite(true);
  282. if ($this->parent->parseFiles($xml->fonts) === false)
  283. {
  284. // Install failed, rollback changes
  285. $this->parent->abort();
  286. return false;
  287. }
  288. $this->parent->setOverwrite($overwrite);
  289. // Get the language description and set it as message
  290. $this->parent->set('message', (string)$xml->description);
  291. /**
  292. * ---------------------------------------------------------------------------------------------
  293. * Finalization and Cleanup Section
  294. * ---------------------------------------------------------------------------------------------
  295. */
  296. // Clobber any possible pending updates
  297. $update = &JTable::getInstance('update');
  298. $uid = $update->find(Array('element'=>$this->get('tag'),
  299. 'type'=>'language',
  300. 'client_id'=>$clientId));
  301. if ($uid)
  302. {
  303. $update->delete($uid);
  304. }
  305. // Update an entry to the extension table
  306. $row = & JTable::getInstance('extension');
  307. $eid = $row->find(Array('element'=>strtolower($this->get('tag')),
  308. 'type'=>'language'));
  309. if ($eid) {
  310. $row->load($eid);
  311. }
  312. else
  313. {
  314. // set the defaults
  315. $row->set('folder', ''); // There is no folder for language
  316. $row->set('enabled', 1);
  317. $row->set('protected', 0);
  318. $row->set('access', 0);
  319. $row->set('client_id', $clientId);
  320. $row->set('params', $this->parent->getParams());
  321. }
  322. $row->set('name', $this->get('name'));
  323. $row->set('type', 'language');
  324. $row->set('element', $this->get('tag'));
  325. $row->set('manifest_cache', $this->parent->generateManifestCache());
  326. if (!$row->store())
  327. {
  328. // Install failed, roll back changes
  329. $this->parent->abort(JText::sprintf('Instr_Abort', $db->getErrorMsg()));
  330. return false;
  331. }
  332. // And now we run the postflight
  333. ob_start();
  334. ob_implicit_flush(false);
  335. if ($this->parent->manifestClass && method_exists($this->parent->manifestClass,'postflight'))
  336. {
  337. $this->parent->manifestClass->postflight('update', $this);
  338. }
  339. $msg .= ob_get_contents(); // append messages
  340. ob_end_clean();
  341. if ($msg != '') {
  342. $this->parent->set('extension_message', $msg);
  343. }
  344. return $row->get('extension_id');
  345. }
  346. /**
  347. * Custom uninstall method
  348. *
  349. * @param string $tag The tag of the language to uninstall
  350. * @param int $clientId The id of the client (unused)
  351. * @return mixed Return value for uninstall method in component uninstall file
  352. * @since 1.5
  353. */
  354. public function uninstall($eid)
  355. {
  356. // load up the extension details
  357. $extension = JTable::getInstance('extension');
  358. $extension->load($eid);
  359. // check the element isn't blank to prevent nuking the languages directory...just in case
  360. $element = $extension->get('element');
  361. if (empty($element))
  362. {
  363. JError::raiseWarning(100, JText::_('Language').' '.JText::_('Uninstall').': '.JText::_('Element is empty, cannot uninstall files'));
  364. return false;
  365. }
  366. // grab a copy of the client details
  367. $client = JApplicationHelper::getClientInfo($extension->get('client_id'));
  368. // construct the path from the client, the language and the extension element name
  369. $path = $client->path.DS.'language'.DS.$element;
  370. // check it exists
  371. if (!JFolder::exists($path))
  372. {
  373. JError::raiseWarning(100, JText::_('Language').' '.JText::_('Uninstall').': '.JText::_('Language path is empty, cannot uninstall files'));
  374. return false;
  375. }
  376. if (!JFolder::delete($path))
  377. {
  378. JError::raiseWarning(100, JText::_('Language').' '.JText::_('Uninstall').': '.JText::_('UNABLE_TO_REMOVE_LANGUAGE_DIRECTORY'));
  379. return false;
  380. }
  381. // Remove the extension table entry
  382. $extension->delete();
  383. // All done!
  384. return true;
  385. }
  386. /**
  387. * Custom discover method
  388. * Finds language files
  389. */
  390. public function discover()
  391. {
  392. $results = Array();
  393. $site_languages = JFolder::folders(JPATH_SITE.DS.'language');
  394. $admin_languages = JFolder::folders(JPATH_ADMINISTRATOR.DS.'language');
  395. foreach ($site_languages as $language)
  396. {
  397. if (file_exists(JPATH_SITE.DS.'language'.DS.$language.DS.$language.'.xml'))
  398. {
  399. $extension = &JTable::getInstance('extension');
  400. $extension->set('type', 'language');
  401. $extension->set('client_id', 0);
  402. $extension->set('element', $language);
  403. $extension->set('name', $language);
  404. $extension->set('state', -1);
  405. $results[] = $extension;
  406. }
  407. }
  408. foreach ($admin_languages as $language)
  409. {
  410. if (file_exists(JPATH_ADMINISTRATOR.DS.'language'.DS.$language.DS.$language.'.xml'))
  411. {
  412. $extension = &JTable::getInstance('extension');
  413. $extension->set('type', 'language');
  414. $extension->set('client_id', 1);
  415. $extension->set('element', $language);
  416. $extension->set('name', $language);
  417. $extension->set('state', -1);
  418. $results[] = $extension;
  419. }
  420. }
  421. return $results;
  422. }
  423. /**
  424. * Custom discover install method
  425. * Basically updates the manifest cache and leaves everything alone
  426. */
  427. function discover_install()
  428. {
  429. // Need to find to find where the XML file is since we don't store this normally
  430. $client = JApplicationHelper::getClientInfo($this->parent->extension->client_id);
  431. $short_element = $this->parent->extension->element;
  432. $manifestPath = $client->path . DS . 'language'. DS . $short_element . DS . $short_element . '.xml';
  433. $this->parent->manifest = $this->parent->isManifest($manifestPath);
  434. $this->parent->setPath('manifest', $manifestPath);
  435. $this->parent->setPath('source', $client->path . DS . 'language'. DS . $short_element);
  436. $this->parent->setPath('extension_root', $this->parent->getPath('source'));
  437. $manifest_details = JApplicationHelper::parseXMLInstallFile($this->parent->getPath('manifest'));
  438. $this->parent->extension->manifest_cache = serialize($manifest_details);
  439. $this->parent->extension->state = 0;
  440. $this->parent->extension->name = $manifest_details['name'];
  441. $this->parent->extension->enabled = 1;
  442. //$this->parent->extension->params = $this->parent->getParams();
  443. try {
  444. $this->parent->extension->store();
  445. }
  446. catch(JException $e)
  447. {
  448. JError::raiseWarning(101, JText::_('Language').' '.JText::_('Discover Install').': '.JText::_('Failed to store extension details'));
  449. return false;
  450. }
  451. return $this->parent->extension->get('extension_id');
  452. }
  453. }