Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attributes & reflection magic #71

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/Attributes/ArrayShape.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace TrueLayer\Attributes;

#[\Attribute]
class ArrayShape
{
public function __construct(public string $type)
{
}
}
13 changes: 13 additions & 0 deletions src/Attributes/Field.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace TrueLayer\Attributes;

#[\Attribute]
class Field
{
public function __construct(public ?string $name = null)
{
}
}
49 changes: 43 additions & 6 deletions src/Entities/Entity.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

namespace TrueLayer\Entities;

use TrueLayer\Attributes\ArrayShape;
use TrueLayer\Attributes\Field;
use TrueLayer\Exceptions\InvalidArgumentException;
use TrueLayer\Interfaces\ArrayableInterface;
use TrueLayer\Interfaces\Factories\EntityFactoryInterface;
use TrueLayer\Interfaces\HasAttributesInterface;
use TrueLayer\Services\Util\Str;
use TrueLayer\Traits\ArrayableAttributes;
use TrueLayer\Traits\CastsAttributes;

Expand All @@ -16,6 +19,10 @@ abstract class Entity implements ArrayableInterface, HasAttributesInterface
use CastsAttributes;
use ArrayableAttributes;

private array $propertyFieldMap = [];
private array $propertyCastMap = [];


/**
* @var EntityFactoryInterface
*/
Expand All @@ -26,16 +33,18 @@ abstract class Entity implements ArrayableInterface, HasAttributesInterface
*/
public function __construct(
EntityFactoryInterface $entityFactory
) {
)
{
$this->entityFactory = $entityFactory;
$this->buildFieldAndCastMaps();
}

