PEAR_Frontend_Gtk2
[ class tree: PEAR_Frontend_Gtk2 ] [ index: PEAR_Frontend_Gtk2 ] [ all elements ]

Source for file Packages.php

Documentation is available at Packages.php

  1. <?php
  2. require_once 'PEAR/Frontend/Gtk2/Package.php';
  3. require_once 'PEAR/Config.php';
  4.  
  5. /**
  6. *   This class deals with packages: local package loading,
  7. *   remote package loading and so.
  8. *
  9. *   The callback is called after everything has been finished
  10. *   with parameters (true, true) to signal that it's done.
  11. *
  12. *   @author Christian Weiske <cweiske@php.net>
  13. */
  14. class PEAR_Frontend_Gtk2_Packages
  15. {
  16.     /**
  17.     *   The currently active channel name
  18.     *   @var string 
  19.     */
  20.     protected $strActiveChannel = null;
  21.  
  22.     /**
  23.     *   Array of channel => package arrays
  24.     *   @var array 
  25.     */
  26.     protected $arPackages = null;
  27.  
  28.     /**
  29.     *   Array of channel => category strings
  30.     *   @var array 
  31.     */
  32.     protected $arCategories = null;
  33.  
  34.     public static $EXCEPTION_NO_REST = 451;
  35.  
  36.  
  37.  
  38.     public function __construct($strActiveChannel = null)
  39.     {
  40.         $this->setActiveChannel($strActiveChannel);
  41.     }//public function __construct($strActiveChannel = null)
  42.  
  43.  
  44.  
  45.     public function setActiveChannel($strActiveChannel)
  46.     {
  47.         $this->strActiveChannel $strActiveChannel;
  48.     }//public function setActiveChannel($strActiveChannel)
  49.  
  50.  
  51.  
  52.     public function getActiveChannel()
  53.     {
  54.         return $this->strActiveChannel;
  55.     }//public function getActiveChannel()
  56.  
  57.  
  58.  
  59.     /**
  60.     *   Returns a list with all packages, or all packages in the given category.
  61.     *   Package list is cached, so that it's faster after the first call.
  62.     *
  63.     *   @param string   $strCategory    If given, the list is filtered by category name
  64.     *   @param callback $callback       The function to call before a package information is downloaded
  65.     *   @param booleab  $bWorkOffline   If the user wants to work offline (don't connect to the internet)
  66.     *
  67.     *   @return array   Array of PEAR_Frontend_Gtk2_Package's
  68.     */
  69.     public function getPackages($strCategory = null$callback = null$bWorkOffline = false)
  70.     {
  71.         if (!$this->packagesLoaded()) {
  72.             $this->arPackages[$this->strActiveChannel= PEAR_Frontend_Gtk2_Packages::getAllPackages($this->strActiveChannel$callback$bWorkOffline);
  73.         }
  74.         if ($strCategory === null{
  75.             return $this->arPackages[$this->strActiveChannel];
  76.         }
  77.  
  78.         $arSelectedPackages = array();
  79.         foreach ($this->arPackages[$this->strActiveChannelas $strName => $package{
  80.             if ($package->getCategory(== $strCategory{
  81.                 $arSelectedPackages[$strName$package;
  82.             }
  83.         }
  84.         return $arSelectedPackages;
  85.     }//public function getPackages($strCategory = null, $callback = null, $bWorkOffline = false)
  86.  
  87.  
  88.  
  89.     /**
  90.     *   Gets an array of packages for the active channel
  91.     *   (local and remote packages)
  92.     *
  93.     *   @param string   $strChannel     Channel to get packages for
  94.     *   @param callback $callback       The callback to call for each single remote package
  95.     *   @param boolean  $bWorkOffline   If the users wants to work offline
  96.     *
  97.     *   @return array   Array of Packages
  98.     */
  99.     public static function getAllPackages($strChannel$callback = null$bWorkOffline = false)
  100.     {
  101.         return PEAR_Frontend_Gtk2_Packages::getRemotePackages(
  102.                     $strChannel,
  103.                     true,
  104.                     $callback,
  105.                     PEAR_Frontend_Gtk2_Packages::getLocalPackages($strChannel),
  106.                     $bWorkOffline
  107.                 );
  108.     }//public static function getAllPackages($strChannel, $callback = null, $bWorkOffline = false)
  109.  
  110.  
  111.  
  112.     /**
  113.     *   Loads the locally installed packages of the given
  114.     *   channel
  115.     *
  116.     *   @param  string  $strChannel         The channel name
  117.     *   @param  array   $arLocalPackages    Array with already existing local packages. If set, package info will be incorporated.
  118.     *   @return array   Array of locally installed packages
  119.     *   @static
  120.     */
  121.     public static function getLocalPackages($strChannel$arLocalPackages = array())
  122.     {
  123.         $config        = PEAR_Config::singleton();
  124.         $arRawPackages $config->getRegistry()->packageInfo(nullnull$strChannel);
  125.         $arExisting    is_null($arLocalPackages? array(array_keys($arLocalPackages);
  126.         $arFound       = array();
  127.  
  128.         foreach ($arRawPackages as $strPackageId => $dontuseit{
  129.             if (isset($arRawPackages[$strPackageId]['name'])) {
  130.                 $strPackageName $arRawPackages[$strPackageId]['name'];
  131.             else {
  132.                 $strPackageName $arRawPackages[$strPackageId]['package'];
  133.             }
  134.             if (!isset($arLocalPackages[$strPackageName])) {
  135.                 $arLocalPackages[$strPackageName= new PEAR_Frontend_Gtk2_Package($strPackageName$strChannel);
  136.                 $arLocalPackages[$strPackageName]->setCategory(PEAR_Frontend_Gtk2_Package::guessCategory($strPackageName));
  137.             }
  138.             $arLocalPackages[$strPackageName]->incorporateLocalInfo($arRawPackages[$strPackageId]);
  139.             $arFound[$strPackageName= true;
  140.         }
  141.  
  142.         foreach ($arExisting as $strId => $strPackageName{
  143.             if (isset($arFound[$strPackageName])) {
  144.                 unset($arExisting[$strId]);
  145.             }
  146.         }
  147.  
  148.         //The ones still in here aren't installed locally any more
  149.         foreach ($arExisting as $strPackageName{
  150.             $arLocalPackages[$strPackageName]->setInstalledVersion(null);
  151.         }
  152.  
  153.         return $arLocalPackages;
  154.     }//public static function getLocalPackages($strChannel, $arLocalPackages = array())
  155.  
  156.  
  157.  
  158.     /**
  159.     *   Loads the remotely available packages for the given channel
  160.     *
  161.     *   @param string   $strChannel         The channel name
  162.     *   @param boolean  $bLoadPackageData   If all the package data shall be loaded, not only the names
  163.     *   @param callback $callback           The callback to call after a package info has been loaded
  164.     *   @param array    $arExistingPackages Array with local packages already loaded
  165.     *   @param boolean  $bWorkOffline       If we should use the local cache if possible
  166.     *
  167.     *   @return array   Array of remotely available packages (PEAR_Frontend_Gtk2_Package)
  168.     *   @throws Exception If the channel has no REST support or if the connection failed
  169.     *   @static
  170.     */
  171.     public static function getRemotePackages($strChannel$bLoadPackageData = true$callback = null$arExistingPackages = array()$bWorkOffline = false)
  172.     {
  173.         $config     = PEAR_Config::singleton();
  174.         $channel    $config->getRegistry()->getChannel($strChannel);
  175.         if ($channel === false{
  176.             throw new Exception('Channel "' $strChannel '" doesn\'t exist');
  177.         }
  178.         $strBaseUrl $channel->getBaseURL('REST1.0');
  179.         $strServer  $channel->getServer();
  180.         $rest       $config->getREST('1.0');
  181.  
  182.         if ($channel->supportsREST($strServer&& $strBaseUrl{
  183.             $arXmlPackages = PEAR_Frontend_Gtk2_Packages::listPackages($strChannel$bWorkOffline);
  184.             if (PEAR::isError($arXmlPackages)) {
  185.                 throw new Exception(
  186.                     'Error listing packages on channel ' $strChannel ":\r\n"
  187.                         . $arXmlPackages->getMessage(),
  188.                     $arXmlPackages->getCode()
  189.                 );
  190.             }
  191.         else {
  192.             throw new Exception($strChannel ' has no REST support'PEAR_Frontend_Gtk2_Packages::$EXCEPTION_NO_REST);
  193.         }
  194.  
  195.         if (count($arXmlPackages== 0
  196.             || (count($arXmlPackages== 1 && $arXmlPackages[0=== null)
  197.         {
  198.             //No packages...
  199.             return $arExistingPackages;
  200.         }
  201.  
  202.         foreach ($arXmlPackages as $id => $strName{
  203.             if (!isset($arExistingPackages[$strName])) {
  204.                 $arExistingPackages[$strName= new PEAR_Frontend_Gtk2_Package($strName$strChannel);
  205.             }
  206.         }
  207.  
  208.         if ($bLoadPackageData === false{
  209.             return $arExistingPackages;
  210.         else {
  211.             return PEAR_Frontend_Gtk2_Packages::loadRemotePackageData($arExistingPackages$strChannel$callback$bWorkOffline);
  212.         }
  213.     }//public static function getRemotePackages($strChannel, $bLoadPackageData = true, $callback = null, $arExistingPackages = array(), $bWorkOffline = false)
  214.  
  215.  
  216.  
  217.     /**
  218.     *   Copy of the PEAR_REST#listPackages function with the change
  219.     *   that this one is able to get the list from the local cache.
  220.     *
  221.     *   @param string   $strChannel     The channel which packages shall be listed
  222.     *   @param boolean  $bWorkOffline   If false, the local cache is used - if true, the online list is loaded
  223.     *
  224.     *   @return mixed   PEAR_Error or array (package list)
  225.     */
  226.     public static function listPackages($strChannel$bWorkOffline = false)
  227.     {
  228.         $config     = PEAR_Config::singleton();
  229.         $channel    $config->getRegistry()->getChannel($strChannel);
  230.         $strBaseUrl $channel->getBaseURL('REST1.0');
  231.         $strServer  $channel->getServer();
  232.         $rest       $config->getREST('1.0');
  233.  
  234.         if ($bWorkOffline{
  235.             //We can't use the retrieveCacheFirst function as it would
  236.             //try to connect if the local cache is empty
  237.             $url       $strBaseUrl 'p/packages.xml';
  238.             $cachefile $config->get('cache_dir'. DIRECTORY_SEPARATOR . md5($url'rest.cachefile';
  239.             if (@file_exists($cachefile)) {
  240.                 //local package list cache file
  241.                 $arCache unserialize(implode(''file($cachefile)));
  242.                 if (PEAR::isError($arCache)) {
  243.                     return $arCache;
  244.                 }
  245.                 if (!is_array($arCache|| !isset($arCache['p'])) {
  246.                     return array();
  247.                 }
  248.                 if (!is_array($arCache['p'])) {
  249.                     $arCache['p'= array($arCache['p']);
  250.                 }
  251.                 return $arCache['p'];
  252.  
  253.             else {
  254.                 //no local cache -> return empty package list
  255.                 return array();
  256.             }
  257.         else {
  258.             //online => list online packages
  259.             return $rest->listPackages($strBaseUrl);
  260.         }
  261.     }//public static function listPackages($strChannel, $bWorkOffline = false)
  262.  
  263.  
  264.  
  265.  
  266.     /**
  267.     *   Loads all available information for the given packages
  268.     *
  269.     *   @param array    $arRemotePackages   Array with PEAR_Frontend_Gtk2_Package-s
  270.     *   @param string   $strChannel         The channel name to retrieve packages from
  271.     *   @param callback $callback           The callback to call after a package info has been loaded
  272.     *   @param boolean  $bWorkOffline       If the local cache *only* shall be used, or (if no local cache is there)
  273.     *                                            an connection to the internet server shall be made
  274.     *   @param boolean  $bUseCache          If the cache shall be used. If not, the only chance to get package data is
  275.     *                                            reading them from the online server (if $bWorkOffline is false)
  276.     *
  277.     *   @return array   Array of packages (locally installed and remotely available) (PEAR_Frontend_Gtk2_Package)
  278.     *   @static
  279.     */
  280.     public static function loadRemotePackageData($arRemotePackages$strChannel$callback = null$bWorkOffline = false$bUseCache = true)
  281.     {
  282.         $config     = PEAR_Config::singleton();
  283.         $rest10     $config->getREST('1.0');
  284.         $rest       $rest10->_rest;//FIXME: could change in future pear versions
  285.         $channel    $config->getRegistry()->getChannel($strChannel);
  286.         $strBaseUrl $channel->getBaseURL('REST1.0');
  287.  
  288.         $nNumberPackages count($arRemotePackages);
  289.         $nCurrentPackageNumber = 0;
  290.  
  291.         foreach ($arRemotePackages as $strId => $dontuseit{
  292.             if ($callback !== null{
  293.                 call_user_func_array($callbackarray($nNumberPackages++$nCurrentPackageNumber));
  294.             }
  295.             $package $arRemotePackages[$strId];
  296.             $inf = PEAR_Frontend_Gtk2_Packages::retrieveCacheFirst(
  297.                         PEAR_Frontend_Gtk2_Packages::getInfoUrl($strBaseUrl$package->getName()),
  298.                         $config,
  299.                         $rest,
  300.                         $bWorkOffline,
  301.                         $bUseCache
  302.                     );
  303.             if (PEAR::isError($inf)) {
  304.                 if (strpos(strtolower($inf->message)'404 not found'!== false{
  305.                     //FIXME: That is a hack because the error hasn't an error code yet.
  306.                     //We continue because it's an 404 error, maybe the package isn't there yet.
  307.                     //Happens if you installed new packages which haven't been uploaded to the server yet.
  308.                     $package->setCategory($package->guessCategory($package->getName()));
  309.                     continue;
  310.                 }
  311.                 throw new Exception($inf->getMessage());
  312.             }
  313.             if (!is_array($inf|| !is_array($inf['ca'])) {
  314.                 //something went wrong retrieving the file.
  315.                 throw new Exception('Something went wrong retrieving infos about '$package->getName());
  316.             }
  317.             if ($inf['ca']['_content'!== null{
  318.                 $package->setCategory(   $inf['ca']['_content']);
  319.             }
  320.             $package->setSummary(    $inf['s']);
  321.             $package->setDescription($inf['d']);
  322.             $package->setLatestVersion(
  323.                 //FIXME: use preferred_state config option
  324.                 PEAR_Frontend_Gtk2_Packages::retrieveCacheFirst(
  325.                     PEAR_Frontend_Gtk2_Packages::getLatestVersionUrl($strBaseUrl$package->getName()),
  326.                     $config,
  327.                     $rest,
  328.                     $bWorkOffline,
  329.                     $bUseCache
  330.                 )
  331.             );
  332.         }
  333.  
  334.         if ($callback !== null{
  335.             call_user_func_array($callbackarray(truetrue));
  336.         }
  337.  
  338.         return $arRemotePackages;
  339.     }//public static function loadRemotePackageData($arRemotePackages, $strChannel, $callback = null, $bWorkOffline = false, $bUseCache = true)
  340.  
  341.  
  342.  
  343.     /**
  344.     *   Copy of the PEAR_REST#retrieveCacheFirst() function with the addition
  345.     *   that one can specify if the cache only shall be loaded, or if the cache
  346.     *   is not available, an connection shall be made.
  347.     *
  348.     *   If the user works offline, and no cache is there, NULL is returned.
  349.     *
  350.     *   @param string       $url            The URL to get the data from
  351.     *   @param PEAR_Config  $config         The PEAR configuration
  352.     *   @param PEAR_REST    $rest           The REST object which can be used to retrieve the data
  353.     *   @param boolean      $bWorkOffline   If the local cache *only* shall be used, or (if no local cache is there)
  354.     *                                            an connection to the internet server shall be made
  355.     *   @param boolean      $bUseCache      If the cache shall be used. If not, the only chance to get package data is
  356.     *                                            reading them from the online server (if $bWorkOffline is false)
  357.     */
  358.     public static function retrieveCacheFirst($url$config$rest$bWorkOffline = false$bUseCache = true)
  359.     {
  360.         if ($bUseCache{
  361.             $cachefile $config->get('cache_dir'. DIRECTORY_SEPARATOR . md5($url'rest.cachefile';
  362.             if (@file_exists($cachefile)) {
  363.                 return unserialize(implode(''file($cachefile)));
  364.             }
  365.         }
  366.         if ($bWorkOffline{
  367.             return null;
  368.         else {
  369.             return $rest->retrieveData($url);
  370.         }
  371.     }//public static function retrieveCacheFirst($url, $config, $rest, $bWorkOffline = false, $bUseCache = true)
  372.  
  373.  
  374.  
  375.  
  376.     /**
  377.     *   Path to info.xml for the specific package
  378.     */
  379.     public static function getInfoUrl($strBaseUrl$strPackageName)
  380.     {
  381.         return $strBaseUrl 'p/' strtolower($strPackageName'/info.xml';
  382.     }//public static function getInfoUrl($strBaseUrl, $strPackageName)
  383.  
  384.  
  385.  
  386.     /**
  387.     *   Path to latest.txt for the specific package
  388.     */
  389.     public static function getLatestVersionUrl($strBaseUrl$strPackageName)
  390.     {
  391.         return $strBaseUrl 'r/' strtolower($strPackageName'/latest.txt';
  392.     }//public static function getLatestVersionUrl($strBaseUrl, $strPackageName)
  393.  
  394.  
  395.  
  396.     /**
  397.     *   Creates an array of categories (strings) of the current
  398.     *   channel server
  399.     *
  400.     *   @param callback $callback       The callback to call when package information is loaded
  401.     *   @param boolean  $bWorkOffline   If the user wants to work offline (don't try to connect to the internet)
  402.     *
  403.     *   @return array   Array of category strings
  404.     */
  405.     public function getCategories($callback = null$bWorkOffline = false)
  406.     {
  407.         if (!isset($this->arCategories[$this->strActiveChannel])) {
  408.             $arPackages $this->getPackages(null$callback$bWorkOffline);
  409.  
  410.             $this->arCategories[$this->strActiveChannel= array();
  411.             if (count($arPackages> 0{
  412.                 foreach ($arPackages as $package{
  413.                     $strCategory $package->getCategory();
  414.                     $this->arCategories[$this->strActiveChannel][$strCategory$strCategory;
  415.                 }
  416.                 natcasesort($this->arCategories[$this->strActiveChannel]);
  417.             }
  418.         }
  419.  
  420.         return $this->arCategories[$this->strActiveChannel];
  421.     }//public function getCategories($callback = null)
  422.  
  423.  
  424.  
  425.     /**
  426.     *   Checks if the packages for the given channel have already been loaded
  427.     *
  428.     *   @param string $strChannel   The channel to check (active channel if null)
  429.     *   @return boolean     true if the packages already have been loaded, false if not
  430.     */
  431.     public function packagesLoaded($strChannel = null)
  432.     {
  433.         if ($strChannel === null{
  434.             $strChannel $this->strActiveChannel;
  435.         }
  436.         return (isset($this->arPackages[$strChannel]&& $this->arPackages[$strChannel!== null);
  437.     }//public function packagesLoaded($strChannel = null)
  438.  
  439.  
  440.  
  441.     /**
  442.     *   Refreshs the package list of the given channel by re-reading
  443.     *   the local package info
  444.     *
  445.     *   @param string   $strChannel     The channel to update. If NULL, the active one is used
  446.     *   @return array   Package list for the given channel
  447.     */
  448.     public function refreshLocalPackages($strChannel = null)
  449.     {
  450.         if ($strChannel === null{
  451.             $strChannel $this->strActiveChannel;
  452.         }
  453.         $this->arPackages[$strChannel= self::getLocalPackages($strChannel$this->arPackages[$strChannel]);
  454.         return $this->arPackages[$strChannel];
  455.     }//public function refreshLocalPackages($strChannel = null)
  456.  
  457.  
  458.  
  459.     /**
  460.     *   Refreshs the package list of the given channel by re-reading the remote
  461.     *   package information.
  462.     *
  463.     *   @param string   $strChannel     The channel to update. If NULL, the active one is used
  464.     *   @return array   Package list for the given channel
  465.     */
  466.     public function refreshRemotePackages($strChannel = null$callback = null)
  467.     {
  468.         if ($strChannel === null{
  469.             $strChannel $this->strActiveChannel;
  470.         }
  471.         $this->arPackages[$strChannel= self::loadRemotePackageData($this->arPackages[$strChannel]$strChannel$callbackfalsefalse);
  472.         return $this->arPackages[$strChannel];
  473.     }//public function refreshRemotePackages($strChannel = null, $callback = null)
  474.  
  475. }//class PEAR_Frontend_Gtk2_Packages
  476. ?>

Documentation generated on Mon, 11 Mar 2019 14:49:19 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.