Source for file component.php

Documentation is available at component.php

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

Documentation generated on Tue, 19 Nov 2013 14:56:23 +0100 by phpDocumentor 1.4.3