Skip to content
Merged
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ composer.phar
composer.lock
.DS_Store
docs
.phpunit.result.cache
.phpunit.result.cache
.claude
3 changes: 2 additions & 1 deletion src/Fields/CarbonField.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Seier\Resting\Fields;

use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Seier\Resting\Parsing\CarbonParser;
use Seier\Resting\Validation\CarbonValidator;
use Seier\Resting\Formatting\CarbonFormatter;
Expand Down Expand Up @@ -63,7 +64,7 @@ public function set($value): static
return parent::set($value);
}

public function get(): ?Carbon
public function get(): Carbon|CarbonImmutable|null
{
return $this->value?->copy();
}
Expand Down
16 changes: 7 additions & 9 deletions src/Fields/CarbonPeriodField.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace Seier\Resting\Fields;

use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Carbon\CarbonPeriod;
use Seier\Resting\Parsing\CarbonParser;
use Seier\Resting\Parsing\CarbonPeriodParser;
Expand Down Expand Up @@ -58,18 +60,14 @@ public function asArray(): array
];
}

public function start(): ?Carbon
public function start(): Carbon|CarbonImmutable|null
{
$carbon = $this->get()?->start?->copy();

return $carbon ? new Carbon($carbon) : null;
return $this->get()?->start?->copy();
}

public function end(): ?Carbon
public function end(): Carbon|CarbonImmutable|null
{
$carbon = $this->get()?->end?->copy();

return $carbon ? new Carbon($carbon) : null;
return $this->get()?->end?->copy();
}

