Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenvanassche committed Jan 17, 2024
1 parent 49a184f commit 0346ce4
Show file tree
Hide file tree
Showing 20 changed files with 579 additions and 249 deletions.
1 change: 1 addition & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The following things are required when upgrading:
- If you were using internal data structures like `DataClass` and `DataProperty` then take a look at what has been changed
- The `DataCollectableTransformer` and `DataTransformer` were replaced with their appropriate resolvers
- If you've cached the data structures, be sure to clear the cache
- In previous versions, when trying to include, exclude, only or except certain data properties that did not exist not exception was thrown. This is now the case, these exceptions can be silenced by setting `ignore_invalid_partials` to true within the config file

We advise you to take a look at the following things:
- Take a look within your data objects if `DataCollection`'s, `DataPaginatedCollection`'s and `DataCursorPaginatedCollection`'s can be replaced with regular arrays, Laravel Collections and Paginator
Expand Down
8 changes: 7 additions & 1 deletion config/data.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,11 @@
* method. By default, only when a request is passed the data is being validated. This
* behaviour can be changed to always validate or to completely disable validation.
*/
'validation_type' => \Spatie\LaravelData\Support\Creation\ValidationType::OnlyRequests->value
'validation_type' => \Spatie\LaravelData\Support\Creation\ValidationType::OnlyRequests->value,

/**
* When using an invalid include, exclude, only or except partial, the package will
* throw an
*/
'ignore_invalid_partials' => false,
];
10 changes: 10 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ parameters:
count: 1
path: src/Casts/DateTimeInterfaceCast.php

-
message: "#^PHPDoc tag @return with type Spatie\\\\LaravelData\\\\CursorPaginatedDataCollection\\<TKey of \\(int\\|string\\), TOtherValue\\> is incompatible with native type static\\(Spatie\\\\LaravelData\\\\CursorPaginatedDataCollection\\<TKey of \\(int\\|string\\), TValue\\>\\)\\.$#"
count: 1
path: src/CursorPaginatedDataCollection.php

-
message: "#^Instanceof between \\*NEVER\\* and Spatie\\\\LaravelData\\\\Contracts\\\\BaseDataCollectable will always evaluate to false\\.$#"
count: 1
Expand Down Expand Up @@ -95,6 +100,11 @@ parameters:
count: 2
path: src/PaginatedDataCollection.php

-
message: "#^PHPDoc tag @return with type Spatie\\\\LaravelData\\\\PaginatedDataCollection\\<TKey of \\(int\\|string\\), TOtherValue\\> is incompatible with native type static\\(Spatie\\\\LaravelData\\\\PaginatedDataCollection\\<TKey of \\(int\\|string\\), TValue\\>\\)\\.$#"
count: 1
path: src/PaginatedDataCollection.php

-
message: "#^Dead catch \\- ArgumentCountError is never thrown in the try block\\.$#"
count: 1
Expand Down
7 changes: 6 additions & 1 deletion src/Concerns/ResponsableData.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,15 @@ public function toResponse($request)

return new JsonResponse(
data: $this->transform($contextFactory),
status: $request->isMethod(Request::METHOD_POST) ? Response::HTTP_CREATED : Response::HTTP_OK,
status: $this->calculateResponseStatus($request),
);
}

protected function calculateResponseStatus(Request $request): int
{
return $request->isMethod(Request::METHOD_POST) ? Response::HTTP_CREATED : Response::HTTP_OK;
}

