Skip to content

Commit

Permalink
Merge pull request #14 from Morning-Train/hotfix/special-api-formatting
Browse files Browse the repository at this point in the history
Add API formatting information to Resources
  • Loading branch information
mschadegg authored Feb 25, 2024
2 parents d4907dd + 175471f commit 1ba49fc
Show file tree
Hide file tree
Showing 24 changed files with 362 additions and 217 deletions.
127 changes: 67 additions & 60 deletions src/Abstracts/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
use DateTime;
use Exception;
use Illuminate\Support\Collection;
use JsonSerializable;
use Morningtrain\Economic\Attributes\Resources\GetSingle;
use Morningtrain\Economic\Attributes\Resources\Properties\PrimaryKey;
use Morningtrain\Economic\Attributes\Resources\Properties\ResourceType;
use Morningtrain\Economic\Classes\EconomicCollection;
use Morningtrain\Economic\Classes\EconomicCollectionIterator;
use Morningtrain\Economic\Interfaces\ApiFormatter;
use Morningtrain\Economic\Services\EconomicApiService;
use Morningtrain\Economic\Services\EconomicLoggerService;
use ReflectionAttribute;
use ReflectionClass;
use ReflectionMethod;

abstract class Resource
abstract class Resource implements JsonSerializable
{
public string $self;

Expand Down Expand Up @@ -129,47 +131,63 @@ public function setPrimaryKey(int|string|float $value): static
return $this;
}

