Source code for file /joomla/installer/adapters/component.php
Documentation is available at component.php
* @version $Id: component.php 6138 2007-01-02 03:44:18Z eddiea $
* @package Joomla.Framework
* @copyright Copyright (C) 2005 - 2007 Open Source Matters. All rights reserved.
* @license GNU/GPL, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant
* to the GNU General Public License, and as distributed it includes or
* is derivative of works licensed under the GNU General Public License or
* other free or open source software licenses.
* See COPYRIGHT.php for copyright notices and details.
// Check to ensure this file is within the rest of the framework
* @package Joomla.Framework
* @param object $parent Parent object [JInstaller instance]
$this->parent =
& $parent;
* Custom install method for components
* @return boolean True on success
// Get a database connector object
$db =
& $this->parent->getDBO();
// Get the extension manifest object
$manifest =
& $this->parent->getManifest();
$this->manifest =
& $manifest->document;
* ---------------------------------------------------------------------------------------------
* Manifest Document Setup Section
* ---------------------------------------------------------------------------------------------
// Set the component name
$name =
& $this->manifest->getElementByPath('name');
$this->set('name', $name->data());
// Get the component description
$description =
& $this->manifest->getElementByPath('description');
if (is_a($description, 'JSimpleXMLElement')) {
$this->parent->set('message', $this->get('name').
'<p>'.
$description->data().
'</p>');
$this->parent->set('message', $this->get('name'));
// Get some important manifest elements
$this->adminElement =
& $this->manifest->getElementByPath('administration');
$this->installElement =
& $this->manifest->getElementByPath('install');
$this->uninstallElement =
& $this->manifest->getElementByPath('uninstall');
// Set the installation target paths
* ---------------------------------------------------------------------------------------------
* Filesystem Processing Section
* ---------------------------------------------------------------------------------------------
* If the component site or admin directory already exists, then we will assume that the component is already
* installed or another component is using that directory.
if ((file_exists($this->parent->getPath('extension_site')) ||
file_exists($this->parent->getPath('extension_administrator'))) &&
!$this->parent->getOverwrite()) {
JError::raiseWarning(1, 'Component Install: '.
JText::_('Another component is already using directory').
': "'.
$this->parent->getPath('extension_site').
'"');
// If the component directory does not exist, lets create it
if (!file_exists($this->parent->getPath('extension_site'))) {
if (!$created =
JFolder::create($this->parent->getPath('extension_site'))) {
JError::raiseWarning(1, 'Component Install: '.
JText::_('Failed to create directory').
': "'.
$this->parent->getPath('extension_site').
'"');
* Since we created the component directory and will want to remove it if we have to roll back
* the installation, lets add it to the installation step stack
$this->parent->pushStep(array ('type' =>
'folder', 'path' =>
$this->parent->getPath('extension_site')));
// If the component admin directory does not exist, lets create it
if (!file_exists($this->parent->getPath('extension_administrator'))) {
if (!$created =
JFolder::create($this->parent->getPath('extension_administrator'))) {
JError::raiseWarning(1, 'Component Install: '.
JText::_('Failed to create directory').
': "'.
$this->parent->getPath('extension_administrator').
'"');
// Install failed, rollback any changes
* Since we created the component admin directory and we will want to remove it if we have to roll
* back the installation, lets add it to the installation step stack
$this->parent->pushStep(array ('type' =>
'folder', 'path' =>
$this->parent->getPath('extension_administrator')));
foreach ($this->manifest->children() as $child)
if (is_a($child, 'JSimpleXMLElement') &&
$child->name() ==
'files') {
if ($this->parent->parseFiles($child) ===
false) {
// Install failed, rollback any changes
foreach ($this->adminElement->children() as $child)
if (is_a($child, 'JSimpleXMLElement') &&
$child->name() ==
'files') {
if ($this->parent->parseFiles($child, 1) ===
false) {
// Install failed, rollback any changes
$this->parent->parseMedia($this->manifest->getElementByPath('media'));
$this->parent->parseMedia($this->manifest->getElementByPath('administration/media'), 1);
$this->parent->parseLanguages($this->manifest->getElementByPath('languages'));
$this->parent->parseLanguages($this->manifest->getElementByPath('administration/languages'), 1);
$this->parent->parseFiles($this->manifest->getElementByPath('images'));
$this->parent->parseFiles($this->manifest->getElementByPath('administration/images'), 1);
// If there is an install file, lets copy it.
$installScriptElement =
& $this->manifest->getElementByPath('installfile');
if (is_a($installScriptElement, 'JSimpleXMLElement')) {
// Make sure it hasn't already been copied (this would be an error in the xml install file)
if (!file_exists($this->parent->getPath('extension_administrator').
DS.
$installScriptElement->data()))
$path['src'] =
$this->parent->getPath('source').
DS.
$installScriptElement->data();
$path['dest'] =
$this->parent->getPath('extension_administrator').
DS.
$installScriptElement->data();
if (!$this->parent->copyFiles(array ($path))) {
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
JText::_('Could not copy PHP install file.'));
$this->set('install.script', $installScriptElement->data());
// If there is an uninstall file, lets copy it.
$uninstallScriptElement =
& $this->manifest->getElementByPath('uninstallfile');
if (is_a($uninstallScriptElement, 'JSimpleXMLElement')) {
// Make sure it hasn't already been copied (this would be an error in the xml install file)
if (!file_exists($this->parent->getPath('extension_administrator').
DS.
$uninstallScriptElement->data()))
$path['src'] =
$this->parent->getPath('source').
DS.
$uninstallScriptElement->data();
$path['dest'] =
$this->parent->getPath('extension_administrator').
DS.
$uninstallScriptElement->data();
if (!$this->parent->copyFiles(array ($path))) {
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
JText::_('Could not copy PHP uninstall file.'));
* ---------------------------------------------------------------------------------------------
* Database Processing Section
* ---------------------------------------------------------------------------------------------
* Let's run the install queries for the component
* If backward compatibility is required - run queries in xml file
* If Joomla 1.5 compatible, with discreet sql files - execute appropriate
* file for utf-8 support or non-utf-8 support
$result =
$this->parent->parseQueries($this->manifest->getElementByPath('install/queries'));
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
JText::_('SQL Error').
" ".
$db->stderr(true));
} elseif ($result ===
0) {
// no backward compatibility queries found - try for Joomla 1.5 type queries
// second argument is the utf compatible version attribute
$utfresult =
$this->parent->parseSQLFiles($this->manifest->getElementByPath('install/sql'));
if ($utfresult ===
false) {
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
JText::_('SQLERRORORFILE').
" ".
$db->stderr(true));
// Time to build the admin menus
$this->_buildAdminMenus();
* ---------------------------------------------------------------------------------------------
* Custom Installation Script Section
* ---------------------------------------------------------------------------------------------
* If we have an install script, lets include it, execute the custom
* install method, and append the return value from the custom install
* method to the installation message.
if ($this->get('install.script')) {
if (is_file($this->parent->getPath('extension_administrator').
DS.
$this->get('install.script'))) {
require_once ($this->parent->getPath('extension_administrator').
DS.
$this->get('install.script'));
if (com_install() ===
false) {
$this->parent->abort('Component Install: '.
JText::_('Custom install routine failure'));
$this->parent ->set('extension.message', $msg);
* ---------------------------------------------------------------------------------------------
* Finalization and Cleanup Section
* ---------------------------------------------------------------------------------------------
// Lastly, we will copy the manifest file to its appropriate place.
if (!$this->parent->copyManifest()) {
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
JText::_('Could not copy setup file'));
* Custom uninstall method for components
* @param int $cid The id of the component to uninstall
* @param int $clientId The id of the client (unused)
* @return mixed Return value for uninstall method in component uninstall file
$db =
& $this->parent->getDBO();
// First order of business will be to load the component object table from the database.
// This should give us the necessary information to proceed.
// Is the component we are trying to uninstall a core one?
// Because that is not a good idea...
// Get the admin and site paths for the component
$this->parent->setPath('extension_administrator', JPath::clean(JPATH_ADMINISTRATOR.
DS.
'components'.
DS.
$row->option));
$this->parent->setPath('extension_site', JPath::clean(JPATH_SITE.
DS.
'components'.
DS.
$row->option));
* ---------------------------------------------------------------------------------------------
* Manifest Document Setup Section
* ---------------------------------------------------------------------------------------------
// Find and load the XML install file for the component
$this->parent->setPath('source', $this->parent->getPath('extension_administrator'));
// Get the package manifest objecct
$manifest =
& $this->parent->getManifest();
if (!is_a($manifest, 'JSimpleXML')) {
// Make sure we delete the folders if no manifest exists
JFolder::delete($this->parent->getPath('extension_administrator'));
JError::raiseWarning(100, 'Component Uninstall: Package manifest file invalid or not found');
// Get the root node of the manifest document
$this->manifest =
& $manifest->document;
* ---------------------------------------------------------------------------------------------
* Custom Uninstallation Script Section
* ---------------------------------------------------------------------------------------------
// Now lets load the uninstall file if there is one and execute the uninstall function if it exists.
$uninstallfileElement =
& $this->manifest->getElementByPath('uninstallfile');
if (is_a($uninstallfileElement, 'JSimpleXMLElement')) {
// Element exists, does the file exist?
if (is_file($this->parent->getPath('extension_administrator').
DS.
$uninstallfileElement->data())) {
require_once ($this->parent->getPath('extension_administrator').
DS.
$uninstallfileElement->data());
if (com_uninstall() ===
false) {
$this->parent->set('extension.message', $msg);
* ---------------------------------------------------------------------------------------------
* Database Processing Section
* ---------------------------------------------------------------------------------------------
* Let's run the uninstall queries for the component
* If backward compatibility is required - run queries in xml file
* If Joomla 1.5 compatible, with discreet sql files - execute appropriate
* file for utf-8 support or non-utf support
$result =
$this->parent->parseQueries($this->manifest->getElementByPath('uninstall/queries'));
// Install failed, rollback changes
} elseif ($result ===
0) {
// no backward compatibility queries found - try for Joomla 1.5 type queries
// second argument is the utf compatible version attribute
$utfresult =
$this->parent->parseSQLFiles($this->manifest->getElementByPath('uninstall/sql'));
if ($utfresult ===
false) {
// Install failed, rollback changes
$this->_removeAdminMenus($row);
* ---------------------------------------------------------------------------------------------
* Filesystem Processing Section
* ---------------------------------------------------------------------------------------------
// Let's remove language files and media in the JROOT/images/ folder that are
// associated with the component we are uninstalling
$this->parent->removeFiles($this->manifest->getElementByPath('media'));
$this->parent->removeFiles($this->manifest->getElementByPath('media'), 1);
$this->parent->removeFiles($this->manifest->getElementByPath('languages'));
$this->parent->removeFiles($this->manifest->getElementByPath('administration/languages'), 1);
// Now we need to delete the installation directories. This is the final step in uninstalling the component.
if (trim($row->option)) {
// Delete the component site directory
if (is_dir($this->parent->getPath('extension_site'))) {
if (!JFolder::delete($this->parent->getPath('extension_site'))) {
// Delete the component admin directory
if (is_dir($this->parent->getPath('extension_administrator'))) {
if (!JFolder::delete($this->parent->getPath('extension_administrator'))) {
// No component option defined... cannot delete what we don't know about
JError::raiseWarning(100, 'Component Uninstall: Option field empty, cannot remove files');
* Method to build menu database entries for a component
* @return boolean True if successful
function _buildAdminMenus()
// Get database connector object
$db =
& $this->parent->getDBO();
// If a component exists with this option in the table than we don't need to add menus
' WHERE `option` = '.
$db->Quote($option);
$exists =
$db->loadResult();
// Check if menu items exist
// Don't do anything if overwrite has not been enabled
if ( ! $this->parent->getOverwrite() ) {
// Remove existing menu items if overwrite has been enabled
$sql =
'DELETE FROM #__components WHERE `option` = '.
$db->Quote($option);
// Ok, now its time to handle the menus. Start with the component root menu, then handle submenus.
$menuElement =
& $this->adminElement->getElementByPath('menu');
if (is_a($menuElement, 'JSimpleXMLElement')) {
$db_name =
$menuElement->data();
$db_link =
"option=".
$option;
$db_admin_menu_link =
"option=".
$option;
$db_admin_menu_alt =
$menuElement->data();
$db_admin_menu_img =
($menuElement->attributes('img')) ?
$menuElement->attributes('img') :
'js/ThemeOffice/component.png';
$db_params =
$this->parent->getParams();
$query =
'INSERT INTO #__components' .
' VALUES( "", "'.
$db_name.
'", "'.
$db_link.
'", '.
$db_menuid.
', '.
$db_parent.
', "'.
$db_admin_menu_link.
'", "'.
$db_admin_menu_alt.
'", "'.
$db_option.
'", '.
$db_ordering.
', "'.
$db_admin_menu_img.
'", '.
$db_iscore.
', "'.
$db_params.
'", "'.
$db_enabled.
'" )';
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
$db->stderr(true));
$menuid =
$db->insertid();
* Since we have created a menu item, we add it to the installation step stack
* so that if we have to rollback the changes we can undo it.
$this->parent->pushStep(array ('type' =>
'menu', 'id' =>
$menuid));
* No menu element was specified so lets first see if we have an admin menu entry for this component
* if we do.. then we obviously don't want to create one -- we'll just attach sub menus to that one.
' WHERE `option` = '.
$db->Quote($option) .
$menuid =
$db->loadResult();
// No menu entry, lets just enter a component entry to the table.
$db_name =
$this->get('name');
$db_admin_menu_link =
"";
$db_admin_menu_alt =
$this->get('name');
$db_params =
$this->parent->getParams();
$query =
'INSERT INTO #__components' .
' VALUES( "", "'.
$db_name.
'", "'.
$db_link.
'", '.
$db_menuid.
', '.
$db_parent.
', "'.
$db_admin_menu_link.
'", "'.
$db_admin_menu_alt.
'", "'.
$db_option.
'", '.
$db_ordering.
', "'.
$db_admin_menu_img.
'", '.
$db_iscore.
', "'.
$db_params.
'", "'.
$db_enabled.
'" )';
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
$db->stderr(true));
$menuid =
$db->insertid();
* Since we have created a menu item, we add it to the installation step stack
* so that if we have to rollback the changes we can undo it.
$this->parent->pushStep(array ('type' =>
'menu', 'id' =>
$menuid));
// Initialize submenu ordering value
$submenu =
$this->adminElement->getElementByPath('submenu');
if (!is_a($submenu, 'JSimpleXMLElement') ||
!count($submenu->children())) {
foreach ($submenu->children() as $child)
if (is_a($child, 'JSimpleXMLElement') &&
$child->name() ==
'menu') {
$com->name =
$child->data();
$com->admin_menu_alt =
$child->data();
$com->ordering =
$ordering ++
;
if ($child->attributes("link")) {
$com->admin_menu_link =
str_replace('&', '&', $child->attributes("link"));
if ($child->attributes('act')) {
$request[] =
'act='.
$child->attributes('act');
if ($child->attributes('task')) {
$request[] =
'task='.
$child->attributes('task');
if ($child->attributes('controller')) {
$request[] =
'controller='.
$child->attributes('controller');
if ($child->attributes('view')) {
$request[] =
'view='.
$child->attributes('view');
if ($child->attributes('layout')) {
$request[] =
'layout='.
$child->attributes('layout');
if ($child->attributes('sub')) {
$request[] =
'sub='.
$child->attributes('sub');
$qstring =
(count($request)) ?
'&'.
implode('&',$request) :
'';
$com->admin_menu_link =
"option=".
$option.
$qstring;
// Set the sub menu image
if ($child->attributes("img")) {
$com->admin_menu_img =
$child->attributes("img");
$com->admin_menu_img =
"js/ThemeOffice/component.png";
// Install failed, rollback changes
$this->parent->abort('Component Install: '.
JText::_('SQL Error').
" ".
$db->stderr(true));
* Since we have created a menu item, we add it to the installation step stack
* so that if we have to rollback the changes we can undo it.
$this->parent->pushStep(array ('type' =>
'menu', 'id' =>
$com->id));
* Method to remove admin menu references to a component
* @param object $component Component table object
* @return boolean True if successful
function _removeAdminMenus(&$row)
// Get database connector object
$db =
& $this->parent->getDBO();
// Delete the submenu items
'WHERE parent = '.(int)
$row->id;
// Next, we will delete the component object
if (!$row->delete($row->id)) {
* - Roll back the component menu item
* @param array $arg Installation step to rollback
* @return boolean True on success
// Get database connector object
$db =
& $this->parent->getDBO;
// Remove the entry from the #__components table
' FROM `#__components` ' .
' WHERE id='.(int)
$arg['id'];
return ($db->query() !==
false);