I'm stuck on nested arrrays within the JSON argument i.e.

I have set up a new type and added a TEXT CCK field - field_html_song_list

{"type":"rundata","uid":"1","title":"TITLE","body":"BODY","field_html_song_list":[{"value":"Song","format":"2"}]}

The above JSON just pulls up a blank page when running manually (/admin/build/services/browse/node.save)
and returns Missing Argument on DrupalCloud

However, this works fine and sets up a a new node:
{"type":"rundata","uid":"1","title":"TITLE","body":"BODY"}

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

matteblacke’s picture

After enabling php errors i get the below after running this JSON

{"type":"rundata","uid":"1","title":"TITLE","body":"BODY","field_html_song_list":[{"value":"Song","format":"2"}]}

Fatal error: Cannot use object of type stdClass as array in public_html/modules/cck/modules/text/text.module

voxpelli’s picture

Title: Services node.save with CCK - Missing Required Arguments » Node.save not working with CCK due to wrong JSON decoding
Project: Services » JSON server
Version: 6.x-2.x-dev » 6.x-2.0-alpha2
Component: Miscellaneous » Code
Category: support » bug
Status: Active » Needs review
FileSize
312 bytes

This is an error in the JSON server module.

Services supports only associated arrays as arguments - not objects. The json_decode of the JSON below results in field_html_song_list containing an object instead of an array.

{"type":"rundata","uid":"1","title":"TITLE","body":"BODY","field_html_song_list":[{"value":"Song","format":"2"}]}

The reason this hasn't been discovered earlier is probably because Services itself does some basic type casting - but no recursive casting.

Attached is a patch that fixes this by specifying to json_decode() that we prefer arrays.

matteblacke’s picture

I have applied the patch and it fixes the problem

thank you

spazefish’s picture

Great and thanks for pointing me to this matt, awesome ! :D

gdd’s picture

Does this break existing implementations of JSON Server? Or does it just fix the stuff that has always been broken?

voxpelli’s picture

Looking at the Services 2.x browser and at issue #945788: Change node.save argument type to array I think my patch is not entirely correct (but it might work anyway?).

JSON Server should check if the argument type is a struct or an array and depending on that parse the JSON differently - my patch treats struct as array and right now arrays are treated like structs. A problem with doing a correct fix now is that until #945788: Change node.save argument type to array is fixed the node.save argument has the wrong type so the core issue here, that CCK fields can't be saved, can't get a correct fix until Services 2.x is fixed.

Also related to this issue is a suggestion for Services 3.x: #954964: Remove argument type 'struct' in favor of 'array' It's a suggestion to simplify the argument types in order to avoid such complexity and confusion for the servers that we see in this and similar issues.

kylebrowning’s picture

Status: Needs review » Fixed

#945788: Change node.save argument type to array

Was fixed and committed. I believe that solved this issue and if not, feel free to mark as needs work.

voxpelli’s picture

Title: Node.save not working with CCK due to wrong JSON decoding » Check if argument is struct or array and parse differently
Status: Fixed » Needs work

JSON Server should still check if the argument type is a struct or an array and depending on that parse the JSON differently - I don't think #945788: Change node.save argument type to array fixed this since JSON Server never checks the type.

kylebrowning’s picture

My apologies, for some reason I thought this was a duplicated ticket in the Services Issue Queue.

batje’s picture

Status: Needs work » Reviewed & tested by the community

I would not mind if this got committed. The patch in #2 works for me

mayur.pimple’s picture

How to pass cck argument in node.save drupal services

{"title":"title1","type":"poll","choice":[{"0"}]:[{"chtext":"1"}],"choice":[{"1"}]:[{"chtext":"2"}]}

elliotttt’s picture

I see this patch worked for some people, but it's didn't work for me however the problem remained the same.

My interim hack-ish fix was to cast the node property as an array like so:

<?php
function json_server_server() {
$_POST = json_decode($_POST['data']);
$_POST = (array)$_POST;
$node = $_POST['node'];
$node = (array)$node;
$_POST['node'] = $node;
...
?>

Any suggestions on how to recursively check for this in a more elegant way would be wonderful. I thought I'd post this anyway in case other people are still stuck on this.

elliotttt’s picture

Came up with a better way to deal with this... I'm going to see what other repercussions it might have before creating a patch.

<?php
function objectToArray($d) {
	if (is_object($d)) {
		// Gets the properties of the given object
		// with get_object_vars function
		$d = get_object_vars($d);
	}

	if (is_array($d)) {
		/*
		* Return array converted to object
		* Using __FUNCTION__ (Magic constant)
		* for recursive call
		*/
		return array_map(__FUNCTION__, $d);
	}
	else {
		// Return array
		return $d;
	}
}
?>

Added the above to the module, then added this to the json_server_server function:

<?php
if(isset($_POST['node'])){ 
  $obj = $_POST['node'];
  $_POST['node'] = objectToArray($obj);   
}
?>