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