diff options
Diffstat (limited to 'inc/mailgun/php-http/discovery/src')
17 files changed, 735 insertions, 0 deletions
diff --git a/inc/mailgun/php-http/discovery/src/ClassDiscovery.php b/inc/mailgun/php-http/discovery/src/ClassDiscovery.php new file mode 100644 index 0000000..2c3e877 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/ClassDiscovery.php @@ -0,0 +1,207 @@ +<?php + +namespace Http\Discovery; + +use Http\Discovery\Exception\ClassInstantiationFailedException; +use Http\Discovery\Exception\DiscoveryFailedException; +use Http\Discovery\Exception\StrategyUnavailableException; + +/** + * Registry that based find results on class existence. + * + * @author David de Boer <david@ddeboer.nl> + * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +abstract class ClassDiscovery +{ + /** + * A list of strategies to find classes. + * + * @var array + */ + private static $strategies = [ + Strategy\PuliBetaStrategy::class, + Strategy\CommonClassesStrategy::class, + ]; + + /** + * Discovery cache to make the second time we use discovery faster. + * + * @var array + */ + private static $cache = []; + + /** + * Finds a class. + * + * @param string $type + * + * @return string|\Closure + * + * @throws DiscoveryFailedException + */ + protected static function findOneByType($type) + { + // Look in the cache + if (null !== ($class = self::getFromCache($type))) { + return $class; + } + + $exceptions = []; + foreach (self::$strategies as $strategy) { + try { + $candidates = call_user_func($strategy.'::getCandidates', $type); + } catch (StrategyUnavailableException $e) { + $exceptions[] = $e; + continue; + } + + foreach ($candidates as $candidate) { + if (isset($candidate['condition'])) { + if (!self::evaluateCondition($candidate['condition'])) { + continue; + } + } + + // save the result for later use + self::storeInCache($type, $candidate); + + return $candidate['class']; + } + } + + throw DiscoveryFailedException::create($exceptions); + } + + /** + * Get a value from cache. + * + * @param string $type + * + * @return string|null + */ + private static function getFromCache($type) + { + if (!isset(self::$cache[$type])) { + return; + } + + $candidate = self::$cache[$type]; + if (isset($candidate['condition'])) { + if (!self::evaluateCondition($candidate['condition'])) { + return; + } + } + + return $candidate['class']; + } + + /** + * Store a value in cache. + * + * @param string $type + * @param string $class + */ + private static function storeInCache($type, $class) + { + self::$cache[$type] = $class; + } + + /** + * Set new strategies and clear the cache. + * + * @param array $strategies string array of fully qualified class name to a DiscoveryStrategy + */ + public static function setStrategies(array $strategies) + { + self::$strategies = $strategies; + self::clearCache(); + } + + /** + * Append a strategy at the end of the strategy queue. + * + * @param string $strategy Fully qualified class name to a DiscoveryStrategy + */ + public static function appendStrategy($strategy) + { + self::$strategies[] = $strategy; + self::clearCache(); + } + + /** + * Prepend a strategy at the beginning of the strategy queue. + * + * @param string $strategy Fully qualified class name to a DiscoveryStrategy + */ + public static function prependStrategy($strategy) + { + array_unshift(self::$strategies, $strategy); + self::clearCache(); + } + + /** + * Clear the cache. + */ + public static function clearCache() + { + self::$cache = []; + } + + /** + * Evaluates conditions to boolean. + * + * @param mixed $condition + * + * @return bool + */ + protected static function evaluateCondition($condition) + { + if (is_string($condition)) { + // Should be extended for functions, extensions??? + return class_exists($condition); + } elseif (is_callable($condition)) { + return $condition(); + } elseif (is_bool($condition)) { + return $condition; + } elseif (is_array($condition)) { + $evaluatedCondition = true; + + // Immediately stop execution if the condition is false + for ($i = 0; $i < count($condition) && false !== $evaluatedCondition; ++$i) { + $evaluatedCondition &= static::evaluateCondition($condition[$i]); + } + + return $evaluatedCondition; + } + + return false; + } + + /** + * Get an instance of the $class. + * + * @param string|\Closure $class A FQCN of a class or a closure that instantiate the class. + * + * @return object + * + * @throws ClassInstantiationFailedException + */ + protected static function instantiateClass($class) + { + try { + if (is_string($class)) { + return new $class(); + } + + if (is_callable($class)) { + return $class(); + } + } catch (\Exception $e) { + throw new ClassInstantiationFailedException('Unexpected exception when instantiating class.', 0, $e); + } + + throw new ClassInstantiationFailedException('Could not instantiate class because parameter is neither a callable nor a string'); + } +} diff --git a/inc/mailgun/php-http/discovery/src/Exception.php b/inc/mailgun/php-http/discovery/src/Exception.php new file mode 100644 index 0000000..973c908 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Exception.php @@ -0,0 +1,12 @@ +<?php + +namespace Http\Discovery; + +/** + * An interface implemented by all discovery related exceptions. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +interface Exception +{ +} diff --git a/inc/mailgun/php-http/discovery/src/Exception/ClassInstantiationFailedException.php b/inc/mailgun/php-http/discovery/src/Exception/ClassInstantiationFailedException.php new file mode 100644 index 0000000..e95bf5d --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Exception/ClassInstantiationFailedException.php @@ -0,0 +1,14 @@ +<?php + +namespace Http\Discovery\Exception; + +use Http\Discovery\Exception; + +/** + * Thrown when a class fails to instantiate. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +final class ClassInstantiationFailedException extends \RuntimeException implements Exception +{ +} diff --git a/inc/mailgun/php-http/discovery/src/Exception/DiscoveryFailedException.php b/inc/mailgun/php-http/discovery/src/Exception/DiscoveryFailedException.php new file mode 100644 index 0000000..304b727 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Exception/DiscoveryFailedException.php @@ -0,0 +1,51 @@ +<?php + +namespace Http\Discovery\Exception; + +use Http\Discovery\Exception; + +/** + * Thrown when all discovery strategies fails to find a resource. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +final class DiscoveryFailedException extends \Exception implements Exception +{ + /** + * @var \Exception[] + */ + private $exceptions; + + /** + * @param string $message + * @param \Exception[] $exceptions + */ + public function __construct($message, array $exceptions = []) + { + $this->exceptions = $exceptions; + + parent::__construct($message); + } + + /** + * @param \Exception[] $exceptions + */ + public static function create($exceptions) + { + $message = 'Could not find resource using any discovery strategy. Find more information at http://docs.php-http.org/en/latest/discovery.html#common-errors'; + foreach ($exceptions as $e) { + $message .= "\n - ".$e->getMessage(); + } + $message .= "\n\n"; + + return new self($message, $exceptions); + } + + /** + * @return \Exception[] + */ + public function getExceptions() + { + return $this->exceptions; + } +} diff --git a/inc/mailgun/php-http/discovery/src/Exception/NotFoundException.php b/inc/mailgun/php-http/discovery/src/Exception/NotFoundException.php new file mode 100644 index 0000000..befbf48 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Exception/NotFoundException.php @@ -0,0 +1,16 @@ +<?php + +namespace Http\Discovery\Exception; + +use Http\Discovery\Exception; + +/** + * Thrown when a discovery does not find any matches. + * + * @final do NOT extend this class, not final for BC reasons + * + * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> + */ +/*final */class NotFoundException extends \RuntimeException implements Exception +{ +} diff --git a/inc/mailgun/php-http/discovery/src/Exception/PuliUnavailableException.php b/inc/mailgun/php-http/discovery/src/Exception/PuliUnavailableException.php new file mode 100644 index 0000000..a6ade73 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Exception/PuliUnavailableException.php @@ -0,0 +1,12 @@ +<?php + +namespace Http\Discovery\Exception; + +/** + * Thrown when we can't use Puli for discovery. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +final class PuliUnavailableException extends StrategyUnavailableException +{ +} diff --git a/inc/mailgun/php-http/discovery/src/Exception/StrategyUnavailableException.php b/inc/mailgun/php-http/discovery/src/Exception/StrategyUnavailableException.php new file mode 100644 index 0000000..89ecf35 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Exception/StrategyUnavailableException.php @@ -0,0 +1,15 @@ +<?php + +namespace Http\Discovery\Exception; + +use Http\Discovery\Exception; + +/** + * This exception is thrown when we cannot use a discovery strategy. This is *not* thrown when + * the discovery fails to find a class. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +class StrategyUnavailableException extends \RuntimeException implements Exception +{ +} diff --git a/inc/mailgun/php-http/discovery/src/HttpAsyncClientDiscovery.php b/inc/mailgun/php-http/discovery/src/HttpAsyncClientDiscovery.php new file mode 100644 index 0000000..6ef60e7 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/HttpAsyncClientDiscovery.php @@ -0,0 +1,36 @@ +<?php + +namespace Http\Discovery; + +use Http\Client\HttpAsyncClient; +use Http\Discovery\Exception\DiscoveryFailedException; + +/** + * Finds an HTTP Asynchronous Client. + * + * @author Joel Wurtz <joel.wurtz@gmail.com> + */ +final class HttpAsyncClientDiscovery extends ClassDiscovery +{ + /** + * Finds an HTTP Async Client. + * + * @return HttpAsyncClient + * + * @throws Exception\NotFoundException + */ + public static function find() + { + try { + $asyncClient = static::findOneByType(HttpAsyncClient::class); + } catch (DiscoveryFailedException $e) { + throw new NotFoundException( + 'No HTTPlug async clients found. Make sure to install a package providing "php-http/async-client-implementation". Example: "php-http/guzzle6-adapter".', + 0, + $e + ); + } + + return static::instantiateClass($asyncClient); + } +} diff --git a/inc/mailgun/php-http/discovery/src/HttpClientDiscovery.php b/inc/mailgun/php-http/discovery/src/HttpClientDiscovery.php new file mode 100644 index 0000000..2654b7e --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/HttpClientDiscovery.php @@ -0,0 +1,36 @@ +<?php + +namespace Http\Discovery; + +use Http\Client\HttpClient; +use Http\Discovery\Exception\DiscoveryFailedException; + +/** + * Finds an HTTP Client. + * + * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> + */ +final class HttpClientDiscovery extends ClassDiscovery +{ + /** + * Finds an HTTP Client. + * + * @return HttpClient + * + * @throws Exception\NotFoundException + */ + public static function find() + { + try { + $client = static::findOneByType(HttpClient::class); + } catch (DiscoveryFailedException $e) { + throw new NotFoundException( + 'No HTTPlug clients found. Make sure to install a package providing "php-http/client-implementation". Example: "php-http/guzzle6-adapter".', + 0, + $e + ); + } + + return static::instantiateClass($client); + } +} diff --git a/inc/mailgun/php-http/discovery/src/MessageFactoryDiscovery.php b/inc/mailgun/php-http/discovery/src/MessageFactoryDiscovery.php new file mode 100644 index 0000000..c21b9bf --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/MessageFactoryDiscovery.php @@ -0,0 +1,36 @@ +<?php + +namespace Http\Discovery; + +use Http\Discovery\Exception\DiscoveryFailedException; +use Http\Message\MessageFactory; + +/** + * Finds a Message Factory. + * + * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> + */ +final class MessageFactoryDiscovery extends ClassDiscovery +{ + /** + * Finds a Message Factory. + * + * @return MessageFactory + * + * @throws Exception\NotFoundException + */ + public static function find() + { + try { + $messageFactory = static::findOneByType(MessageFactory::class); + } catch (DiscoveryFailedException $e) { + throw new NotFoundException( + 'No message factories found. To use Guzzle, Diactoros or Slim Framework factories install php-http/message and the chosen message implementation.', + 0, + $e + ); + } + + return static::instantiateClass($messageFactory); + } +} diff --git a/inc/mailgun/php-http/discovery/src/NotFoundException.php b/inc/mailgun/php-http/discovery/src/NotFoundException.php new file mode 100644 index 0000000..d59dadb --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/NotFoundException.php @@ -0,0 +1,14 @@ +<?php + +namespace Http\Discovery; + +/** + * Thrown when a discovery does not find any matches. + * + * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> + * + * @deprecated since since version 1.0, and will be removed in 2.0. Use {@link \Http\Discovery\Exception\NotFoundException} instead. + */ +final class NotFoundException extends \Http\Discovery\Exception\NotFoundException +{ +} diff --git a/inc/mailgun/php-http/discovery/src/Strategy/CommonClassesStrategy.php b/inc/mailgun/php-http/discovery/src/Strategy/CommonClassesStrategy.php new file mode 100644 index 0000000..cbed15d --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Strategy/CommonClassesStrategy.php @@ -0,0 +1,76 @@ +<?php + +namespace Http\Discovery\Strategy; + +use GuzzleHttp\Psr7\Request as GuzzleRequest; +use Http\Message\MessageFactory\GuzzleMessageFactory; +use Http\Message\StreamFactory\GuzzleStreamFactory; +use Http\Message\UriFactory\GuzzleUriFactory; +use Http\Message\MessageFactory\DiactorosMessageFactory; +use Http\Message\StreamFactory\DiactorosStreamFactory; +use Http\Message\UriFactory\DiactorosUriFactory; +use Zend\Diactoros\Request as DiactorosRequest; +use Http\Message\MessageFactory\SlimMessageFactory; +use Http\Message\StreamFactory\SlimStreamFactory; +use Http\Message\UriFactory\SlimUriFactory; +use Slim\Http\Request as SlimRequest; +use Http\Adapter\Guzzle6\Client as Guzzle6; +use Http\Adapter\Guzzle5\Client as Guzzle5; +use Http\Client\Curl\Client as Curl; +use Http\Client\Socket\Client as Socket; +use Http\Adapter\React\Client as React; +use Http\Adapter\Buzz\Client as Buzz; + +/** + * @internal + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +final class CommonClassesStrategy implements DiscoveryStrategy +{ + /** + * @var array + */ + private static $classes = [ + 'Http\Message\MessageFactory' => [ + ['class' => GuzzleMessageFactory::class, 'condition' => [GuzzleRequest::class, GuzzleMessageFactory::class]], + ['class' => DiactorosMessageFactory::class, 'condition' => [DiactorosRequest::class, DiactorosMessageFactory::class]], + ['class' => SlimMessageFactory::class, 'condition' => [SlimRequest::class, SlimMessageFactory::class]], + ], + 'Http\Message\StreamFactory' => [ + ['class' => GuzzleStreamFactory::class, 'condition' => [GuzzleRequest::class, GuzzleStreamFactory::class]], + ['class' => DiactorosStreamFactory::class, 'condition' => [DiactorosRequest::class, DiactorosStreamFactory::class]], + ['class' => SlimStreamFactory::class, 'condition' => [SlimRequest::class, SlimStreamFactory::class]], + ], + 'Http\Message\UriFactory' => [ + ['class' => GuzzleUriFactory::class, 'condition' => [GuzzleRequest::class, GuzzleUriFactory::class]], + ['class' => DiactorosUriFactory::class, 'condition' => [DiactorosRequest::class, DiactorosUriFactory::class]], + ['class' => SlimUriFactory::class, 'condition' => [SlimRequest::class, SlimUriFactory::class]], + ], + 'Http\Client\HttpAsyncClient' => [ + ['class' => Guzzle6::class, 'condition' => Guzzle6::class], + ['class' => Curl::class, 'condition' => Curl::class], + ['class' => React::class, 'condition' => React::class], + ], + 'Http\Client\HttpClient' => [ + ['class' => Guzzle6::class, 'condition' => Guzzle6::class], + ['class' => Guzzle5::class, 'condition' => Guzzle5::class], + ['class' => Curl::class, 'condition' => Curl::class], + ['class' => Socket::class, 'condition' => Socket::class], + ['class' => Buzz::class, 'condition' => Buzz::class], + ['class' => React::class, 'condition' => React::class], + ], + ]; + + /** + * {@inheritdoc} + */ + public static function getCandidates($type) + { + if (isset(self::$classes[$type])) { + return self::$classes[$type]; + } + + return []; + } +} diff --git a/inc/mailgun/php-http/discovery/src/Strategy/DiscoveryStrategy.php b/inc/mailgun/php-http/discovery/src/Strategy/DiscoveryStrategy.php new file mode 100644 index 0000000..641485a --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Strategy/DiscoveryStrategy.php @@ -0,0 +1,23 @@ +<?php + +namespace Http\Discovery\Strategy; + +use Http\Discovery\Exception\StrategyUnavailableException; + +/** + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +interface DiscoveryStrategy +{ + /** + * Find a resource of a specific type. + * + * @param string $type + * + * @return array The return value is always an array with zero or more elements. Each + * element is an array with two keys ['class' => string, 'condition' => mixed]. + * + * @throws StrategyUnavailableException if we cannot use this strategy. + */ + public static function getCandidates($type); +} diff --git a/inc/mailgun/php-http/discovery/src/Strategy/MockClientStrategy.php b/inc/mailgun/php-http/discovery/src/Strategy/MockClientStrategy.php new file mode 100644 index 0000000..ea464cf --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Strategy/MockClientStrategy.php @@ -0,0 +1,24 @@ +<?php + +namespace Http\Discovery\Strategy; + +use Http\Client\HttpClient; +use Http\Mock\Client as Mock; + +/** + * Find the Mock client. + * + * @author Sam Rapaport <me@samrapdev.com> + */ +final class MockClientStrategy implements DiscoveryStrategy +{ + /** + * {@inheritdoc} + */ + public static function getCandidates($type) + { + return ($type === HttpClient::class) + ? [['class' => Mock::class, 'condition' => Mock::class]] + : []; + } +} diff --git a/inc/mailgun/php-http/discovery/src/Strategy/PuliBetaStrategy.php b/inc/mailgun/php-http/discovery/src/Strategy/PuliBetaStrategy.php new file mode 100644 index 0000000..2666fb3 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/Strategy/PuliBetaStrategy.php @@ -0,0 +1,91 @@ +<?php + +namespace Http\Discovery\Strategy; + +use Http\Discovery\Exception\PuliUnavailableException; +use Puli\Discovery\Api\Discovery; +use Puli\GeneratedPuliFactory; + +/** + * Find candidates using Puli. + * + * @internal + * @final + * + * @author David de Boer <david@ddeboer.nl> + * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> + */ +class PuliBetaStrategy implements DiscoveryStrategy +{ + /** + * @var GeneratedPuliFactory + */ + protected static $puliFactory; + + /** + * @var Discovery + */ + protected static $puliDiscovery; + + /** + * @return GeneratedPuliFactory + * + * @throws PuliUnavailableException + */ + private static function getPuliFactory() + { + if (null === self::$puliFactory) { + if (!defined('PULI_FACTORY_CLASS')) { + throw new PuliUnavailableException('Puli Factory is not available'); + } + + $puliFactoryClass = PULI_FACTORY_CLASS; + + if (!class_exists($puliFactoryClass)) { + throw new PuliUnavailableException('Puli Factory class does not exist'); + } + + self::$puliFactory = new $puliFactoryClass(); + } + + return self::$puliFactory; + } + + /** + * Returns the Puli discovery layer. + * + * @return Discovery + * + * @throws PuliUnavailableException + */ + private static function getPuliDiscovery() + { + if (!isset(self::$puliDiscovery)) { + $factory = self::getPuliFactory(); + $repository = $factory->createRepository(); + + self::$puliDiscovery = $factory->createDiscovery($repository); + } + + return self::$puliDiscovery; + } + + /** + * {@inheritdoc} + */ + public static function getCandidates($type) + { + $returnData = []; + $bindings = self::getPuliDiscovery()->findBindings($type); + + foreach ($bindings as $binding) { + $condition = true; + if ($binding->hasParameterValue('depends')) { + $condition = $binding->getParameterValue('depends'); + } + $returnData[] = ['class' => $binding->getClassName(), 'condition' => $condition]; + } + + return $returnData; + } +} diff --git a/inc/mailgun/php-http/discovery/src/StreamFactoryDiscovery.php b/inc/mailgun/php-http/discovery/src/StreamFactoryDiscovery.php new file mode 100644 index 0000000..7bcc8ce --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/StreamFactoryDiscovery.php @@ -0,0 +1,36 @@ +<?php + +namespace Http\Discovery; + +use Http\Discovery\Exception\DiscoveryFailedException; +use Http\Message\StreamFactory; + +/** + * Finds a Stream Factory. + * + * @author Михаил Красильников <m.krasilnikov@yandex.ru> + */ +final class StreamFactoryDiscovery extends ClassDiscovery +{ + /** + * Finds a Stream Factory. + * + * @return StreamFactory + * + * @throws Exception\NotFoundException + */ + public static function find() + { + try { + $streamFactory = static::findOneByType(StreamFactory::class); + } catch (DiscoveryFailedException $e) { + throw new NotFoundException( + 'No stream factories found. To use Guzzle, Diactoros or Slim Framework factories install php-http/message and the chosen message implementation.', + 0, + $e + ); + } + + return static::instantiateClass($streamFactory); + } +} diff --git a/inc/mailgun/php-http/discovery/src/UriFactoryDiscovery.php b/inc/mailgun/php-http/discovery/src/UriFactoryDiscovery.php new file mode 100644 index 0000000..1eef1e6 --- /dev/null +++ b/inc/mailgun/php-http/discovery/src/UriFactoryDiscovery.php @@ -0,0 +1,36 @@ +<?php + +namespace Http\Discovery; + +use Http\Discovery\Exception\DiscoveryFailedException; +use Http\Message\UriFactory; + +/** + * Finds a URI Factory. + * + * @author David de Boer <david@ddeboer.nl> + */ +final class UriFactoryDiscovery extends ClassDiscovery +{ + /** + * Finds a URI Factory. + * + * @return UriFactory + * + * @throws Exception\NotFoundException + */ + public static function find() + { + try { + $uriFactory = static::findOneByType(UriFactory::class); + } catch (DiscoveryFailedException $e) { + throw new NotFoundException( + 'No uri factories found. To use Guzzle, Diactoros or Slim Framework factories install php-http/message and the chosen message implementation.', + 0, + $e + ); + } + + return static::instantiateClass($uriFactory); + } +} |