public static function allowedRequestIncludes(): ?array
{
return [];
Expand Down
26 changes: 26 additions & 0 deletions src/Exceptions/CannotPerformPartialOnDataField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Spatie\LaravelData\Exceptions;

use ErrorException;
use Exception;
use Spatie\LaravelData\Support\DataClass;
use Spatie\LaravelData\Support\Partials\PartialType;
use Spatie\LaravelData\Support\Transformation\TransformationContext;

class CannotPerformPartialOnDataField extends Exception
{
public static function create(
ErrorException $exception,
PartialType $partialType,
string $field,
DataClass $dataClass,
TransformationContext $transformationContext,
): self {
$message = "Tried to {$partialType->getVerb()} a non existing field `{$field}` on `{$dataClass->name}`.".PHP_EOL;
$message .= 'Provided transformation context:'.PHP_EOL.PHP_EOL;
$message .= (string) $transformationContext;

return new self(message: $message, previous: $exception);
}
}
2 changes: 1 addition & 1 deletion src/Resolvers/RequestQueryStringPartialsResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ protected function validateSegments(
);

if ($nextSegments === null) {
return [$segment];
return [new FieldsPartialSegment([$field])];
}

return [$segment, ...$nextSegments];
Expand Down
66 changes: 56 additions & 10 deletions src/Resolvers/VisibleDataFieldsResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

namespace Spatie\LaravelData\Resolvers;

use ErrorException;
use Spatie\LaravelData\Contracts\BaseData;
use Spatie\LaravelData\Exceptions\CannotPerformPartialOnDataField;
use Spatie\LaravelData\Lazy;
use Spatie\LaravelData\Optional;
use Spatie\LaravelData\Support\DataClass;
use Spatie\LaravelData\Support\DataProperty;
use Spatie\LaravelData\Support\Lazy\ConditionalLazy;
use Spatie\LaravelData\Support\Lazy\RelationalLazy;
use Spatie\LaravelData\Support\Partials\PartialType;
use Spatie\LaravelData\Support\Transformation\TransformationContext;

class VisibleDataFieldsResolver
Expand Down Expand Up @@ -45,15 +48,15 @@ public function execute(
}

if ($transformationContext->exceptPartials) {
$this->performExcept($fields, $transformationContext);
$this->performExcept($fields, $transformationContext, $dataClass);
}

if (empty($fields)) {
return [];
}

if ($transformationContext->onlyPartials) {
$this->performOnly($fields, $transformationContext);
$this->performOnly($fields, $transformationContext, $dataClass);
}

$includedFields = $transformationContext->includePartials ? $this->resolveIncludedFields(
Expand Down Expand Up @@ -110,7 +113,8 @@ public function execute(
*/
protected function performExcept(
array &$fields,
TransformationContext $transformationContext
TransformationContext $transformationContext,
DataClass $dataClass,
): void {
$exceptFields = [];

Expand All @@ -126,7 +130,11 @@ protected function performExcept(
}

if ($nested = $exceptPartial->getNested()) {
$fields[$nested]->addExceptResolvedPartial($exceptPartial->next());
try {
$fields[$nested]->addExceptResolvedPartial($exceptPartial->next());
} catch (ErrorException $exception) {
$this->handleNonExistingNestedField($exception, PartialType::Except, $nested, $dataClass, $transformationContext);
}

continue;
}
Expand All @@ -146,7 +154,8 @@ protected function performExcept(
*/
protected function performOnly(
array &$fields,
TransformationContext $transformationContext
TransformationContext $transformationContext,
DataClass $dataClass,
): void {
$onlyFields = null;

Expand All @@ -159,8 +168,12 @@ protected function performOnly(
$onlyFields ??= [];

if ($nested = $onlyPartial->getNested()) {
$fields[$nested]->addOnlyResolvedPartial($onlyPartial->next());
$onlyFields[] = $nested;
try {
$fields[$nested]->addOnlyResolvedPartial($onlyPartial->next());
$onlyFields[] = $nested;
} catch (ErrorException $exception) {
$this->handleNonExistingNestedField($exception, PartialType::Only, $nested, $dataClass, $transformationContext);
}

continue;
}
Expand Down Expand Up @@ -214,8 +227,12 @@ protected function resolveIncludedFields(
}

if ($nested = $includedPartial->getNested()) {
$fields[$nested]->addIncludedResolvedPartial($includedPartial->next());
$includedFields[] = $nested;
try {
$fields[$nested]->addIncludedResolvedPartial($includedPartial->next());
$includedFields[] = $nested;
} catch (ErrorException $exception) {
$this->handleNonExistingNestedField($exception, PartialType::Include, $nested, $dataClass, $transformationContext);
}

continue;
}
Expand Down Expand Up @@ -258,7 +275,11 @@ protected function resolveExcludedFields(
}

if ($nested = $excludePartial->getNested()) {
$fields[$nested]->addExcludedResolvedPartial($excludePartial->next());
try {
$fields[$nested]->addExcludedResolvedPartial($excludePartial->next());
} catch (ErrorException $exception) {
$this->handleNonExistingNestedField($exception, PartialType::Exclude, $nested, $dataClass, $transformationContext);
}

continue;
}
Expand All @@ -270,4 +291,29 @@ protected function resolveExcludedFields(

return $excludedFields;
}


protected function handleNonExistingNestedField(
ErrorException $exception,
PartialType $partialType,
string $field,
DataClass $dataClass,
TransformationContext $transformationContext,
): void {
if (str_starts_with($exception->getMessage(), 'Undefined array key: ')) {
throw $exception;
}

if(config('data.ignore_invalid_partials')){
return;
}

throw CannotPerformPartialOnDataField::create(
$exception,
$partialType,
$field,
$dataClass,
$transformationContext
);
}
}
1 change: 0 additions & 1 deletion src/Support/Creation/CreationContextFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public static function createFromConfig(
return new self(
dataClass: $dataClass,
validationType: ValidationType::from($config['validation_type']),
// TODO: maybe also add these to config, we should do the same for transormation so maybe some config cleanup is needed
mapPropertyNames: true,
withoutMagicalCreation: false,
ignoredMagicalMethods: null,
Expand Down
9 changes: 9 additions & 0 deletions src/Support/Partials/Partial.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ public function resolve(BaseData|BaseDataCollectable $data): ?ResolvedPartial
return null;
}

public function toArray(): array
{
return [
'segments' => $this->segments,
'permanent' => $this->permanent,
'condition' => $this->condition,
];
}

public function __toString(): string
{
return implode('.', $this->segments);
Expand Down
10 changes: 10 additions & 0 deletions src/Support/Partials/PartialType.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ public function getRequestParameterName(): string
};
}

public function getVerb(): string
{
return match ($this) {
self::Include => 'include',
self::Exclude => 'exclude',
self::Only => 'only',
self::Except => 'except',
};
}

/**
* @return string[]|null
*/
Expand Down
21 changes: 21 additions & 0 deletions src/Support/Partials/PartialsCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,25 @@
*/
class PartialsCollection extends SplObjectStorage
{
public static function create(Partial ...$partials): self
{
$collection = new self();

foreach ($partials as $partial) {
$collection->attach($partial);
}

return $collection;
}

public function toArray(): array
{
$output = [];

foreach ($this as $partial) {
$output[] = $partial->toArray();
}

return $output;
}
}
2 changes: 1 addition & 1 deletion src/Support/Partials/ResolvedPartialsCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function toArray(): array

public function __toString(): string
{
$output = "- partials:".PHP_EOL;
$output = '';

foreach ($this as $partial) {
$output .= " - {$partial}".PHP_EOL;
Expand Down
4 changes: 4 additions & 0 deletions src/Support/Transformation/TransformationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,22 @@ public function __toString(): string
}

if ($this->includePartials !== null && $this->includePartials->count() > 0) {
$output .= "- include partials:".PHP_EOL;
$output .= $this->includePartials;
}

if ($this->excludePartials !== null && $this->excludePartials->count() > 0) {
$output .= "- exclude partials:".PHP_EOL;
$output .= $this->excludePartials;
}

if ($this->onlyPartials !== null && $this->onlyPartials->count() > 0) {
$output .= "- only partials:".PHP_EOL;
$output .= $this->onlyPartials;
}

if ($this->exceptPartials !== null && $this->exceptPartials->count() > 0) {
$output .= "- except partials:".PHP_EOL;
$output .= $this->exceptPartials;
}

Expand Down
Loading

0 comments on commit 0346ce4

Please sign in to comment.