/**
* @param mixed[] $data
*
* @return $this
* @throws InvalidArgumentException
*
* @return $this
*/
public function fill(array $data): self
{
Expand All @@ -49,11 +58,11 @@ public function fill(array $data): self
* @template T
*
* @param class-string<T> $abstract
* @param mixed[]|null $data
* @param mixed[]|null $data
*
* @return T
* @throws InvalidArgumentException
*
* @return T
*/
protected function make(string $abstract, ?array $data = null)
{
Expand All @@ -64,16 +73,44 @@ protected function make(string $abstract, ?array $data = null)
* @template T
*
* @param class-string<T> $abstract
* @param mixed[]|null $data
* @param mixed[]|null $data
*
* @return T[]
* @throws InvalidArgumentException
*
* @return T[]
*/
protected function makeMany(string $abstract, ?array $data = null)
{
return $data ?
$this->entityFactory->makeMany($abstract, $data)
: [];
}

private function buildFieldAndCastMaps(): void
{
$reflectionClass = new \ReflectionClass(get_called_class());

foreach ($reflectionClass->getProperties() as $property) {
$fieldAttributes = $property->getAttributes(Field::class);

// If the property is not annotated with the Field attribute, we skip it.
if (empty($fieldAttributes)) {
continue;
}

$propertyName = $property->getName();
$dotNotationFieldName = $fieldAttributes[0]->newInstance()->name ?? Str::snake($propertyName);;
$this->propertyFieldMap[$dotNotationFieldName] = $propertyName;

$arrayTypeAttributes = $property->getAttributes(ArrayShape::class);
if (!empty($arrayTypeAttributes)) {
$this->propertyCastMap["{$dotNotationFieldName}.*"] = $arrayTypeAttributes[0]->newInstance()->type;
} else {
$propertyType = $property->getType();
if ($propertyType instanceof \ReflectionNamedType) {
$this->propertyCastMap[$dotNotationFieldName] = $propertyType->getName();
}
}
}
}
}
25 changes: 10 additions & 15 deletions src/Entities/Hpp.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace TrueLayer\Entities;

use TrueLayer\Attributes\Field;
use TrueLayer\Interfaces\HppInterface;
use TrueLayer\Services\Util\Str;

Expand All @@ -12,51 +13,45 @@ final class Hpp extends Entity implements HppInterface
/**
* @var string
*/
#[Field]
protected string $baseUrl;

/**
* @var string
*/
#[Field]
protected string $paymentId;

/**
* @var string
*/
#[Field]
protected string $resourceToken;

/**
* @var string
*/
#[Field]
protected string $returnUri;

/**
* @var string
*/
#[Field('c_primary')]
protected string $primaryColour;

/**
* @var string
*/
#[Field('c_secondary')]
protected string $secondaryColour;

/**
* @var string
*/
#[Field('c_tertiary')]
protected string $tertiaryColour;

/**
* @var string[]
*/
protected array $arrayFields = [
'base_url',
'payment_id',
'resource_token' => 'resource_token',
'return_uri',
'c_primary' => 'primary_colour',
'c_secondary' => 'secondary_colour',
'c_tertiary' => 'tertiary_colour',
];

/**
* @param string $baseUrl
*
Expand Down Expand Up @@ -206,8 +201,8 @@ public function toUrl(): string
unset($params['base_url']);

return $this->baseUrl . '#' . \http_build_query(
$params, '', '&', PHP_QUERY_RFC3986
);
$params, '', '&', PHP_QUERY_RFC3986
);
}

/**
Expand Down
9 changes: 2 additions & 7 deletions src/Entities/Payment/AuthorizationFlow/Action.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace TrueLayer\Entities\Payment\AuthorizationFlow;

use TrueLayer\Attributes\Field;
use TrueLayer\Entities\Entity;
use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\ActionInterface;

Expand All @@ -12,15 +13,9 @@ class Action extends Entity implements ActionInterface
/**
* @var string
*/
#[Field]
protected string $type;

/**
* @var string[]
*/
protected array $arrayFields = [
'type',
];

/**
* @return string
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace TrueLayer\Entities\Payment\AuthorizationFlow\Action;

use TrueLayer\Attributes\ArrayShape;
use TrueLayer\Attributes\Field;
use TrueLayer\Entities\Payment\AuthorizationFlow\Action;
use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\ProviderSelectionActionInterface;
use TrueLayer\Interfaces\Provider\ProviderInterface;
Expand All @@ -13,23 +15,9 @@ class ProviderSelectionAction extends Action implements ProviderSelectionActionI
/**
* @var ProviderInterface[]
*/
#[Field, ArrayShape(ProviderInterface::class)]
protected array $providers = [];

/**
* @var array|string[]
*/
protected array $arrayFields = [
'type',
'providers',
];

/**
* @var string[]
*/
protected array $casts = [
'providers.*' => ProviderInterface::class,
];

/**
* @return ProviderInterface[]
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace TrueLayer\Entities\Payment\AuthorizationFlow\Action;

use TrueLayer\Attributes\Field;
use TrueLayer\Entities\Payment\AuthorizationFlow\Action;
use TrueLayer\Interfaces\Payment\AuthorizationFlow\Action\RedirectActionInterface;
use TrueLayer\Interfaces\Provider\ProviderInterface;
Expand All @@ -13,29 +14,15 @@ class RedirectAction extends Action implements RedirectActionInterface
/**
* @var string
*/
#[Field]
protected string $uri;

/**
* @var ProviderInterface
*/
#[Field('metadata')]
protected ProviderInterface $provider;

/**
* @var array|string[]
*/
protected array $casts = [
'metadata' => ProviderInterface::class,
];

/**
* @var string[]
*/
protected array $arrayFields = [
'type',
'uri',
'metadata' => 'provider',
];

/**
* @return string
*/
Expand Down
13 changes: 3 additions & 10 deletions src/Entities/Payment/AuthorizationFlow/AuthorizationFlow.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace TrueLayer\Entities\Payment\AuthorizationFlow;

use TrueLayer\Attributes\Field;
use TrueLayer\Entities\Entity;
use TrueLayer\Interfaces\Payment\AuthorizationFlow\ActionInterface;
use TrueLayer\Interfaces\Payment\AuthorizationFlow\AuthorizationFlowInterface;
Expand All @@ -14,23 +15,15 @@ final class AuthorizationFlow extends Entity implements AuthorizationFlowInterfa
/**
* @var ActionInterface
*/
#[Field('actions.next')]
protected ActionInterface $nextAction;

/**
* @var ConfigurationInterface
*/
#[Field]
protected ConfigurationInterface $configuration;

protected array $casts = [
'actions.next' => ActionInterface::class,
'configuration' => ConfigurationInterface::class,
];

protected array $arrayFields = [
'actions.next' => 'next_action',
'configuration' => 'configuration',
];

/**
* @return ConfigurationInterface|null
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,23 @@

namespace TrueLayer\Entities\Payment\AuthorizationFlow;

use TrueLayer\Attributes\Field;
use TrueLayer\Interfaces\Payment\AuthorizationFlow\AuthorizationFlowAuthorizationFailedInterface;

final class AuthorizationFlowAuthorizationFailed extends AuthorizationFlowResponse implements AuthorizationFlowAuthorizationFailedInterface
{
/**
* @var string
*/
#[Field]
protected string $failureStage;

/**
* @var string
*/
#[Field]
protected string $failureReason;

protected function arrayFields(): array
{
return \array_merge(parent::arrayFields(), [
'failure_stage',
'failure_reason',
]);
}

/**
* @return string
*/
Expand Down
Loading