├── .githooks
├── pre-commit
└── pre-push
├── .github
├── dependabot.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE-MIT
├── README.md
├── assets
└── obdb.png
├── composer.json
├── examples
├── builder.php
└── simple.php
├── justfile
├── phpstan.neon.dist
├── phpunit.xml.dist
├── pint.json
├── rector.php
├── src
├── Builder.php
├── Client.php
├── Contracts
│ ├── Concerns
│ │ └── Arrayable.php
│ ├── ConnectorContract.php
│ ├── Resources
│ │ └── BreweriesContract.php
│ └── ResponseContract.php
├── Enums
│ ├── HttpMethod.php
│ └── MediaType.php
├── Exceptions
│ ├── ConnectorException.php
│ ├── ErrorException.php
│ └── UnserializableResponseException.php
├── Http
│ └── Connector.php
├── OpenBreweryDb.php
├── Resources
│ └── Breweries.php
├── Responses
│ ├── Breweries
│ │ ├── AutocompleteResponse.php
│ │ ├── FindResponse.php
│ │ ├── ListResponse.php
│ │ └── MetadataResponse.php
│ └── Concerns
│ │ └── ArrayAccessible.php
└── ValueObjects
│ ├── Connector
│ ├── BaseUri.php
│ ├── Headers.php
│ ├── QueryParams.php
│ └── Response.php
│ ├── Payload.php
│ ├── ResourceUri.php
│ └── Version.php
└── tests
├── Architecture.php
├── Pest.php
├── Resources
├── AutocompleteBreweries.php
├── FindBrewery.php
├── ListBreweries.php
├── MetadataBreweries.php
├── RandomBreweries.php
└── SearchBreweries.php
└── Version.php
/.githooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | composer run fmt
4 |
--------------------------------------------------------------------------------
/.githooks/pre-push:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | composer run ci
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 |
3 | updates:
4 | - package-ecosystem: 'composer'
5 | directory: '/'
6 | schedule:
7 | interval: 'weekly'
8 | open-pull-requests-limit: 5
9 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [ 'push', 'pull_request' ]
4 |
5 | jobs:
6 | ci:
7 | runs-on: ${{ matrix.os }}
8 | strategy:
9 | fail-fast: true
10 | matrix:
11 | os: [ ubuntu-latest ]
12 | php: [ 8.3 ]
13 | dependency-version: [ prefer-stable ]
14 |
15 | name: PHP ${{ matrix.php }} | OS ${{ matrix.os }} | Dependency Resolution ${{ matrix.dependency-version }}
16 |
17 | steps:
18 |
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 |
22 | - name: Cache dependencies
23 | uses: actions/cache@v1
24 | with:
25 | path: ~/.composer/cache/files
26 | key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
27 |
28 | - name: Setup PHP
29 | uses: shivammathur/setup-php@v2
30 | with:
31 | php-version: ${{ matrix.php }}
32 |
33 | - name: Install Composer dependencies
34 | run: composer update --${{ matrix.dependency-version }} --no-interaction --prefer-dist
35 |
36 | - name: Run CI checks
37 | run: composer run ci
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | vendor
3 | phpunit.xml
4 | .DS_STORE
5 | composer.lock
6 | .phpdoc
7 | .vscode
8 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Joey McKenzie
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 |
5 |

6 |

