Location: PHPKode > projects > Open Eats > oe_1.2/plugins/sfFeed2Plugin/lib/sfFeedPeer.class.php
<?php

/*
 * This file is part of the sfFeed2 package.
 * (c) 2004-2006 Fabien Potencier <hide@address.com>
 * (c) 2004-2007 Francois Zaninotto <hide@address.com>
 * 
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * sfFeedPeer
 *
 *
 * @package    sfFeed2
 * @author     Fabien Potencier <hide@address.com>
 * @author     Francois Zaninotto <hide@address.com>
 */
class sfFeedPeer
{
  /**
   * Retrieve a new sfFeed implementation instance.
   *
   * @param string A sfFeed implementation name.
   *
   * @return sfFeed A sfFeed implementation instance.
   *
   * @throws sfFactoryException If a new syndication feed implementation instance cannot be created.
   */
  public static function newInstance($format = '')
  {
    try
    {
      $class = 'sf'.ucfirst($format).'Feed';

      // the class exists
      $object = new $class();

      if (!($object instanceof sfFeed))
      {
          // the class name is of the wrong type
          $error = 'Class "%s" is not of the type sfFeed';
          $error = sprintf($error, $class);

          throw new sfFactoryException($error);
      }

      return $object;
    }
    catch (sfException $e)
    {
      $e->printStackTrace();
    }
  }

  /**
   * Retrieve a new sfFeed implementation instance, populated from a web feed.
   * The class of the returned instance depends on the nature of the web feed.
   * This method uses the sfWebBrowser plugin.
   *
   * @param string A web feed URI
   *
   * @return sfFeed A sfFeed implementation instance.
   */
  public static function createFromWeb($uri, $options = array())
  {
    if(isset($options['adapter']))
    {
      $browser = new sfWebBrowser(array(), $options['adapter'], isset($options['adapter_options']) ? $options['adapter_options'] : array());
    }
    else
    {
      $browser = new sfWebBrowser();
    }
    $browser->setUserAgent(isset($options['userAgent']) ? $options['userAgent'] : 'sfFeedReader/0.9');
    if($browser->get($uri)->responseIsError())
    {
      $error = 'The given URL (%s) returns an error (%s: %s)';
      $error = sprintf($error, $uri, $browser->getResponseCode(), $browser->getResponseMessage());
      throw new Exception($error);
    }
    $feedString = $browser->getResponseText(); 
    
    return self::createFromXml($feedString, $uri);    
  }
  
  /**
   * Retrieve a new sfFeed implementation instance, populated from a xml feed.
   * The class of the returned instance depends on the nature of the xml feed.
   *
   * @param string $feedString a feed as xml string
   * @param string A web feed URI
   * 
   * @return sfFeed A sfFeed implementation instance.
   */
  public static function createFromXml($feedString, $uri)
  {
    $feedClass = '';
    if(preg_match('/xmlns=[\"\'](http:\/\/www\.w3\.org\/2005\/Atom|http:\/\/purl\.org\/atom)/', $feedString))
    {
      $feedClass = 'sfAtom1Feed';
    }
    if(strpos($feedString, '<rss') !== false)
    {
      $feedClass = 'sfRssFeed'; 
    }
    if(strpos($feedString, '<rdf:RDF') !== false)
    {
      $feedClass = 'sfRss10Feed'; 
    }
    
    if($feedClass)
    {
      $object = new $feedClass();
      $object->setFeedUrl($uri);
      $object->fromXml($feedString);
      return $object; 
    }
    else
    {
      throw new Exception('Impossible to decode feed format'); 
    }
  }

