PageRenderTime 9ms CodeModel.GetById 205ms app.highlight 111ms RepoModel.GetById 162ms app.codeStats 1ms

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

http://github.com/joomla/joomla-platform
PHP | 1823 lines | 1015 code | 295 blank | 513 comment | 170 complexity | 9f8a9524dc48564a57aac0fc51fd8bee MD5 | raw file

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

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

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