Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract the code to create a transport from the client builder to a transport factory #855

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ branches:
only:
- master
- develop
- /^release\/.+$/

environment:
matrix:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.13",
"monolog/monolog": "^1.3|^2.0",
"php-http/mock-client": "^1.0",
"php-http/mock-client": "^1.3",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.11",
"phpstan/phpstan-phpunit": "^0.11",
Expand Down
16 changes: 12 additions & 4 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,31 @@ parameters:
ignoreErrors:
- '/Argument of an invalid type object supplied for foreach, only iterables are supported/'
- '/Binary operation "\*" between array and 2 results in an error\./'
- '/Http\\Client\\Curl\\Client/'
- '/^Parameter #1 \$object of method ReflectionProperty::setValue\(\) expects object, null given\.$/' # https://github.com/phpstan/phpstan/pull/2340
-
message: /^Cannot assign offset 'os' to array\|string\.$/
path: src/Event.php
-
message: "/^Parameter #1 \\$function of function register_shutdown_function expects callable\\(\\): void, 'register_shutdown…' given\\.$/"
path: src/Transport/HttpTransport.php
-
message: '/^Class Http\\Client\\Curl\\Client not found\.$/'
path: src/HttpClient/HttpClientFactory.php
-
message: '/^Class Http\\Adapter\\Guzzle6\\Client not found\.$/'
path: src/ClientBuilder.php
path: src/HttpClient/HttpClientFactory.php
-
message: '/^Instantiated class Http\\Client\\Curl\\Client not found\.$/'
path: src/HttpClient/HttpClientFactory.php
-
message: '/^Call to static method createWithConfig\(\) on an unknown class Http\\Adapter\\Guzzle6\\Client\.$/'
path: src/ClientBuilder.php
path: src/HttpClient/HttpClientFactory.php
-
message: '/^Access to constant PROXY on an unknown class GuzzleHttp\\RequestOptions\.$/'
path: src/ClientBuilder.php
path: src/HttpClient/HttpClientFactory.php
-
message: '/^Property Sentry\\HttpClient\\HttpClientFactory::\$httpClient \(Http\\Client\\HttpAsyncClient\|null\) does not accept Http\\Client\\Curl\\Client.$/'
path: src/HttpClient/HttpClientFactory.php
excludes_analyse:
- tests/resources
- tests/Fixtures
4 changes: 4 additions & 0 deletions src/Breadcrumb.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,13 @@ public function __construct(string $level, string $type, string $category, ?stri
* @param \ErrorException $exception The exception
*
* @return string
*
* @deprecated since version 2.3, to be removed in 3.0
*/
public static function levelFromErrorException(\ErrorException $exception): string
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);

switch ($exception->getSeverity()) {
case E_DEPRECATED:
case E_USER_DEPRECATED:
Expand Down
134 changes: 57 additions & 77 deletions src/ClientBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,17 @@

namespace Sentry;

use GuzzleHttp\RequestOptions as GuzzleHttpClientOptions;
use Http\Adapter\Guzzle6\Client as GuzzleHttpClient;
use Http\Client\Common\Plugin as PluginInterface;
use Http\Client\Common\Plugin\AuthenticationPlugin;
use Http\Client\Common\Plugin\BaseUriPlugin;
use Http\Client\Common\Plugin\DecoderPlugin;
use Http\Client\Common\Plugin\ErrorPlugin;
use Http\Client\Common\Plugin\HeaderSetPlugin;
use Http\Client\Common\Plugin\RetryPlugin;
use Http\Client\Common\PluginClient;
use Http\Client\Curl\Client as CurlHttpClient;
use Http\Client\HttpAsyncClient;
use Http\Discovery\ClassDiscovery;
use Http\Discovery\HttpAsyncClientDiscovery;
use Http\Discovery\MessageFactoryDiscovery;
use Http\Discovery\StreamFactoryDiscovery;
use Http\Discovery\UriFactoryDiscovery;
use Http\Message\MessageFactory as MessageFactoryInterface;
use Http\Message\StreamFactory as StreamFactoryInterface;
use Http\Message\UriFactory as UriFactoryInterface;
use Jean85\PrettyVersions;
use Sentry\HttpClient\Authentication\SentryAuthentication;
use Sentry\HttpClient\Plugin\GzipEncoderPlugin;
use Sentry\HttpClient\HttpClientFactory;
use Sentry\HttpClient\PluggableHttpClientFactory;
use Sentry\Integration\ErrorListenerIntegration;
use Sentry\Integration\ExceptionListenerIntegration;
use Sentry\Integration\FatalErrorListenerIntegration;
Expand All @@ -36,8 +24,8 @@
use Sentry\Serializer\RepresentationSerializerInterface;
use Sentry\Serializer\Serializer;
use Sentry\Serializer\SerializerInterface;
use Sentry\Transport\HttpTransport;
use Sentry\Transport\NullTransport;
use Sentry\Transport\DefaultTransportFactory;
use Sentry\Transport\TransportFactoryInterface;
use Sentry\Transport\TransportInterface;

/**
Expand Down Expand Up @@ -67,6 +55,11 @@ final class ClientBuilder implements ClientBuilderInterface
*/
private $messageFactory;

/**
* @var TransportFactoryInterface|null The transport factory
*/
private $transportFactory;

/**
* @var TransportInterface|null The transport
*/
Expand Down Expand Up @@ -144,6 +137,8 @@ public function getOptions(): Options
*/
public function setUriFactory(UriFactoryInterface $uriFactory): ClientBuilderInterface
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);