  /**
   * Merge the items from several feeds and retrieve a sfFeed instance
   * Populated with all the items, and sorted.
   *
   * @param array an array of sfFeed objects
   * @param array an associative array of feed parameters
   *
   * @return sfFeed A sfFeed implementation instance.
   */
  public static function aggregate($feeds, $parameters = array())
  {
    // merge all items
    $feed_items = array();
    foreach($feeds as $feed)
    {
      foreach($feed->getItems() as $item)
      {
        $index = is_integer($item->getPubDate()) ?  $item->getPubDate() : 0;
        while(isset($feed_items[$index]))
        {
          $index++;
        }
        $feed_items[$index] = $item;
      } 
    }
    
    // sort in reverse chronological order
    krsort($feed_items);
    
    // limit the number of feed items to be added
    if(isset($parameters['limit']))
    {
      $feed_items = array_slice($feed_items, 0, $parameters['limit']);
    }
    
    // create a feed with these items
    $feed = self::newInstance(isset($parameters['format']) ? $parameters['format'] : '');
    $feed->initialize($parameters);
    foreach($feed_items as $item)
    {
      $origin_feed = clone $item->getFeed();
      $origin_feed->setItems();
      $feed->addItem($item);
      $item->setFeed($origin_feed);
    }
    
    return $feed;
  }

  /**
   * Populates a feed with items based on objects
   * Inspects the available methods of the objects to populate items properties.
   *
   * @param array an array of objects
   * @param string A route name for building the URIs to the items
   * @param array An associative array of options
   *
   * @return sfFeed the current sfFeed object
   */
  public static function convertObjectsToItems($objects, $options = array())
  {
    $items = array();
    foreach($objects as $object)
    {
      $item = new sfFeedItem();
  
      // For each item property, check if an object method is provided, 
      // and if not, guess it. Here is what it does for the link property
      if(isset($options['methods']['link']))
      {
        if($options['methods']['link'])
        {
          $item->setLink(call_user_func(array($object, $options['methods']['link'])));
        }
        else
        {
          $item->setLink('');
        }
      }
      else
      {
        $routeName = (isset($options['routeName'])) ? $options['routeName'] : '';
        $fallbackUrl = (isset($options['fallbackUrl'])) ? $options['fallbackUrl'] : '';
        $item->setLink(self::getItemFeedLink($object, $routeName, $fallbackUrl));
      }
      
      // For the other properties, it can be automated
      // Not as readable but definitely more concise
      $details = array('title', 'description', 'content', 'authorEmail', 'authorName', 'authorLink', 'pubdate', 'comments', 'uniqueId', 'enclosure', 'categories');
      foreach($details as $detail)
      {
        $itemMethod = 'set'.ucfirst($detail);
        if(isset($options['methods'][$detail]))
        {
          if($options['methods'][$detail])
          {
            call_user_func(array($item, $itemMethod), call_user_func(array($object, $options['methods'][$detail])));            
          }
          else
          {
            call_user_func(array($item, $itemMethod), '');            
          }
        }
        else
        { 
          call_user_func(array($item, $itemMethod), call_user_func(array('sfFeedPeer', 'getItemFeed'.ucfirst($detail)), $object));
        }
      }
        
      $items[] = $item;
    }
    
    return $items;
  }

  /**
   * Creates and populates a feed with items based on objects
   * This is a proxy method that combines calls to newInstance() and convertObjectsToItems()
   *
   * @param array an array of objects
   * @param array an associative array of feed parameters
   *
   * @return sfFeed A sfFeed implementation instance, containing the parameters and populated with the objects
   */
  public static function createFromObjects($objects, $options = array())
  {
    $feed = self::newInstance(isset($options['format']) ? $options['format'] : '');
    $feed->initialize($options);
    $options['fallbackUrl'] = $feed->getLink();
    $feed->addItems(self::convertObjectsToItems($objects, $options));
    
    return $feed;
  }
  
