diff --git a/psalm-baseline.xml b/psalm-baseline.xml index b0f323f..821d2bf 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,11 +1,2 @@ - - - - object - - - $locator() - - - + diff --git a/psalm.xml b/psalm.xml index c090de7..1015d2f 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,5 +1,8 @@ diff --git a/src/Api.php b/src/Api.php index f596653..4f9dc05 100644 --- a/src/Api.php +++ b/src/Api.php @@ -8,6 +8,7 @@ use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\Psr18ClientDiscovery; use Prismic\Document\Fragment\DocumentLink; +use Prismic\Exception\InvalidArgument; use Prismic\Exception\InvalidPreviewToken; use Prismic\Exception\JsonError; use Prismic\Exception\PrismicError; @@ -121,44 +122,64 @@ public static function get( ?ResultSetFactory $resultSetFactory = null, ?CacheItemPoolInterface $cache = null ): self { - /** - * @return ClientInterface|RequestFactoryInterface|UriFactoryInterface - */ - $factory = static function (?object $given, callable $locator, string $message): object { - if ($given) { - return $given; - } - - /** @psalm-suppress InvalidCatch */ - try { - return $locator(); - } catch (DiscoveryError $error) { - throw new RuntimeError( - $message, - (int) $error->getCode(), - $error - ); - } - }; - - /** @psalm-suppress ArgumentTypeCoercion */ + /** @psalm-suppress PossiblyInvalidArgument */ return new self( $apiBaseUri, - $factory($httpClient, static function (): ClientInterface { - return Psr18ClientDiscovery::find(); - }, 'An HTTP client cannot be determined.'), + $httpClient ?? self::psrFactory( + ClientInterface::class, + 'An HTTP client cannot be determined.' + ), (string) $accessToken === '' ? null : $accessToken, - $factory($requestFactory, static function (): RequestFactoryInterface { - return Psr17FactoryDiscovery::findRequestFactory(); - }, 'A request factory cannot be determined'), - $factory($uriFactory, static function (): UriFactoryInterface { - return Psr17FactoryDiscovery::findUriFactory(); - }, 'A URI factory cannot be determined'), + $requestFactory ?? self::psrFactory( + RequestFactoryInterface::class, + 'A request factory cannot be determined' + ), + $uriFactory ?? self::psrFactory( + UriFactoryInterface::class, + 'A URI factory cannot be determined' + ), $resultSetFactory ?? new StandardResultSetFactory(), $cache ); } + /** + * phpcs:disable Generic.Files.LineLength.TooLong, Squiz.Commenting.FunctionComment.SpacingAfterParamType + * @param T|null $instance + * @param class-string|class-string|class-string $type + * + * @return ClientInterface|RequestFactoryInterface|UriFactoryInterface + * + * @template T of object + */ + private static function psrFactory(string $type, string $message) + { + try { + switch ($type) { + case ClientInterface::class: + return Psr18ClientDiscovery::find(); + + case RequestFactoryInterface::class: + return Psr17FactoryDiscovery::findRequestFactory(); + + case UriFactoryInterface::class: + return Psr17FactoryDiscovery::findUriFactory(); + + default: + throw new InvalidArgument(sprintf( + 'Invalid class-string: "%s"', + $type + )); + } + } catch (DiscoveryError $error) { + throw new RuntimeError( + $message, + (int) $error->getCode(), + $error + ); + } + } + public function host(): string { return $this->baseUri->getHost(); diff --git a/src/ApiClient.php b/src/ApiClient.php index 89eeec4..ba0e46f 100644 --- a/src/ApiClient.php +++ b/src/ApiClient.php @@ -30,6 +30,11 @@ interface ApiClient */ public const EXPERIMENTS_COOKIE = 'io.prismic.experiment'; + /** + * The maximum page size of result sets returned by the API + */ + public const MAX_PAGE_SIZE = 100; + /** Return the host name of the api endpoint */ public function host(): string; diff --git a/src/Document/Fragment/Embed.php b/src/Document/Fragment/Embed.php index e48cc80..363a974 100644 --- a/src/Document/Fragment/Embed.php +++ b/src/Document/Fragment/Embed.php @@ -73,7 +73,6 @@ private function setAttributes(iterable $attributes): void private function setAttribute(string $name, $value): void { /** - * @psalm-suppress RedundantConditionGivenDocblockType * @psalm-suppress DocblockTypeContradiction */ if ($value !== null && ! is_scalar($value)) { diff --git a/src/Query.php b/src/Query.php index b8b2524..6f96e10 100644 --- a/src/Query.php +++ b/src/Query.php @@ -19,6 +19,7 @@ /** * @psalm-type QueryParams = array|null> + * @final */ class Query { @@ -145,6 +146,8 @@ private function defaultParameters(): array * Limit document count per page. * * The default is 20 per page and the maximum is 100 + * + * @param positive-int $count */ public function resultsPerPage(int $count): self { @@ -153,6 +156,8 @@ public function resultsPerPage(int $count): self /** * Set the result page to retrieve. + * + * @param positive-int $page */ public function page(int $page): self { diff --git a/test/Smoke/TestCase.php b/test/Smoke/TestCase.php index e66c416..325aa8a 100644 --- a/test/Smoke/TestCase.php +++ b/test/Smoke/TestCase.php @@ -15,8 +15,11 @@ use Psr\Http\Client\ClientInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use function assert; use function file_exists; use function getenv; +use function is_array; +use function is_string; class TestCase extends PHPUnitTestCase { @@ -65,11 +68,23 @@ protected function compileEndPoints(): array /** @psalm-suppress MissingFile $content */ $content = require $configPath; + if (! is_array($content)) { + return $endpoints; + } $configured = $content['endpoints'] ?? []; + assert(is_array($configured)); foreach ($configured as $spec) { - $endpoints[$spec['url']] = $spec['token']; + assert(is_array($spec)); + $url = isset($spec['url']) && is_string($spec['url']) ? $spec['url'] : null; + $token = isset($spec['token']) && is_string($spec['token']) ? $spec['token'] : null; + + if (! $url) { + continue; + } + + $endpoints[$url] = $token; } return $endpoints; diff --git a/test/Unit/ResultSet/StandardResultTest.php b/test/Unit/ResultSet/StandardResultTest.php index ee209fb..3d9eeaa 100644 --- a/test/Unit/ResultSet/StandardResultTest.php +++ b/test/Unit/ResultSet/StandardResultTest.php @@ -4,6 +4,8 @@ namespace PrismicTest\ResultSet; +use DateTimeImmutable; +use DateTimeZone; use Prismic\Document; use Prismic\Json; use Prismic\ResultSet\StandardResultSet; @@ -27,13 +29,21 @@ public function testBasicAccessors(): void $this->assertSame(1, $this->resultSet->currentPageNumber()); $this->assertSame(99, $this->resultSet->totalResults()); $this->assertSame(99, $this->resultSet->pageCount()); - $this->assertNotNull($this->resultSet->expiresAt()); $this->assertSame('https://example.com/next', $this->resultSet->nextPage()); $this->assertSame('https://example.com/prev', $this->resultSet->previousPage()); $this->assertCount(2, $this->resultSet->results()); $this->assertContainsOnlyInstancesOf(DocumentData::class, $this->resultSet->results()); } + public function testThatTheCacheExpiryDateWillBeTheCurrentTimeInUTC(): void + { + $now = new DateTimeImmutable('now', new DateTimeZone('UTC')); + self::assertInstanceOf(DateTimeImmutable::class, $now); + + self::assertEqualsWithDelta($now, $this->resultSet->expiresAt(), 0.0001); + self::assertEquals('UTC', $this->resultSet->expiresAt()->getTimezone()->getName()); + } + public function testThatResultSetsAreCountable(): void { $this->assertCount(2, $this->resultSet);