PHP code example of andydefer / php-client

1. Go to this page and download the library: Download andydefer/php-client library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

andydefer / php-client example snippets


// ❌ Sans ce package - Fragile, non typé, difficile à maintenir
$response = $client->get('https://api.example.com/users');
$data = json_decode($response->getBody(), true);
$userName = $data['data']['user']['name'] ?? null; 
// ↑ Si l'API change, tout casse sans prévenir
// ↑ Pas d'autocomplétion
// ↑ Pas de typage

// ✅ Avec PHP HTTP Client - Typé, sûr, auto-complétion
$request = new GetUserRequest();
$request->setUserId(123);

$response = $client->get(
    'https://api.example.com/users', 
    $request, 
    UserListResponse::class
);

$users = $response->getUsers(); // Typé : UserCollection
// ↑ Autocomplétion
// ↑ Types sûrs (int, string, Enum, etc.)
// ↑ Validation automatique des données

use AndyDefer\PhpClient\Abstracts\Request;
use AndyDefer\PhpClient\Enums\HttpMethod;
use AndyDefer\PhpClient\ValueObjects\UrlVO;
use AndyDefer\PhpClient\ValueObjects\RequestBodyVO;
use AndyDefer\PhpClient\Abstracts\Struct;
use AndyDefer\PhpClient\Enums\ContentType;

final class GetUserRequest extends Request
{
    private ?int $userId = null;

    public function setUserId(int $userId): self
    {
        $this->userId = $userId;
        return $this;
    }

    protected function setMethod(): HttpMethod
    {
        return HttpMethod::GET;
    }

    protected function setUrl(): UrlVO
    {
        $url = new UrlVO('https://api.example.com/users');
        if ($this->userId !== null) {
            $url = $url->withPath('/users/' . $this->userId);
        }
        return $url;
    }

    protected function setBody(): RequestBodyVO
    {
        return new RequestBodyVO(
            new class extends Struct {},
            ContentType::JSON
        );
    }
}

use AndyDefer\PhpClient\Abstracts\Response;

final class UserListResponse extends Response
{
    public function getUsers(): array
    {
        return $this->getBody()->getValue()->users ?? [];
    }

    public function getTotal(): int
    {
        return $this->getBody()->getValue()->total ?? 0;
    }

    public static function getStructClass(): string
    {
        return UserListStruct::class;
    }
}

use AndyDefer\PhpClient\Clients\ClientService;

$client = new ClientService();

$response = $client->get(
    'https://api.example.com/users',  // URI (absolue ou relative)
    $request,                          // Instance de Request
    UserListResponse::class            // Classe de réponse attendue
);

use AndyDefer\PhpClient\ValueObjects\HeadersVO;
use AndyDefer\PhpClient\Enums\ContentType;

$headers = new HeadersVO();
$headers
    ->setAuthorization('token123')                 // Authorization: Bearer token123
    ->setContentType(ContentType::JSON)            // Content-Type: application/json
    ->setAccept(ContentType::JSON)                 // Accept: application/json
    ->setHost('api.example.com')                   // Host: api.example.com
    ->setUserAgent('PHP/8.2')                      // User-Agent: PHP/8.2
    ->setXRequestId('req-123-456')                 // X-Request-Id: req-123-456
    ->setCustom('X-Custom-Header', 'value');       // Header personnalisé

use AndyDefer\PhpClient\ValueObjects\OptionsVO;