$this->uriFactory = $uriFactory;

return $this;
Expand All @@ -154,6 +149,8 @@ public function setUriFactory(UriFactoryInterface $uriFactory): ClientBuilderInt
*/
public function setMessageFactory(MessageFactoryInterface $messageFactory): ClientBuilderInterface
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);

$this->messageFactory = $messageFactory;

return $this;
Expand All @@ -164,6 +161,8 @@ public function setMessageFactory(MessageFactoryInterface $messageFactory): Clie
*/
public function setTransport(TransportInterface $transport): ClientBuilderInterface
RageZBla marked this conversation as resolved.
Show resolved Hide resolved
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0. Use the setTransportFactory() method instead.', __METHOD__), E_USER_DEPRECATED);

$this->transport = $transport;

return $this;
Expand All @@ -174,6 +173,8 @@ public function setTransport(TransportInterface $transport): ClientBuilderInterf
*/
public function setHttpClient(HttpAsyncClient $httpClient): ClientBuilderInterface
RageZBla marked this conversation as resolved.
Show resolved Hide resolved
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);

$this->httpClient = $httpClient;

return $this;
Expand All @@ -184,6 +185,8 @@ public function setHttpClient(HttpAsyncClient $httpClient): ClientBuilderInterfa
*/
public function addHttpClientPlugin(PluginInterface $plugin): ClientBuilderInterface
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);

$this->httpClientPlugins[] = $plugin;

return $this;
Expand All @@ -194,6 +197,8 @@ public function addHttpClientPlugin(PluginInterface $plugin): ClientBuilderInter
*/
public function removeHttpClientPlugin(string $className): ClientBuilderInterface
RageZBla marked this conversation as resolved.
Show resolved Hide resolved
{
@trigger_error(sprintf('Method %s() is deprecated since version 2.3 and will be removed in 3.0.', __METHOD__), E_USER_DEPRECATED);

foreach ($this->httpClientPlugins as $index => $httpClientPlugin) {
if (!$httpClientPlugin instanceof $className) {
continue;
Expand Down Expand Up @@ -274,40 +279,17 @@ public function getClient(): ClientInterface
}

/**
* Creates a new instance of the HTTP client.
* Sets the transport factory.
*
* @return PluginClient
* @param TransportFactoryInterface $transportFactory The transport factory
*
* @return $this
*/
private function createHttpClientInstance(): PluginClient
public function setTransportFactory(TransportFactoryInterface $transportFactory): ClientBuilderInterface
{
if (null === $this->uriFactory) {
throw new \RuntimeException('The PSR-7 URI factory must be set.');
}
$this->transportFactory = $transportFactory;

if (null === $this->streamFactory) {
throw new \RuntimeException('The PSR-17 stream factory must be set.');
}

if (null === $this->httpClient) {
throw new \RuntimeException('The PSR-18 HTTP client must be set.');
}

if (null !== $this->options->getDsn()) {
$this->addHttpClientPlugin(new BaseUriPlugin($this->uriFactory->createUri($this->options->getDsn())));
}

$this->addHttpClientPlugin(new HeaderSetPlugin(['User-Agent' => $this->sdkIdentifier . '/' . $this->sdkVersion]));
$this->addHttpClientPlugin(new AuthenticationPlugin(new SentryAuthentication($this->options, $this->sdkIdentifier, $this->sdkVersion)));

if ($this->options->isCompressionEnabled()) {
$this->addHttpClientPlugin(new GzipEncoderPlugin($this->streamFactory));
$this->addHttpClientPlugin(new DecoderPlugin());
}

$this->addHttpClientPlugin(new RetryPlugin(['retries' => $this->options->getSendAttempts()]));
$this->addHttpClientPlugin(new ErrorPlugin());

return new PluginClient($this->httpClient, $this->httpClientPlugins);
return $this;
}

/**
Expand All @@ -321,38 +303,9 @@ private function createTransportInstance(): TransportInterface
return $this->transport;
}

if (null === $this->options->getDsn()) {
return new NullTransport();
}
$transportFactory = $this->transportFactory ?? $this->createDefaultTransportFactory();

$this->messageFactory = $this->messageFactory ?? MessageFactoryDiscovery::find();
$this->streamFactory = $this->streamFactory ?? StreamFactoryDiscovery::find();
$this->uriFactory = $this->uriFactory ?? UriFactoryDiscovery::find();

if (null !== $this->options->getHttpProxy()) {
if (null !== $this->httpClient) {
throw new \RuntimeException('The `http_proxy` option does not work together with a custom client.');
}

if (ClassDiscovery::safeClassExists(GuzzleHttpClient::class)) {
/** @psalm-suppress InvalidPropertyAssignmentValue */
$this->httpClient = GuzzleHttpClient::createWithConfig([
GuzzleHttpClientOptions::PROXY => $this->options->getHttpProxy(),
]);
} elseif (ClassDiscovery::safeClassExists(CurlHttpClient::class)) {
/** @psalm-suppress InvalidPropertyAssignmentValue */
$this->httpClient = new CurlHttpClient(null, null, [
CURLOPT_PROXY => $this->options->getHttpProxy(),
]);
}

throw new \RuntimeException('The `http_proxy` option requires either the `php-http/curl-client` or the `php-http/guzzle6-adapter` package to be installed.');
}