public function toArray(): array
protected static function resolveArgs(array $args, bool $forApiRequest = false)
{
$reflection = new ReflectionClass(static::class);
foreach ($args as $key => &$value) {
if ($value === null) {
if ($forApiRequest) {
unset($args[$key]); // We don't want to send null values to the API
}

$properties = [];
continue; // We don't want to format null values
}

foreach ($reflection->getProperties() as $property) {
// If not public then skip
if (! $property->isPublic()) {
continue;
// Try to convert to resource
try {
$reflection = new ReflectionClass(static::class);

$propertyReflection = $reflection->getProperty($key);

$reflectionTypeName = $propertyReflection->getType()->getName();

// If is a class
if (
is_a($reflectionTypeName, Resource::class, true) &&
! is_a($value, Resource::class)
) {
$value = new ($propertyReflection->getType()->getName())($value);
}
} catch (Exception $e) {
// Do nothing, since we can't format the value
}

// Set self if not set
if (
$property->getName() == 'self' &&
empty($this->{$property->getName()}) &&
! empty($this->getPrimaryKey())
) {
// If is for API request then we have some special format cases
if ($forApiRequest) {
// Format the value if it has a special case defined
try {
$self = EconomicApiService::createURL($this->getEndpoint(GetSingle::class, $this->getPrimaryKey()));
$reflection = new ReflectionClass(static::class);

$propertyReflection = $reflection->getProperty($key);

$this->self = $self;
$attribute = $propertyReflection->getAttributes(ApiFormatter::class, ReflectionAttribute::IS_INSTANCEOF);

if (! empty($attribute[0]) && ! empty($value)) {
$apiFormatter = $attribute[0]->newInstance();

$value = $apiFormatter->format($value);
}
} catch (Exception $e) {
// Do nothing, since we can't get the self
// Do nothing, since we can't format the value
}
}

// If property is not set then skip
if (! isset($this->{$property->getName()})) {
continue;
}

$value = $this->{$property->getName()};

// If is EconomicCollection then only get the self property
if ($property->getType() == EconomicCollection::class) {
if (is_a($value, EconomicCollection::class)) {
$value = $value->getSelf();
}

// If is Resource then get the array representation
if (is_a($value, Resource::class)) {
// If is Collection
if (is_a($value, Collection::class)) {
$value = $value->toArray();
}

Expand All @@ -178,53 +196,42 @@ public function toArray(): array
$value = $value->format(DateTime::ATOM);
}

$properties[$property->getName()] = $value;
}

return $properties;
}

public function __toString(): string
{
return json_encode($this->toArray());
}

protected static function filterEmpty(array $values): array
{
foreach ($values as $key => $value) {
// If is array (NOTE: need to be before converting to Resource to ensure we follow the Resource formatting)
if (is_array($value)) {
$values[$key] = static::filterEmpty($value);
$value = static::resolveArgs($value, $forApiRequest);
}

if ($values[$key] === null) {
unset($values[$key]);
// If is Resource then get the array representation
if (is_a($value, Resource::class)) {
$value = $value->toArray($forApiRequest);
}
}

return $values;
return $args;
}

protected static function getMethodArgs(string $function, array $arguments): array
public function toArray(bool $forApiRequest = false): array
{
$reflection = new ReflectionMethod(...explode('::', $function));

$assoc = [];
$vars = get_object_vars($this);

foreach ($reflection->getParameters() as $i => $parameter) {
$assoc[$parameter->getName()] = $arguments[$i] ?? null;
if (empty($vars['self']) && ! empty($this->getPrimaryKey())) {
try {
$vars['self'] = EconomicApiService::createURL($this->getEndpoint(GetSingle::class, $this->getPrimaryKey()));
} catch (Exception $e) {
// Do nothing, since we can't get the self
}
}

return $assoc;
return static::resolveArgs($vars, $forApiRequest);
}

protected static function resolveArguments(array $arguments): array
public function __toString(): string
{
$creationParameters = [];

foreach ($arguments as $name => $value) {
$creationParameters[$name] = static::resolvePropertyValue($name, $value);
}
return json_encode($this->toArray());
}

return $creationParameters;
public function jsonSerialize(): array
{
return $this->toArray();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Morningtrain\Economic\Attributes\Resources\Properties\ApiFormatting;

use Attribute;
use Morningtrain\Economic\Abstracts\Resource;
use Morningtrain\Economic\Interfaces\ApiFormatter;

#[Attribute(Attribute::TARGET_PROPERTY)] class ResourceToArray implements ApiFormatter
{
protected array $properties;

public function __construct(...$properties)
{
$this->properties = $properties;
}

public function format($value): array
{
if (! is_a($value, Resource::class)) {
throw new \InvalidArgumentException('ResourceToArray can only be used on properties of type Resource');
}

$resourceAsArray = $value->toArray();

$returnArray = [];

foreach ($this->properties as $key) {
if (isset($resourceAsArray[$key])) {
$returnArray[$key] = $resourceAsArray[$key];
}
}

return $returnArray;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Morningtrain\Economic\Attributes\Resources\Properties\ApiFormatting;

use Attribute;
use Morningtrain\Economic\Abstracts\Resource;
use Morningtrain\Economic\Interfaces\ApiFormatter;

#[Attribute(Attribute::TARGET_PROPERTY)] class ResourceToPrimaryKey implements ApiFormatter
{
public function __construct()
{
}

public function format($value): mixed
{
if (! is_a($value, Resource::class)) {
throw new \InvalidArgumentException('ResourceToArray can only be used on properties of type Resource');
}

return $value->getPrimaryKey();
}
}
8 changes: 8 additions & 0 deletions src/Interfaces/ApiFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Morningtrain\Economic\Interfaces;

interface ApiFormatter
{
public function format($value): mixed;
}
6 changes: 3 additions & 3 deletions src/Resources/Currency.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ class Currency extends Resource
{
use GetCollectionable, GetSingleable;

public string $code;
public ?string $code = null;

#[PrimaryKey]
public string $isoNumber;
public ?string $isoNumber = null;

public string $name;
public ?string $name = null;
}
33 changes: 28 additions & 5 deletions src/Resources/Customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Customer extends Resource

public float $balance;

public bool $barred;
public ?bool $barred;

public ?string $city;

Expand Down Expand Up @@ -67,7 +67,7 @@ class Customer extends Resource

public ?string $ean;

public bool $eInvoicingDisabledByDefault;
public ?bool $eInvoicingDisabledByDefault;

public ?string $email;

Expand Down Expand Up @@ -131,9 +131,32 @@ public static function create(
Layout|int|null $layout = null,
Employee|int|null $salesPerson = null,
): static {
$creationParameters = static::resolveArguments(static::getMethodArgs(__METHOD__, func_get_args()));

return static::createRequest($creationParameters);
return static::createRequest(compact(
'name',
'customerGroup',
'currency',
'vatZone',
'paymentTerms',
'email',
'address',
'zip',
'city',
'country',
'corporateIdentificationNumber',
'pNumber',
'vatNumber',
'ean',
'publicEntryNumber',
'website',
'mobilePhone',
'telephoneAndFaxNumber',
'barred',
'eInvoicingDisabledByDefault',
'creditLimit',
'customerNumber',
'layout',
'salesPerson'
));
}

public static function new(
Expand Down
2 changes: 2 additions & 0 deletions src/Resources/Customer/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Morningtrain\Economic\Attributes\Resources\Delete;
use Morningtrain\Economic\Attributes\Resources\GetCollection;
use Morningtrain\Economic\Attributes\Resources\GetSingle;
use Morningtrain\Economic\Attributes\Resources\Properties\ApiFormatting\ResourceToArray;
use Morningtrain\Economic\Attributes\Resources\Properties\PrimaryKey;
use Morningtrain\Economic\Attributes\Resources\Update;
use Morningtrain\Economic\Classes\EconomicRelatedResource;
Expand All @@ -28,6 +29,7 @@ class Contact extends Resource
{
use Creatable, Deletable, EndpointResolvable, GetCollectionable, GetSingleable, Updatable;

#[ResourceToArray('customerNumber', 'self')]
public Customer $customer;

#[PrimaryKey]
Expand Down
20 changes: 0 additions & 20 deletions src/Resources/Invoice/DraftInvoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,6 @@ public static function create(
// ?Project|int $project = null, // TODO: Implement
?Reference $references = null
): ?static {
if (is_a($currency, Currency::class)) {
$currency = $currency->isoNumber;
}

if (is_int($customer)) {
$customer = new Customer(['customerNumber' => $customer]);
}

if (is_int($layout)) {
$layout = new Layout(['layoutNumber' => $layout]);
}

if (is_int($paymentTerms)) {
$paymentTerms = new PaymentTerm(['paymentTermsNumber' => $paymentTerms]);
}

return static::createRequest(compact(
'currency',
'customer',
Expand Down Expand Up @@ -94,10 +78,6 @@ public static function new(
// ?Project|int $project = null, // TODO: Implement
?Reference $references = null
): ?static {
if (is_a($currency, Currency::class)) {
$currency = $currency->isoNumber;
}

return new static(array_filter(compact(
'currency',
'customer',
Expand Down
7 changes: 6 additions & 1 deletion src/Resources/Invoice/Invoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

use DateTime;
use Morningtrain\Economic\Abstracts\Resource;
use Morningtrain\Economic\Attributes\Resources\Properties\ApiFormatting\ResourceToArray;
use Morningtrain\Economic\Attributes\Resources\Properties\ApiFormatting\ResourceToPrimaryKey;
use Morningtrain\Economic\DTOs\Invoice\Note;
use Morningtrain\Economic\DTOs\Invoice\Recipient;
use Morningtrain\Economic\DTOs\Invoice\Reference;
use Morningtrain\Economic\Resources\Currency;
use Morningtrain\Economic\Resources\Customer;
use Morningtrain\Economic\Resources\Layout;
use Morningtrain\Economic\Resources\PaymentTerm;
Expand All @@ -22,8 +25,10 @@ class Invoice extends Resource
use GetSingleable;
use HasLines;

public ?string $currency = null;
#[ResourceToPrimaryKey()]
public ?Currency $currency = null;

#[ResourceToArray('customerNumber', 'self')]
public ?Customer $customer = null;

public ?DateTime $date = null;
Expand Down
Loading

0 comments on commit 1ba49fc

Please sign in to comment.