public function withFormat($format): static
Expand Down Expand Up @@ -145,7 +143,7 @@ private function fromArray(array $values): CarbonPeriod
$parsed = [];
foreach ($values as $index => $value) {

if (!$value instanceof Carbon) {
if (!$value instanceof CarbonInterface) {
$errors[] = (new NotCarbonValidationError($value))->prependPath($index);
continue;
}
Expand Down
23 changes: 23 additions & 0 deletions src/Fields/ResourceField.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,29 @@ public function set($value): static
return $this;
}

public function apply(Closure $apply): static
{
$resource = $this->resource;
$apply($resource);
$this->set($resource);

return $this;
}

public function applyNullable(mixed $value, Closure $apply): static
{
if ($value === null) {
$this->set(null);
return $this;
}

$resource = $this->resource;
$apply($resource, $value);
$this->set($resource);

return $this;
}

public function resourceAsDefault(): static
{
$this->nullDefault($this->resourceFactory);
Expand Down
3 changes: 2 additions & 1 deletion src/Fields/Time.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@


use Carbon\Carbon;
use Carbon\CarbonInterface;

class Time
{
Expand Down Expand Up @@ -58,7 +59,7 @@ private function toCarbon(): Carbon
);
}

public static function fromCarbon(Carbon $carbon): static
public static function fromCarbon(CarbonInterface $carbon): static
{
return new static(
hours: $carbon->hour,
Expand Down
4 changes: 2 additions & 2 deletions src/Fields/TimeField.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Seier\Resting\Fields;

use Carbon\Carbon;
use Carbon\CarbonInterface;
use Seier\Resting\Parsing\TimeParser;
use Seier\Resting\Validation\TimeValidator;
use Seier\Resting\Formatting\TimeFormatter;
Expand Down Expand Up @@ -74,7 +74,7 @@ private function parsed($value): ?Time
return $value;
}

if ($value instanceof Carbon) {
if ($value instanceof CarbonInterface) {
return Time::fromCarbon($value);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Formatting/CarbonFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace Seier\Resting\Formatting;


use Carbon\Carbon;
use Carbon\CarbonInterface;
use Seier\Resting\Validation\Secondary\Panics;

class CarbonFormatter implements Formatter
Expand All @@ -20,7 +20,7 @@ public function format(mixed $value): ?string
return null;
}

if (!$value instanceof Carbon) {
if (!$value instanceof CarbonInterface) {
$this->panic();
}

Expand Down
34 changes: 19 additions & 15 deletions src/Marshaller/ResourceMarshaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
namespace Seier\Resting\Marshaller;


use stdClass;
use Seier\Resting\UnionResource;
use Seier\Resting\ResourceFactory;
use Seier\Resting\Fields\ResourceField;
use Seier\Resting\Fields\ResourceArrayField;
use Seier\Resting\Resource as RestingResource;
use Seier\Resting\Parsing\DefaultParseContext;
use Seier\Resting\Validation\Errors\ValidationError;
use Seier\Resting\ResourceValidation\ResourceValidator;
use Seier\Resting\Exceptions\ValidationExceptionHandler;
use Seier\Resting\Validation\Errors\NotArrayValidationError;
use Seier\Resting\Validation\Errors\RequiredValidationError;
use Seier\Resting\Validation\Errors\NullableValidationError;
use Seier\Resting\Validation\Predicates\ArrayResourceContext;
use Seier\Resting\Validation\Errors\ForbiddenValidationError;
use Seier\Resting\Validation\Errors\NotObjectValidationError;
use Seier\Resting\Validation\Errors\UnknownUnionDiscriminatorValidationError;

class ResourceMarshaller
Expand All @@ -44,7 +45,7 @@ public function pushPathError(string $path, ValidationError $validationError)
$this->validationErrors[] = $validationError->prependPath($path);
}

private function pushRootError(NotArrayValidationError $validationError)
private function pushRootError(NotArrayValidationError|NotObjectValidationError $validationError)
{
$this->pushPathError('', $validationError);
}
Expand Down Expand Up @@ -79,9 +80,8 @@ public function marshalResource(ResourceFactory $factory, mixed $content): Resou
$this->reset();

$resource = $factory->create();

if (!is_array($content)) {
$this->pushRootError(new NotArrayValidationError($content));
if (!$content instanceof stdClass) {
$this->pushRootError(new NotObjectValidationError($content));
return new ResourceMarshallerResult($resource, $this->validationErrors);
}

Expand All @@ -97,18 +97,18 @@ public function marshalResource(ResourceFactory $factory, mixed $content): Resou
return new ResourceMarshallerResult($resource, $this->validationErrors);
}

private function getUnionSubResource(UnionResource $baseResource, $content): ResourceMarshallerResult|UnionResource
private function getUnionSubResource(UnionResource $baseResource, stdClass $content): ResourceMarshallerResult|UnionResource
{
$dependantResources = $baseResource->getResourceMap();
$discriminatorKey = $baseResource->getDiscriminatorKey();

if (!array_key_exists($discriminatorKey, $content)) {
if (!property_exists($content, $discriminatorKey)) {
$path = $this->getCurrentPath($discriminatorKey);
$this->pushPathError($path, new RequiredValidationError());
return new ResourceMarshallerResult($baseResource, $this->validationErrors);
}

$discriminatorValue = $content[$discriminatorKey];
$discriminatorValue = $content->{$discriminatorKey};
if (!is_scalar($discriminatorValue) || !array_key_exists($discriminatorValue, $dependantResources)) {
$path = $this->getCurrentPath($discriminatorKey);
$this->pushPathError($path, new UnknownUnionDiscriminatorValidationError(
Expand All @@ -121,18 +121,22 @@ private function getUnionSubResource(UnionResource $baseResource, $content): Res
return $dependantResources[$discriminatorValue];
}

public function marshalResourceFields(RestingResource $resource, array $content)
public function marshalResourceFields(RestingResource $resource, array|stdClass $content)
{
if (is_array($content)) {
$content = (object)$content;
}

$fields = $this->getFields($resource);
$resourceContext = new ArrayResourceContext($fields, $content, $this->isStringBased);
$resourceContext = new ArrayResourceContext($fields, (array)$content, $this->isStringBased);
$resource->prepare($resourceContext);

foreach ($fields as $key => $field) {

$requiredValidator = $field->getRequiredValidator();
$nullableValidator = $field->getNullableValidator();
$forbiddenValidator = $field->getForbiddenValidator();
$isProvided = array_key_exists($key, $content);
$isProvided = property_exists($content, $key);
$field->setFilled($isProvided);

if (!$isProvided) {
Expand Down Expand Up @@ -166,7 +170,7 @@ public function marshalResourceFields(RestingResource $resource, array $content)

}

$fieldValue = $isProvided ? $content[$key] : $defaultValue;
$fieldValue = $isProvided ? $content->{$key} : $defaultValue;

if ($fieldValue === null) {
foreach ($nullableValidator->getDefaultValues() as $possibleDefault) {
Expand Down Expand Up @@ -267,7 +271,7 @@ public function marshalResourceFields(RestingResource $resource, array $content)
continue;
}

$exceptionHandler->suppress($this->getCurrentPath($key), fn() => $field->set($fieldValue));
$exceptionHandler->suppress($this->getCurrentPath($key), fn () => $field->set($fieldValue));
foreach ($exceptionHandler->getErrors() as $validationError) {
$this->pushError($validationError);
}
Expand Down Expand Up @@ -328,9 +332,9 @@ public function marshalResources(ResourceFactory $factory, $content): ResourceMa
$this->pushPath($key);
$resource = $factory->create();

if (!is_array($value)) {
if (!is_object($value)) {
$path = $this->getCurrentPath();
$this->pushPathError($path, new NotArrayValidationError($value));
$this->pushPathError($path, new NotObjectValidationError($value));
continue;
}

Expand Down
25 changes: 20 additions & 5 deletions src/Parsing/CarbonParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@


use Carbon\Carbon;
use Carbon\CarbonImmutable;
use Seier\Resting\RestingSettings;
use Seier\Resting\Fields\EmptyStringAsNull;
use Carbon\Exceptions\InvalidFormatException;

Expand Down Expand Up @@ -35,11 +37,12 @@ public function canParse(ParseContext $context): array
}

try {
$carbonClass = $this->carbonClass();

if ($this->format) {
Carbon::createFromFormat($this->format, $raw);
$carbonClass::createFromFormat($this->format, $raw);
} else {
Carbon::parse($raw);
$carbonClass::parse($raw);
}

return [];
Expand All @@ -48,17 +51,29 @@ public function canParse(ParseContext $context): array
}
}

public function parse(ParseContext $context): ?Carbon
public function parse(ParseContext $context): Carbon|CarbonImmutable|null
{
$raw = $context->getValue();
$raw = $this->maybeEmptyStringAsNull($raw);
if ($raw === null) {
return null;
}

$carbonClass = $this->carbonClass();

return $this->format
? Carbon::createFromFormat($this->format, $raw, now()->timezone)
: Carbon::parse($raw);
? $carbonClass::createFromFormat($this->format, $raw, now()->timezone)
: $carbonClass::parse($raw);
}

/**
* @return class-string<Carbon|CarbonImmutable>
*/
private function carbonClass(): string
{
return RestingSettings::instance()->useImmutableCarbon
? CarbonImmutable::class
: Carbon::class;
}

public function shouldParse(ParseContext $context): bool
Expand Down
1 change: 0 additions & 1 deletion src/Parsing/EnumParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

namespace Seier\Resting\Parsing;

use Exception;
use Throwable;
use BackedEnum;
use ReflectionEnum;
Expand Down
14 changes: 12 additions & 2 deletions src/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Seier\Resting;

use stdClass;
use Seier\Resting\Fields\Field;
use Illuminate\Support\Collection;
use Seier\Resting\Fields\ResourceField;
Expand Down Expand Up @@ -33,7 +34,7 @@ public static function create(): static

public static function fromArray(array $values): static
{
return static::fromCollection(collect($values));
return static::fromCollection(collect((object)$values));
}

public static function fromCollection(Collection $values): static
Expand Down Expand Up @@ -89,7 +90,7 @@ public function set(array|Collection $values): static
public function setFieldsFromCollection(Collection $collection): static
{
$marshaller = new ResourceMarshaller();
$marshaller->marshalResourceFields($this, $collection->toArray());
$marshaller->marshalResourceFields($this, (object)$collection->toArray());
if ($errors = $marshaller->getValidationErrors()) {
throw new ValidationException($errors);
}
Expand Down Expand Up @@ -280,6 +281,15 @@ public function toResponseArray(array $filter = null, array $rename = null, bool
});
}

public function toResponseObject(array $filter = null, array $rename = null, bool $requireFilled = false): stdClass
{
return (object)$this->toResponseArray(
filter: $filter,
rename: $rename,
requireFilled: $requireFilled
);
}

public function removeNulls(bool $should): static
{
$this->removeNulls = $should;
Expand Down
1 change: 0 additions & 1 deletion src/ResourceValidation/ResourceValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Seier\Resting\ResourceValidation;

use Seier\Resting\Fields\Field;
use Seier\Resting\Validation\Predicates\Predicate;

trait ResourceValidation
{
Expand Down
Loading