$options = new OptionsVO();
$options
    // Timeouts
    ->setTimeout(30)                    // Délai d'attente global
    ->setConnectTimeout(10)             // Délai de connexion
    
    // SSL
    ->setVerify(true)                   // Vérification SSL
    ->setCert('/path/to/cert.pem')      // Certificat SSL
    ->setSslKey('/path/to/key.pem')     // Clé SSL
    
    // Redirections
    ->setAllowRedirects(false)          // Suivre les redirections
    ->setMaxRedirects(5)                // Nombre max de redirections
    
    // Proxy
    ->setProxy('tcp://localhost:8080')  // Proxy
    ->setNoProxy(['.example.com'])      // Exclure du proxy
    
    // Authentification
    ->setAuth(['username', 'password']) // Basic auth
    
    // Environnement
    ->setBaseUri('https://api.example.com')  // Base URI
    ->setQuery(['page' => 1])                // Query params
    ->setDecodeContent(true)                 // Décoder le contenu
    ->setHttpErrors(false);                  // Ne pas lancer d'exception sur erreur HTTP

use AndyDefer\PhpClient\ValueObjects\RequestBodyVO;
use AndyDefer\PhpClient\Abstracts\Struct;

// Corps JSON
$struct = new UserCreateStruct(name: 'John', email: '[email protected]');
$body = new RequestBodyVO($struct, ContentType::JSON);

$json = $body->toString();   // '{"name":"John","email":"..."}'
$array = $body->toArray();   // ['name' => 'John', 'email' => '...']
$struct = $body->getStruct(); // UserCreateStruct

// Corps formulaire
$body = new RequestBodyVO($struct, ContentType::FORM);
$formData = $body->toString(); // 'name=John&email=...'

use AndyDefer\PhpClient\ValueObjects\ResponseBodyVO;

$body = new ResponseBodyVO(
    $jsonResponse,              // Chaîne JSON
    UserListStruct::class,      // Classe de structure
    ContentType::JSON           // Content-Type attendu
);

$struct = $body->getValue();    // UserListStruct hydraté
$formatted = $body->format();   // stdClass ou array
$isEmpty = $body->isEmpty();    // true si le corps est vide
$isValid = $body->isValidJson(); // true si le JSON est valide

use AndyDefer\PhpClient\ValueObjects\UrlVO;

$url = new UrlVO('https://api.example.com:8080/v2/users?page=1#section');

$url->getScheme();    // 'https'
$url->getHost();      // 'api.example.com'
$url->getPort();      // 8080
$url->getPath();      // '/v2/users'
$url->getQuery();     // UrlQueryVO avec 'page=1'
$url->getFragment();  // 'section'
$url->getBaseUrl();   // 'https://api.example.com:8080'
$url->getFullPath();  // '/v2/users?page=1#section'

// Modification (retourne une nouvelle instance)
$newUrl = $url->withPath('/v3/users');
$newUrl = $url->withQuery(new UrlQueryVO('limit=10'));
$newUrl = $url->withFragment(null);

use AndyDefer\PhpClient\ValueObjects\UrlQueryVO;

$query = new UrlQueryVO('page=1&limit=10');
$query = $query
    ->withParameter('page', 2)
    ->withParameter('sort', 'asc')
    ->withoutParameter('limit');

echo $query->toString(); // 'page=2&sort=asc'

// Intégration avec UrlVO
$url = new UrlVO('https://api.example.com/users?page=1');
$newUrl = $url->withQuery($query);
echo $newUrl->getValue(); // 'https://api.example.com/users?page=2&sort=asc'



declare(strict_types=1);

ts\Graph;
use AndyDefer\PhpClient\Abstracts\Request;
use AndyDefer\PhpClient\Abstracts\Response;
use AndyDefer\PhpClient\Abstracts\Struct;
use AndyDefer\PhpClient\Clients\ClientService;
use AndyDefer\PhpClient\Enums\ContentType;
use AndyDefer\PhpClient\Enums\HttpMethod;
use AndyDefer\PhpClient\ValueObjects\RequestBodyVO;
use AndyDefer\PhpClient\ValueObjects\UrlQueryVO;
use AndyDefer\PhpClient\ValueObjects\UrlVO;

// 1. Enum - Centralisation des URLs avec UrlVO
enum PlaceholderEndpoint: string
{
    case POSTS = 'https://jsonplaceholder.typicode.com/posts';
    case COMMENTS = 'https://jsonplaceholder.typicode.com/comments';

    public function getUrl(): UrlVO
    {
        return new UrlVO($this->value);
    }

    public function withId(int $id): UrlVO
    {
        $baseUrl = $this->getUrl();
        $path = parse_url($this->value, PHP_URL_PATH) . '/' . $id;
        return $baseUrl->withPath($path);
    }

    public function withQuery(array $params): UrlVO
    {
        $baseUrl = $this->getUrl();
        $query = http_build_query($params);
        return $baseUrl->withQuery(new UrlQueryVO($query));
    }
}

// 2. Graph
final class PostGraph extends Graph
{
    public function __construct(
        public readonly int $userId,
        public readonly int $id,
        public readonly string $title,
        public readonly string $body,
    ) {}
}

final class CommentGraph extends Graph
{
    public function __construct(
        public readonly int $postId,
        public readonly int $id,
        public readonly string $name,
        public readonly string $email,
        public readonly string $body,
    ) {}
}

// 3. Struct
final class PostListStruct extends Struct
{
    public function __construct(
        public readonly array $posts,
    ) {}
}

final class CommentListStruct extends Struct
{
    public function __construct(
        public readonly array $comments,
    ) {}
}

final class CreatedPostStruct extends Struct
{
    public function __construct(
        public readonly int $id,
        public readonly string $title,
        public readonly string $body,
        public readonly int $user_id,
    ) {}
}

final class CreatePostStruct extends Struct
{
    public function __construct(
        public readonly string $title,
        public readonly string $body,
        public readonly int $userId,
    ) {}
}

// 4. Requests avec UrlVO
final class GetPostsRequest extends Request
{
    protected function setMethod(): HttpMethod
    {
        return HttpMethod::GET;
    }

    protected function setUrl(): UrlVO
    {
        return PlaceholderEndpoint::POSTS->getUrl();
    }

    protected function setBody(): RequestBodyVO
    {
        return new RequestBodyVO(
            new class extends Struct {},
            ContentType::JSON
        );
    }
}

final class GetCommentsRequest extends Request
{
    private ?int $postId = null;

    public function setPostId(int $postId): self
    {
        $this->postId = $postId;
        return $this;
    }

    protected function setMethod(): HttpMethod
    {
        return HttpMethod::GET;
    }

    protected function setUrl(): UrlVO
    {
        if ($this->postId !== null) {
            return PlaceholderEndpoint::COMMENTS->withQuery(['postId' => $this->postId]);
        }
        return PlaceholderEndpoint::COMMENTS->getUrl();
    }

    protected function setBody(): RequestBodyVO
    {
        return new RequestBodyVO(
            new class extends Struct {},
            ContentType::JSON
        );
    }
}

final class GetCommentRequest extends Request
{
    private int $id = 0;

    public function setId(int $id): self
    {
        $this->id = $id;
        return $this;
    }

    protected function setMethod(): HttpMethod
    {
        return HttpMethod::GET;
    }

    protected function setUrl(): UrlVO
    {
        return PlaceholderEndpoint::COMMENTS->withId($this->id);
    }

    protected function setBody(): RequestBodyVO
    {
        return new RequestBodyVO(
            new class extends Struct {},
            ContentType::JSON
        );
    }
}

final class CreatePostRequest extends Request
{
    private string $title = '';
    private string $content = '';
    private int $userId = 0;

    public function setTitle(string $title): self
    {
        $this->title = $title;
        return $this;
    }

    public function setContent(string $content): self
    {
        $this->content = $content;
        return $this;
    }

    public function setUserId(int $userId): self
    {
        $this->userId = $userId;
        return $this;
    }

    protected function setMethod(): HttpMethod
    {
        return HttpMethod::POST;
    }

    protected function setUrl(): UrlVO
    {
        return PlaceholderEndpoint::POSTS->getUrl();
    }

    protected function setBody(): RequestBodyVO
    {
        $struct = new CreatePostStruct(
            title: $this->title,
            body: $this->content,
            userId: $this->userId
        );
        return new RequestBodyVO($struct, ContentType::JSON);
    }
}

// 5. Responses
final class PostListResponse extends Response
{
    public function getPosts(): array
    {
        $data = $this->getBody()->format();
        $posts = [];
        foreach ($data as $item) {
            $posts[] = PostGraph::from($item);
        }
        return $posts;
    }

    public static function getStructClass(): string
    {
        return PostListStruct::class;
    }
}

final class CommentListResponse extends Response
{
    public function getComments(): array
    {
        $data = $this->getBody()->format();
        $comments = [];
        foreach ($data as $item) {
            $comments[] = CommentGraph::from($item);
        }
        return $comments;
    }

    public static function getStructClass(): string
    {
        return CommentListStruct::class;
    }
}

final class CommentResponse extends Response
{
    public function getComment(): CommentGraph
    {
        $data = $this->getBody()->format();
        return CommentGraph::from($data);
    }

    public static function getStructClass(): string
    {
        return CommentStruct::class;
    }
}

final class CreatePostResponse extends Response
{
    public function getCreatedPost(): CreatedPostStruct
    {
        $data = $this->getBody()->format();
        if (is_object($data)) {
            $data = (array) $data;
        }
        return new CreatedPostStruct(
            id: (int) ($data['id'] ?? 0),
            title: (string) ($data['title'] ?? ''),
            body: (string) ($data['body'] ?? ''),
            user_id: (int) ($data['user_id'] ?? 0)
        );
    }

    public function getId(): int
    {
        return $this->getCreatedPost()->id;
    }

    public static function getStructClass(): string
    {
        return CreatedPostStruct::class;
    }
}

// 6. Client
class JsonPlaceholderClient
{
    private ClientService $client;

    public function __construct()
    {
        $this->client = new ClientService();
    }

    public function getPosts(): array
    {
        $request = new GetPostsRequest();
        $response = $this->client->get(
            PlaceholderEndpoint::POSTS->getUrl()->getValue(),
            $request,
            PostListResponse::class
        );
        return $response->getPosts();
    }

    public function getComments(?int $postId = null): array
    {
        $request = new GetCommentsRequest();
        if ($postId !== null) {
            $request->setPostId($postId);
        }
        $response = $this->client->get(
            PlaceholderEndpoint::COMMENTS->getUrl()->getValue(),
            $request,
            CommentListResponse::class
        );
        return $response->getComments();
    }

    public function getComment(int $id): CommentGraph
    {
        $request = new GetCommentRequest();
        $request->setId($id);
        $response = $this->client->get(
            PlaceholderEndpoint::COMMENTS->withId($id)->getValue(),
            $request,
            CommentResponse::class
        );
        return $response->getComment();
    }

    public function createPost(string $title, string $content, int $userId): CreatedPostStruct
    {
        $request = new CreatePostRequest();
        $request
            ->setTitle($title)
            ->setContent($content)
            ->setUserId($userId);

        $request->getHeaders()
            ->setContentType(ContentType::JSON)
            ->setAccept(ContentType::JSON);

        $response = $this->client->post(
            PlaceholderEndpoint::POSTS->getUrl()->getValue(),
            $request,
            CreatePostResponse::class
        );
        return $response->getCreatedPost();
    }
}

// 7. Utilisation avec HeadersVO et OptionsVO
$client = new JsonPlaceholderClient();

// Récupérer tous les posts
$posts = $client->getPosts();
echo "Posts: " . count($posts) . "\n";

// Récupérer un commentaire
$comment = $client->getComment(1);
echo "Commentaire: " . $comment->name . "\n";

// Créer un post avec headers et options
$request = new CreatePostRequest();
$request
    ->setTitle('Mon titre')
    ->setContent('Mon contenu')
    ->setUserId(1);

