PageRenderTime 198ms CodeModel.GetById 60ms app.highlight 96ms RepoModel.GetById 25ms app.codeStats 1ms

/libraries/joomla/installer/adapters/component.php

https://bitbucket.org/pasamio/jhttprequest
PHP | 1741 lines | 958 code | 304 blank | 479 comment | 217 complexity | e40c9a9273ea01ad0f5f44f9525da811 MD5 | raw file

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

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

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