1. Go to this page and download the library: Download brahmic/clientdto 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/ */
brahmic / clientdto example snippets
// In the Controller
// Get resource and sets the data from the Request to the Children request
public function (Person $person, Request $request) {
return $person->children()->set($request)->send();
}
// The request data will be automatically filled in from the Request.
public function (Children $children) {
return $children->send();
}
// Returns CustomResponse (extended of ClientResponse, implements Illuminate\Contracts\Support\Responsable)
$customClient->person()->children()->send()
// Returns null or the received answer as DTO object - MyPageableResultDto in this case.
$customClient->person()->children()->send()->resolved()
/** @var FileResponse|null $fileResponse */
$fileResponse = $customClient->person()->report()->send()->->resolved()
// Also we can get size, MIME type, set new name, etc.
// If it is an archive, it will be automatically unpacked.
$fileResponse->file()
->openInBrowser(true)
->saveAs('path/someReport');
$fileResponse->files()->saveTo('path/someReport');
class CustomClient extends ClientDTO
{
public function __construct(array $config = [])
{
$this
->cache(false)
->setBaseUrl('https://customapiservice.com/')
->setTimeout(60)
->requestCache() // Enable HTTP request caching
->requestCacheRaw() // Enable RAW response caching
->postIdempotent() // Allow POST request caching
->requestCacheTtl(3600) // Cache TTL: 1 hour
->requestCacheSize(5 * 1024 * 1024) // Cache size limit: 5MB
->onClearCache(function () {
$this->report()->clearCache();
})
->setDebug(app()->hasDebugModeEnabled());
}
public function person(): Person
{
return new Person();
}
//Primary processing of the response, all further resources along the chain receive the transformed response.
public static function handle(array $data): mixed
{
if (array_key_exists('response', $data)) {
return DefaultDto::from($data);
}
if (array_key_exists('query_type', $data) && array_key_exists('uuid', $data)) {
return OtherDto::from($data);
}
return $data;
}
/**
* @throws \Exception
*/
public function validation(mixed $data, AbstractRequest $abstractRequest, Response $response): mixed
{
if ($data instanceof DefaultDto) {
$exceptionTitle = $data->statusTitle();
return match ($data->status) {
SecondaryStatus::AnswerReceived->value => true,
SecondaryStatus::WaitingForAResponse->value => throw new AttemptNeededException($exceptionTitle, 202),
SecondaryStatus::SourceUnavailable->value => throw new AttemptNeededException($exceptionTitle, 523),
SecondaryStatus::CriticalError->value => throw new Exception($exceptionTitle, 500),
SecondaryStatus::UnknownError->value, => throw new Exception($exceptionTitle, 520),
default => throw new \Exception($exceptionTitle, 500)
};
}
if ($abstractRequest instanceof Report) {
return $data;
}
if ($response->getStatusCode() === 200) {
if ($status = Arr::get($data, 'status')) {
SecondaryStatus::check($status);
}
throw new UnresolvedResponseException("Response received but not recognized", $response);
}
throw new Exception("Unknown request. Check the request parameters, the request processing chain, including data processing via the `handle` method.", 500);
}
public function beforeExecute(AbstractRequest $request): void
{
if ($request instanceof CheckRequest) {
$this->addQueryParam('token', '123bbd2113da3s3f1xc23c8b4927');
}
}
public function getResponseClass(): string
{
return CustomResponse::class;
}
}
class Person extends AbstractResource
{
public const string NAME = 'Person'; //optional
public function children(): Children
{
return new Children();
}
public function report(): PersonReport
{
return new PersonReport();
}
}
class Children extends GetRequest implements PaginableRequestInterface
{
use Uuid, Paginable;
public const string NAME = "The person's children"; //optional
#[Wrapped(CaseDto::class)]
protected ?string $dto = MyPageableResultDto::class;
public const string URI = 'person/{uuid}/children';
//Optional. This name will be used when sending a request to the remote API instead of "filterText"
#[MapOutputName('filter_text')]
//Optional. This information can be extracted later to create a registry of queries created.
#[Filter(title: 'Search string', description: 'Enter text', note: 'Search by name')]
public ?string $filterText = null;
public function set(
string $uuid,
?int $page = null,
?int $rows = null,
?string $filterText = null,
): static
{
return $this->assignSetValues();
}
}
class PersonReport extends GetRequest
{
use Uuid;
public const string NAME = 'Get report'; //optional
public const string URI = 'person/{uuid}/report';
protected ?string $dto = FileResponse::class;
public Format $event = Format::Pdf;
public function set(string $uuid, ?Format $event = null): static
{
return $this->assignSetValues();
}
public function postProcess(FileResponse $fileResponse): void
{
$fileResponse->file()->openInBrowser(false)->prependFilename(self::NAME);
}
}
class MyClient extends ClientDTO
{
public function __construct()
{
$this->setBaseUrl('https://api.example.com');
// Handler for all resolved data
$this->addResolvedHandler(function($dto, $request) {
if (is_object($dto) && property_exists($dto, 'timestamp')) {
$dto->timestamp = now();
}
});
// Handler for specific DTO class only
$this->addResolvedHandler(
function(UserDto $dto, AbstractRequest $request) {
$dto->displayName = ucfirst($dto->firstName . ' ' . $dto->lastName);
// Access request parameters for additional logic
if ($request->
// Simple function handler for all resolved data
$client->addResolvedHandler(function($dto, AbstractRequest $request) {
// Process any resolved data
// The $request parameter provides access to the original request context
});
// Type-specific handler with parameter hints
$client->addResolvedHandler(
function(TelegramResponseDto $dto, AbstractRequest $request) {
// Modify DTO based on response data
$dto->processedAt = now();
// Access request properties and methods for conditional logic
if ($request instanceof SearchTelegramByPhoneRequest) {
$dto->searchType = 'phone';
$dto->userName = '6787'; // Example modification
}
// Use request parameters
if ($request->debugMode ?? false) {
$dto->requestTrace = [
'class' => get_class($request),
'url' => $request->getFullUrl(),
'timestamp' => microtime(true)
];
}
},
TelegramResponseDto::class
);
use Brahmic\ClientDTO\Contracts\ResolvedHandlerInterface;
use Brahmic\ClientDTO\Requests\AbstractRequest;
class UserDataEnhancer implements ResolvedHandlerInterface
{
public function handle(mixed $dto, AbstractRequest $request): void
{
if ($dto instanceof UserDto) {
// Enhance user data
$dto->avatar = $this->generateAvatarUrl($dto->email);
$dto->lastSeen = $this->formatLastSeen($dto->lastSeenAt);
// Use request context for conditional processing
if ($request->debugMode ?? false) {
$dto->debug = [
'request_id' => $request->getTrackingId() ?? uniqid(),
'request_class' => get_class($request),
'processed_at' => now()->toISOString()
];
}
// Access request-specific properties
if ($request instanceof GetUserProfileRequest) {
$dto->
class MyClient extends ClientDTO
{
public function __construct()
{
$this
->requestCache() // Enable caching
->requestCacheRaw() // RAW mode: handlers run each time
// This handler will run every time in RAW mode
// or once before caching in DTO mode
->addResolvedHandler(
function(ApiResponseDto $dto) {
$dto->processingTime = microtime(true) - $dto->startTime;
},
ApiResponseDto::class
);
}
}
use Brahmic\ClientDTO\Attributes\Label;
use Brahmic\ClientDTO\Attributes\WithLabels;
use Brahmic\ClientDTO\Support\Data;
#[WithLabels(autoTransform: true)]
class UserProfileDto extends Data
{
#[Label('User ID')]
public ?int $id;
#[Label('Full Name')]
public ?string $name;
#[Label('Email Address')]
public ?string $email;
#[Label('Registration Date')]
public ?Carbon $created_at;
#[Label('Profile Status')]
public ?string $status;
}
use Brahmic\ClientDTO\Attributes\WithLabels;
class OrderDto extends Data
{
#[Label('Order Number')]
public ?string $number;
#[Label('Order Date')]
public ?Carbon $created_at;
// Force labels ON for this property (overrides CustomerDto class-level setting)
#[WithLabels(autoTransform: true, withKey: false)]
public ?CustomerDto $customer;
// Force labels OFF for this property
#[WithLabels(autoTransform: false)]
public ?DeliveryDto $delivery;
}
#[WithLabels(autoTransform: false, withKey: true)] // Class-level default: no labels
class CustomerDto extends Data
{
#[Label('Customer Name')]
public ?string $name;
#[Label('Customer Email')]
public ?string $email;
}
class DeliveryDto extends Data
{
// No labels defined - regular DTO
public ?string $method;
public ?string $address;
}
use Brahmic\ClientDTO\Contracts\GroupedRequest;
use Illuminate\Support\Collection;
class HouseCompleteInfoRequest extends GetRequest implements GroupedRequest
{
public const string NAME = 'Complete house information';
// Final DTO that will be returned to user
protected ?string $dto = HouseCompleteInfoDto::class;
protected bool $groupedWithKeys = true;
public ?string $house_id = null;
public function set(string $house_id): static
{
return $this->assignSetValues();
}
// Define which requests to execute
public function getRequestClasses(): Collection
{
return collect([
HouseInfoRequest::class,
HousePassportRequest::class,
]);
}
}
class HouseCompleteInfoDto extends Data
{
/**
* House basic information (from HouseInfoRequest)
*/
public ?HouseInfoDto $houseInfoDto;
/**
* House passport data (from HousePassportRequest)
*/
public ?HousePassportDto $housePassportDto;
}
class HouseAnalyticsRequest extends GetRequest implements GroupedRequest
{
public const string NAME = 'House analytics with processing';
// Final DTO (what user gets)
protected ?string $dto = HouseAnalyticsDto::class;
// Intermediate DTO (for data collection)
protected ?string $groupedDto = HouseCompleteInfoDto::class;
protected bool $groupedWithKeys = true;
public ?string $house_id = null;
public function set(string $house_id): static
{
return $this->assignSetValues();
}
public function getRequestClasses(): Collection
{
return collect([
HouseInfoRequest::class,
HousePassportRequest::class,
]);
}
/**
* Process the intermediate DTO before final transformation
* Returns array for creating HouseAnalyticsDto::from()
*/
public static function handle(HouseCompleteInfoDto $intermediateDto): array
{
// Process the collected data and return array for final DTO creation
return [
'condition_score' => static::calculateScore($intermediateDto),
'investment_rating' => static::calculateRating($intermediateDto),
'recommendations' => static::generateRecommendations($intermediateDto),
'analysis_date' => now()->toDateString(),
'processed_data_count' => 2, // HouseInfo + HousePassport
];
}
private static function calculateScore(HouseCompleteInfoDto $data): int
{
$score = 100;
if ($data->houseInfoDto?->deterioration > 50) {
$score -= 30;
}
return max(0, $score);
}
}
class HouseAnalyticsDto extends Data
{
public ?int $condition_score;
public ?float $investment_rating;
public ?array $recommendations;
}
class MyClient extends ClientDTO
{
public function __construct()
{
$this
->requestCache() // Enable HTTP request caching
->requestCacheRaw() // Enable RAW response caching (optional)
->postIdempotent() // Allow POST request caching (optional)
->requestCacheTtl(3600) // Cache TTL: 1 hour (optional)
->requestCacheSize(5 * 1024 * 1024); // Cache size limit: 5MB (optional)
}
}
use Brahmic\ClientDTO\Attributes\Cacheable;
#[Cacheable(enabled: true, ttl: 7200)] // Cache for 2 hours
class GetUserRequest extends GetRequest
{
// This request will be cached regardless of global settings
}
#[Cacheable(enabled: false)] // Never cache
class CreateUserRequest extends PostRequest
{
// This request will never be cached
}
// Clear all ClientDTO caches
$client->clearRequestCache();
// Access cached response info
$response = $client->users()->get()->send();
if ($response->getMessage() === 'Successful (cached)') {
// Response came from cache
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.