$request->getHeaders()
    ->setAuthorization('token-123')
    ->setContentType(ContentType::JSON)
    ->setAccept(ContentType::JSON)
    ->setXRequestId('req-123-456');

$request->getOptions()
    ->setTimeout(30)
    ->setConnectTimeout(10)
    ->setHttpErrors(false);

$response = $client->post(
    PlaceholderEndpoint::POSTS->getUrl()->getValue(),
    $request,
    CreatePostResponse::class
);

$created = $response->getCreatedPost();
echo "Post créé: " . $created->id . "\n";

final class PokemonListStruct extends Struct
{
    public function __construct(
        public readonly int $count,
        public readonly ?string $next,
        public readonly ?string $previous,
        public readonly PokemonCollection $results,
    ) {}
}

// Utilisation
$struct = PokemonListStruct::fromJson($json);
$json = $struct->encode(ContentType::JSON);

final class TypeGraph extends Graph
{
    public function __construct(
        public readonly string $name,
        public readonly string $url,
    ) {}
}

// Hydratation automatique
$type = TypeGraph::from([
    'name' => 'grass',
    'url' => 'https://pokeapi.co/api/v2/type/12/'
]);

$request->getHeaders()
    ->setContentType(ContentType::JSON)               // Content-Type
    ->setAuthorization('token123')                    // Authorization: Bearer token123
    ->setBasicAuth('username', 'password')            // Basic auth
    ->setApiKey('abc123')                             // X-API-Key: abc123
    ->setCookie('session=xyz')                        // Cookie
    ->setAccept(ContentType::JSON)                    // Accept
    ->setAcceptEncoding(ContentEncoding::GZIP)        // Accept-Encoding
    ->setAcceptLanguage('fr-FR')                      // Accept-Language
    ->setHost('api.example.com')                      // Host
    ->setUserAgent('PHP/8.2')                         // User-Agent
    ->setCacheControl(CacheControl::NO_CACHE)         // Cache-Control
    ->setXRequestId('req-123')                        // X-Request-Id
    ->setXCorrelationId('corr-123')                   // X-Correlation-Id
    ->setXsrfToken('token-xyz')                       // X-CSRF-Token
    ->setCustom('X-Custom', 'value');                 // Custom header

$request->getOptions()
    // Timeouts
    ->setTimeout(30)
    ->setConnectTimeout(10)
    ->setReadTimeout(60)
    
    // SSL
    ->setVerify(true)
    ->setCert('/path/to/cert.pem')
    ->setSslKey('/path/to/key.pem')
    
    // Redirections
    ->setAllowRedirects(false)
    ->setMaxRedirects(5)
    
    // Proxy
    ->setProxy('tcp://localhost:8080')
    ->setNoProxy(['.example.com'])
    
    // Authentification
    ->setAuth(['username', 'password'])
    
    // Environnement
    ->setBaseUri('https://api.example.com')
    ->setQuery(['page' => 1])
    ->setDecodeContent(true)
    ->setForceIpResolve('v4')
    ->setHttpErrors(false)
    ->setDebug(true);

use AndyDefer\PhpClient\ValueObjects\UrlVO;
use AndyDefer\PhpClient\ValueObjects\UrlQueryVO;

$url = new UrlVO('https://api.example.com:8080/v2/users?page=1#section');

// Accès aux composants
$url->getScheme();    // 'https'
$url->getHost();      // 'api.example.com'
$url->getPort();      // 8080
$url->getPath();      // '/v2/users'
$url->getQuery();     // UrlQueryVO
$url->getFragment();  // 'section'
$url->getBaseUrl();   // 'https://api.example.com:8080'
$url->getFullPath();  // '/v2/users?page=1#section'

// Modifications (immuables)
$newUrl = $url
    ->withPath('/v3/users')
    ->withQuery(new UrlQueryVO('limit=20'))
    ->withFragment('new-section');

