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

Laravel - $this->null() returns an empty array instead of empty object #469

Closed
buglinjo opened this issue Jan 11, 2019 · 20 comments
Closed

Comments

@buglinjo
Copy link

buglinjo commented Jan 11, 2019

I'm having a problem with Fractal library. I'm using spatie\laravel-fractal library which is just wrapper for thephpleague/fractal. So...

I want to return an empty object instead of an empty array.

public function includeDocumentType(Question $question)
{
    return $question->documentType
        ? $this->item($question->documentType, new DocumentTypeTransformer)
        : $this->null();
}

$this->null() always returns [] after generation and I want to return {}. Tbh I want to have 2 functions like $this->nullItem() and $this->nullCollection().

Does anyone know what's the solution to this problem?

@lordrhodos
Copy link

Withouth looking further into the issue, can you check if this is duplicate of #433 ?

@buglinjo
Copy link
Author

@lordrhodos I think it's a different issue, because, I can't override anything. The only object this function is waiting to be returned is ResourceInterface and this object is automatically converted as an array if it's empty. I have tried creating empty transformer and I was returning it as $this->item($question->documentType, new NullTransformer) but still... If it's empty it is returned as an empty array :/

@catalinux
Copy link

How about returning an object new stdclass()

@buglinjo
Copy link
Author

How about returning an object new stdclass()

The only object this function is waiting to be returned is ResourceInterface :(

@buglinjo buglinjo changed the title Laravel / League Fractal returns an empty array instead of empty object Laravel - thephpleague/fractal returns an empty array instead of empty object Feb 5, 2019
@buglinjo buglinjo changed the title Laravel - thephpleague/fractal returns an empty array instead of empty object Laravel - $this->null() returns an empty array instead of empty object Feb 5, 2019
@buglinjo buglinjo changed the title Laravel - $this->null() returns an empty array instead of empty object Laravel - $this->null() returns an empty array instead of empty object Feb 5, 2019
@matthewtrask
Copy link
Contributor

have you tried json_encode($this->null()); by chance?

@buglinjo
Copy link
Author

@matthewtrask
It won't work as json_encode is returning a string.

I have still tried and got this error:
Invalid return value from League\Fractal\TransformerAbstract::includeParent(). Expected League\Fractal\Resource\ResourceInterface, received string.

@KorvinSzanto
Copy link
Contributor

What serializer are you using? What specific output are you hoping for?

@BRafols
Copy link

BRafols commented Mar 21, 2019

I'm also using the default serializer.

The most optinal, non-breaking and clean solution would be to allow the following two methods:
nullItem return an empty object
nullCollection returns an empty array

@hotrush
Copy link

hotrush commented Mar 27, 2019

Hello @buglinjo , @BRafols
I have a similar issue, but i want to return null when include is empty (because return empty array is too weird). So, i've just implemented my own serializer:

<?php

namespace App\Serializers;

use League\Fractal\Serializer\ArraySerializer as DefaultArraySerializer;

class ArraySerializer extends DefaultArraySerializer
{
    /**
     * Serialize null resource.
     *
     * @return null
     */
    public function null()
    {
        return null;
    }
}

And it works as expected for me. But if you try to change null to '{}' or 'new \stdClass()' it will throw an error @KorvinSzanto , and it may cause an issue.

+"message": "array_merge(): Argument #1 is not an array"
  +"exception": "ErrorException"
  +"file": "/home/vagrant/vendor/league/fractal/src/Scope.php"
  +"line": 288

Also to return [] for empty collection you can just use anything like this

return $this->collection([], new AnyTransformer());

and it will return "include":{"data":[]} with ArraySerializer, don't sure about others. But $this->nullCollection() will be much easier and usefull i think

@buglinjo
Copy link
Author

buglinjo commented Apr 4, 2019

json_encode([]) -> '[]'
json_encode(['hello' => 'world']) -> '{'hello':'world'}'
json_encode((object)[]) -> '{}'
json_encode((object)['hello' => 'world']) -> '{'hello':'world'}'

So... Conclusion... We need this function to be fixed:

/vendor/league/fractal/src/Scope.php

public function toJson($options = 0)
{
    return json_encode($this->toArray(), $options);
}

To

public function toJson($options = 0)
{
    return json_encode((object)$this->toArray(), $options);
}

Idk if it will break anything though, but it fixes my problem if I do that.

@MylesKingsnorth
Copy link

MylesKingsnorth commented Aug 5, 2019

Is there any solution to this?

I have an item include which obviously returns an object but when I have no data for this, I want an empty object, not an empty array.

I have created my own ArraySerializer as I needed to anyway and I tried overriding the null function with return (object) []; but I get the following error:

Notice: Object of class stdClass could not be converted to number.

Update: I just decided to fork the package and add my own resource type EmptyObject which is similar to using null() and does exactly what I need. As it appears the package doesn't have that many frequent releases, it's probably worth just forking and making your own changes.

@matthewtrask
Copy link
Contributor

We are working on a 1.0 for this package and looking to include something like this in the Scope class.

@buglinjo
Copy link
Author

Any updates on this?

@zlanich
Copy link

zlanich commented Nov 21, 2019

I too am looking for an update on this. I'd personally like a null item resource to look like so:

{
  "key": {
    "data: null
  }
}

An empty array or object doesn't make any sense for a non-existent object.

@mtx-z
Copy link

mtx-z commented Feb 24, 2020

Any updates on this? Would be nice to have to prevent additional if checks... Ty

@singleseeker
Copy link

Any solution?

@matthewtrask
Copy link
Contributor

I have an almost working POC. Im working with the other maintainers to figure out how to release it.

The plan is that the NullResource is going to be in line (as close as I can get it) to what is being discussed. However this would be a huge breaking change to anyone who currently relies on the null resource to be [], so I am adding a new EmptyResource which will be in line with what is the current behavior.

The issue though is that this is a breaking change, so I dont want to unilaterally release something like this.

Thanks for your patience!

@lucasres
Copy link

I dont know if solve your problem. But you can try

return $question->documentType
        ? $this->item($question->documentType, new DocumentTypeTransformer)
        : $this->primitive(null);

And return is

{
  "foo": null
}

this is dont {} but is better than []

@joelharkes
Copy link

yea weirdly enough, i expected $this->null() to return null as well.

now i make the code like this to make it work:

return null === $transaction->segment
            ? null
            : $this->item($transaction->segment, new SegmentTransformer());

@buglinjo
Copy link
Author

@lucasres found the solution to this issue. Thank you!

Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests