Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Requesting a node that has multiple values in a field works. Creating a node with multi value field (that is not a reference) field doesn't work.
If this already works, then it's not documented how to send the values.
Comment | File | Size | Author |
---|---|---|---|
#34 | interdiff_2301237-9-33.txt | 5.79 KB | m.stenta |
#34 | 2301237-34.patch | 4.65 KB | m.stenta |
#34 | 2301237-test-fail-34.patch | 3.65 KB | m.stenta |
#29 | 2301237-9.patch | 3.25 KB | lokapujya |
#9 | interdiff-2301237-9.txt | 405 bytes | lokapujya |
Comments
Comment #1
lokapujyaPossibly, this belongs to the enity API queue; I'm not sure yet. The modules are closely related.
Attaching a test to demonstrate the problem.
Comment #2
lokapujyaComment #4
lokapujyaIf this passes, then entity API is probably off the hook. Here, I'm testing the part of entity API that is used, when making the REST call, to create the node with a multi-value field.
Comment #5
lokapujyaLooks like Entity API is ok.
I think I am sending the multi-value field correctly.
Creating the multi-value array:
Setting the field:
Comment #6
lokapujyaFixing the test. Previous patches changes were affecting the test that follows the new test.
Comment #7
lokapujyaCopied the example from testResourceArray within the REST tests. Instead of id and resource, just used the value; it seems to be working.
Comment #8
lokapujyaRe-opening since the test still fails.
Here is the test-only patch.
Comment #9
lokapujyaHere is the fix.
Comment #10
lokapujyaComment #11
lokapujyaComment #12
lokapujyatest me.
Comment #14
nicxvan CreditAttribution: nicxvan commentedThis patch seems to work.
The format I had to use for the array was as follows:
'field_name' => array(
array( 'value1' ),
array( 'value2')
)
Works for text fields. I am going to test it on image fields now.
Comment #15
nicxvan CreditAttribution: nicxvan commentedI was not able to get this working with images in conjunction with the following patch: https://www.drupal.org/node/1819594
Adding a single image works like this:
'field_image' =>
'data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg')
encode file just base64 encodes the image from the local file.
Attempted the following three structures with no success:
'field_image' =>
'data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg'),
'data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg')
ERROR: 406 Not Acceptable: Unknown data property 0.
'field_image' => array(
'data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg'),
'data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg')
)
ERROR: Warning: preg_split() expects parameter 2 to be string, array given in restws_image_support()
'field_image' => array(
array('data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg')),
array('data:image/jpeg;base64,'.encode_file('../sites/default/files/pengoothumb.jpg'))
)
ERROR: 406 Not Acceptable: Invalid data value given. Be sure it matches the required data type and format.
I think the third format is the closest to what we need. The second error is from the code in the patch in the attached issue.
The first I think is the most wrong.
Comment #16
nicxvan CreditAttribution: nicxvan commentedJust a note, a single image on the multivalue image field works fine.
Comment #17
nicxvan CreditAttribution: nicxvan commentedWith both patches the following script will add an image to the restws site assuming you point encode_file at a valid file.
(you need to add the website and the username and password along with typical restws permissions and username structure.
Comment #18
nicxvan CreditAttribution: nicxvan commentedThis is the same as above except SHOULD do the multivalue image with the same caveats
Comment #19
lokapujyaSince this patch gets multi-value text fields working, I'm moving the multi-value images to a new issue: #2320083: Allow creating nodes with multi-value image fields.
Comment #20
nicxvan CreditAttribution: nicxvan commentedMultivalue images work with this: format is: 'field_image' => array(
'data:image/jpeg;base64,'.encode_file('../sites/default/files/penguinthumb.jpg'),
'data:image/jpeg;base64,'.encode_file('../sites/default/files/tulipthumb.jpg')
)
encode_file is a function that just base 64 encodes the images referenced. The function is copied below for clarity THIS IS NOT PART OF RESTWS!!!
Only works with the following patches: https://www.drupal.org/node/1819594
Comment #21
lokapujyaComment #26
lokapujyaThe errors don't seem to have anything to do with this patch.
Comment #27
lokapujyaPostponed on #2484829
Comment #28
lokapujyaComment #29
lokapujyaRetest.
Comment #30
m.stentaI'd like to resurrect this issue, because we are experiencing something similar in farmOS 7.x-1.x. However, the patch here does not fix the issue we're having, and I think the real culprit might be somewhere different in the code.
The specific issue we are seeing is with regard to
list_text
fields. We have a "flags" field that is a set of checkboxes. When youGET
an entity via the API, these flags look like this:However, sending that same format in a
POST
orPUT
request (to create/update entities, respectively), it fails. No error is displayed, and there is no response from the server. However, there is aTypeError
and about 15 PHP Warnings in the "Recent log messages".TypeError: Argument 2 passed to RestWSBaseFormat::getResourceReferenceValue() must be of the type array, string given, called in /var/www/html/profiles/farm/modules/contrib/restws/restws.formats.inc on line 278 in RestWSBaseFormat->getResourceReferenceValue() (line 311 of /var/www/html/profiles/farm/modules/contrib/restws/restws.formats.inc).
At quick glance, it seems that the "flags" field (which is of type
list_text
), is being parsed as a reference field, which it is not.It is also curious that the patch for this issue is making a change to
getResourceReferenceValue()
as well. But why? Text fields are not reference fields, so why does making a change to that method fix it? It seems that there is a deeper issue here, where multi-value fields are always assumed to be reference fields.Notably, we stumbled upon a form of JSON that DOES work to set the "flags" field for us:
The only reason that works is because
restws
is assuming that all arrays are arrays of references. So if you wrap your text in an object with anid
, it works. But it shouldn't.Comment #31
m.stentaHere is the curl command I am running to create a Log entity in farmOS (note that I'm omitting the cookie and csrf token stuff for simplicity):
curl -X POST -H 'Content-Type: application/json' -d '{"name": "Test API flags", "type": "farm_activity", "flags": ["priority"]}' http://localhost/log
Tracing this with XDebug, I can see that:
1.
restws_handle_request()
takes the payload (the JSON string after the-d
flag in the command above), and passes it toRestWSBaseFormat->createResource()
which unserializes it usingRestWSFormatJSON->unserialize()
2.
RestWSFormatJSON->unserialize()
simply runs the payload throughdrupal_json_decode()
, and then passes the output of that as reference intoRestWSBaseFormat->getPropertyValues()
.3.
RestWSBaseFormat->getPropertyValues()
iterates through each item in the payload array, and only continues with it if the property's value is an array.4. Then, it looks to see if the field property info array has a key called
property info
. If it does, it recursively runsgetPropertyValues()
again on the values. Otherwise, it passes it intoRestWSBaseFormat->getResourceReferenceValue()
.So, it appears that values inside arrays are ALWAYS passed into
getResourceReferenceValue()
, even when they are NOT reference fields. This seems wrong.It seems that
getPropertyValues()
should be checking to see if the field is a reference field first, and if it isn't then it should NOT process it any further. As it's written right now, it seems to have an implicit assumption that multi-value fields are always reference fields.Comment #32
m.stentaJust to test this theory, I added a
return;
at the very top ofgetPropertyValues()
so that it would not do ANY processing of the values. Then I ran the curl command from my last comment, and it worked! It created the entity with the flags associated with it properly. Then, I added a multi-value textfield to the entity and tested with that as well, and that also worked!So that seems to prove my hypothesis that
getPropertyValues()
is the source of this issue. It does not do anything to prevent non-reference fields from being treated as references.Comment #33
m.stentaAssuming the above is correct, and the issue has been pinpointed... the next question is: how do we fix it? How do test that a field is a reference field inside
getPropertyValues()
to ensure that it does not process non-reference fields?Comment #34
m.stentaAttached are two patches and an interdiff.
The first patch demonstrates the problem, and the tests should fail. It is inspired by @lokapujya's patch, and also includes a test for a
list_text
field, in addition to a test of atext
field.The second patch fixes the issue by checking to see if the value that will be passed from
getPropertyValues()
togetResourceReferenceValue
is an array. If it is not an array, then it skips it. This works because reference fields are always an array (converted from a JSON object like{"id": 123}
), whereas non-references are just a flat value. Previously, these flat values were being passed intogetResourceReferenceValue
, which explicitly requires an array as its second argument (assuming it will be a reference value). This is what leads to the error described above:TypeError: Argument 2 passed to RestWSBaseFormat::getResourceReferenceValue() must be of the type array, string given
So, this just adds a simple check to make sure that the value being passed into
getResourceReferenceValue
is actually an array. If it isn't then it skips it.