Skip to content

Commit 6838fc2

Browse files
committed
Updated dependencies, include newer Symfony versions
1 parent 025ce6c commit 6838fc2

2 files changed

Lines changed: 110 additions & 54 deletions

File tree

composer.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"require": {
3434
"php": "^7.3 || ^8.0",
3535
"ext-json": "*",
36-
"symfony/options-resolver": "^4.4 || ^5 || ^6",
36+
"symfony/options-resolver": "^4.4 || ^5 || ^6 || ^7 || ^8",
3737
"psr/cache": "^1 || ^2 || ^3",
3838
"psr/simple-cache": "^1 || ^2 || ^3",
3939
"psr/event-dispatcher": "^1",
@@ -44,22 +44,22 @@
4444
"psr/http-client-implementation": "^1",
4545
"psr/http-factory": "^1",
4646
"psr/http-factory-implementation": "^1",
47-
"psr/http-message": "^1"
47+
"psr/http-message": "^1 || ^2"
4848
},
4949
"require-dev": {
5050
"nyholm/psr7": "^1.2",
5151
"php-http/mock-client": "^1.2",
52-
"slevomat/coding-standard": "^8.8",
53-
"squizlabs/php_codesniffer": "^3.5.8",
54-
"symfony/cache": "^4.4 || ^5 || ^6",
55-
"symfony/event-dispatcher": "^4.4 || ^5 || ^6",
52+
"slevomat/coding-standard": "^8.27.1",
53+
"squizlabs/php_codesniffer": "^4.0.1",
54+
"symfony/cache": "^4.4 || ^5 || ^6 || ^7 || ^8",
55+
"symfony/event-dispatcher": "^4.4 || ^5 || ^6 || ^7 || ^8",
5656
"phpstan/phpstan": "^1.8.1",
5757
"phpstan/phpstan-deprecation-rules": "^1.1",
5858
"spaze/phpstan-disallowed-calls": "^2.11",
59-
"phpunit/phpunit": "^9.6.3",
59+
"phpunit/phpunit": "^12.5.8",
6060
"php-http/guzzle7-adapter": "^1.0",
6161
"monolog/monolog": "^2.9.1 || ^3.0",
62-
"php-http/cache-plugin": "^1.7",
62+
"php-http/cache-plugin": "^1.7 || ^2.0",
6363
"jeroen/psr-log-test-doubles": "^2.1 || ^3"
6464
},
6565
"scripts": {

lib/Tmdb/Client.php

Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
use Psr\Http\Message\ResponseFactoryInterface;
2323
use Psr\Http\Message\StreamFactoryInterface;
2424
use Psr\Http\Message\UriFactoryInterface;
25+
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
26+
use Symfony\Component\OptionsResolver\Options;
2527
use Symfony\Component\OptionsResolver\OptionsResolver;
2628
use Tmdb\HttpClient\HttpClient;
2729
use Tmdb\Token\Api\ApiToken;
@@ -64,6 +66,11 @@ class Client
6466
*/
6567
private $options = [];
6668

69+
private static function debugType($value): string
70+
{
71+
return is_object($value) ? get_class($value) : gettype($value);
72+
}
73+
6774
/**
6875
* Construct our client
6976
*
@@ -95,52 +102,25 @@ protected function configureOptions(array $options)
95102
'base_uri' => null,
96103
'api_token' => null,
97104
'guest_session_token' => null,
98-
'http' => function (OptionsResolver $optionsResolver) {
99-
$optionsResolver->setDefaults(
100-
[
101-
'client' => null,
102-
'request_factory' => null,
103-
'response_factory' => null,
104-
'stream_factory' => null,
105-
'uri_factory' => null,
106-
]
107-
);
108-
$optionsResolver->setRequired(
109-
[
110-
'client',
111-
'request_factory',
112-
'response_factory',
113-
'stream_factory',
114-
'uri_factory'
115-
]
116-
);
117-
$optionsResolver->setAllowedTypes('client', [ClientInterface::class, 'null']);
118-
$optionsResolver->setAllowedTypes('request_factory', [RequestFactoryInterface::class, 'null']);
119-
$optionsResolver->setAllowedTypes('response_factory', [ResponseFactoryInterface::class, 'null']);
120-
$optionsResolver->setAllowedTypes('stream_factory', [StreamFactoryInterface::class, 'null']);
121-
$optionsResolver->setAllowedTypes('uri_factory', [UriFactoryInterface::class, 'null']);
122-
},
123-
'hydration' => function (OptionsResolver $optionsResolver) {
124-
$optionsResolver->setDefaults(
125-
[
126-
'event_listener_handles_hydration' => false,
127-
'only_for_specified_models' => []
128-
]
129-
);
130-
$optionsResolver->setAllowedTypes('event_listener_handles_hydration', ['bool']);
131-
// @todo 4.1 validate these are actually models
132-
$optionsResolver->setAllowedTypes('only_for_specified_models', ['array']);
133-
},
134-
'event_dispatcher' => function (OptionsResolver $optionsResolver) {
135-
$optionsResolver->setDefaults(
136-
[
137-
'adapter' => null
138-
]
139-
);
140-
141-
$optionsResolver->setRequired(['adapter']);
142-
$optionsResolver->setAllowedTypes('adapter', [EventDispatcherInterface::class]);
143-
}
105+
'http' => [
106+
'client' => null,
107+
'request_factory' => null,
108+
'response_factory' => null,
109+
'stream_factory' => null,
110+
'uri_factory' => null,
111+
],
112+
'hydration' => [
113+
'event_listener_handles_hydration' => false,
114+
'only_for_specified_models' => [],
115+
],
116+
'event_dispatcher' => [
117+
'adapter' => new class implements EventDispatcherInterface {
118+
public function dispatch(object $event)
119+
{
120+
return $event;
121+
}
122+
},
123+
],
144124
]
145125
);
146126

@@ -161,6 +141,82 @@ protected function configureOptions(array $options)
161141
$resolver->setAllowedTypes('secure', ['bool']);
162142
$resolver->setAllowedTypes('http', ['array']);
163143
$resolver->setAllowedTypes('event_dispatcher', ['array']);
144+
$resolver->setAllowedTypes('hydration', ['array']);
145+
146+
$resolver->setNormalizer('http', function (Options $options, $value) {
147+
if (!is_array($value)) {
148+
throw new InvalidOptionsException(sprintf('The option "http" is expected to be of type "array", but is of type "%s".', self::debugType($value)));
149+
}
150+
151+
$allowedKeys = ['client', 'request_factory', 'response_factory', 'stream_factory', 'uri_factory'];
152+
$unknownKeys = array_diff(array_keys($value), $allowedKeys);
153+
if (!empty($unknownKeys)) {
154+
throw new InvalidOptionsException(sprintf('The option "http" has unknown keys: %s.', implode(', ', $unknownKeys)));
155+
}
156+
157+
foreach ($allowedKeys as $key) {
158+
if (!array_key_exists($key, $value)) {
159+
throw new InvalidOptionsException(sprintf('The option "http" must define the key "%s".', $key));
160+
}
161+
}
162+
163+
if ($value['client'] !== null && !$value['client'] instanceof ClientInterface) {
164+
throw new InvalidOptionsException(sprintf('The option "http[client]" is expected to be an instance of %s or null, but got %s.', ClientInterface::class, self::debugType($value['client'])));
165+
}
166+
if ($value['request_factory'] !== null && !$value['request_factory'] instanceof RequestFactoryInterface) {
167+
throw new InvalidOptionsException(sprintf('The option "http[request_factory]" is expected to be an instance of %s or null, but got %s.', RequestFactoryInterface::class, self::debugType($value['request_factory'])));
168+
}
169+
if ($value['response_factory'] !== null && !$value['response_factory'] instanceof ResponseFactoryInterface) {
170+
throw new InvalidOptionsException(sprintf('The option "http[response_factory]" is expected to be an instance of %s or null, but got %s.', ResponseFactoryInterface::class, self::debugType($value['response_factory'])));
171+
}
172+
if ($value['stream_factory'] !== null && !$value['stream_factory'] instanceof StreamFactoryInterface) {
173+
throw new InvalidOptionsException(sprintf('The option "http[stream_factory]" is expected to be an instance of %s or null, but got %s.', StreamFactoryInterface::class, self::debugType($value['stream_factory'])));
174+
}
175+
if ($value['uri_factory'] !== null && !$value['uri_factory'] instanceof UriFactoryInterface) {
176+
throw new InvalidOptionsException(sprintf('The option "http[uri_factory]" is expected to be an instance of %s or null, but got %s.', UriFactoryInterface::class, self::debugType($value['uri_factory'])));
177+
}
178+
179+
return $value;
180+
});
181+
182+
$resolver->setNormalizer('hydration', function (Options $options, $value) {
183+
if (!is_array($value)) {
184+
throw new InvalidOptionsException(sprintf('The option "hydration" is expected to be of type "array", but is of type "%s".', self::debugType($value)));
185+
}
186+
187+
$allowedKeys = ['event_listener_handles_hydration', 'only_for_specified_models'];
188+
$unknownKeys = array_diff(array_keys($value), $allowedKeys);
189+
if (!empty($unknownKeys)) {
190+
throw new InvalidOptionsException(sprintf('The option "hydration" has unknown keys: %s.', implode(', ', $unknownKeys)));
191+
}
192+
193+
if (!array_key_exists('event_listener_handles_hydration', $value) || !is_bool($value['event_listener_handles_hydration'])) {
194+
throw new InvalidOptionsException('The option "hydration[event_listener_handles_hydration]" is expected to be of type "bool".');
195+
}
196+
if (!array_key_exists('only_for_specified_models', $value) || !is_array($value['only_for_specified_models'])) {
197+
throw new InvalidOptionsException('The option "hydration[only_for_specified_models]" is expected to be of type "array".');
198+
}
199+
200+
return $value;
201+
});
202+
203+
$resolver->setNormalizer('event_dispatcher', function (Options $options, $value) {
204+
if (!is_array($value)) {
205+
throw new InvalidOptionsException(sprintf('The option "event_dispatcher" is expected to be of type "array", but is of type "%s".', self::debugType($value)));
206+
}
207+
208+
$allowedKeys = ['adapter'];
209+
$unknownKeys = array_diff(array_keys($value), $allowedKeys);
210+
if (!empty($unknownKeys)) {
211+
throw new InvalidOptionsException(sprintf('The option "event_dispatcher" has unknown keys: %s.', implode(', ', $unknownKeys)));
212+
}
213+
214+
if (!array_key_exists('adapter', $value) || !$value['adapter'] instanceof EventDispatcherInterface) {
215+
throw new InvalidOptionsException(sprintf('The option "event_dispatcher[adapter]" is expected to be an instance of %s.', EventDispatcherInterface::class));
216+
}
217+
218+
return $value;
219+
});
164220

165221
// @todo 4.1 fix smelly stuff
166222
$resolver->setAllowedTypes(

0 commit comments

Comments
 (0)