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.         if ($strChannel === null{
  124.             return array();
  125.         }
  126.  
  127.         $config        = PEAR_Config::singleton();
  128.         $arRawPackages $config->getRegistry()->packageInfo(nullnull$strChannel);
  129.         $arExisting    is_null($arLocalPackages? array(array_keys($arLocalPackages);
  130.         $arFound       = array();
  131.  
  132.         foreach ($arRawPackages as $strPackageId => $dontuseit{
  133.             if (isset($arRawPackages[$strPackageId]['name'])) {
  134.                 $strPackageName $arRawPackages[$strPackageId]['name'];
  135.             else {
  136.                 $strPackageName $arRawPackages[$strPackageId]['package'];
  137.             }
  138.             if (!isset($arLocalPackages[$strPackageName])) {
  139.                 $arLocalPackages[$strPackageName= new PEAR_Frontend_Gtk2_Package($strPackageName$strChannel);
  140.                 $arLocalPackages[$strPackageName]->setCategory(PEAR_Frontend_Gtk2_Package::guessCategory($strPackageName));
  141.             }
  142.             $arLocalPackages[$strPackageName]->incorporateLocalInfo($arRawPackages[$strPackageId]);
  143.             $arFound[$strPackageName= true;
  144.         }
  145.  
  146.         foreach ($arExisting as $strId => $strPackageName{
  147.             if (isset($arFound[$strPackageName])) {
  148.                 unset($arExisting[$strId]);
  149.             }
  150.         }
  151.  
  152.         //The ones still in here aren't installed locally any more
  153.         foreach ($arExisting as $strPackageName{
  154.             $arLocalPackages[$strPackageName]->setInstalledVersion(null);
  155.         }
  156.  
  157.         return $arLocalPackages;
  158.     }//public static function getLocalPackages($strChannel, $arLocalPackages = array())
  159.  
  160.  
  161.  
  162.     /**
  163.     *   Loads the remotely available packages for the given channel
  164.     *
  165.     *   @param string   $strChannel         The channel name
  166.     *   @param boolean  $bLoadPackageData   If all the package data shall be loaded, not only the names
  167.     *   @param callback $callback           The callback to call after a package info has been loaded
  168.     *   @param array    $arExistingPackages Array with local packages already loaded
  169.     *   @param boolean  $bWorkOffline       If we should use the local cache if possible
  170.     *
  171.     *   @return array   Array of remotely available packages (PEAR_Frontend_Gtk2_Package)
  172.     *   @throws Exception If the channel has no REST support or if the connection failed
  173.     *   @static
  174.     */
  175.     public static function getRemotePackages(
  176.         $strChannel$bLoadPackageData = true$callback = null,
  177.         $arExistingPackages = array()$bWorkOffline = false
  178.     {
  179.         $config     = PEAR_Config::singleton();
  180.         $channel    $config->getRegistry()->getChannel($strChannel);
  181.         if ($channel === false || PEAR::isError($channel)) {
  182.             throw new Exception('Channel "' $strChannel '" doesn\'t exist');
  183.         }
  184.         $strBaseUrl $channel->getBaseURL('REST1.0');
  185.         $strServer  $channel->getServer();
  186.         $rest       $config->getREST('1.0');
  187.  
  188.         if ($channel->supportsREST($strServer&& $strBaseUrl{
  189.             $arXmlPackages = PEAR_Frontend_Gtk2_Packages::listPackages($strChannel$bWorkOffline);
  190.             if (PEAR::isError($arXmlPackages)) {
  191.                 throw new Exception(
  192.                     'Error listing packages on channel ' $strChannel ":\r\n"
  193.                         . $arXmlPackages->getMessage(),
  194.                     $arXmlPackages->getCode()
  195.                 );
  196.             }
  197.         else {
  198.             throw new Exception($strChannel ' has no REST support'PEAR_Frontend_Gtk2_Packages::$EXCEPTION_NO_REST);
  199.         }
  200.  
  201.         if (count($arXmlPackages== 0
  202.             || (count($arXmlPackages== 1 && $arXmlPackages[0=== null)
  203.         {
  204.             //No packages...
  205.             return $arExistingPackages;
  206.         }
  207.  
  208.         foreach ($arXmlPackages as $id => $strName{
  209.             if (!isset($arExistingPackages[$strName])) {
  210.                 $arExistingPackages[$strName= new PEAR_Frontend_Gtk2_Package($strName$strChannel);
  211.             }
  212.         }
  213.  
  214.         if ($bLoadPackageData === false{
  215.             return $arExistingPackages;
  216.         else {
  217.             return PEAR_Frontend_Gtk2_Packages::loadRemotePackageData($arExistingPackages$strChannel$callback$bWorkOffline);
  218.         }
  219.     }//public static function getRemotePackages($strChannel, $bLoadPackageData = true, $callback = null, $arExistingPackages = array(), $bWorkOffline = false)
  220.  
  221.  
  222.  
  223.     /**
  224.     *   Copy of the PEAR_REST#listPackages function with the change
  225.     *   that this one is able to get the list from the local cache.
  226.     *
  227.     *   @param string   $strChannel     The channel which packages shall be listed
  228.     *   @param boolean  $bWorkOffline   If false, the local cache is used - if true, the online list is loaded
  229.     *
  230.     *   @return mixed   PEAR_Error or array (package list)
  231.     */
  232.     public static function listPackages($strChannel$bWorkOffline = false)
  233.     {
  234.         $config     = PEAR_Config::singleton();
  235.         $channel    $config->getRegistry()->getChannel($strChannel);
  236.         $strBaseUrl $channel->getBaseURL('REST1.0');
  237.         $strServer  $channel->getServer();
  238.         $rest       $config->getREST('1.0');
  239.  
  240.         if ($bWorkOffline{
  241.             //We can't use the retrieveCacheFirst function as it would
  242.             //try to connect if the local cache is empty
  243.             $url       $strBaseUrl 'p/packages.xml';
  244.             $cachefile $config->get('cache_dir'. DIRECTORY_SEPARATOR . md5($url'rest.cachefile';
  245.             if (@file_exists($cachefile)) {
  246.                 //local package list cache file
  247.                 $arCache unserialize(implode(''file($cachefile)));
  248.                 if (PEAR::isError($arCache)) {
  249.                     return $arCache;
  250.                 }
  251.                 if (!is_array($arCache|| !isset($arCache['p'])) {
  252.                     return array();
  253.                 }
  254.                 if (!is_array($arCache['p'])) {
  255.                     $arCache['p'= array($arCache['p']);
  256.                 }
  257.                 return $arCache['p'];
  258.  
  259.             else {
  260.                 //no local cache -> return empty package list
  261.                 return array();
  262.             }
  263.         else {
  264.             //online => list online packages
  265.             return $rest->listPackages($strBaseUrl);
  266.         }
  267.     }//public static function listPackages($strChannel, $bWorkOffline = false)
  268.  
  269.  
  270.  
  271.  
  272.     /**
  273.     *   Loads all available information for the given packages
  274.     *
  275.     *   @param array    $arRemotePackages   Array with PEAR_Frontend_Gtk2_Package-s
  276.     *   @param string   $strChannel         The channel name to retrieve packages from
  277.     *   @param callback $callback           The callback to call after a package info has been loaded
  278.     *   @param boolean  $bWorkOffline       If the local cache *only* shall be used, or (if no local cache is there)
  279.     *                                            an connection to the internet server shall be made
  280.     *   @param boolean  $bUseCache          If the cache shall be used. If not, the only chance to get package data is
  281.     *                                            reading them from the online server (if $bWorkOffline is false)
  282.     *
  283.     *   @return array   Array of packages (locally installed and remotely available) (PEAR_Frontend_Gtk2_Package)
  284.     *   @static
  285.     */
  286.     public static function loadRemotePackageData($arRemotePackages$strChannel$callback = null$bWorkOffline = false$bUseCache = true)
  287.     {
  288.         $config     = PEAR_Config::singleton();
  289.         $rest10     $config->getREST('1.0');
  290.         $rest       $rest10->_rest;//FIXME: could change in future pear versions
  291.         $channel    $config->getRegistry()->getChannel($strChannel);
  292.         $strBaseUrl $channel->getBaseURL('REST1.0');
  293.  
  294.         $nNumberPackages count($arRemotePackages);
  295.         $nCurrentPackageNumber = 0;
  296.  
  297.         foreach ($arRemotePackages as $strId => $dontuseit{
  298.             if ($callback !== null{
  299.                 call_user_func_array($callbackarray($nNumberPackages++$nCurrentPackageNumber));
  300.             }
  301.             $package $arRemotePackages[$strId];
  302.             $inf = PEAR_Frontend_Gtk2_Packages::retrieveCacheFirst(
  303.                         PEAR_Frontend_Gtk2_Packages::getInfoUrl($strBaseUrl$package->getName()),
  304.                         $config,
  305.                         $rest,
  306.                         $bWorkOffline,
  307.                         $bUseCache
  308.                     );
  309.             if (PEAR::isError($inf)) {
  310.                 if (strpos(strtolower($inf->message)'404 not found'!== false{
  311.                     //FIXME: That is a hack because the error hasn't an error code yet.
  312.                     //We continue because it's an 404 error, maybe the package isn't there yet.
  313.                     //Happens if you installed new packages which haven't been uploaded to the server yet.
  314.                     $package->setCategory($package->guessCategory($package->getName()));
  315.                     continue;
  316.                 }
  317.                 throw new Exception($inf->getMessage());
  318.             }
  319.             if (!is_array($inf|| !is_array($inf['ca'])) {
  320.                 //something went wrong retrieving the file.
  321.                 throw new Exception('Something went wrong retrieving infos about '$package->getName());
  322.             }
  323.             if ($inf['ca']['_content'!== null{
  324.                 $package->setCategory(   $inf['ca']['_content']);
  325.             }
  326.             $package->setSummary(    $inf['s']);
  327.             $package->setDescription($inf['d']);
  328.             $package->setLatestVersion(
  329.                 //FIXME: use preferred_state config option
  330.                 PEAR_Frontend_Gtk2_Packages::retrieveCacheFirst(
  331.                     PEAR_Frontend_Gtk2_Packages::getLatestVersionUrl($strBaseUrl$package->getName()),
  332.                     $config,
  333.                     $rest,
  334.                     $bWorkOffline,
  335.                     $bUseCache
  336.                 )
  337.             );
  338.         }
  339.  
  340.         if ($callback !== null{
  341.             call_user_func_array($callbackarray(truetrue));
  342.         }
  343.  
  344.         return $arRemotePackages;
  345.     }//public static function loadRemotePackageData($arRemotePackages, $strChannel, $callback = null, $bWorkOffline = false, $bUseCache = true)
  346.  
  347.  
  348.  
  349.     /**
  350.     *   Copy of the PEAR_REST#retrieveCacheFirst() function with the addition
  351.     *   that one can specify if the cache only shall be loaded, or if the cache
  352.     *   is not available, an connection shall be made.
  353.     *
  354.     *   If the user works offline, and no cache is there, NULL is returned.
  355.     *
  356.     *   @param string       $url            The URL to get the data from
  357.     *   @param PEAR_Config  $config         The PEAR configuration
  358.     *   @param PEAR_REST    $rest           The REST object which can be used to retrieve the data
  359.     *   @param boolean      $bWorkOffline   If the local cache *only* shall be used, or (if no local cache is there)
  360.     *                                            an connection to the internet server shall be made
  361.     *   @param boolean      $bUseCache      If the cache shall be used. If not, the only chance to get package data is
  362.     *                                            reading them from the online server (if $bWorkOffline is false)
  363.     */
  364.     public static function retrieveCacheFirst($url$config$rest$bWorkOffline = false$bUseCache = true)
  365.     {
  366.         if ($bUseCache{
  367.             $cachefile $config->get('cache_dir'. DIRECTORY_SEPARATOR . md5($url'rest.cachefile';
  368.             if (@file_exists($cachefile)) {
  369.                 return unserialize(implode(''file($cachefile)));
  370.             }
  371.         }
  372.         if ($bWorkOffline{
  373.             return null;
  374.         else {
  375.             return $rest->retrieveData($url);
  376.         }
  377.     }//public static function retrieveCacheFirst($url, $config, $rest, $bWorkOffline = false, $bUseCache = true)
  378.  
  379.  
  380.  
  381.  
  382.     /**
  383.     *   Path to info.xml for the specific package
  384.     */
  385.     public static function getInfoUrl($strBaseUrl$strPackageName)
  386.     {
  387.         return $strBaseUrl 'p/' strtolower($strPackageName'/info.xml';
  388.     }//public static function getInfoUrl($strBaseUrl, $strPackageName)
  389.  
  390.  
  391.  
  392.     /**
  393.     *   Path to latest.txt for the specific package
  394.     */
  395.     public static function getLatestVersionUrl($strBaseUrl$strPackageName)
  396.     {
  397.         return $strBaseUrl 'r/' strtolower($strPackageName'/latest.txt';
  398.     }//public static function getLatestVersionUrl($strBaseUrl, $strPackageName)
  399.  
  400.  
  401.  
  402.     /**
  403.     *   Creates an array of categories (strings) of the current
  404.     *   channel server
  405.     *
  406.     *   @param callback $callback       The callback to call when package information is loaded
  407.     *   @param boolean  $bWorkOffline   If the user wants to work offline (don't try to connect to the internet)
  408.     *
  409.     *   @return array   Array of category strings
  410.     */
  411.     public function getCategories($callback = null$bWorkOffline = false)
  412.     {
  413.         if (!isset($this->arCategories[$this->strActiveChannel])) {
  414.             $arPackages $this->getPackages(null$callback$bWorkOffline);
  415.  
  416.             $this->arCategories[$this->strActiveChannel= array();
  417.             if (count($arPackages> 0{
  418.                 foreach ($arPackages as $package{
  419.                     $strCategory $package->getCategory();
  420.                     $this->arCategories[$this->strActiveChannel][$strCategory$strCategory;
  421.                 }
  422.                 natcasesort($this->arCategories[$this->strActiveChannel]);
  423.             }
  424.         }
  425.  
  426.         return $this->arCategories[$this->strActiveChannel];
  427.     }//public function getCategories($callback = null)
  428.  
  429.  
  430.  
  431.     /**
  432.     *   Checks if the packages for the given channel have already been loaded
  433.     *
  434.     *   @param string $strChannel   The channel to check (active channel if null)
  435.     *   @return boolean     true if the packages already have been loaded, false if not
  436.     */
  437.     public function packagesLoaded($strChannel = null)
  438.     {
  439.         if ($strChannel === null{
  440.             $strChannel $this->strActiveChannel;
  441.         }
  442.         return (isset($this->arPackages[$strChannel]&& $this->arPackages[$strChannel!== null);
  443.     }//public function packagesLoaded($strChannel = null)
  444.  
  445.  
  446.  
  447.     /**
  448.     *   Refreshs the package list of the given channel by re-reading
  449.     *   the local package info
  450.     *
  451.     *   @param string   $strChannel     The channel to update. If NULL, the active one is used
  452.     *   @return array   Package list for the given channel
  453.     */
  454.     public function refreshLocalPackages($strChannel = null)
  455.     {
  456.         if ($strChannel === null{
  457.             $strChannel $this->strActiveChannel;
  458.         }
  459.         if ($this->strActiveChannel === null{
  460.             $strChannel 'pear.php.net';
  461.         }
  462.  
  463.         $this->arPackages[$strChannel= self::getLocalPackages($strChannel$this->arPackages[$strChannel]);
  464.         return $this->arPackages[$strChannel];
  465.     }//public function refreshLocalPackages($strChannel = null)
  466.  
  467.  
  468.  
  469.     /**
  470.     *   Refreshs the package list of the given channel by re-reading the remote
  471.     *   package information.
  472.     *
  473.     *   @param string   $strChannel     The channel to update. If NULL, the active one is used
  474.     *   @return array   Package list for the given channel
  475.     */
  476.     public function refreshRemotePackages($strChannel = null$callback = null)
  477.     {
  478.         if ($strChannel === null{
  479.             $strChannel $this->strActiveChannel;
  480.         }
  481.         $this->arPackages[$strChannel= self::loadRemotePackageData($this->arPackages[$strChannel]$strChannel$callbackfalsefalse);
  482.         return $this->arPackages[$strChannel];
  483.     }//public function refreshRemotePackages($strChannel = null, $callback = null)
  484.  
  485. }//class PEAR_Frontend_Gtk2_Packages
  486. ?>

Documentation generated on Mon, 11 Mar 2019 15:46:48 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.