-
Notifications
You must be signed in to change notification settings - Fork 347
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
Implementation of configurable serializers. #45
Conversation
What is the reasoning behind a static |
*/ | ||
public function setMeta(array $meta) | ||
{ | ||
$this->meta = $meta; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use array_merge_recursive() here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well it's a setter, an overwrite makes sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only reason I didn't do any merging is because you'd most likely be only setting the meta data once since you need the resource instance to do so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, agree
Hm, can't remember why I had it as static. There's no reason for it to be static. Will change after breakfast. |
} | ||
} | ||
|
||
return $output; | ||
$data = array_merge($data, $serializer->serializeEmbeds($this->availableEmbeds)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to try and build up various aspects of the data variable then just merge once at the end?
I could probably do that myself at the end, but... :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean have like a $meta
, $embeds
, $pagination
, and $cursors
variables then do a the merge?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I guess. Big arrays being merged multiple times could get a little slow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely. I'm about to crash for the night so will get on it in the morning. 😄
In your example: $user = new User('Bob', '23');
$resource = new League\Fractal\Resource\Item($user, new UserTransformer);
$user->setMeta(array('token' => 'kan1$isdd098hjasd89hsa#$9q')); Is the setMeta method really on |
And how well does this work with embedded data? Can meta be added to a nested collection or items in a nested collection? |
My bad, that should be on |
Cool. This all looks great. |
No, that's the only thing that I wasn't sure on. If that were the case you would probably have to do it a bit differently I think. Especially if you wanted all meta data to be merged at the top level. |
Meta data definitely should be merged at the top level, but stick to the respective level.
That is a fairly normal looking output for the default serializer. With meta it would look like this:
Does that make sense? Stuff like paginates need to be able to go into embedded resources too eventually, as by default you will only receive a sub-set of data and want links to fetch more. |
Yeah that makes sense and is a whole lot easier then what I was thinking. So would you prefer the current method of setting the meta data on the resource or defining it in the transformer with a |
Nice work. I wonder if the use of array_filter in the ArraySerializer is correct. I think by default Fractal (or the basic serializer for that matter) should not change the output data even when values are null, false or empty. No? |
The default serializer does not put null embeds in. Others can, but that is how it works now. :) -- On May 4, 2014 at 8:43:43 PM, Rolf (notifications@github.com) wrote: Nice work. I wonder if the use of array_filter in the ArraySerializer is correct. I think by default Fractal (or the basic serializer for that matter) should not change the output data even when values are null, false or empty. No? — |
Okay so it's no longer using public function embedPosts(User $user)
{
$posts = $user->posts;
return $this->collection($posts, new PostTransformer)->setMeta(array('foo' => 'bar'));
} The meta data would be nested alongside the embedded data. So: {
"data": {
"foo": "bar",
"posts": {
"meta": {
"foo": "bar"
},
"data": [
{
"message": "durp"
}
]
}
}
} |
*/ | ||
public function serializeData(array $data) | ||
{ | ||
return array('data' => $data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all looks great, but I am not sure it will cover the use-case of some users. It definitely will let me have my data
arrays nested, but other users with other serializers will be more tricky.
- There is no differenciation between serializing a singular item or multiple, meaning JSON-API is not gonna work.
- There is no context of what the item is, so instead of data having
posts
for JSON-API will not work either. - JSON-API wants an array of items, even when only one item is returned. If there was a way to handle item and collection resources differently, you could simply wrap the item in an extra array.
I know that might sound like a bit of an arse, but think, if you can support HAL and JSON-RPC out of the box with this package then your API package users will flip out. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll have to look into HAL.
As for the context I suppose each of the serializers methods could accept the resource itself or the serializer can implement a setResource
method so it can internally inspect the resource. Would that be the best way of going about that do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I sit down and fight with the code I am not sure off the top of my head. I think the original plan was to implement JSON-API and HAL in the core, and have them error if certain properties are not available.
Whatever happens it cannot be directly tied to the transformer. A transformer is just the data structure, which could be implemented for multiple different types of "thing". A user transformer could be "friends" and "owners" for example.
It sounds like we're on the same page though. The resource can handle it once created, with setResourceKey or something. By default it can be "data"
, or it could be null and the JSON-API serializer can shout at you if its not set.
I think I prefer the shouting approach, as its less silent hidden magic.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to paste an example:
public function embedImages(Moment $moment)
{
return $this
->collection($moment->getAllImages(), new ImageTransformer)
->setResourceKey('avatars');
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that makes sense. So once you have a resource of posts, for example, you'd do something like this.
$resource = new League\Fractal\Resource\Collection($posts, new PostTransformer);
$resource->setResourceKey('posts');
That's what you're getting at, right? And then the JSON API serializer will simply throw a tantrum if there's no key. Because it shouldn't try and guess at the key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I'm with you now. Will push some changes shortly. 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah thats what I’m getting at. :)
Then you can do the same in your controller, and everything should be happy and flexible. We document that they are optional, and its a good idea to set them if you plan on changing formats, but also mention WHY THE HELL WOULD YOU CHANGE FORMATS.
Like those Laravel folks who pretend people are swapping from MySQL to Mongo and back again every other Tuesday. :D
--
Phil Sturgeon
On May 6, 2014 at 1:35:47 PM, Jason Lewis (notifications@github.com) wrote:
In src/Serializer/DataArraySerializer.php:
@@ -0,0 +1,29 @@
+<?php namespace League\Fractal\Serializer;
+
+class DataArraySerializer extends ArraySerializer
+{
+
- /**
\* Serialize the top level data.
\*
\* @param array $data
\*
\* @return array
*/
- public function serializeData(array $data)
- {
Yeah that makes sense. So once you have a resource of posts, for example, you'd do something like this.return array('data' => $data);
$resource = new League\Fractal\Resource\Collection($posts, new PostTransformer);
$resource->setResourceKey('posts');
That's what you're getting at, right? And then the JSON API serializer will simply throw a tantrum if there's no key. Because it shouldn't try and guess at the key.
—
Reply to this email directly or view it on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository ALL the things!
@philsturgeon Thoughts on changing |
@jasonlewis keep in mind that that would require a new major version to be released. Another option would be to have a ResourceAbstract which implements the ResourceInterface so you have a non-BC-breaking change. |
@FrenkyNet Good point, will do that for now. 👍 |
We’d only need a minor as this is still 0.x and we can break BC as much as we like. Obviously I’d like to minimize it, but not at the sake of complicating the design process. |
Would you like to support HAL with another package, or coded from scratch? I've had good experience with |
I’ve come across this package in my adventures, but I think trying to smash the two together could end up being rather difficult, or maybe a little pointless. We just need to make a seralizer that knows the rules of the spec, which is not hard to implement given how fractal is (or should be). :) |
I was using this for me, but its silly to give it to everyone else.
Allows for generic "modifiers" and "params" to be passed around to nested relationships. The values will be available in the transformers for folks to play with when fetching extra data.
👍 For this |
Okay so I've worked on this a bit more and have made a few changes to the Anyway. The {
"users": [
{
"id": 1,
"name": "Jason"
}
],
"linked": {
"posts": [
{
"id": 1,
"user_id": 1,
"title": "Foo"
},
{
"id": 2,
"user_id": 1,
"title": "Bar"
}
]
}
} Note that the resource key (in this case, $resource = new League\Fractal\Resource\Item($user, new UserTransformer, 'users');
// Or...
$resource->setResourceKey('users'); JSON API is a real bitch though, especially when Fractal doesn't really deal with much more then just transformed arrays so it's hard to really manipulate the data too much more. So before I go any further and look at HAL I'd like to have some feedback on it in its current state. |
I hope to check in the coming days. I was away the last couple of days.. by a quick scan I wondered what happens if there's no resourceKey set, I didn't see a check or fallback if the value is null. |
Ah, yes, if no resource key is set it's meant to throw a hissy fit. I was talking with Phil about it and basically it would be too much guessing to try and have a fallback when no resource key is set. So, really, if someone (for whatever reason) plans on switching out their serializer they'll need to either have set the resource key in advance or have to go through and set it. It should throw an exception though if you try and use the |
Why not just fallback to |
Hm, no, I still think it's best of it throws an exception. Falling back to |
Looks good to me. I'll pull this into a local branch and have a play with it. |
…develop Conflicts: src/Scope.php src/TransformerAbstract.php tests/ScopeTest.php tests/TransformerAbstractTest.php
@jasonlewis can you merge my changes from |
Also re-pr against develop if you can. |
Final answer: I merged most of it and put it in the feature/serializers branch, but there are two failing tests I'd like you to look at.
|
Okay so those two tests are only failing because now it checks if the transformer has any included resources before processing (https://github.com/thephpleague/fractal/pull/45/files#diff-e3a7ce8ca66c42dd21b489b30f7daecfR161) So it's a non-issue I think. I've rebased onto the |
Yes please! |
Signed-off-by: Jason Lewis <jason.lewis1991@gmail.com>
@@ -20,7 +20,7 @@ | |||
"php": ">=5.3" | |||
}, | |||
"require-dev": { | |||
"phpunit/phpunit": "~4.0", | |||
"phpunit/phpunit": "~4", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What? Why have you done that? That means we can load phpunit 6.x for example. That is not desired. ~4.0
was correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're like a hawk.
Yeah this went from 3.7 to 4.0 again, and when it came back it was missing a .0. With PHPUnit 5 probably another year away im not too scared about this, but I'll get it changed back. :)
Being taken care of in #47. |
This is a PR in relation to #24 and #18.
Seeing as @joshuajabbour doesn't have the time at the moment to continue working on the PR I've had a crack at an implementation and would love some feedback.
The Implementation
At its core is the
SerializerInterface
which has 5 method signatures declared. Each serializer implements these methods to return the data in a format of their desire. Included is a basicArraySerializer
, which returns the data in what I consider an untouched form. Resulting JSON from theArraySerializer
would be:Benefit here is for systems returning pre-keyed data (above would have the user data keyed to
user
, for example).The default used serializer would be the (current)
DataArraySerializer
which keys the top level data todata
.The serializer is set on the
Manager
via thesetSerializer
method.If no serializer is set the default
DataArraySerializer
is used.Meta Data
This PR also includes meta data support for resources. Instead of defining a method on transformers I've opted for a (hopefully) better approach by setting the meta data on the resource.
The
ArraySerializer
simply merges with the top level much like it does with the standard data and theDataArraySerializer
would key it tometa
and merge to the top level.Tests
I've not done any tests yet merely patched the existing tests that failed due to the new meta data key. Will do tests once some more feedback is received on the approach and implementation.
Cheers.