Giter Club home page Giter Club logo

fractalistic's Introduction

A developer friendly wrapper around Fractal

Latest Version on Packagist Software License GitHub Workflow Status Quality Score Total Downloads

Fractal is an amazing package to transform data before using it in an API. Unfortunately working with Fractal can be a bit verbose.

Using Fractal data can be transformed like this:

use League\Fractal\Manager;
use League\Fractal\Resource\Collection;

$books = [
   ['id'=>1, 'title'=>'Hogfather', 'characters' => [...]], 
   ['id'=>2, 'title'=>'Game Of Thrones', 'characters' => [...]]
];

$manager = new Manager();

$resource = new Collection($books, new BookTransformer());

$manager->parseIncludes('characters');

$manager->createData($resource)->toArray();

This package makes that process a tad easier:

Fractal::create()
   ->collection($books)
   ->transformWith(new BookTransformer())
   ->includeCharacters()
   ->toArray();

There's also a very short syntax available to quickly transform data:

Fractal::create($books, new BookTransformer())->toArray();

If you want to use this package inside Laravel, it's recommend to use laravel-fractal instead. That package contains a few more whistles and bells specifically targetted at Laravel users.

Spatie is a webdesign agency based in Antwerp, Belgium. You'll find an overview of all our open source projects on our website.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Install

You can pull in the package via composer:

composer require spatie/fractalistic

Usage

In the following examples were going to use the following array as example input:

$books = [['id'=>1, 'title'=>'Hogfather'], ['id'=>2, 'title'=>'Game Of Kill Everyone']];

But know that any structure that can be looped (for instance a collection) can be used.

Let's start with a simple transformation.

Spatie\Fractalistic\Fractal::create()
   ->collection($books)
   ->transformWith(function($book) { return ['id' => $book['id']];})
   ->toArray();

This will return:

