JSON data with duplicate keys via PHP - php

Apache SOLR calls for a quirky JSON format when you want to add multiple entries at once. ( http://wiki.apache.org/solr/UpdateJSON#Update_Commands -- notice the 'add' nodes)
In a nutshell, I need to be able to create JSON that looks like this:
{
"key": "val 1",
"key": "val 2"
}
In PHP, you can easily create an array, but this JSON structure calls for an object with two keys of identical name that are explicitly not in an array.

While json_encode can't do that directly, you can work around it. Try this:
$php_friendly_json = json_encode([
"key1" => "val 1",
"key2" => "val 2"
]);
$apache_weird_json = str_replace(["key1", "key2"], "key", $php_friendly_json);
Of course, be sure to pick key1 and key2 such that they aren't going to be in the values of your JSON!

You aren't going to be able to do this using json_encode because it's not valid JSON. (Keyspace collision)
You are going to need to assemble the object manually.
You might consider creating the individual items, then using implode(). Then you can prepend and append { and }.
This would actually feel cleaner to me then hacking away at PHP to get json encoding to work.
Suggested Alternative
I'm a big fan of the Solarium Project for PHP and Solr.
Bulk Adds and pretty easy take a look here: http://wiki.solarium-project.org/index.php/V2:BufferedAdd_plugin

Related

PHP, Laravel: Eliminate Specific Complex Array from JSON

I'm currently developing an API using Laravel for my project, the concept:
Retrieve JSON data from MySQL.
Receive user input from the Front-end (string).
Convert both JSON and string input into an array with similar structure. The array structure here is basically ["ObjectA", "ObjectA_quantity", "ObjectB", "ObjectB_quantity", ...].
Basically, eliminate the quantity of every object of Database's Array, based on every object that User Input's Array got. For example, if the Database's Array got ["pizza", "1", "burger", "2"], and the User Input's Array got ["pizza", "1"], the output of the method is expected to be ["burger", "2"].
The method that I developed will give inconsistent and confusing output, like for some object, it works well, for other it doesn't eliminate anything and if the User Input's Array too big (> 1 object), it also doesn't eliminate anything. I really welcome different approach or anything else that will give the expected output as above. Thank you very much
Here's the source code of the method I've develop: (method's located on: else if ($transactionGetter->type == 'return'), Line 148 and so forth)
https://github.com/andre-nk23/packme-backend/blob/master/app/Http/Controllers/API/TransactionController.php
if it's a JSON you must decode the value before access
$transactionGetter=json_decode($transactionGetter);

Set multiple keys having multiple values to Redis

I have a php backend using phpredis (a php client for the redis server) to store key value pairs to a Redis server. The data I need to store is of this form:
"key1" => "v1", "v2", "v3"
"key2" => "m1", "m2", "m3"
"key3" => "n1", "n2", "n3"
...
Based on my research, I can set multiple keys in a redis using the mset command like so:
$redis->mSet(array('key0' => 'value0', 'key1' => 'value1'));
But what I actually need is something like this:
$redis->mSet(array('key0' => array('v1','v2','v3') , 'key1' => array('m1', 'm2', 'm3')));
But this just stores the value for each key as "Array" instead of the actual array specified.
Is this possible to do with a single command like mset or do I need to iterate my data and set each key separately using something like lPush?
phpredis documentation: https://github.com/phpredis/phpredis
So rather than using mSet you can probably use sADD to get your desired functionality.
$redis->sAdd($key, ...$data);
Full documentation on it here.
This would mean iterating and doing it in multiple steps for which I'd reccomend reading into Redis Pipelines and the non-shameless plug link which contains more information.
Which would look something like;
$redis = new Redis();
$pipeline = $redis->multi(Redis::PIPELINE);
foreach ($dataset as $data) {
$pipeline->sAdd($data['key'], ...$data['values']);
}
$pipeline->exec();
I can't think off the top of my head a way to do this in a singular operation, someone else might come along though who knows more than me :)
Edit: Looks like I misunderstood your question a little as it was more focused on doing this in a single operation. Hopefully the above is still useful but to my knowledge you'll have to do this with multiple.

What is meant by 'a valid array format for collections'?

When calling an REST API method I get back that there is an error
Error processing request stream. The payload must represent a valid array format for collections.
But when searching for:
valid array format for collections
I get back a lot, but nothing clarifies what is meant by this. I'm guessing the data i send is not valid (currently i'm sending an array('foo' => 'Bar')) but this is probably not correct.
Has anybody got a pointer to what is happening here? Or what i could check?
The documentation of ExactOnline (which I'm posting to) is not sufficient. It only states what fields they have, but nothing about these kind of error messages.
==========================
Ok, this needs some clarification, my bad!
As written, i'm communication with ExactOnline, via their API.
I'm calling the method to post a sales order. With that, i'm using a set of scripts Exact provides on their website (for developers).
on page:
https://start.exactonline.nl/docs/HlpRestAPIResourcesDetails.aspx?name=SalesOrderSalesOrders
under 'POST', you can read the mandatory fields, under which 'SalesOrderLines' is one of them. It does not tell me what it expects or in what format.
I wrapped my array in a json_encode and tried again, but no luck. It still tells me the same error.
I'am currently using the same ExactOnline API. Have to say that the documentation lacks in information on this topic indeed!
To make a valid array for collections you have to use the following base:
$array = array(
'InvoiceTo' => 'bc960e43-be9d-409c-9cfe-31ce56cc3238',
'SubscriptionLines' => array(
array('Item' => '7e50702b-5bbf-4b77-ab73-5dad50016e82')
)
)
The json_encode($array) on this list would be:
{
"InvoiceTo":"bc960e43-be9d-409c-9cfe-31ce56cc3238",
"SubscriptionLines":[
{"Item":"7e50702b-5bbf-4b77-ab73-5dad50016e82"}
]
}
So the important part here is to do array(array()) inside the SubScriptionLines. This tells the JSON that you want to use an JSON Array instead of the JSON Object notation.
For your particular question you need to change the keys into the keys given in the documentation for a SalesOrder. Not all manditory fields of the api are included here, because this solution is for Subscriptions. However, the principle will be the same.
Hope this will help you and others implementing the exact API fully :)
How are you serializing your payload? If it is meant to be in JSON format, a collection would look like this:
[
{
"foo": "bar"
},
{
"foo": "baz"
}
]

PHP multidimensional array to JSON

So im trying to figure out the best way to get MySql table data into either a multidimensional PHP array or convert that multidimensional array into a json string.
Essentially what im trying to do is have a php include that returns the JSON string so i can iterate through it. I am needing a single key with multiple values, so im not 100% sure that im headed in the right direction.
I want to assign multiple values to the same key, for example:
[{"key1": "package1", "package2", "package3"}, {"key2": "package1", "package2", "package3", "package4"}]
I think that is not going to work right? Because i dont have any type of index's?
That is not valid JSON. The structure you are looking for would be something like:
[
{"key1": ["package1", "package2", "package3"]},
{"key2": ["package1", "package2", "package3", "package4"}]
^ An array as the value to the key "key1", "key2", etc..
]
At the PHP side, you would need something like:
For every row fetched from MySQL
$arr[$key] = <new array>
for each package:
append package to $arr[$key]
echo out json_encode($arr)
JS arrays have an implicit array keying, starting at index 0. What you've got is a perfectly valid JS array, the equivalent of having written:
var x = []; // create new empty array
x[0] = {"key1": .... }; // first object
x[1] = {"key2": ....} // second object
Note that the contents of your {} sub-objects is NOT valid.
You should never EVER built a JSON string by hand. It's too unreliable and easy to mess up. It's just easier to use a native data structure (php arrays/objects), then json_encode() them. Ditto on the other end of the process - don't decode the string manually. Convert to a native data structure (e.g. json_decode(), JSON.parse()) and then deal with the native structure directly.
essentially, JSON is a transmission format, not a manipulation format.

Problem with json_encode()

i have an simple array:
array
0 => string 'Kum' (length=3)
1 => string 'Kumpel' (length=6)
when I encode the array using json_encode(), i get following:
["Kum","Kumpel"]
My question is, what is the reason to get ["Kum","Kumpel"] instead of { "0" : "Kum", "1" : "Kumpel" }?
"{}" brackets specify an object and "[]" are used for arrays according to JSON specification. Arrays don't have enumeration, if you look at it from memory allocation perspective. It's just data followed by more data, objects from other hand have properties with names and the data is assigned to the properties, therefore to encode such object you must also pass the correct property names. But for array you don't need to specify the indexes, because they always will be 0..n, where n is the length of the array - 1, the only thing that matters is the order of data.
$array = array("a","b","c");
json_encode($array); // ["a","b","c"]
json_encode($array, JSON_FORCE_OBJECT); // {"0":"a", "1":"b","2":"c"}
The reason why JSON_FORCE_OBJECT foces it to use "0,1,2" is because to assign data to obeject you must assign it to a property, since no property names are given by developer (only the data) the encoder uses array indexes as property names, because those are the only names which would make sense.
Note: according to PHP manual the options parameters are only available from PHP 5.3.
For older PHP versions refer to chelmertz's answer for a way to make json_encode to use indexes.
As Gumbo said, on the JS-side it won't matter. To force PHP into it, try this:
$a = new stdClass();
$a->{0} = "Kum";
$a->{1} = "Kumpel";
echo json_encode($a);
Not that usable, I'd stick with the array notation.
Just cast as an object and it will work fine...the JSON_FORCE_OBJECT parameter does exactly the same thing.
json_encode((object)$array);
Don't forget to convert it back into a php array so you can access its values in php:
$array = (object)$array;
$array = (array)$array;
json_encode($array);
Since you’re having a PHP array with just numeric keys, there is no need to use a JavaScript object. But if you need one, try Maiku Mori’s suggestion.
I personally think this is a bug that needs to be fixed in PHP. JSON_FORCE_OBJECT is absolutely not an answer. If you try to do any sort of generic programming you get tripped up constantly. For example, the following is valid PHP:
array("0" => array(0,1,2,3), "1" => array(4,5,6,7));
And should be converted to
{"0": [0,1,2,3], "1": [4,5,6,7]}
Yet PHP expects me to either accept
[[0,1,2,3],[4,5,6,7]]
or
{"0":{"0":1,"1":1,"2":2,"3":3},"1":{"0":4,"1":5,"2":6,"3":7}}
Neither of which are right at all. How can I possibly decode an object like that? What possible reason is there to ever change something that is clearly using strings as indexes? It's like PHP was trying to be clever to help out idiotic people who can't differentiate strings from ints, but in the process messed up anyone legitimately using strings as indexes, regardless of what the value COULD be turned into.

Categories