Skip to content
This repository has been archived by the owner on Jan 21, 2020. It is now read-only.

Hal tries to extract entity when content negotiation is set to Json (then fails with exception) #38

Closed
jdelisle opened this issue Jun 5, 2014 · 5 comments

Comments

@jdelisle
Copy link

jdelisle commented Jun 5, 2014

Resolution as mentioned below:

we should likely make it possible to create the Hal\Entity without needing to serialize it first

Transcript from IRC:

<djule5> weierophinney: I want to return plain json representations, but it seems that Apigility is dependent on the Hal module.
<weierophinney> djule5: you can choose a different content negotiation selector for all API services, and while HalJson is the default for REST, you can also select just Json, which will return bare JSON. THAT SAID: we do not do any auto-extraction of objects to JSON for you; you will need to define that logic yourself, or ensure you return JsonSerializable objects.
<djule5> weierophinney: Yes, that's basically what I've been doing. I also tried deleting the zf-hal config array, and it seemed to work. However, going back to apigility-admin and saving a service, it creates back the zf-hal array with the default values for the service and then calling the service returns me a "Zend\Stdlib\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()". Do I need to have zf-hal config if none of my services return HalJson?
<weierophinney> djule5: the admin API creates that information, even if you're not using it.
<weierophinney> djule5: you _could_ potentially use that information yourself to do the object extraction, too.
<djule5> weierophinney: Following our discussion yesterday, would you recommend not using the admin interface when not using HalJson (if I don't want the zf-hal config)? Or could zf-apigility-admin take in account the chosen Content Negotiation Selector (i.e. Json) and not regenerate the zf-hal/metadata_map accordingly?
<weierophinney> djule5: the admin will continue generating the zf-hal information, even if ultimately it won't be used. I'd use the admin interface, personally; lot less to remember and worry about in the configuration.
<djule5> weierophinney: the problem is that it's actually used, the Hal plugin gets called and tries to extract the entity (in ZF\Hal\Plugin\Hal::convertEntityToArray) using the hydrator set by the admin interface (i.e. ArraySerializable) which I do not implement the required methods on my Entity. I would expect my Entity left untouched by Hal and forwarded to ZF\ContentNegotiation\JsonModel to be serialized, or maybe I'm missing something?
<weierophinney> djule5: run a `composer update` in your project. :) We actually fixed that behavior in zf-hal for this latest release, so that it retains the original entity in the ZF\Hal\Entity object now.
<weierophinney> djule5: and you're right -- we _are_ casting to a ZF\Hal\Entity/ZF\Hal\Collection.
<weierophinney> djule5: however, we have some logic in ZF\ContentNegotiation\JsonModel to pull the original entity/collection out of the HAL objects.
<weierophinney> djule5: so with the upgrade, it should now work.
<djule5> weierophinney: interesting... I actually ran the update yesterday, and I'm testing the behavior right now and it's still doing it (500 with "Zend\Stdlib\Hydrator\ArraySerializable::extract expects the provided object to implement getArrayCopy()")
<weierophinney> djule5: ah -- that makes sense. The logic when creating the HAL entity does use the hydrator to cast to array in order to be able to extract the identifier (as a Hal\Entity object requires both the original entity AND an identifier)
<weierophinney> djule5: can you file an issue for that, please? I'll see if I can find a way to create a flag for disabling that.
<weierophinney> djule5: what it does is serialize, extract the identifier, but then injects the original object in to the Hal\Entity. (We cache the seriailized version for when serialization happens later)
<weierophinney> (if it ever happens)
<djule5> weierophinney: yes ok I see what you mean... I do think however that I was getting the same behavior before that fix you're referring to (I'm looking at the commit diff on github)
<djule5> weierophinney: Hal is just responsing accordingly to the metadata map config... hence why I was thinking probably it should just not be there in the first place
<weierophinney> djule5: the problem is that we do the Hal\{Entity|Collection} creation in zf-hal. We don't want to do a ton of conditional logic in there based on the selected view model -- that's the whole point of having zf-content-negotiation in the first place. That said, we should likely make it possible to create the Hal\Entity without needing to serialize it first. File the issue, and I'll work on a fix; I have a few ideas.
@weierophinney
Copy link
Member

Now I cannot remember what my ideas were. :-/ @jdelisle -- can you pull the current master branch and let me know if it still poses a problem? My guess is it does -- which would likely require that we change Entity to allow specifying a null identifier, and then attempting to extract it later, only during rendering.

@weierophinney
Copy link
Member

@jdelisle I've got a workaround: Use/create a different object for your entity than is listed in the configuration for the service. This will ensure that we don't call createEntityFromMetadata(), which means it will not attempt to serialize the object. createEntityFromMetadata() is only called if the object is in the metadata map; if it's not, then it is ignored.

You have two ways of accomplishing that:

  • Create a different entity type in your service, and make sure your resource class returns entities using that type.
  • Change the metadata map to remove the entry for the entity type.

The first will definitely work -- if the entity type is not in the metadata map, then it won't attempt to serialize it.

I think you might be suggesting that the latter option does not work. If that's the case, let's open an issue on zfcampus/zf-apigility-admin to fix that.

Now, where it all falls down... if you want to allow serialization BOTH to plain JSON as well as HAL, as that would require that the entity type be in the metadata map for those cases where HAL is going to be used. Is that a scenario you are considering?

@jdelisle
Copy link
Author

Yeah, I believe either can work.

The only problem with the second one is the admin recreating the entry in the metadata map on a Json resource. For the meantime anyway, I can just use a different entity. Should I still file an issue on zfcampus/zf-apigility-admin? It seems to me like it would be a good idea not to impose those entries.

I'm only using JSON serialization at the moment, so I wouldn't need it in the metadata map.

@weierophinney
Copy link
Member

@jdelisle Yes, please open an issue on zfcampus/zf-apigility-admin; basically, we shouldn't be re-populating the metadata map on updates to the service, and that's the problem you're having.

@weierophinney
Copy link
Member

Closing, as the real issue is on zf-apigility-admin.

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

No branches or pull requests

2 participants