Skip to content

Commit 81df125

Browse files
Merge pull request #16 from JustSteveKing/feature/new-release
Feature/new release
2 parents fcab5ec + 5757605 commit 81df125

40 files changed

+874
-969
lines changed

.github/workflows/tests.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@ jobs:
1010
strategy:
1111
fail-fast: true
1212
matrix:
13-
php: [ 8.0, 8.1 ]
13+
php: [ 8.3 ]
1414

1515
name: PHP ${{ matrix.php }} on Linux
1616

1717
steps:
1818
- name: Checkout Code
19-
uses: actions/checkout@v2
19+
uses: actions/checkout@v4
2020

2121
- name: Setup PHP
2222
uses: shivammathur/setup-php@v2
2323
with:
2424
php-version: ${{ matrix.php }}
25-
extensions: dom, curl, libxml, mbstring, zip, http
25+
extensions: dom, curl, fileinfo, json, libxml, mbstring, zip, http
2626
tools: composer:v2
2727
coverage: none
2828

@@ -37,7 +37,7 @@ jobs:
3737
strategy:
3838
fail-fast: true
3939
matrix:
40-
php: [ 8.0, 8.1 ]
40+
php: [ 8.3 ]
4141

4242
name: PHP ${{ matrix.php }} on Windows
4343

@@ -48,13 +48,13 @@ jobs:
4848
git config --global core.autocrlf false
4949
git config --global core.eol lf
5050
- name: Checkout code
51-
uses: actions/checkout@v2
51+
uses: actions/checkout@v4
5252

5353
- name: Setup PHP
5454
uses: shivammathur/setup-php@v2
5555
with:
5656
php-version: ${{ matrix.php }}
57-
extensions: dom, curl, libxml, mbstring, zip, http
57+
extensions: dom, curl, fileinfo, json, libxml, mbstring, zip, http
5858
tools: composer:v2
5959
coverage: none
6060
ini-values: memory_limit=512M

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
.idea/
44
.phpunit.result.cache
55
composer.lock
6+
/.phpunit.cache

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2020 Steve McDougall
3+
Copyright (c) 2023 Steve McDougall<[email protected]>
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 100 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
# PHP SDK
22

3-
<p align="center">
4-
5-
![](./banner.png)
6-
7-
</p>
8-
93
<!-- BADGES_START -->
104
[![Latest Version][badge-release]][packagist]
115
[![PHP Version][badge-php]][php]
@@ -21,7 +15,7 @@
2115
[downloads]: https://packagist.org/packages/juststeveking/php-sdk
2216
<!-- BADGES_END -->
2317

24-
A framework for building simple to use SDKs in PHP 8.0 and above.
18+
A framework for building SDKs in PHP.
2519

2620
## Installation
2721

@@ -35,203 +29,150 @@ The purpose of this package is to provide a consistent and interoperable way to
3529

3630
## Usage
3731