['data' => [['id' => 1], ['id' => 2]]

In all following examples it's assumed that you imported the Spatie\Fractalistic\Fractal at the top of your php file.

Instead of using a closure you can also pass a Transformer:

Fractal::create()
   ->collection($books)
   ->transformWith(new BookTransformer())
   ->toArray();

You can also pass the classname of the Transformer:

Fractal::create()
   ->collection($books)
   ->transformWith(BookTransformer::class)
   ->toArray();

To make your code a bit shorter you could also pass the transform closure, class, or classname as a second parameter of the collection-method:

Fractal::create()->collection($books, new BookTransformer())->toArray();

Want to get some sweet json output instead of an array? No problem!

Fractal::create()->collection($books, new BookTransformer())->toJson();

A single item can also be transformed:

Fractal::create()->item($books[0], new BookTransformer())->toArray();

Using a serializer

Let's take a look again at the output of the first example:

['data' => [['id' => 1], ['id' => 2]];

Notice that data-key? That's part of Fractal's default behaviour. Take a look at Fractals's documentation on serializers to find out why that happens.

If you want to use another serializer you can specify one with the serializeWith-method. The Spatie\Fractalistic\ArraySerializer comes out of the box. It removes the data namespace for both collections and items.

Fractal::create()
   ->collection($books)
   ->transformWith(function($book) { return ['id' => $book['id']];})
   ->serializeWith(new \Spatie\Fractalistic\ArraySerializer())
   ->toArray();

//returns [['id' => 1], ['id' => 2]]

You can also pass the serializer classname instead of an instantiation:

Fractal::create()
   ->collection($books)
   ->transformWith(BookTransformer::class)
   ->serializeWith(MySerializer::class)
   ->toArray();

Changing the default serializer

You can change the default serializer by providing the classname or an instantiation of your favorite serializer in the config file.

Using includes

Fractal provides support for optionally including data on the relationships for the data you're exporting. You can use Fractal's parseIncludes which accepts a string or an array:

Fractal::create()
   ->collection($this->testBooks, new TestTransformer())
   ->parseIncludes(['characters', 'publisher'])
   ->toArray();

To improve readablity you can also use a function named include followed by the name of the include you want to... include:

Fractal::create()
   ->collection($this->testBooks, new TestTransformer())
   ->includeCharacters()
   ->includePublisher()
   ->toArray();

Using excludes

Similar to includes Fractal also provides support for optionally excluding data on the relationships for the data you're exporting. You can use Fractal's parseExcludes which accepts a string or an array:

Fractal::create()
   ->collection($this->testBooks, new TestTransformer())
   ->parseExcludes(['characters', 'publisher'])
   ->toArray();

To improve readability you can also use a function named exclude followed by the name of the include you want to... exclude:

Fractal::create()
   ->collection($this->testBooks, new TestTransformer())
   ->excludeCharacters()
   ->excludePublisher()
   ->toArray();

Including meta data

Fractal has support for including meta data. You can use addMeta which accepts one or more arrays:

Fractal::create()
   ->collection($this->testBooks, function($book) { return ['name' => $book['name']];})
   ->addMeta(['key1' => 'value1'], ['key2' => 'value2'])
   ->toArray();

This will return the following array:

[
   'data' => [
        ['title' => 'Hogfather'],
        ['title' => 'Game Of Thrones'],
    ],
   'meta' => [
        ['key1' => 'value1'], 
        ['key2' => 'value2'],
    ]
];

Using pagination

Fractal provides a Laravel-specific paginator, IlluminatePaginatorAdapter, which accepts an instance of Laravel's LengthAwarePaginator and works with paginated Eloquent results. When using some serializers, such as the JsonApiSerializer, pagination data can be automatically generated and included in the result set:

$paginator = Book::paginate(5);
$books = $paginator->getCollection();

Fractal::create()
    ->collection($books, new TestTransformer())
    ->serializeWith(new JsonApiSerializer())
    ->paginateWith(new IlluminatePaginatorAdapter($paginator))
    ->toArray();

Using a cursor

Fractal provides a simple cursor class, League\Fractal\Pagination\Cursor. You can use any other cursor class as long as it implements the League\Fractal\Pagination\CursorInterface interface. When using it, the cursor information will be automatically included in the result metadata:

$books = $paginator->getCollection();

$currentCursor = 0;
$previousCursor = null;
$count = count($books);
$newCursor = $currentCursor + $count;

Fractal::create()
  ->collection($books, new TestTransformer())
  ->serializeWith(new JsonApiSerializer())
  ->withCursor(new Cursor($currentCursor, $previousCursor, $newCursor, $count))
  ->toArray();

Setting a custom resource name

Certain serializers wrap the array output with a data element. The name of this element can be customized:

Fractal::create()
    ->collection($this->testBooks, new TestTransformer())
    ->serializeWith(new ArraySerializer())
    ->withResourceName('books')
    ->toArray();
Fractal::create()
    ->item($this->testBooks[0], new TestTransformer(), 'book')
    ->serializeWith(new ArraySerializer())
    ->toArray();

Limit recursion

To increase or decrease the level of embedded includes you can use limitRecursion.

Fractal::create()
    ->collection($this->testBooks, new TestTransformer())
    ->includesDataThatHasALotOfRecursion
    ->limitRecursion(5);

If you do not call limitRecursion a default value of 10 is used.

Quickly transform data with the short function syntax

You can also pass arguments to the fractal-function itself. The first arguments should be the data you which to transform. The second one should be a transformer or a closure that will be used to transform the data. The third one should be a serializer.

Here are some examples

Fractal::create($books, new BookTransformer())->toArray();

Fractal::create($books, new BookTransformer(), new ArraySerializer())->toArray();

Fractal::create($books, BookTransformer::class, ArraySerializer::class)->toArray();

Fractal::create(['item1', 'item2'], function ($item) {
   return $item . '-transformed';
})->toArray();

Changelog

Please see CHANGELOG for more information what has changed recently.

Testing

$ composer test

Contributing

Please see CONTRIBUTING for details.

Security

If you've found a bug regarding security please mail [email protected] instead of using the issue tracker.

Postcardware

You're free to use this package, but if it makes it to your production environment we highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using.

Our address is: Spatie, Kruikstraat 22, 2018 Antwerp, Belgium.

We publish all received postcards on our company website.

Credits

License

The MIT License (MIT). Please see License File for more information.

fractalistic's People

Contributors

adrianmrn avatar akoepcke avatar albertoarena avatar alexjezior avatar antonkomarev avatar ayoobmh avatar balping avatar casperhr avatar cviebrock avatar dczajkowski avatar dependabot[bot] avatar freekmurze avatar github-actions[bot] avatar julianbustamante avatar lukasvy avatar mahmoudz avatar mannikj avatar oanhnn avatar patinthehat avatar ronnievisser avatar sebastiandedeyne avatar supianidz avatar vigneshgurusamy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

fractalistic's Issues

Invalid return value for resource

Hi all.

I'm using transformer and includes. But if I return NullResource I'm getting an empty array instead of the null value.

image

image

Why I'm getting an empty array instead null ?

Thanks for advice.

Incorrectly determines datatype for single item

Imagine this code:

$one_book = [
    'id' => '1',
    'title' => 'Hogfather',
    'yr' => '1998',
    'author_name' => 'Philip K Dick',
    'author_email' => '[email protected]',
    'characters' => [['name' => 'Death'], ['name' => 'Hex']],
    'publisher' => 'Elephant books',
];

Fractal::create($one_book, new BookTransformer())->toArray();

Results in:

TypeError: Argument 1 passed to BookTransformer::transform() must be of the type array, 
string given, called in .../vendor/league/fractal/src/Scope.php on line 407

This is because determineDataType() assumes that if you are passing an array, then you must be trying to transform to a Collection.

Arguably, most people are going to pass in objects instead of arrays as the first argument of Fractal::create() if they are trying to transform an Item. But -- even as you do in the tests -- there is nothing stopping someone from transforming an array to an Item.

I think the only way to determine correctly if passed data represents an Item or a Collection (or a Primative, with Fractal 0.17.0) is if the data is an array of the same type of object: an array of arrays, or an array of objects, or an array of primitives. This is probably not super performant. :(

Question concerning includes

Hello! First off, thanks for the package :) I have a question concerning the includes and the manager. I am trying to do something similar as what's in Fractal's documentation concerning includes and I don't get how I can do with this package.

I would like to have different includes available and be able to include them from the querystring.

Here what Fractal's documentation says:

<?php namespace App\Transformer;

use Acme\Model\Book;
use League\Fractal\TransformerAbstract;

class BookTransformer extends TransformerAbstract
{
    /**
     * List of resources possible to include
     *
     * @var array
     */
    protected $availableIncludes = [
        'author'
    ];

    /**
     * Turn this item object into a generic array
     *
     * @return array
     */
    public function transform(Book $book)
    {
        return [
            'id'    => (int) $book->id,
            'title' => $book->title,
            'year'    => (int) $book->yr,
            'links'   => [
                [
                    'rel' => 'self',
                    'uri' => '/books/'.$book->id,
                ]
            ],
        ];
    }

    /**
     * Include Author
     *
     * @return League\Fractal\ItemResource
     */
    public function includeAuthor(Book $book)
    {
        $author = $book->author;

        return $this->item($author, new AuthorTransformer);
    }
}

These includes will be available but can never be requested unless the Manager::parseIncludes() method is called:

<?php
use League\Fractal;

$fractal = new Fractal\Manager();

if (isset($_GET['include'])) {
    $fractal->parseIncludes($_GET['include']);
}

With this set, include can do some great stuff. If a client application were to call the URL /books?include=author then they would see author data in the response.

Now, I understand from Fractalistic documentation that I can manually include or exclude relationships, but is there a way to do as in the example above and let it be customizable from the querystring globally?

Setting `withResourceName` results in an empty ParamBag for Includes.

I'm not yet sure if this issue ultimately rests on Fractalistic or the underlying Fractal package. Will close if I determine this is the inappropriate place for this issue.

When \League\Fractal\TransformerAbstract::callIncludeMethod calls the \League\Fractal\Scope::getIdentifier method the resulting identifier is "incorrect" IF \Spatie\Fractalistic\Fractal::withResourceName was called to set a "top level identifier". It's "incorrect" in the sense that \League\Fractal\Manager::getIncludeParams method has no entry for the resulting identifier.

Code example:

url: /api/v1/abcd/users/36?include=comments:status_in(deleted)

... 
return fractal($user, $transformer, new JsonApiSerializer($base_url))
                ->withResourceName('abcd-users')
                ->respond($status, $headers);

Then in \League\Fractal\TransformerAbstract::callIncludeMethod

protected function callIncludeMethod(Scope $scope, $includeName, $data)
    {
        $scopeIdentifier = $scope->getIdentifier($includeName);
        // resulting `$scopeIdentifer` is `abcd-users.comments`
        $params = $scope->getManager()->getIncludeParams($scopeIdentifier);
        // `$params` is empty as the manager only has `includeParams` for `comments` (not `abcd-users.comments`).
       ... 
} 

Support for fractal 0.16

Are there any incompatibilities with league/fractal 0.16? If not, what about allowing that version, too?

Custom Scope injection

I want to use a custom Scope implementation.
The League's package allows using it by injecting a custom ScopeFactory into the Manager.
I don't see a way to do this since Spatie\Fractalistic\Fractal creates an instance without arguments.

Using \Spatie\Fractalistic\ArraySerializer() on includes file

HI,

I've been wondering is there any chance that i can use above class at includes?

For example:


class OrderTransformer extends TransformerAbstract
{
    public $availableIncludes = ['user', 'items'];

    /**
     * A Fractal transformer.
     *
     * @param $resource
     * @return array
     */
    public function transform($resource)
    {
        return [
            'id'         => $resource->id,
            'receiver'   => $resource->receiver,
            'totalPrice' => $resource->totalPrice,
            'address'    => $resource->address,
            'phone'      => $resource->phone,
            'orderedAt'  => $resource->createdAt->format('Y-m-d H:i:s'),
        ];
    }

    public function includeUser($resource)
    {
        $resource = $resource->user;

        return $this->item($resource, new UserTransformer);
    }

    public function includeItems($resource)
    {
        $resource = $resource->items;

        return $this->collection($resource, new OrderItemTransformer); // I want to use spatie array serializer here
    }
}

I need to use those fractal to remove the additional data key on the result.

Here is the result I get:

{
    "orders": [
        {
            "id": "C170620PVJM6",
            "receiver": "Example",
            "totalPrice": 10,
            "address": "Anywhere near the horizon",
            "phone": "081234567",
            "orderedAt": "2017-06-20 22:42:43",
            "items": {
                "data": [
                    {
                        "price": 2,
                        "menu": {
                            "name": "VERY tired of.",
                            "image": {
                                "web": "https://lorempixel.com/413/413/?87962",
                                "mobile": "https://lorempixel.com/413/413/?87962",
                                "square": "https://lorempixel.com/413/413/?87962"
                            }
                        }
                    },
                    {
                        "price": 6,
                        "menu": {
                            "name": "Queen jumped up in.",
                            "image": {
                                "web": "https://lorempixel.com/413/413/?77046",
                                "mobile": "https://lorempixel.com/413/413/?77046",
                                "square": "https://lorempixel.com/413/413/?77046"
                            }
                        }
                    },
                    {
                        "price": 2,
                        "menu": {
                            "name": "And oh, I wish you.",
                            "image": {
                                "web": "https://lorempixel.com/413/413/?22822",
                                "mobile": "https://lorempixel.com/413/413/?22822",
                                "square": "https://lorempixel.com/413/413/?22822"
                            }
                        }
                    }
                ]
            }
        }
    ],
    "meta": {
        "pagination": {
            "total": 5,
            "count": 1,
            "per_page": 1,
            "current_page": 1,
            "total_pages": 5,
            "links": {
                "next": "https://api.butterfish.dev/v1/user/orders?page=2"
            }
        }
    }
}

Expected result:

{
    "orders": [
        {
            "id": "C170620PVJM6",
            "receiver": "Example",
            "totalPrice": 10,
            "address": "Anywhere near the horizon",
            "phone": "0123123123",
            "orderedAt": "2017-06-20 22:42:43",
            "items": [
                    {
                        "price": 2,
                        "menu": {
                            "name": "VERY tired of.",
                            "image": {
                                "web": "https://lorempixel.com/413/413/?87962",
                                "mobile": "https://lorempixel.com/413/413/?87962",
                                "square": "https://lorempixel.com/413/413/?87962"
                            }
                        }
                    },
                    {
                        "price": 6,
                        "menu": {
                            "name": "Queen jumped up in.",
                            "image": {
                                "web": "https://lorempixel.com/413/413/?77046",
                                "mobile": "https://lorempixel.com/413/413/?77046",
                                "square": "https://lorempixel.com/413/413/?77046"
                            }
                        }
                    },
                    {
                        "price": 2,
                        "menu": {
                            "name": "And oh, I wish you.",
                            "image": {
                                "web": "https://lorempixel.com/413/413/?22822",
                                "mobile": "https://lorempixel.com/413/413/?22822",
                                "square": "https://lorempixel.com/413/413/?22822"
                            }
                        }
                    }
                ]
        }
    ],
    "meta": {
        "pagination": {
            "total": 5,
            "count": 1,
            "per_page": 1,
            "current_page": 1,
            "total_pages": 5,
            "links": {
                "next": "https://api.butterfish.dev/v1/user/orders?page=2"
            }
        }
    }
}

Right now I'm using league fractal array serializer and use foreach to remove "data" key inside items.

ParentScope identifier is set null

Actual Behavior

I have a resource named Portfolio that includes another resource called Company. So there's a relationship between Portfolio and Company. When the Company is included in the Portfolio resource I need to show some data which is not displayed in another context. In order to check the context in the CompanyTransformer, I need the parentScopes to be properly set. But the Scope for the Portfolio resource is created with a null identifier.

Expected Behavior

The Scope for the Portfolio resource (which is the parentScope for Company) should have an identifier instead of null.

Specifications

spatie/fractalistic 2.7.1
spatie/laravel-fractal 5.3.2

Additional Details

When the wrapper method createData located in Fractal.php line 380 calls createData from the manager, the scopeIdentifier parameter is not passed, so the Scope returned has a null identifier.

Proposed Solution

To pass the scopeIdentifier string (Could be the resourceName) as the second parameter when createData is called in the line 408.

return $this->manager->createData($this->getResource(), $this->resourceName);

A unit test could be

/** @test */
public function it_uses_an_identifier_for_the_scope()
{
    $scope = $this->fractal
        ->collection($this->testBooks, new TestTransformer(), 'books')
        ->parseIncludes('characters')
        ->createData();

    $this->assertEquals('books', $scope->getIdentifier());
}

PHP 8.1 deprecations

Hey.

There are PHP 8.1 deprecations that this package doesn't account for. One of them is with JsonSerializable:

During inheritance of JsonSerializable: Uncaught ErrorException: Return type of Spatie\Fractalistic\Fractal::jsonSerialize() should either be compatible with JsonSerializable::jsonSerialize(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /app/vendor/spatie/fractalistic/src/Fractal.php:458
Stack trace:
#0 /app/vendor/spatie/fractalistic/src/Fractal.php(13): Tests\TestCase::{closure}()

Replacing docblocks with type hints

Hey, I was wondering if the docblocks in Fractal.php can be replaced with typehints. Example:

Change:

class Fractal implements JsonSerializable
{
    /** @var \League\Fractal\Manager */
    protected $manager;

    /** @var int */
    protected $recursionLimit = 10;

    /** @var string|\League\Fractal\Serializer\SerializerAbstract */
    protected $serializer;

    /** @var string|callable|\League\Fractal\TransformerAbstract */
    protected $transformer;

    /** @var \League\Fractal\Pagination\PaginatorInterface */
    protected $paginator;

    /** @var \League\Fractal\Pagination\CursorInterface */
    protected $cursor;

    /** @var array */
    protected $includes = [];

To:

class Fractal implements JsonSerializable
{
    protected Manager $manager;

    protected int $recursionLimit = 10;

    /** @var string|\League\Fractal\Serializer\SerializerAbstract */
    protected SerializerAbstract $serializer;

    /** @var string|callable|\League\Fractal\TransformerAbstract */
    protected $transformer;

    protected PaginatorInterface $paginator;

    protected CursorInterface $cursor;

    protected array $includes = [];

Would it also make sense to drop PHP 7.4 support for this and add union types where necessary?

Happy to work on the PR for this!

Exception in ArraySerializer

I got an exception in ArraySerializer.
For ex.: "local.ERROR: Declaration of Spatie\Fractalistic\ArraySerializer::collection(string $resourceKey, array $data): array must be compatible with League\Fractal\Serializer\ArraySerializer::collection(?string $resourceKey, array $data): array"

In the collection method, you need to add question mark before: "string $resourceKey" which invoke the exception,
because the method changed in "League\Fractal\Serializer\ArraySerializer"
To fix it, you need to add a question mark:
public function collection(?string $resourceKey, array $data): array in

screen_1.jpg
screen_2.jpg
screen_3.jpg
screen_4.jpg

Response code attachment?

Hello. I have a proposition regarding Fractal and response codes. If you feel like it is more Laravel connected, I'll make sure to move this issue there.

The problem

Fractal's main responsibility is to change given array into given format. But. By many (or almost everyone) it is (ab)used to create JSON responses in our APIs.

return fractal()
    ->collection($users)
    ->transformWith(new UserTransformer)
    ->toArray();

And this is awesome. There is just one problem though. It does everything except adding a status code into our response. And that is understandable, considering Fractal's main goal, but it makes creating responses with status codes pretty hairy:

return response()->json(
    fractal()
        ->item('These credentials do not match our records.')
        ->transformWith(new ErrorTransformer)
        ->serializeWith(new ArraySerializer)
        ->toArray()
, 401);

Proposition

My proposal is to add a public method to attach status codes like so:

return fractal()
    ->item('These credentials do not match our records.')
    ->transformWith(new ErrorTransformer)
    ->serializeWith(new ArraySerializer)
    ->withStatusCode(403)
    ->respond();

// and/or

return fractal()
    ->item('These credentials do not match our records.')
    ->transformWith(new ErrorTransformer)
    ->serializeWith(new ArraySerializer)
    ->respond(403);

This would generate a JSON response attaching provided status code.

Concerns

Whilst making responses in Laravel is easy (it is opinionated, the method's/function's/class' names are known. The method would be just a wrapper for response()->json()) in a generic package as this the response would need to be generated, either by a passed-in ResponseFactory, or by our own ResponseManager.

Proposition

My proposition is to make this functionality only into Laravel's package, while it would be too messy to include it in this generic package.

TL;DR

I suggest creating a helper method ->respond($statusCode) that would generate a HTTP JSON Response. I suggest doing that in Laravel's variant of this package, but I throw it here as it may be a good idea to include it in a more generic package.


P.S. I really appreciate you making Fractal even better than it already is.

null return error

I had my ArraySerializer overriden to avoid "[]" values on ->null() to just return null

public function null(): ?array
{
    return null;
}

After upgrading from 2.9.1 -> 2.9.4 I get this error

TypeError: Return value of Spatie\Fractalistic\Fractal::jsonSerialize() must be of the type array, null returned in file /var/www/app/vendor/spatie/fractalistic/src/Fractal.php on line 463

#0 [internal function]: Spatie\Fractalistic\Fractal->jsonSerialize()
#1 /var/www/app/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(80): json_encode(Array, 0)
#2 /var/www/app/vendor/symfony/http-foundation/JsonResponse.php(54): Illuminate\Http\JsonResponse->setData(Object(Spatie\Fractal\Fractal))
#3 /var/www/app/vendor/laravel/framework/src/Illuminate/Http/JsonResponse.php(32): Symfony\Component\HttpFoundation\JsonResponse->__construct(Object(Spatie\Fractal\Fractal), 200, Array, false)
#4 /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(818): Illuminate\Http\JsonResponse->__construct(Object(Spatie\Fractal\Fractal))
#5 /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(789): Illuminate\Routing\Router::toResponse(Object(Illuminate\Http\Request), Object(Spatie\Fractal\Fractal))
#6 /var/www/app/vendor/laravel/framework/src/Illuminate/Routing/Router.php(721): Illuminate\Routing\Router->prepareResponse(Object(Illuminate\Http\Request), Object(Spatie\Fractal\Fractal))
#7 /var/www/app/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(128): Illuminate\Routing\Router->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))
#8 /var/www/app/app/Core/Http/Middleware/Country.php(19): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

Paginator links property is either array or object

I've checked in both this repo as well as laravel-fractal and I believe my issue originates here. I'm noticing an issue with the paginateWith method which adds pagination info to the meta key in my json responses.
When there are no links for the pagination the meta property looks like this:

"meta": {
        "pagination": {
...
            "links": []
        }
    }

When there are, it looks like this:

"meta": {
        "pagination": {
...
            "links": {
                "next": "[url]"
            }
        }
    }

You can see that in an empty resultset the links property is an array and when set, it's an object. This causes issues for client implementing our API. Any idea on where to fix this?

include depth

Hi,

I was wondering if it's possible to set and include depth. I have an API with might return a large collection of data. I know I can paginate but that's just not sufficient enough.

I handle sports data statistics so let's say I have a paginated response with 25 seasons on a page. the season entity has and option to include fixtures which on it's turn has the possibility to include a lineup, events, stats etc.

you can image that, since a season has around 380 fixtures, the response can be big. especially when including more related includes.

so I was wondering if it's possible to set a max depth to set it for example to 1 so that on a given endpoint only fixtures can be included and all other related includes are not handled.

or would there be any other solution to achieve such?

Using `withResourceName` makes fractal include parameters not working

Example:

$fractal = Fractal::create($users, new UserTransformer())->withResourceName('users');
$fractal->parseIncludes(['posts'])->toArray();

In League\Fractal\TransformerAbstract at callIncludeMethod method we get the following result:

// this line will get 'users.posts' as identifier
$scopeIdentifier = $scope->getIdentifier($includeName);

// this line will try to find include params for 'users.posts' identifier instead 'posts'
$params = $scope->getManager()->getIncludeParams($scopeIdentifier);

But League\Fractal\Scope object is being built like this:

League\Fractal\Scope Object
(
    [availableIncludes:protected] => Array
        (
            [0] => posts
        )
    [scopeIdentifier:protected] => users
    [manager:protected] => League\Fractal\Manager Object
        (
            [requestedIncludes:protected] => Array
                (
                    [0] => posts
                )
            [includeParams:protected] => Array
                (
                    [posts] => Array
                        (
                            [limit] => Array
                                (
                                    [0] => 5,
                                    [1] => 1,
                                )
                        )
                )

As you can see League\Fractal\Manager will not find the posts include params because getIncludeParams method will look for users.posts key instead.

Fractal::jsonSerialize() triggers a Type error (PHP 7.4.24)

This change done to support PHP 8.1 triggers a Type error.

Commit:
4d3b8a6#diff-9ebff18d48644c7d6e2c1006245d57ef9028099e796f76f967c8656aedadcf4bR458

Change:

public function jsonSerialize(): mixed

Error:

TypeError
Return value of Spatie\Fractalistic\Fractal::jsonSerialize() must be an instance of Spatie\Fractalistic\mixed, array returned 

Reason:

  • Fractal::toArray return type is array
  • Fractal::jsonSerialize() return type os mixed

Further details:

  • PHP version: 7.4.24

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.