7 |
8 |
9 |
10 | (Un)official PHP bindings for the [Open Brewery DB API](https://openbrewerydb.org/). Open Brewery DB provides a public
11 | dataset for breweries around the world, as well as offering an API to retrieve data in various forms. This library aims to
12 | provide straight and easy-to-use PHP bindings for querying the API. The library is inspired by the [Open AI client for PHP](https://github.com/openai-php/client) - please give it star as well!
13 |
14 | To get started, first install the package with composer:
15 |
16 | ```shell
17 | $ composer require joeymckenzie/openbrewerydb-php-client
18 | ```
19 |
20 | Next, spin up a new client within your code and fire away!
21 |
22 | ```php
23 | breweries()->list([
35 | 'by_city' => 'Sacramento',
36 | ]);
37 | var_dump($breweries);
38 |
39 | // Retrieve various metadata about breweries from the API
40 | $metadata = $client->breweries()->metadata();
41 | var_dump($metadata);
42 |
43 | // Get a random brewery with a specified page size
44 | $randomBrewery = $client->breweries()->random(5);
45 | var_dump($randomBrewery);
46 | ```
47 |
48 | The library relies on autodiscovery and will use whichever package that implements PSR-17 within your composer
49 | dependencies. You are free to use the HTTP client of you choice, though a popular package
50 | is [Guzzle](https://docs.guzzlephp.org/en/stable/).
51 |
52 | Though I am not affiliated with organization itself, check out the entire set of APIs offered by Open Brewery DB, check
53 | out the docs on their [website](https://openbrewerydb.org/documentation).
54 |
--------------------------------------------------------------------------------
/assets/obdb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JoeyMckenzie/openbrewerydb-php-client/81f7bc75261b23339fd609c5cf3b753e6463cfdf/assets/obdb.png
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "joeymckenzie/openbrewerydb-php-client",
3 | "description": "An Open Brewery DB API client for PHP.",
4 | "type": "library",
5 | "license": "MIT",
6 | "version": "0.9.0",
7 | "homepage": "https://github.com/joeymckenzie/openbrewerydb-php-client",
8 | "autoload": {
9 | "psr-4": {
10 | "OpenBreweryDb\\": "src/"
11 | },
12 | "files": [
13 | "src/OpenBreweryDb.php"
14 | ]
15 | },
16 | "autoload-dev": {
17 | "psr-4": {
18 | "Tests\\": "tests/"
19 | }
20 | },
21 | "authors": [
22 | {
23 | "name": "Joey McKenzie",
24 | "email": "joey.mckenzie27@gmail.com",
25 | "homepage": "https://github.com/joeymckenzie"
26 | }
27 | ],
28 | "minimum-stability": "stable",
29 | "require": {
30 | "php": ">=8.3",
31 | "php-http/discovery": "^1.19.2",
32 | "php-http/multipart-stream-builder": "^1.3.0",
33 | "psr/http-client": "^1.0.3",
34 | "psr/http-client-implementation": "*",
35 | "psr/http-factory-implementation": "*",
36 | "psr/http-message": "^2.0.0"
37 | },
38 | "require-dev": {
39 | "guzzlehttp/guzzle": "^7.8",
40 | "laravel/pint": "^1.13",
41 | "pestphp/pest": "^2.32",
42 | "pestphp/pest-plugin-type-coverage": "^2.8",
43 | "pestphp/pest-plugin-watch": "^2.0",
44 | "phpstan/phpstan": "^1.10",
45 | "phpstan/phpstan-strict-rules": "^1.5",
46 | "rector/rector": "^1.0",
47 | "symfony/http-client": "^7.0"
48 | },
49 | "scripts": {
50 | "test:integration": "./vendor/bin/pest --parallel --colors=always",
51 | "test:watch": "./vendor/bin/pest --watch --parallel",
52 | "test:types": "./vendor/bin/pest --type-coverage --min=100",
53 | "test": [
54 | "@test:types",
55 | "@test:integration"
56 | ],
57 | "lint": "./vendor/bin/phpstan analyze",
58 | "fmt": "./vendor/bin/pint -v",
59 | "check": "./vendor/bin/pint --test",
60 | "prepare": "git config core.hookspath .githooks",
61 | "ci": [
62 | "@check",
63 | "@rector:dry",
64 | "@lint",
65 | "@test"
66 | ],
67 | "rector": "vendor/bin/rector process",
68 | "rector:dry": "vendor/bin/rector process --dry-run",
69 | "refactor": [
70 | "@rector",
71 | "@fmt"
72 | ]
73 | },
74 | "config": {
75 | "allow-plugins": {
76 | "pestphp/pest-plugin": true,
77 | "php-http/discovery": true
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/examples/builder.php:
--------------------------------------------------------------------------------
1 | 5,
19 | ]);
20 |
21 | $openBreweryDbClient = OpenBreweryDb::builder()
22 | ->withHttpClient($guzzleClient)
23 | ->withHeader('foo', 'bar')
24 | ->build();
25 |
26 | // Get a list of breweries, based on all types of different search criteria
27 | $breweries = $openBreweryDbClient->breweries()->list([
28 | 'by_city' => 'Sacramento',
29 | ]);
30 | var_dump($breweries);
31 |
32 | // Retrieve various metadata about breweries from the API
33 | $metadata = $openBreweryDbClient->breweries()->metadata();
34 | var_dump($metadata);
35 |
36 | // Get a random brewery with a specified page size
37 | $randomBrewery = $openBreweryDbClient->breweries()->random(5);
38 | var_dump($randomBrewery);
39 |
40 | /**
41 | * Since we're not limited to a specific HTTP client, we can mix and match
42 | * depending on what client you have installed or want to use.
43 | */
44 | $symfonyClient = (new Symfony\Component\HttpClient\Psr18Client())->withOptions([
45 | 'headers' => ['symfony' => 'is-awesome'],
46 | ]);
47 |
48 | $openBreweryDbClientWithSymfony = OpenBreweryDb::builder()
49 | ->withHttpClient($symfonyClient)
50 | ->withHeader('foo', 'bar')
51 | ->build();
52 |
53 | // Get a list of breweries, based on all types of different search criteria
54 | $breweries = $openBreweryDbClientWithSymfony->breweries()->list([
55 | 'by_city' => 'Sacramento',
56 | ]);
57 | var_dump($breweries);
58 |
59 | // Retrieve various metadata about breweries from the API
60 | $metadata = $openBreweryDbClientWithSymfony->breweries()->metadata();
61 | var_dump($metadata);
62 |
63 | // Get a random brewery with a specified page size
64 | $randomBrewery = $openBreweryDbClientWithSymfony->breweries()->random(5);
65 | var_dump($randomBrewery);
66 |
--------------------------------------------------------------------------------
/examples/simple.php:
--------------------------------------------------------------------------------
1 | breweries()->list([
13 | 'by_city' => 'Sacramento',
14 | ]);
15 | var_dump($breweries);
16 |
17 | // Retrieve various metadata about breweries from the API
18 | $metadata = $client->breweries()->metadata();
19 | var_dump($metadata);
20 |
21 | // Get a random brewery with a specified page size
22 | $randomBrewery = $client->breweries()->random(5);
23 | var_dump($randomBrewery);
24 |
--------------------------------------------------------------------------------
/justfile:
--------------------------------------------------------------------------------
1 | default: lint
2 |
3 | # Continuously test and lint, helpful for local development
4 | dev:
5 | just lint & just test
6 |
7 | # Check types on any file change
8 | lint:
9 | find src/ tests/ | entr -s 'composer run lint'
10 |
11 | # Run tests in parallel
12 | test:
13 | find src/ tests/ | entr -s 'composer run test'
14 |
15 | # Run tests in parallel
16 | fmt:
17 | find src/ tests/ | entr -s 'composer run refactor'
18 |
--------------------------------------------------------------------------------
/phpstan.neon.dist:
--------------------------------------------------------------------------------
1 | includes:
2 | - vendor/phpstan/phpstan-strict-rules/rules.neon
3 |
4 | parameters:
5 | level: max
6 | paths:
7 | - src
8 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | ./tests
10 |
11 |
12 |
13 |
14 | ./src
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/pint.json:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "laravel",
3 | "rules": {
4 | "array_push": true,
5 | "backtick_to_shell_exec": true,
6 | "declare_strict_types": true,
7 | "final_class": true,
8 | "fully_qualified_strict_types": true,
9 | "global_namespace_import": {
10 | "import_classes": true,
11 | "import_constants": true,
12 | "import_functions": true
13 | },
14 | "ordered_class_elements": {
15 | "order": [
16 | "use_trait",
17 | "case",
18 | "constant",
19 | "constant_public",
20 | "constant_protected",
21 | "constant_private",
22 | "property_public",
23 | "property_protected",
24 | "property_private",
25 | "construct",
26 | "destruct",
27 | "magic",
28 | "phpunit",
29 | "method_abstract",
30 | "method_public_static",
31 | "method_public",
32 | "method_protected_static",
33 | "method_protected",
34 | "method_private_static",
35 | "method_private"
36 | ],
37 | "sort_algorithm": "none"
38 | },
39 | "ordered_interfaces": true,
40 | "ordered_traits": true
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/rector.php:
--------------------------------------------------------------------------------
1 | withPaths([
12 | __DIR__.'/src',
13 | ])
14 | ->withPhpSets(php83: true)
15 | ->withRules([
16 | AddVoidReturnTypeWhereNoReturnRector::class,
17 | InlineConstructorDefaultToPropertyRector::class,
18 | ])
19 | ->withSets([
20 | SetList::CODE_QUALITY,
21 | SetList::DEAD_CODE,
22 | SetList::EARLY_RETURN,
23 | SetList::TYPE_DECLARATION,
24 | SetList::PRIVATIZATION,
25 | ]);
26 |
--------------------------------------------------------------------------------
/src/Builder.php:
--------------------------------------------------------------------------------
1 |
28 | */
29 | private array $headers = [];
30 |
31 | /**
32 | * The query parameters to be included on each outgoing request.
33 | *
34 | * @var array
35 | */
36 | private array $queryParams = [];
37 |
38 | /**
39 | * Sets the HTTP client for the requests. If no client is provided the
40 | * factory will try to find one using PSR-18 HTTP Client Discovery.
41 | */
42 | public function withHttpClient(ClientInterface $client): self
43 | {
44 | $this->httpClient = $client;
45 |
46 | return $this;
47 | }
48 |
49 | /**
50 | * Adds a custom header to each outgoing request.
51 | */
52 | public function withHeader(string $name, string $value): self
53 | {
54 | $this->headers[$name] = $value;
55 |
56 | return $this;
57 | }
58 |
59 | /**
60 | * Adds a custom query parameter to the request url for each outgoing request.
61 | */
62 | public function withQueryParam(string $name, string $value): self
63 | {
64 | $this->queryParams[$name] = $value;
65 |
66 | return $this;
67 | }
68 |
69 | /**
70 | * Creates a new Open Brewery DB client based on the provided builder options.
71 | */
72 | public function build(): Client
73 | {
74 | $headers = Headers::create();
75 |
76 | // For any default headers configured for the client, we'll add those to each outbound request
77 | foreach ($this->headers as $name => $value) {
78 | $headers = $headers->withCustomHeader($name, $value);
79 | }
80 |
81 | $baseUri = BaseUri::from(Client::API_BASE_URL);
82 | $queryParams = QueryParams::create();
83 |
84 | // As with the headers, we'll also include any query params configured on each request
85 | foreach ($this->queryParams as $name => $value) {
86 | $queryParams = $queryParams->withParam($name, $value);
87 | }
88 |
89 | $client = $this->httpClient ??= Psr18ClientDiscovery::find();
90 | $connector = new Connector($client, $baseUri, $headers, $queryParams);
91 |
92 | return new Client($connector);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/Client.php:
--------------------------------------------------------------------------------
1 | connector);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Contracts/Concerns/Arrayable.php:
--------------------------------------------------------------------------------
1 | >
24 | *
25 | * @throws ErrorException|UnserializableResponseException|ConnectorException
26 | */
27 | public function requestData(Payload $payload): Response;
28 | }
29 |
--------------------------------------------------------------------------------
/src/Contracts/Resources/BreweriesContract.php:
--------------------------------------------------------------------------------
1 | $parameters
29 | *
30 | * @see https://openbrewerydb.org/documentation#search-breweries
31 | */
32 | public function list(array $parameters = []): ListResponse;
33 |
34 | /**
35 | * Retrieves one or more random breweries.
36 | *
37 | * @see https://openbrewerydb.org/documentation#random
38 | */
39 | public function random(int $size = 1): ListResponse;
40 |
41 | /**
42 | * Searches for breweries that meet the query criteria.
43 | *
44 | * @see https://openbrewerydb.org/documentation#list-breweries
45 | */
46 | public function search(string $query, int $perPage = Client::PER_PAGE): ListResponse;
47 |
48 | /**
49 | * Lists breweries with only ID and name based on the query criteria, useful for drop down lists and the like.
50 | *
51 | * @see https://openbrewerydb.org/documentation#autocomplete
52 | */
53 | public function autocomplete(string $query): AutocompleteResponse;
54 |
55 | /**
56 | * Lists metadata about breweries based on the optional query criteria.
57 | *
58 | * @param array $parameters
59 | *
60 | * @see https://openbrewerydb.org/documentation#autocomplete
61 | */
62 | public function metadata(array $parameters = []): MetadataResponse;
63 | }
64 |
--------------------------------------------------------------------------------
/src/Contracts/ResponseContract.php:
--------------------------------------------------------------------------------
1 | , value-of>
16 | * @extends Arrayable
17 | *
18 | * @internal
19 | */
20 | interface ResponseContract extends Arrayable, ArrayAccess
21 | {
22 | /**
23 | * @param key-of $offset
24 | */
25 | public function offsetExists(mixed $offset): bool;
26 |
27 | /**
28 | * @template TOffsetKey of key-of
29 | *
30 | * @param TOffsetKey $offset
31 | * @return TArray[TOffsetKey]
32 | */
33 | public function offsetGet(mixed $offset): mixed;
34 |
35 | /**
36 | * @template TOffsetKey of key-of
37 | *
38 | * @param TOffsetKey|null $offset
39 | * @param TArray[TOffsetKey] $value
40 | */
41 | public function offsetSet(mixed $offset, mixed $value): never;
42 |
43 | /**
44 | * @template TOffsetKey of key-of
45 | *
46 | * @param TOffsetKey $offset
47 | */
48 | public function offsetUnset(mixed $offset): never;
49 | }
50 |
--------------------------------------------------------------------------------
/src/Enums/HttpMethod.php:
--------------------------------------------------------------------------------
1 | getMessage(), 0, $exception);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Exceptions/ErrorException.php:
--------------------------------------------------------------------------------
1 | getMessage();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Exceptions/UnserializableResponseException.php:
--------------------------------------------------------------------------------
1 | getMessage(), 0, $exception);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/Http/Connector.php:
--------------------------------------------------------------------------------
1 | toRequest($this->baseUri, $this->headers, $this->queryParams);
52 | $response = $this->sendRequest(fn (): ResponseInterface => $this->client->sendRequest($request));
53 | $contents = $response->getBody()->getContents();
54 |
55 | $this->throwIfJsonError($response, $contents);
56 |
57 | try {
58 | $data = json_decode($contents, true, flags: JSON_THROW_ON_ERROR);
59 | } catch (JsonException $jsonException) {
60 | throw new UnserializableResponseException($jsonException);
61 | }
62 |
63 | // @phpstan-ignore-next-line: we'll assume the $data in the response model is a valid model
64 | return Response::from($data);
65 | }
66 |
67 | /**
68 | * Sends the composed request to the server.
69 | *
70 | * @throws ConnectorException|ErrorException|UnserializableResponseException
71 | */
72 | private function sendRequest(Closure $callable): ResponseInterface
73 | {
74 | try {
75 | return $callable();
76 | } catch (ClientExceptionInterface $clientException) {
77 | if ($clientException instanceof ClientException) {
78 | $this->throwIfJsonError($clientException->getResponse(), $clientException->getResponse()->getBody()->getContents());
79 | }
80 |
81 | throw new ConnectorException($clientException);
82 | }
83 | }
84 |
85 | /**
86 | * Analyzes the current error response to determine if the server sent us something we cannot deserialize.
87 | *
88 | * @throws ErrorException|UnserializableResponseException
89 | */
90 | private function throwIfJsonError(ResponseInterface $response, string|ResponseInterface $contents): void
91 | {
92 | // If we received a successful status despite sending the request throwing an exception,
93 | // bypass the checking for unserializable responses and propagate an connector exception
94 | if ($response->getStatusCode() < 400) {
95 | return;
96 | }
97 |
98 | // In the case the content type returned from the service is not JSON, bypass checking
99 | if (! str_contains($response->getHeaderLine('Content-Type'), MediaType::JSON->value)) {
100 | return;
101 | }
102 |
103 | if ($contents instanceof ResponseInterface) {
104 | $contents = $contents->getBody()->getContents();
105 | }
106 |
107 | try {
108 | /** @var array{message: ?string} $response */
109 | $response = json_decode($contents, true, flags: JSON_THROW_ON_ERROR);
110 |
111 | // Open Brewery DB will send back a "message" property in the JSON, so we'll
112 | // throw whatever is returned in those cases that it's detected on the response
113 | if (isset($response['message'])) {
114 | throw new ErrorException($response['message']);
115 | }
116 | } catch (JsonException $jsonException) {
117 | throw new UnserializableResponseException($jsonException);
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/src/OpenBreweryDb.php:
--------------------------------------------------------------------------------
1 | withHeader('User-Agent', "openbrewerydb-php-client/$version")
24 | ->build();
25 | }
26 |
27 | /**
28 | * Creates a new client builder to configure with custom options.
29 | */
30 | public static function builder(): Builder
31 | {
32 | return new Builder();
33 | }
34 |
35 | /**
36 | * Gets the current version information for the library.
37 | */
38 | public function getVersion(): string
39 | {
40 | return Version::current();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Resources/Breweries.php:
--------------------------------------------------------------------------------
1 | $response
37 | */
38 | $response = $this->connector->requestData($payload);
39 |
40 | return FindResponse::from($response->data());
41 | }
42 |
43 | /**
44 | * {@inheritDoc}
45 | */
46 | #[Override]
47 | public function random(int $size = 1): ListResponse
48 | {
49 | $parameters = [
50 | 'size' => $size,
51 | ];
52 |
53 | $payload = Payload::list('breweries', $parameters, 'random');
54 |
55 | /**
56 | * @var Response> $response
57 | */
58 | $response = $this->connector->requestData($payload);
59 |
60 | return ListResponse::from($response->data());
61 | }
62 |
63 | /**
64 | * {@inheritDoc}
65 | */
66 | #[Override]
67 | public function list(array $parameters = []): ListResponse
68 | {
69 | $payload = Payload::list('breweries', $parameters);
70 |
71 | /**
72 | * @var Response> $response
73 | */
74 | $response = $this->connector->requestData($payload);
75 |
76 | return ListResponse::from($response->data());
77 | }
78 |
79 | /**
80 | * {@inheritDoc}
81 | */
82 | #[Override]
83 | public function search(string $query, int $perPage = Client::PER_PAGE): ListResponse
84 | {
85 | $parameters = [
86 | 'per_page' => $perPage,
87 | 'query' => urlencode($query),
88 | ];
89 |
90 | $payload = Payload::list('breweries', $parameters, 'search');
91 |
92 | /**
93 | * @var Response> $response
94 | */
95 | $response = $this->connector->requestData($payload);
96 |
97 | return ListResponse::from($response->data());
98 | }
99 |
100 | /**
101 | * {@inheritDoc}
102 | */
103 | #[Override]
104 | public function autocomplete(string $query): AutocompleteResponse
105 | {
106 | $parameters = [
107 | 'query' => urlencode($query),
108 | ];
109 |
110 | $payload = Payload::list('breweries', $parameters, 'autocomplete');
111 |
112 | /**
113 | * @var Response> $response
114 | */
115 | $response = $this->connector->requestData($payload);
116 |
117 | return AutocompleteResponse::from($response->data());
118 | }
119 |
120 | /**
121 | * {@inheritDoc}
122 | */
123 | #[Override]
124 | public function metadata(array $parameters = []): MetadataResponse
125 | {
126 | $payload = Payload::list('breweries', $parameters, 'meta');
127 |
128 | /**
129 | * @var Response> $response
130 | */
131 | $response = $this->connector->requestData($payload);
132 |
133 | return MetadataResponse::from($response->data());
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/Responses/Breweries/AutocompleteResponse.php:
--------------------------------------------------------------------------------
1 | >
18 | */
19 | final readonly class AutocompleteResponse implements ResponseContract
20 | {
21 | /**
22 | * @use ArrayAccessible>
23 | */
24 | use ArrayAccessible;
25 |
26 | /**
27 | * @param array $data
28 | */
29 | private function __construct(public array $data)
30 | {
31 | }
32 |
33 | /**
34 | * Acts as static factory, and returns a new Response instance.
35 | *
36 | * @param array $attributes
37 | */
38 | public static function from(array $attributes): self
39 | {
40 | return new self($attributes);
41 | }
42 |
43 | /**
44 | * {@inheritDoc}
45 | */
46 | #[Override]
47 | public function toArray(): array
48 | {
49 | return $this->data;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Responses/Breweries/FindResponse.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | final readonly class FindResponse implements ResponseContract
19 | {
20 | /**
21 | * @use ArrayAccessible
22 | */
23 | use ArrayAccessible;
24 |
25 | private function __construct(
26 | public string $id,
27 | public string $name,
28 | public ?string $brewery_type,
29 | public ?string $address_1,
30 | public ?string $address_2,
31 | public ?string $address_3,
32 | public string $city,
33 | public string $state_province,
34 | public string $postal_code,
35 | public string $country,
36 | public ?string $longitude,
37 | public ?string $latitude,
38 | public ?string $phone,
39 | public ?string $website_url,
40 | public string $state,
41 | public ?string $street,
42 | ) {
43 | }
44 |
45 | /**
46 | * Acts as static factory, and returns a new Response instance.
47 | *
48 | * @param array{id: string, name: string, brewery_type: ?string, address_1: ?string, address_2: ?string, address_3: ?string, city: string, state_province: string, postal_code: string, country: string, longitude: ?string, latitude: ?string, phone: ?string, website_url: ?string, state: string, street: ?string} $attributes
49 | */
50 | public static function from(array $attributes): self
51 | {
52 | return new self(
53 | $attributes['id'],
54 | $attributes['name'],
55 | $attributes['brewery_type'],
56 | $attributes['address_1'],
57 | $attributes['address_2'],
58 | $attributes['address_3'],
59 | $attributes['city'],
60 | $attributes['state_province'],
61 | $attributes['postal_code'],
62 | $attributes['country'],
63 | $attributes['longitude'],
64 | $attributes['latitude'],
65 | $attributes['phone'],
66 | $attributes['website_url'],
67 | $attributes['state'],
68 | $attributes['street'],
69 | );
70 | }
71 |
72 | /**
73 | * {@inheritDoc}
74 | */
75 | #[Override]
76 | public function toArray(): array
77 | {
78 | return [
79 | 'id' => $this->id,
80 | 'name' => $this->name,
81 | 'brewery_type' => $this->brewery_type,
82 | 'address_1' => $this->address_1,
83 | 'address_2' => $this->address_2,
84 | 'address_3' => $this->address_3,
85 | 'city' => $this->city,
86 | 'state_province' => $this->state_province,
87 | 'postal_code' => $this->postal_code,
88 | 'country' => $this->country,
89 | 'longitude' => $this->longitude,
90 | 'latitude' => $this->latitude,
91 | 'phone' => $this->phone,
92 | 'website_url' => $this->website_url,
93 | 'state' => $this->state,
94 | 'street' => $this->street,
95 | ];
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/Responses/Breweries/ListResponse.php:
--------------------------------------------------------------------------------
1 | >
18 | */
19 | final readonly class ListResponse implements ResponseContract
20 | {
21 | /**
22 | * @use ArrayAccessible>
23 | */
24 | use ArrayAccessible;
25 |
26 | /**
27 | * @param FindResponse[] $data
28 | */
29 | private function __construct(public array $data)
30 | {
31 | }
32 |
33 | /**
34 | * Acts as static factory, and returns a new Response instance.
35 | *
36 | * @param array $attributes
37 | */
38 | public static function from(array $attributes): self
39 | {
40 | $mappedData = array_map(fn (array $result): FindResponse => FindResponse::from(
41 | $result,
42 | ), $attributes);
43 |
44 | return new self($mappedData);
45 | }
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | #[Override]
51 | public function toArray(): array
52 | {
53 | return array_map(
54 | static fn (FindResponse $response): array => $response->toArray(),
55 | $this->data,
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Responses/Breweries/MetadataResponse.php:
--------------------------------------------------------------------------------
1 | >
17 | */
18 | final readonly class MetadataResponse implements ResponseContract
19 | {
20 | /**
21 | * @use ArrayAccessible>
22 | */
23 | use ArrayAccessible;
24 |
25 | /**
26 | * @param array $data
27 | */
28 | private function __construct(public array $data)
29 | {
30 | }
31 |
32 | /**
33 | * Acts as static factory, and returns a new Response instance.
34 | *
35 | * @param array $attributes
36 | */
37 | public static function from(array $attributes): self
38 | {
39 | return new self($attributes);
40 | }
41 |
42 | /**
43 | * {@inheritDoc}
44 | */
45 | #[Override]
46 | public function toArray(): array
47 | {
48 | return $this->data;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Responses/Concerns/ArrayAccessible.php:
--------------------------------------------------------------------------------
1 |
16 | *
17 | * @internal
18 | */
19 | trait ArrayAccessible
20 | {
21 | /**
22 | * {@inheritDoc}
23 | */
24 | public function offsetExists(mixed $offset): bool
25 | {
26 | return array_key_exists($offset, $this->toArray());
27 | }
28 |
29 | /**
30 | * {@inheritDoc}
31 | */
32 | public function offsetGet(mixed $offset): mixed
33 | {
34 | return $this->toArray()[$offset];
35 | }
36 |
37 | /**
38 | * {@inheritDoc}
39 | */
40 | public function offsetSet(mixed $offset, mixed $value): never
41 | {
42 | throw new BadMethodCallException('Responses are immutable. Values are not allowed to be set on responses.');
43 | }
44 |
45 | /**
46 | * {@inheritDoc}
47 | */
48 | public function offsetUnset(mixed $offset): never
49 | {
50 | throw new BadMethodCallException('Responses are immutable. Values are not allowed to be removed on responses.');
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/ValueObjects/Connector/BaseUri.php:
--------------------------------------------------------------------------------
1 | baseUri, $protocol)) {
29 | return "$this->baseUri/";
30 | }
31 | }
32 |
33 | return "https://$this->baseUri/";
34 | }
35 |
36 | /**
37 | * Creates a new Base URI value object.
38 | */
39 | public static function from(string $baseUri): self
40 | {
41 | return new self($baseUri);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/ValueObjects/Connector/Headers.php:
--------------------------------------------------------------------------------
1 | >
15 | *
16 | * @internal
17 | */
18 | final readonly class Headers implements Arrayable
19 | {
20 | /**
21 | * Creates a new Headers value object.
22 | *
23 | * @param array $headers
24 | */
25 | private function __construct(private array $headers)
26 | {
27 | }
28 |
29 | /**
30 | * Creates a new Headers value object.
31 | */
32 | public static function create(): self
33 | {
34 | return new self([]);
35 | }
36 |
37 | /**
38 | * Creates a new Headers value object, with the given content type, and the existing headers.
39 | */
40 | public function withAccept(MediaType $mediaType, string $suffix = ''): self
41 | {
42 | return new self([
43 | ...$this->headers,
44 | 'Accept' => $mediaType->value.$suffix,
45 | ]);
46 | }
47 |
48 | /**
49 | * Creates a new Headers value object, with the newly added header, and the existing headers.
50 | */
51 | public function withCustomHeader(string $name, string $value): self
52 | {
53 | return new self([
54 | ...$this->headers,
55 | $name => $value,
56 | ]);
57 | }
58 |
59 | #[Override]
60 | public function toArray(): array
61 | {
62 | return $this->headers;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/ValueObjects/Connector/QueryParams.php:
--------------------------------------------------------------------------------
1 | >
14 | *
15 | * @internal
16 | */
17 | final readonly class QueryParams implements Arrayable
18 | {
19 | /**
20 | * Creates a new Query Params value object.
21 | *
22 | * @param array $params
23 | */
24 | private function __construct(private array $params)
25 | {
26 | }
27 |
28 | /**
29 | * Creates a new Query Params value object.
30 | */
31 | public static function create(): self
32 | {
33 | return new self([]);
34 | }
35 |
36 | /**
37 | * Creates a new Query Params value object, with the newly added param, and the existing params.
38 | */
39 | public function withParam(string $name, string|int $value): self
40 | {
41 | return new self([
42 | ...$this->params,
43 | $name => $value,
44 | ]);
45 | }
46 |
47 | #[Override]
48 | public function toArray(): array
49 | {
50 | return $this->params;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/ValueObjects/Connector/Response.php:
--------------------------------------------------------------------------------
1 |
32 | */
33 | public static function from(array $attributes): self
34 | {
35 | return new self($attributes);
36 | }
37 |
38 | /**
39 | * Returns the response data.
40 | *
41 | * @return TData
42 | */
43 | public function data(): mixed
44 | {
45 | return $this->data;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/ValueObjects/Payload.php:
--------------------------------------------------------------------------------
1 | $parameters
26 | */
27 | private function __construct(
28 | private MediaType $accept,
29 | private HttpMethod $method,
30 | private ResourceUri $uri,
31 | private array $parameters = [],
32 | ) {
33 | }
34 |
35 | /**
36 | * Creates a new Payload value object from the given parameters.
37 | *
38 | * @param array $parameters
39 | */
40 | public static function list(string $resource, array $parameters = [], ?string $suffix = null): self
41 | {
42 | $accept = MediaType::JSON;
43 | $method = HttpMethod::GET;
44 | $uri = ResourceUri::list($resource, $suffix);
45 |
46 | return new self($accept, $method, $uri, $parameters);
47 | }
48 |
49 | /**
50 | * Creates a new Payload value object from the given parameters.
51 | *
52 | * @param array $parameters
53 | */
54 | public static function retrieve(string $resource, string $id, array $parameters = []): self
55 | {
56 | $accept = MediaType::JSON;
57 | $method = HttpMethod::GET;
58 | $uri = ResourceUri::retrieve($resource, $id);
59 |
60 | return new self($accept, $method, $uri, $parameters);
61 | }
62 |
63 | /**
64 | * Creates a new Psr 7 Request instance based on information passed on the request payload.
65 | * In the case of query parameters, if the client is constructed with any parameters,
66 | * we'll append them to each request that is sent to the server.
67 | */
68 | public function toRequest(BaseUri $baseUri, Headers $headers, QueryParams $queryParams): RequestInterface
69 | {
70 | $psr17Factory = new Psr17Factory();
71 | $uri = "$baseUri$this->uri";
72 | $queryParams = [...$queryParams->toArray(), ...$this->parameters];
73 |
74 | if ($queryParams !== []) {
75 | $uri .= '?'.http_build_query($queryParams);
76 | }
77 |
78 | $headers = $headers->withAccept($this->accept);
79 | $request = $psr17Factory->createRequest($this->method->value, $uri);
80 |
81 | foreach ($headers->toArray() as $name => $value) {
82 | $request = $request->withHeader($name, $value);
83 | }
84 |
85 | return $request;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/ValueObjects/ResourceUri.php:
--------------------------------------------------------------------------------
1 | uri;
28 | }
29 |
30 | /**
31 | * Creates a new resource URI value object that lists the given resource.
32 | */
33 | public static function list(string $resource, ?string $suffix = null): self
34 | {
35 | $uri = isset($suffix)
36 | ? "$resource/$suffix"
37 | : $resource;
38 |
39 | return new self($uri);
40 | }
41 |
42 | /**
43 | * Creates a new resource URI value object that retrieves the given resource.
44 | */
45 | public static function retrieve(string $resource, string $id): self
46 | {
47 | return new self("$resource/$id");
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/ValueObjects/Version.php:
--------------------------------------------------------------------------------
1 | expect('OpenBreweryDb\\')
9 | ->toUseStrictTypes();
10 |
11 | test('All tests files are strictly typed')
12 | ->expect('Tests\\')
13 | ->toUseStrictTypes();
14 |
15 | test('Value objects should be immutable')
16 | ->expect('OpenBreweryDb\\ValueObjects\\')
17 | ->toBeFinal()
18 | ->and('OpenBreweryDb\\ValueObjects\\')
19 | ->toBeReadonly();
20 |
21 | test('Responses should be immutable')
22 | ->expect('OpenBreweryDb\\Responses\\Breweries\\')
23 | ->toBeFinal()
24 | ->and('OpenBreweryDb\\Responses\\Breweries\\')
25 | ->toBeReadonly();
26 |
27 | test('Contracts should be abstract')
28 | ->expect('OpenBreweryDb\\Contracts\\')
29 | ->toBeInterfaces();
30 |
31 | test('All Enums are backed')
32 | ->expect('OpenBreweryDb\\Enums\\')
33 | ->toBeStringBackedEnums();
34 |
--------------------------------------------------------------------------------
/tests/Pest.php:
--------------------------------------------------------------------------------
1 | breweries()->autocomplete('dog');
16 |
17 | // Assert
18 | expect(count($breweries->toArray()))->toBe(15);
19 | foreach ($breweries->toArray() as $brewery) {
20 | expect($brewery)->not()->toBeNull()
21 | ->and($brewery['id'])->not()->toBeNull()
22 | ->and($brewery['name'])->not()->toBeNull()
23 | ->and(strtolower($brewery['name']))->toContain('dog');
24 | }
25 | });
26 |
27 | it('returns no breweries for autocomplete if the search criteria is not met', function () {
28 | // Arrange
29 | $client = OpenBreweryDb::client();
30 |
31 | // Act
32 | $breweries = $client->breweries()->autocomplete('pneumonoultramicroscopicsilicovolcanoconiosis');
33 |
34 | // Assert
35 | expect($breweries->toArray())->toBeEmpty();
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/tests/Resources/FindBrewery.php:
--------------------------------------------------------------------------------
1 | breweries()->find('b54b16e1-ac3b-4bff-a11f-f7ae9ddc27e0');
17 |
18 | // Assert
19 | expect($brewery)->not()->toBeNull()
20 | ->and($brewery['id'])->not()->toBeNull()
21 | ->and($brewery['brewery_type'])->not()->toBeNull()
22 | ->and($brewery['state'])->not()->toBeNull()
23 | ->and($brewery['state_province'])->not()->toBeNull()
24 | ->and($brewery['postal_code'])->not()->toBeNull()
25 | ->and($brewery['country'])->not()->toBeNull()
26 | ->and($brewery['city'])->not()->toBeNull()
27 | ->and($brewery['name'])->not()->toBeNull();
28 | });
29 |
30 | it('returns an error if no brewery is found', function () {
31 | // Arrange
32 | $client = OpenBreweryDb::client();
33 |
34 | // Act/Assert
35 | expect(fn () => $client->breweries()->find('not-a-brewery'))->toThrow(ErrorException::class, 'Couldn\'t find Brewery');
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/tests/Resources/ListBreweries.php:
--------------------------------------------------------------------------------
1 | breweries()->list();
17 |
18 | // Assert
19 | expect(count($breweries->toArray()))->toBe(Client::PER_PAGE);
20 | foreach ($breweries->toArray() as $brewery) {
21 | expect($brewery)->not()->toBeNull()
22 | ->and($brewery['id'])->not()->toBeNull()
23 | ->and($brewery['brewery_type'])->not()->toBeNull()
24 | ->and($brewery['state'])->not()->toBeNull()
25 | ->and($brewery['state_province'])->not()->toBeNull()
26 | ->and($brewery['postal_code'])->not()->toBeNull()
27 | ->and($brewery['country'])->not()->toBeNull()
28 | ->and($brewery['city'])->not()->toBeNull()
29 | ->and($brewery['name'])->not()->toBeNull();
30 | }
31 | });
32 |
33 | it('returns a valid list of breweries with properties set to the number of paginated results', function () {
34 | // Arrange
35 | $client = OpenBreweryDb::client();
36 | $pagedResults = rand(50, 200);
37 |
38 | // Act
39 | $breweries = $client->breweries()->list([
40 | 'per_page' => $pagedResults,
41 | ]);
42 |
43 | // Assert
44 | expect(count($breweries->toArray()))->toBe($pagedResults);
45 | foreach ($breweries->toArray() as $brewery) {
46 | expect($brewery)->not()->toBeNull()
47 | ->and($brewery['id'])->not()->toBeNull()
48 | ->and($brewery['brewery_type'])->not()->toBeNull()
49 | ->and($brewery['state'])->not()->toBeNull()
50 | ->and($brewery['state_province'])->not()->toBeNull()
51 | ->and($brewery['postal_code'])->not()->toBeNull()
52 | ->and($brewery['country'])->not()->toBeNull()
53 | ->and($brewery['city'])->not()->toBeNull()
54 | ->and($brewery['name'])->not()->toBeNull();
55 | }
56 | });
57 |
58 | it('retrieves a list of breweries by name', function () {
59 | // Arrange
60 | $client = OpenBreweryDb::client();
61 |
62 | // Act
63 | $breweries = $client->breweries()->list([
64 | 'by_name' => 'Dog',
65 | ]);
66 |
67 | // Assert
68 | expect($breweries->toArray())->toBeGreaterThan(1);
69 | foreach ($breweries->toArray() as $brewery) {
70 | expect($brewery)->not()->toBeNull()
71 | ->and($brewery['id'])->not()->toBeNull()
72 | ->and($brewery['brewery_type'])->not()->toBeNull()
73 | ->and($brewery['state'])->not()->toBeNull()
74 | ->and($brewery['state_province'])->not()->toBeNull()
75 | ->and($brewery['postal_code'])->not()->toBeNull()
76 | ->and($brewery['country'])->not()->toBeNull()
77 | ->and($brewery['city'])->not()->toBeNull()
78 | ->and($brewery['name'])->not()->toBeNull()
79 | ->and(strtolower($brewery['name']))->toContain('dog');
80 | }
81 | });
82 |
83 | it('retrieves a list of breweries by state', function () {
84 | // Arrange
85 | $client = OpenBreweryDb::client();
86 |
87 | // Act
88 | $breweries = $client->breweries()->list([
89 | 'by_state' => 'Oregon',
90 | ]);
91 |
92 | // Assert
93 | expect($breweries->toArray())->toBeGreaterThan(1);
94 | foreach ($breweries->toArray() as $brewery) {
95 | expect($brewery)->not()->toBeNull()
96 | ->and($brewery['id'])->not()->toBeNull()
97 | ->and($brewery['brewery_type'])->not()->toBeNull()
98 | ->and($brewery['state'])->not()->toBeNull()
99 | ->and($brewery['state_province'])->not()->toBeNull()
100 | ->and($brewery['postal_code'])->not()->toBeNull()
101 | ->and($brewery['country'])->not()->toBeNull()
102 | ->and($brewery['city'])->not()->toBeNull()
103 | ->and($brewery['name'])->not()->toBeNull()
104 | ->and($brewery['state'])->toBe('Oregon');
105 | }
106 | });
107 |
108 | it('retrieves a list of breweries by multiple state names', function () {
109 | // Arrange
110 | $client = OpenBreweryDb::client();
111 |
112 | // Act
113 | $breweries = $client->breweries()->list([
114 | 'by_state' => 'New York',
115 | ]);
116 |
117 | // Assert
118 | expect($breweries->toArray())->toBeGreaterThan(1);
119 | foreach ($breweries->toArray() as $brewery) {
120 | expect($brewery)->not()->toBeNull()
121 | ->and($brewery['id'])->not()->toBeNull()
122 | ->and($brewery['brewery_type'])->not()->toBeNull()
123 | ->and($brewery['state'])->not()->toBeNull()
124 | ->and($brewery['state_province'])->not()->toBeNull()
125 | ->and($brewery['postal_code'])->not()->toBeNull()
126 | ->and($brewery['country'])->not()->toBeNull()
127 | ->and($brewery['city'])->not()->toBeNull()
128 | ->and($brewery['name'])->not()->toBeNull()
129 | ->and($brewery['state'])->toBe('New York');
130 | }
131 | });
132 |
133 | it('retrieves a list of breweries by type', function () {
134 | // Arrange
135 | $client = OpenBreweryDb::client();
136 |
137 | // Act
138 | $breweries = $client->breweries()->list([
139 | 'by_type' => 'micro',
140 | ]);
141 |
142 | // Assert
143 | expect($breweries->toArray())->toBeGreaterThan(1);
144 | foreach ($breweries->toArray() as $brewery) {
145 | expect($brewery)->not()->toBeNull()
146 | ->and($brewery['id'])->not()->toBeNull()
147 | ->and($brewery['brewery_type'])->not()->toBeNull()
148 | ->and($brewery['state'])->not()->toBeNull()
149 | ->and($brewery['state_province'])->not()->toBeNull()
150 | ->and($brewery['postal_code'])->not()->toBeNull()
151 | ->and($brewery['country'])->not()->toBeNull()
152 | ->and($brewery['city'])->not()->toBeNull()
153 | ->and($brewery['name'])->not()->toBeNull()
154 | ->and($brewery['brewery_type'])->toBe('micro');
155 | }
156 | });
157 |
158 | it('returns a valid list of breweries', function () {
159 | // Arrange
160 | $client = OpenBreweryDb::client();
161 |
162 | // Act
163 | $breweries = $client->breweries()->list([
164 | 'by_name' => 'dog',
165 | 'by_state' => 'California',
166 | 'by_type' => 'micro',
167 | ]);
168 |
169 | // Assert
170 | expect($breweries->toArray())->toBeGreaterThan(1);
171 | foreach ($breweries->toArray() as $brewery) {
172 | expect($brewery)->not()->toBeNull()
173 | ->and($brewery['id'])->not()->toBeNull()
174 | ->and($brewery['brewery_type'])->not()->toBeNull()
175 | ->and($brewery['state'])->not()->toBeNull()
176 | ->and($brewery['state_province'])->not()->toBeNull()
177 | ->and($brewery['postal_code'])->not()->toBeNull()
178 | ->and($brewery['country'])->not()->toBeNull()
179 | ->and($brewery['city'])->not()->toBeNull()
180 | ->and($brewery['name'])->not()->toBeNull()
181 | ->and(strtolower($brewery['name']))->toContain('dog')
182 | ->and($brewery['state'])->toContain('California');
183 | }
184 | });
185 | });
186 |
--------------------------------------------------------------------------------
/tests/Resources/MetadataBreweries.php:
--------------------------------------------------------------------------------
1 | breweries()->metadata();
16 |
17 | // Assert
18 | expect($meta)->not()->toBeNull()
19 | ->and($meta['total'])->toBe('8257')
20 | ->and($meta['page'])->toBe('1')
21 | ->and($meta['per_page'])->toBe('50');
22 | });
23 |
24 | it('returns metadata for all breweries when parameters provided', function () {
25 | // Arrange
26 | $client = OpenBreweryDb::client();
27 |
28 | // Act
29 | $meta = $client->breweries()->metadata([
30 | 'by_type' => 'micro',
31 | ]);
32 |
33 | // Assert
34 | expect($meta)->not()->toBeNull()
35 | ->and($meta['total'])->toBe('4282')
36 | ->and($meta['page'])->toBe('1')
37 | ->and($meta['per_page'])->toBe('50');
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/tests/Resources/RandomBreweries.php:
--------------------------------------------------------------------------------
1 | breweries()->random();
17 | $brewery = $breweries[0];
18 |
19 | // Assert
20 | expect(count($breweries->toArray()))->toBe(1)
21 | ->and($brewery)->not()->toBeNull()
22 | ->and($brewery['id'])->not()->toBeNull()
23 | ->and($brewery['brewery_type'])->not()->toBeNull()
24 | ->and($brewery['state'])->not()->toBeNull()
25 | ->and($brewery['state_province'])->not()->toBeNull()
26 | ->and($brewery['postal_code'])->not()->toBeNull()
27 | ->and($brewery['country'])->not()->toBeNull()
28 | ->and($brewery['city'])->not()->toBeNull()
29 | ->and($brewery['name'])->not()->toBeNull();
30 | });
31 |
32 | it('returns specified number of random breweries', function () {
33 | // Arrange
34 | $client = OpenBreweryDb::client();
35 | $randomBreweries = rand(2, Client::PER_PAGE);
36 |
37 | // Act
38 | $breweries = $client->breweries()->random($randomBreweries);
39 |
40 | // Assert
41 | expect(count($breweries->toArray()))->toBe($randomBreweries);
42 | foreach ($breweries->toArray() as $brewery) {
43 | expect($brewery)->not()->toBeNull()
44 | ->and($brewery['id'])->not()->toBeNull()
45 | ->and($brewery['brewery_type'])->not()->toBeNull()
46 | ->and($brewery['state'])->not()->toBeNull()
47 | ->and($brewery['state_province'])->not()->toBeNull()
48 | ->and($brewery['postal_code'])->not()->toBeNull()
49 | ->and($brewery['country'])->not()->toBeNull()
50 | ->and($brewery['city'])->not()->toBeNull()
51 | ->and($brewery['name'])->not()->toBeNull();
52 | }
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/tests/Resources/SearchBreweries.php:
--------------------------------------------------------------------------------
1 | breweries()->search('dog', 3);
16 |
17 | // Assert
18 | foreach ($breweries->toArray() as $brewery) {
19 | expect($brewery)->not()->toBeNull()
20 | ->and($brewery['id'])->not()->toBeNull()
21 | ->and($brewery['brewery_type'])->not()->toBeNull()
22 | ->and($brewery['state'])->not()->toBeNull()
23 | ->and($brewery['state_province'])->not()->toBeNull()
24 | ->and($brewery['postal_code'])->not()->toBeNull()
25 | ->and($brewery['country'])->not()->toBeNull()
26 | ->and($brewery['city'])->not()->toBeNull()
27 | ->and($brewery['name'])->not()->toBeNull()
28 | ->and(strtolower($brewery['name']))->toContain('dog');
29 | }
30 | });
31 |
32 | it('returns no breweries if the search criteria is not met', function () {
33 | // Arrange
34 | $client = OpenBreweryDb::client();
35 |
36 | // Act
37 | $breweries = $client->breweries()->search('not a brewery');
38 |
39 | // Assert
40 | expect($breweries->toArray())->toBeEmpty();
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/tests/Version.php:
--------------------------------------------------------------------------------
1 | expect(Version::current())->toBe('0.9.0'));
10 |
--------------------------------------------------------------------------------