38-
Working with this library is relatively simple, and an example can be found in the [demo](./demo) and [examples](./examples) directories.
39-
40-
The basic concept is that you will need to provide:
41-
42-
- PSR-17 Request and Response Factory.
43-
- PSR-7 Messages
44-
45-
Inside this library we are using a PSR-18 implementation allowing you to connect the pieces together under the hood and provide SDK functionality using a replaceable set of components.
46-
47-
I highly recommend either:
48-
49-
- [nyholm/psr7](https://github.com/Nyholm/psr7/)
50-
- [slim/psr7](https://github.com/slimphp/Slim-Psr7)
51-
- [symfony/http-client](https://github.com/symfony/http-client)
52-
- [laminas/diactoros](https://github.com/laminas/laminas-diactoros)
53-
54-
To handle the Http PSRs as they are lightweight and designed to be simple and PSR compliant.
55-
56-
### Building the SDK
57-
58-
To begin with we need to be able to build our SDK, to do this we can either use the `constructor` or use the static `build` method.:
59-
60-
#### SDK constructor
61-
62-
To create an SDK instance; simply pass through a uri, a Http Client that uses auto-discovery to find the available PSR-18 client, an authentication strategy, and an instance of the `Container`.
63-
64-
```php
65-
use JustSteveKing\HttpAuth\Strategies\BasicStrategy;
66-
use JustSteveKing\HttpSlim\HttpClient;
67-
use JustSteveKing\UriBuilder\Uri;
68-
use JustSteveKing\PhpSdk\SDK;
69-
use PHPFox\Container\Container;
70-
71-
$sdk = new SDK(
72-
uri: Uri::fromString('https://www.domain.com'),
73-
client: HttpClient::build(),
74-
strategy: new BasicStrategy(
75-
authString: base64_encode("username:password")
76-
),
77-
container: Container::getInstance(),
78-
);
79-
```
80-
81-
#### SDK build
32+
To get started with this library, you need to start by extending the `Client` class. Let's walk through building an SDK.
8233

83-
To use the static build method, the only requirement is to pass through a uri. If you want to set a custom Authentication Strategy you can also pass this through otherwise it will default to a Null Strategy.
34+
### Create your SDK class
8435

8536
```php
86-
use JustSteveKing\UriBuilder\Uri;
87-
use JustSteveKing\PhpSdk\SDK;
37+
use JustSteveKing\Sdk\Client;
8838

89-
$sdk = SDK::build(
90-
uri: 'https://www.domain.com',
91-
);
39+
final class YourSDK extends Client
40+
{
41+
//
42+
}
9243
```
9344

94-
### Adding Resources to our SDK
95-
96-
Each Resource you add to your SDK requires 2 things:
97-
98-
- Implements `ResourceContract`
99-
- Extends `AbstractResource`
100-
101-
Your resource should look like this:
45+
Once this is in place, you can start adding your resources to the class. Let's add a `projects` method for a projects resource.
10246

10347
```php
104-
use JustSteveKing\PhpSdk\Contracts\ResourceContract;
105-
use JustSteveKing\PhpSdk\Resources\AbstractResource;
48+
use JustSteveKing\Sdk\Client;
49+
use JustSteveKing\Sdk\Tests\Stubs\Resources\ProjectResource;
10650

107-
class TestResource extends AbstractResource implements ResourceContract
51+
final class YourSDK extends Client
10852
{
109-
protected string $path = '/test';
110-
111-
public static function name(): string
53+
public function projects()
11254
{
113-
return 'tests';
55+
return new ProjectResource(
56+
client: $this,
57+
);
11458
}
11559
}
116-
11760
```
11861

119-
The Path property allows you to set the uri path for this resource, and the static name method is how this resource is stored on the container.
62+
We return a new instance of our resource classes, passing through your SDK as a `client`. This is so that each resource is able to talk through the client to send requests.
12063

121-
To add this resource to the SDK, you can use the add method:
64+
Now, let's look at how to structure a resource.
12265

12366
```php
124-
$sdk->add(
125-
name: TestResource::name(),
126-
resource: TestResource::class,
127-
);
67+
final class ProjectResource
68+
{
69+
//
70+
}
12871
```
12972

130-
Internally this will add the resource onto container and inject the SDK into the constructor, allowing you to access the Http Client and other aspects of the SDK.
73+
To save time, there are a collection of traits that you can use on your resources.
13174

132-
### Calling a Resource
75+
- `CanAccessClient` - which will add the default constructor required for a resource.
76+
- `CanCreateDataObjects` - which will allow you to create DataObjects from API responses.
77+
- `CanCreateRequests` - which will allow you to create HTTP requests and payloads using PSR-17 Factories.
13378

134-
Now that you have added a resource to the SDK, you are able to call it using the PHP magic __get method:
79+
Let's look at an example of a full resource class.
13580

13681
```php
137-
$response = $sdk->tests->get();
138-
```
139-
140-
This will return a nice PSR-7 response for you to work with inside your SDK code.
141-
142-
### API
82+
use Exception;
83+
use JustSteveKing\Sdk\Concerns\Resources;
84+
use JustSteveKing\Tools\Http\Enums\Method;
85+
use Ramsey\Collection\Collection;
86+
use Throwable;
14387

144-
The below documents the API of the PHP-SDK:
88+
final class ProjectResource
89+
{
90+
use Resources\CanAccessClient;
91+
use Resources\CanCreateDataObjects;
92+
use Resources\CanCreateRequests;
14593

146-
#### SDK class
94+
public function all(): Collection
95+
{
96+
$request = $this->request(
97+
method: Method::GET,
98+
uri: '/projects',
99+
);
147100

148-
Your own SDK class should extend the base SDK class for easier integration.
101+
try {
102+
$response = $this->client->send(
103+
request: $request,
104+
);
105+
} catch (Throwable $exception) {
106+
throw new Exception(
107+
message: 'Failed to list test.',
108+
code: $exception->getCode(),
109+
previous: $exception,
110+
);
111+
}
112+
113+
return (new Collection(
114+
collectionType: Project::class,
115+
data: array_map(
116+
callback: static fn(array $data): Project => Project::make(
117+
data: $data,
118+
),
119+
array: (array) json_decode(
120+
json: $response->getBody()->getContents(),
121+
associative: true,
122+
flags: JSON_THROW_ON_ERROR,
123+
),
124+
),
125+
));
126+
}
127+
}
128+
```
149129

150-
- `__construct(URI $uri, HttpClient $client, Container $container, null|StrategyInterface $strategy)` **The SDK constructor.**
151-
- `static build(string $uri, null|StrategyInterface $strategy = null, null|Container = null): SDK` **This static build method allows the defaults to be set for you to get an SDK quickly.**
152-
- `add(string $name, string $resource): self` **The add method allows you to add resources onto the SDK container, and checks that the resource being passed extends the AbstractResource and implements the ResourceContract.**
153-
- `uri(): Uri` **Return the setup instance of UriBuilder that is being used, to allow you to manipulate the URI string.**
154-
- `client(): HttpClient` **Return the setup instance of the HttpClient that is being used, to allow you to enforce any changes that are required.**
155-
- `strategy(): StrategyInterface` **Returns the setup instance of the Authentication Strategy that is being used, to allow you to export the auth header array.**
156-
- `container(): Container` **Returns the setup instance of the Container, to allow you to bind make and work with the container directly should it be required.**
157-
- `__get(string $name): ResourceContract` **Returns a build instance of the called Resource if it has been added to the container.**
130+
We start by creating a request, and then try to get a response by sending it through the client.
158131

159-
#### AbstractResource class
132+
Once we have a response, we create a `Collection` thanks to a package by Ben Ramsey. We pass through the type of each item we expect it to be,
133+
then the data as an array. To create the data we map over the response content and statically create a new Data Object.
160134

161-
Your resources must all extend the Abstract Resource class.
135+
This allows us to keep our code clean, concise, and testable.
162136

163-
- `__construct(SDK $sdk, null|string $path = null, string $authHeader = 'Bearer', array $with = [], array $relations = [], bool $strictRelations = false, null|string $load = null)` **The Resource constructor.**
164-
- `sdk(): SDK` **Return the setup instance of the SDK that has been passed through to the resource.**
165-
- `getWith(): array` **Return an array of relations to sideload onto the request.**
166-
- `getLoad(): string|null` **Return a string or null if a specific resource identifier has been passed in.**
167-
- `load(string|int $identifier): self` **The load method allows you to set a specific resource identifier to look for on an API.**
168-
- `uri(Uri $uri): self` **The uri method allows you to completely override the URI Builder on the SDK.**
169-
- `client(HttpClient $http): self` **The client method allows you to completely override the Http Client on the SDK.**
170-
- `strategy(StrategyInterface $strategy): self` **The strategy method allows you to completely override the Authentication Strategy on the SDK.**
171-
- `loadPath(): self` **Loads the path from the resource into to URI builder on the SDK.**
172-
- `get(): ResponseInterface` **Performs a GET request to the resource path, to return a list of resources.**
173-
- `find(string|int $identifier): ResponseInterface` **Performs a GET request to the resource path with an identifier appended to it, to return a single resource.**
174-
- `create(array $data): ResponseInterface` **Performs a POST request to the resource path, to create a new single resource.**
175-
- `update($identifier, array $data, string $method = 'patch'): ResponseInterface` **Performs either a PATCH or PUT request to the resource path with an identifier appended to it, to update a single resource.**
176-
- `delete(string|int $identifier): ResponseInterface` **Performs a DELETE request to the resource path with an identifier appended to it, to remove a resource.**
177-
- `where(string $key, $value): self` **Builds the query parameters in a famility query builder style syntax.**
137+
## Testing
178138

179-
#### ResourceContract Interface
139+
To run the test:
180140

181-
Your resources must implement the ResourceContract interface.
141+
```bash
142+
composer run test
143+
```
182144

183-
- `static name(): string` **Returns a string representation of the resource name, to allow it to be bound the the SDK container.**
145+
## Static analysis
184146

147+
To run the static analysis checks:
185148

186-
It is highly recommended that you use all of these internally in your API to give you the ability to control the process.
149+
```bash
150+
composer run stan
151+
```
187152

188-
### Building an SDK
153+
## Code Style
189154

190-
To build an SDK, you can simply extend the SDK like so:
155+
To run the code style fixer:
191156

192-
```php
193-
use Demo\Resources\Server;
194-
use JustSteveKing\HttpAuth\Strategies\NullStrategy;
195-
use JustSteveKing\HttpSlim\HttpClient;
196-
use JustSteveKing\PhpSdk\SDK;
197-
use JustSteveKing\UriBuilder\Uri;
198-
use PHPFox\Container\Container;
199-
200-
class MySDK extends SDK
201-
{
202-
public function __construct()
203-
{
204-
parent::__construct(
205-
uri: Uri::fromString(
206-
uri: 'https://www.domain.tld',
207-
),
208-
client: HttpClient::build(),
209-
container: Container::getInstance(),
210-
strategy: new NullStrategy()),
211-
);
212-
}
157+
```bash
158+
composer run pint
159+
```
213160

214-
public static function boot(): MySDK
215-
{
216-
$client = new MySDK();
161+
## Refactoring
217162

218-
$client->add(
219-
name: TestResource::name(),
220-
resource: TestResource::class,
221-
);
163+
To run the rector code refactoring:
222164

223-
return $client;
224-
}
225-
}
165+
```bash
166+
composer run refactor
226167
```
227168

228-
## Testing
169+
## Special Thanks
229170

230-
TO run the test:
171+
Without the following packages and people, this framework would have been a lot harder to build.
231172

232-
```bash
233-
composer run test
234-
```
173+
- [The PHP League - Object Mapper](https://github.com/thephpleague/object-mapper)
174+
- [Ben Ramsey - Collection](https://github.com/ramsey/collection)
175+
- [Larry Garfield - Serde](https://github.com/crell/serde)
235176

236177
## Credits
237178

@@ -240,4 +181,4 @@ composer run test
240181

241182
## LICENSE
242183

243-
The MIT LIcense (MIT). Please see [License File](./LICENSE) for more information.
184+
The MIT License (MIT). Please see [License File](./LICENSE) for more information.

banner.png

-112 KB
Binary file not shown.

0 commit comments

Comments
 (0)