Skip to content
This repository has been archived by the owner on Oct 28, 2020. It is now read-only.

Commit

Permalink
switch to php-http/adapter for http client
Browse files Browse the repository at this point in the history
  • Loading branch information
kbond committed Oct 22, 2015
1 parent 7d71bda commit d5cc54f
Show file tree
Hide file tree
Showing 16 changed files with 392 additions and 162 deletions.
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ language: php
sudo: false

php:
- 5.3
- 5.4
- 5.5
- 5.6
Expand Down
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,10 @@ One or more url providers must be registered.

## HttpCache Warmup Command

```
Usage:
zenstruck:http-cache:warmup [-p|--parallel-requests="..."] [-t|--timeout="..."] [-r|--follow-redirects]

Options:
--parallel-requests (-p) The number of requests to send in parallel (default: "10")
--timeout (-t) The timeout in seconds (default: "10")
--follow-redirects (-r) Follow redirects?

Help:
The zenstruck:http-cache:warmup command warms up the http cache.
```
app/console zenstruck:http-cache:warmup
```
## Sitemap Provider
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
"require": {
"symfony/framework-bundle": "~2.3",
"symfony/console": "~2.3",
"psr/http-message": "~1.0"
"php-http/adapter": "~0.1",
"php-http/message-factory": "~0.1",
"php-http/discovery": "~0.1"
},
"require-dev": {
"zendframework/zend-diactoros": "~1.1",
"symfony/dom-crawler": "~2.3",
"symfony/css-selector": "~2.3",
"phpunit/phpunit": "~4.0",
Expand Down
17 changes: 5 additions & 12 deletions src/Command/HttpCacheWarmupCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Response;
use Zenstruck\CacheBundle\Url\Crawler;
Expand All @@ -25,10 +24,6 @@ protected function configure()
{
$this
->setName('zenstruck:http-cache:warmup')
->setDefinition(array(
new InputOption('timeout', 't', InputOption::VALUE_REQUIRED | InputOption::VALUE_REQUIRED, 'The timeout in seconds', '10'),
new InputOption('follow-redirects', 'r', InputOption::VALUE_NONE, 'Follow redirects?'),
))
->setDescription('Warms up an http cache');
}

Expand All @@ -38,12 +33,10 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
/** @var Crawler $crawler */
$crawler = $this->getContainer()->get('zenstruck_cache.crawler');
$timeout = (int) $input->getOption('timeout');
$redirects = $input->getOption('follow-redirects');
$summary = array();
$total = count($crawler);
$progress = new ProgressBar($output, $total);
$crawler = $this->getContainer()->get('zenstruck_cache.crawler');
$summary = array();
$total = count($crawler);
$progress = new ProgressBar($output, $total);

if (0 === $total) {
throw new \RuntimeException('No URL providers registered.');
Expand All @@ -66,7 +59,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
++$summary[$status];
};

$crawler->crawl($redirects, $timeout, $callback);
$crawler->crawl($callback);

$progress->finish();
$output->writeln("\n");
Expand Down
9 changes: 7 additions & 2 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ public function getConfigTreeBuilder()

$rootNode
->children()
->scalarNode('client')
->info('Either a class or a service that implements Zenstruck\CacheBundle\Http\Client.')
->scalarNode('http_adapter')
->info('Either a class or a service that implements Http\Adapter\HttpAdapter.')
->isRequired()
->defaultNull()
->end()
->scalarNode('message_factory')
->info('Either a class or a service that implements Http\Message\MessageFactory.')
->isRequired()
->defaultNull()
->end()
Expand Down
59 changes: 46 additions & 13 deletions src/DependencyInjection/ZenstruckCacheExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.xml');

$this->configureClient($mergedConfig['client'], $container);
$this->configureHttpAdapter($mergedConfig['http_adapter'], $container);
$this->configureMessageFactory($mergedConfig['message_factory'], $container);

if ($mergedConfig['sitemap_provider']['enabled']) {
$container->setParameter('zenstruck_cache.sitemap_provider.hosts', $mergedConfig['sitemap_provider']['hosts']);
Expand All @@ -31,34 +32,66 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container
}

/**
* @param string $client
* @param string $httpAdapter
* @param ContainerBuilder $container
*/
private function configureClient($client, ContainerBuilder $container)
private function configureHttpAdapter($httpAdapter, ContainerBuilder $container)
{
if (!class_exists($client)) {
if (!class_exists($httpAdapter)) {
// is a service
$container->setAlias('zenstruck_cache.client', $client);
$container->setAlias('zenstruck_cache.http_adapter', $httpAdapter);

return;
}

$r = new \ReflectionClass($client);
$r = new \ReflectionClass($httpAdapter);

if (!$r->implementsInterface('Zenstruck\CacheBundle\Http\Client')) {
throw new InvalidConfigurationException('Client class must implement "Zenstruck\CacheBundle\Http\Client".');
if (!$r->implementsInterface('Http\Adapter\HttpAdapter')) {
throw new InvalidConfigurationException('HttpAdapter class must implement "Http\Adapter\HttpAdapter".');
}

if ($r->isAbstract()) {
throw new InvalidConfigurationException('Client class must not be abstract.');
throw new InvalidConfigurationException('HttpAdapter class must not be abstract.');
}

if (null !== $r->getConstructor() && 0 !== $r->getConstructor()->getNumberOfRequiredParameters()) {
throw new InvalidConfigurationException('Client class must not have required constructor arguments.');
throw new InvalidConfigurationException('HttpAdapter class must not have required constructor arguments.');
}

$client = new Definition($client);
$client->setPublic(false);
$container->setDefinition('zenstruck_cache.client', $client);
$httpAdapter = new Definition($httpAdapter);
$httpAdapter->setPublic(false);
$container->setDefinition('zenstruck_cache.http_adapter', $httpAdapter);
}

/**
* @param string $messageFactory
* @param ContainerBuilder $container
*/
private function configureMessageFactory($messageFactory, ContainerBuilder $container)
{
if (!class_exists($messageFactory)) {
// is a service
$container->setAlias('zenstruck_cache.message_factory', $messageFactory);

return;
}

$r = new \ReflectionClass($messageFactory);

if (!$r->implementsInterface('Http\Message\MessageFactory')) {
throw new InvalidConfigurationException('MessageFactory class must implement "Http\Message\MessageFactory".');
}

if ($r->isAbstract()) {
throw new InvalidConfigurationException('MessageFactory class must not be abstract.');
}

if (null !== $r->getConstructor() && 0 !== $r->getConstructor()->getNumberOfRequiredParameters()) {
throw new InvalidConfigurationException('MessageFactory class must not have required constructor arguments.');
}

$messageFactory = new Definition($messageFactory);
$messageFactory->setPublic(false);
$container->setDefinition('zenstruck_cache.message_factory', $messageFactory);
}
}
22 changes: 0 additions & 22 deletions src/Http/Client.php

This file was deleted.

3 changes: 2 additions & 1 deletion src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

<services>
<service id="zenstruck_cache.crawler" class="%zenstruck_cache.crawler.class%">
<argument type="service" id="zenstruck_cache.client" />
<argument type="service" id="zenstruck_cache.http_adapter" />
<argument type="service" id="zenstruck_cache.message_factory" />
<argument type="service" id="logger" on-invalid="null" />
<tag name="monolog.logger" channel="httpcache_warmup" />
</service>
Expand Down
3 changes: 2 additions & 1 deletion src/Resources/config/sitemap_provider.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
<services>
<service id="zenstruck_cache.sitemap_provider" class="%zenstruck_cache.sitemap_provider.class%" public="false">
<argument>%zenstruck_cache.sitemap_provider.hosts%</argument>
<argument type="service" id="zenstruck_cache.client" />
<argument type="service" id="zenstruck_cache.http_adapter" />
<argument type="service" id="zenstruck_cache.message_factory" />
<tag name="zenstruck_cache.url_provider" />
</service>
</services>
Expand Down
26 changes: 14 additions & 12 deletions src/Url/Crawler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@

namespace Zenstruck\CacheBundle\Url;

use Http\Adapter\HttpAdapter;
use Http\Message\MessageFactory;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Zenstruck\CacheBundle\Http\Client;

/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
class Crawler implements \Countable
{
private $client;
private $httpAdapter;
private $messageFactory;
private $logger;
private $urlProviders;

/**
* @param Client $client
* @param HttpAdapter $httpAdapter
* @param MessageFactory $messageFactory
* @param LoggerInterface $logger
* @param UrlProvider[] $urlProviders
*/
public function __construct(Client $client, LoggerInterface $logger = null, array $urlProviders = array())
public function __construct(HttpAdapter $httpAdapter, MessageFactory $messageFactory, LoggerInterface $logger = null, array $urlProviders = array())
{
$this->client = $client;
$this->logger = $logger;
$this->urlProviders = $urlProviders;
$this->httpAdapter = $httpAdapter;
$this->messageFactory = $messageFactory;
$this->logger = $logger;
$this->urlProviders = $urlProviders;
}

/**
Expand All @@ -51,18 +55,16 @@ public function count()
}

/**
* @param bool $followRedirects
* @param int $timeout
* @param callable $callback Response as first argument, calling URL as second.
* @param callable $callback Response as first argument, calling URL as second
*/
public function crawl($followRedirects = false, $timeout = 10, $callback = null)
public function crawl($callback = null)
{
if (null !== $callback && !is_callable($callback)) {
throw new \InvalidArgumentException('Valid callback required.');
}

foreach ($this->getUrls() as $url) {
$response = $this->client->fetch($url, $followRedirects, $timeout);
$response = $this->httpAdapter->sendRequest($this->messageFactory->createRequest('GET', $url));

$this->log($response, $url);

Expand Down
20 changes: 12 additions & 8 deletions src/Url/SitemapUrlProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@

namespace Zenstruck\CacheBundle\Url;

use Http\Adapter\HttpAdapter;
use Http\Message\MessageFactory;
use Symfony\Component\DomCrawler\Crawler as DomCrawler;
use Zenstruck\CacheBundle\Http\Client;

/**
* @author Kevin Bond <kevinbond@gmail.com>
*/
class SitemapUrlProvider implements UrlProvider
{
private $hosts;
private $client;
private $httpAdapter;
private $messageFactory;
private $urls;

/**
* @param array $hosts
* @param Client $client
* @param array $hosts
* @param HttpAdapter $httpAdapter
* @param MessageFactory $messageFactory
*/
public function __construct(array $hosts, Client $client)
public function __construct(array $hosts, HttpAdapter $httpAdapter, MessageFactory $messageFactory)
{
if (!class_exists('Symfony\\Component\\DomCrawler\\Crawler') || !class_exists('Symfony\\Component\\CssSelector\\CssSelector')) {
throw new \RuntimeException('symfony/dom-crawler and symfony/css-selector must be installed to use SitemapUrlProvider.');
}

$this->hosts = $hosts;
$this->client = $client;
$this->hosts = $hosts;
$this->httpAdapter = $httpAdapter;
$this->messageFactory = $messageFactory;
}

/**
Expand Down Expand Up @@ -95,7 +99,7 @@ private function addPathToHost($path, $host)
*/
private function getSitemapEntries($url)
{
$response = $this->client->fetch($url);
$response = $this->httpAdapter->sendRequest($this->messageFactory->createRequest('GET', $url));

if (200 !== $response->getStatusCode()) {
return array();
Expand Down
Loading

0 comments on commit d5cc54f

Please sign in to comment.