use AndyDefer\PhpClient\ValueObjects\UrlQueryVO;

$query = new UrlQueryVO('page=1&limit=10');

// Accès
$query->get('page');     // '1'
$query->has('limit');    // true
$query->isEmpty();       // false
$query->getParameters(); // ['page' => '1', 'limit' => '10']

// Modifications (immuables)
$newQuery = $query
    ->withParameter('page', 2)
    ->withParameter('sort', 'asc')
    ->withoutParameter('limit')
    ->merge(['filter' => 'active']);

echo $newQuery->toString(); // 'page=2&sort=asc&filter=active'

// Comparaison (ordre ignoré)
$query1 = new UrlQueryVO('page=1&limit=10');
$query2 = new UrlQueryVO('limit=10&page=1');
$query1->equals($query2); // true

$statusCode = $response->getStatusCode();
$statusCode->isSuccess();        // 2xx
$statusCode->isError();          // 4xx ou 5xx
$statusCode->isOk();             // 200
$statusCode->isNotFound();       // 404
$statusCode->isUnauthorized();   // 401
$statusCode->isUnprocessableEntity(); // 422
$statusCode->getPhrase();        // 'OK', 'Not Found', etc.

// ✅ Bon - Une classe par endpoint avec UrlVO
final class GetUserRequest extends Request
{
    private ?int $userId = null;

    public function setUserId(int $userId): self
    {
        $this->userId = $userId;
        return $this;
    }

    protected function setUrl(): UrlVO
    {
        $url = new UrlVO('https://api.example.com/users');
        if ($this->userId !== null) {
            $url = $url->withPath('/users/' . $this->userId);
        }
        return $url;
    }
}

// ❌ Mauvais - Concaténation de strings
protected function setUrl(): UrlVO
{
    return new UrlVO('https://api.example.com/users/' . $this->userId);
}

// ✅ Bon - URLs centralisées
enum ApiEndpoint: string
{
    case USERS = 'https://api.example.com/users';
    case POSTS = 'https://api.example.com/posts';

    public function getUrl(): UrlVO
    {
        return new UrlVO($this->value);
    }

    public function withId(int $id): UrlVO
    {
        return $this->getUrl()->withPath(parse_url($this->value, PHP_URL_PATH) . '/' . $id);
    }
}

// ❌ Mauvais - URLs dispersées dans le code
protected function setUrl(): UrlVO
{
    return new UrlVO('https://api.example.com/users/123');
}

// ✅ Bon - Enum pour les valeurs fixes
$request->getHeaders()->setContentType(ContentType::JSON);
$request->getOptions()->setTimeout(30);

// ❌ Mauvais - String magique
$request->getHeaders()->setCustom('Content-Type', 'application/json');
$request->getOptions()->setCustom('timeout', 30);

// ✅ Bon - Configuration groupée
$request->getHeaders()
    ->setAuthorization($token)
    ->setContentType(ContentType::JSON)
    ->setAccept(ContentType::JSON)
    ->setXRequestId($requestId);

// ❌ Mauvais - Configuration dispersée
$request->getHeaders()->setAuthorization($token);
// ... 20 lignes plus tard
$request->getHeaders()->setContentType(ContentType::JSON);

$headers = new HeadersVO();
$headers
    ->setStrictTransportSecurity('max-age=31536000')
    ->setXsrfToken($csrfToken)
    ->setAuthorization($token)
    ->setContentType(ContentType::JSON)
    ->setAccept(ContentType::JSON);

public function test_get_users_success(): void
{
    $client = new ClientService();
    $request = new GetUserRequest();
    $request->setUserId(1);
    
    $response = $client->get(
        ApiEndpoint::USERS->withId(1)->getValue(),
        $request,
        UserResponse::class
    );
    
    $this->assertTrue($response->isSuccess());
    $this->assertSame(1, $response->getId());
}
bash
composer