/** @psalm-suppress PossiblyInvalidPropertyAssignmentValue */
$this->httpClient = $this->httpClient ?? HttpAsyncClientDiscovery::find();

return new HttpTransport($this->options, $this->createHttpClientInstance(), $this->messageFactory);
return $transportFactory->create($this->options);
}

/**
Expand All @@ -367,4 +320,31 @@ private function createEventFactory(): EventFactoryInterface

return new EventFactory($this->serializer, $this->representationSerializer, $this->options, $this->sdkIdentifier, $this->sdkVersion);
}

/**
* Creates a new instance of the {@see DefaultTransportFactory} factory.
*
* @return DefaultTransportFactory
*/
private function createDefaultTransportFactory(): DefaultTransportFactory
RageZBla marked this conversation as resolved.
Show resolved Hide resolved
{
$this->messageFactory = $this->messageFactory ?? MessageFactoryDiscovery::find();
$this->uriFactory = $this->uriFactory ?? UriFactoryDiscovery::find();
$this->streamFactory = $this->streamFactory ?? StreamFactoryDiscovery::find();

$httpClientFactory = new HttpClientFactory(
$this->uriFactory,
$this->messageFactory,
$this->streamFactory,
$this->httpClient,
$this->sdkIdentifier,
$this->sdkVersion
);

if (!empty($this->httpClientPlugins)) {
$httpClientFactory = new PluggableHttpClientFactory($httpClientFactory, $this->httpClientPlugins);
}

return new DefaultTransportFactory($this->messageFactory, $httpClientFactory);
}
}
15 changes: 15 additions & 0 deletions src/ClientBuilderInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@
use Http\Message\UriFactory as UriFactoryInterface;
use Sentry\Serializer\RepresentationSerializerInterface;
use Sentry\Serializer\SerializerInterface;
use Sentry\Transport\TransportFactoryInterface;
use Sentry\Transport\TransportInterface;

/**
* A configurable builder for Client objects.
*
* @author Stefano Arlandini <[email protected]>
*
* @method self setTransportFactory(TransportFactoryInterface $transportFactory)
*/
interface ClientBuilderInterface
{
Expand All @@ -41,6 +44,8 @@ public function getOptions(): Options;
* @param UriFactoryInterface $uriFactory The factory
*
* @return $this
*
* @deprecated Since version 2.3, to be removed in 3.0
*/
public function setUriFactory(UriFactoryInterface $uriFactory): self;

Expand All @@ -50,6 +55,8 @@ public function setUriFactory(UriFactoryInterface $uriFactory): self;
* @param MessageFactoryInterface $messageFactory The factory
*
* @return $this
*
* @deprecated Since version 2.3, to be removed in 3.0
*/
public function setMessageFactory(MessageFactoryInterface $messageFactory): self;

Expand All @@ -59,6 +66,8 @@ public function setMessageFactory(MessageFactoryInterface $messageFactory): self
* @param TransportInterface $transport The transport
*
* @return $this
*
* @deprecated Since version 2.3, to be removed in 3.0
*/
public function setTransport(TransportInterface $transport): self;

Expand All @@ -68,6 +77,8 @@ public function setTransport(TransportInterface $transport): self;
* @param HttpAsyncClient $httpClient The HTTP client
*
* @return $this
*
* @deprecated Since version 2.3, to be removed in 3.0
*/
public function setHttpClient(HttpAsyncClient $httpClient): self;

Expand All @@ -77,6 +88,8 @@ public function setHttpClient(HttpAsyncClient $httpClient): self;
* @param PluginInterface $plugin The plugin instance
*
* @return $this
*
* @deprecated Since version 2.3, to be removed in 3.0
*/
public function addHttpClientPlugin(PluginInterface $plugin): self;

Expand All @@ -86,6 +99,8 @@ public function addHttpClientPlugin(PluginInterface $plugin): self;
* @param string $className The class name
*
* @return $this
*
* @deprecated Since version 2.3, to be removed in 3.0
*/
public function removeHttpClientPlugin(string $className): self;

Expand Down
1 change: 0 additions & 1 deletion src/HttpClient/Authentication/SentryAuthentication.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public function authenticate(RequestInterface $request): RequestInterface
$data = [
'sentry_version' => Client::PROTOCOL_VERSION,
'sentry_client' => $this->sdkIdentifier . '/' . $this->sdkVersion,
'sentry_timestamp' => sprintf('%F', microtime(true)),
'sentry_key' => $publicKey,
];

Expand Down
Loading