  private static function getItemFeedTitle($item)
  {
    foreach (array('getFeedTitle', 'getTitle', 'getName', '__toString') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    return '';
  }

  private static function getItemFeedLink($item, $routeName = '', $fallback_url = '')
  {
    if ($routeName)
    {
      $routing = sfRouting::getInstance();
      $route = $routing->getRouteByName($routeName);

      $url = $route[0];
      $defaults = $route[4];

      // we get all parameters
      $params = array();
      if (preg_match_all('/\:([^\/]+)/', $url, $matches))
      {
        foreach ($matches[1] as $paramName)
        {
          $value = null;
          $name = ucfirst(sfInflector::camelize($paramName));

          $found = false;
          foreach (array('getFeed'.$name, 'get'.$name) as $methodName)
          {
            if (method_exists($item, $methodName))
            {
              $value = $item->$methodName();
              $found = true;
              break;
            }
          }

          if (!$found)
          {
            if (array_key_exists($paramName, $defaults))
            {
              $value = $defaults[$paramName];
            }
            else
            {
              $error = 'Cannot find a "getFeed%s()" or "get%s()" method for object "%s" to generate URL with the "%s" route';
              $error = sprintf($error, $name, $name, get_class($item), $routeName);
              throw new sfException($error);
            }
          }

          $params[] = $paramName.'='.$value;
        }
      }

      return sfContext::getInstance()->getController()->genUrl($routeName.($params ? '?'.implode('&', $params) : ''), true);
    }

    foreach (array('getFeedLink', 'getLink', 'getUrl') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return sfContext::getInstance()->getController()->genUrl($item->$methodName(), true);
      }
    }

    if ($fallback_url)
    {
      return sfContext::getInstance()->getController()->genUrl($fallback_url, true);
    }
    else
    {
      return sfContext::getInstance()->getController()->genUrl('/', true);
    }
  }

  private static function getItemFeedDescription($item)
  {
    foreach (array('getFeedDescription', 'getDescription', 'getBody') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    return '';
  }

  private static function getItemFeedContent($item)
  {
    foreach (array('getFeedContent', 'getContent', 'getHtmlBody', 'getBody') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    return '';
  }

  private static function getItemFeedUniqueId($item)
  {
    foreach (array('getFeedUniqueId', 'getUniqueId', 'getId') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    return '';
  }

  private static function getItemFeedAuthorEmail($item)
  {
    foreach (array('getFeedAuthorEmail', 'getAuthorEmail') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    // author as an object link
    if ($author = self::getItemFeedAuthor($item))
    {
      foreach (array('getEmail', 'getMail') as $methodName)
      {
        if (method_exists($author, $methodName))
        {
          return $author->$methodName();
        }
      }
    }

    return '';
  }

  private static function getItemFeedAuthorName($item)
  {
    foreach (array('getFeedAuthorName', 'getAuthorName') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    // author as an object link
    if ($author = self::getItemFeedAuthor($item))
    {
      foreach (array('getName', '__toString') as $methodName)
      {
        if (method_exists($author, $methodName))
        {
          return $author->$methodName();
        }
      }
    }

    return '';
  }

  private static function getItemFeedAuthorLink($item)
  {
    foreach (array('getFeedAuthorLink', 'getAuthorLink') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    // author as an object link
    if ($author = self::getItemFeedAuthor($item))
    {
      foreach (array('getLink') as $methodName)
      {
        if (method_exists($author, $methodName))
        {
          return $author->$methodName();
        }
      }
    }

    return '';
  }

  private static function getItemFeedAuthor($item)
  {
    foreach (array('getAuthor', 'getUser', 'getPerson') as $methodName)
    {
      if (method_exists($item, $methodName) && is_object($item->$methodName()))
      {
        return $item->$methodName();
      }
    }

    return null;
  }

  private static function getItemFeedPubdate($item)
  {
    foreach (array('getFeedPubdate', 'getPubdate', 'getCreatedAt', 'getDate') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName('U');
      }
    }

    return '';
  }

  private static function getItemFeedComments($item)
  {
    foreach (array('getFeedComments', 'getComments') as $methodName)
    {
      if (method_exists($item, $methodName))
      {
        return $item->$methodName();
      }
    }

    return '';
  }

  private static function getItemFeedCategories($item)
  {
    foreach (array('getFeedCategories', 'getCategories') as $methodName)
    {
      if (method_exists($item, $methodName) && is_object($item->$methodName()))
      {
        // categories as an object
        $categories = $item->$methodName();
        if (is_array($categories))
        {
          $cats = array();
          foreach ($categories as $category)
          {
            $cats[] = (string) $category;
          }

          return $cats;
        }
      }
    }

    return array();
  }

  private static function getItemFeedEnclosure($item)
  {
    if (method_exists($item, 'getFeedEnclosure'))
    {
      return $item->getFeedEnclosure();
    }

    return '';
  }

}

?>
Return current item: Open Eats