Zend\Feed\Reader, Guzzle und PSR-7

Zend\Feed ist eine mächtige Bibliothek zum Auffinden, Lesen und Schreiben von RSS-Feeds in verschiedenen Formaten (uns interessieren hier nur das Auffinden und Lesen). Standardmäßig verwendet Zend\Feed\Reader\Reader – eine Sammlung statischer Methoden für den Zugriff auf die Funktionalität zum Lesen und Auffinden von Feeds – einen Zend\Http\Client, um die HTTP-Kommunikation abzuwickeln. Leider hat Zend\Http\Client einige Probleme im praktischen Einsatz, etwa: „Incorrect handling of negative MaxAge cookie attribute“ oder „ChunkedBody decoding with Curl Adapter“ oder einige andere.

Deshalb haben wir versucht, Zend\Feed\Reader\Reader mit einer anderen HTTP-Client-Bibliothek zu integrieren, die bereits Teil des Projekts war: Guzzle. Guzzle ist ein leistungsfähiger HTTP-Client und unterstützt PSR-7 – den PHP-FIG-Standard für HTTP-Message-Interfaces. Auf Basis dieses Standards funktionierte die Integration wie am Schnürchen, denn in Zend\Feed\Reader ist eine kaum dokumentierte PSR-7-Kompatibilitätsschicht enthalten – der Zend\Feed\Reader\Http\Psr7ResponseDecorator.

Um Guzzle in Zend\Feed\Reader\Reader zu integrieren, war allerdings nur eine Klasse nötig – eine Implementierung von Zend\Feed\Reader\Http\ClientInterface, einem der einfachsten Interfaces, die man sich vorstellen kann:


namespace Zend\Feed\Reader\Http;

interface ClientInterface
{
    /**
     * Make a GET request to a given URI
     *
     * @param  string $uri
     * @return ResponseInterface
     */
    public function get($uri);
}

Unser AppBundle\Feed\GuzzleClient fiel am Ende so einfach aus:


namespace AppBundle\Feed;

use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface as GuzzleClientInterface;
use Zend\Feed\Reader\Http\ClientInterface as FeedReaderHttpClientInterface;
use Zend\Feed\Reader\Http\Psr7ResponseDecorator;

/**
 * Class GuzzleClient
 *
 * @package AppBundle\Feed
 */
class GuzzleClient implements FeedReaderHttpClientInterface
{
    /**
     * @var GuzzleClientInterface
     */
    private $client;

    /**
     * GuzzleClient constructor.
     *
     * @param GuzzleClientInterface|null $client
     */
    public function __construct(GuzzleClientInterface $client = null)
    {
        $this->client = $client ?: new Client();
    }

    /**
     * {@inheritdoc}
     */
    public function get($uri)
    {
        $response = $this->client->request('GET', $uri);

        return new Psr7ResponseDecorator($response);
    }
}

GuzzleHttp\ClientInterface::request() liefert ein Psr\Http\Message\ResponseInterface zurück, das direkt in eine Instanz von Zend\Feed\Reader\Http\Psr7ResponseDecorator gesteckt werden kann.

Nun konnten wir den HTTP-Client von Zend\Feed\Reader\Reader einfach durch unseren neuen Guzzle-Decorator ersetzen:


Zend\Feed\Reader\Reader::setHttpClient(new AppBundle\Feed\GuzzleClient());

Das war’s – das Auffinden von Feeds (Zend\Feed\Reader\Reader::findFeedLinks($uri)) und das Lesen von Feeds (Zend\Feed\Reader\Reader::import($uri)) kommunizieren nun über die robustere Guzzle-Bibliothek statt über Zend\Http\Client.

Made with in Stuttgart, Germany