The application I am designing consumes JSON objects returned by PHP scripts that select from a SQL Server 2008 database. The problem I am encountering is that when the database is missing a value for a certain field, it returns as a null in JSON. Then when the app parses the JSON (I am using NSJSONSerialization), the dictionary contains a value. When using this dictionary to populate my view, the application crashes when encountering the null value.
What would be the easiest way to bypass this problem? I am thinking I could just replace all nulls with empty string before the PHP returns the data as JSON; however, that might not be the best solution. Is there a simple way to check in iOS?
Thanks for the help.
To check for null values you need to see if the object is [NSNull null].
id object = [dict objectForKey:#"key"];
if(object == [NSNull null])
{
//Handle null value
}
Related
I have a Laravel application. In the users table, I have a boolean column called active:
$table->boolean('active')->default(false);
And in the front-end I normally check to see if the user is active or not like this:
Plain JS: if(user.active){ // do stuff }
VueJS: v-if="user.active"
This approach assumes that the value of user.active property, which of course is coming from the json response, is a non-string value: either 0 or 1. And that's what indeed I am receiving in the local machine:
Here pink colored values represent String values and green colored values represent Number values.
So, clearly, my local machine is interpreting it as a Numeric value and when the number 0 or 1 is used in a conditional expression, it is converted to boolean.
However that's not the case on my production server. The json response in the production server is converted to string which leads to unintended behavior of my application:
Notice that the value for the active key is not a Number, it is a String here! And since it's interpreted as a String, any non-empty string will always evaluate to true; hence my condition will always evaluate to true.
I have two questions: a) Why is this happening? b) How can I fix it?
Additional information: Both the production and local server are running same mysql version. PHP version on prod: 7.2.8 and PHP version on local: 7.2.9.
I think you are assigning the value for the active key as a numeric value 0. But JSON interprets BOOLEAN only with two values true and false. Just try to assign the value to true and false instead of 0 and 1.
For Reference please check https://www.tutorialspoint.com/json/json_data_types.htm
Edit From Comments
Yes, you can modify the record in the front-end in the way you need, because you will use array and objects in the front-end. But when you post the values to the server you will convert the array objects into json string, and the json string will assume 0 or 1 as number or string and will take true and false as boolean values. So you have to assign the key in the way the JSON works. Hope this method may work when sending data from client to server as well as from server to client.
This is because of the following reasons,
Most of the front end languages are interpreted, so they execute freely without compiling. But the back end languages will compile before executing. That's why we are using var to define any datatypes and js will use them in any way. But backend languages like java and .NET needs the variable type to get defined.
And in other hand JSON is not a language. Similar to XML it is used to send raw data between client and server. And it is designed in the way to work with both front end and backend. So you have to assign the values that both platforms will accept. That why you have to assign true or false instead of 0 and 1.
If you are using an Eloquent Model for your database table you may assign the $casts property to your model to assure the data type within the JSON response.
For example with your "users" table:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [ 'active' => 'boolean' ];
}
Documentation is here.
Since the question is still receiving answers, I am going to leave the actual answer to this particular problem (Type mismatch).
Enabling the MySQL native driver for PHP on the production server, solved my problem.
So... I need to save a large-ish amount of data from a platform with an excruciatingly limited amount of memory.
Because of this, I'm basically storing the data on my webserver, using a php script to just write JSON to a flat file, because I'm lazy af.
I could go to the trouble of having it store the data in my mysql server, but frankly the flat file thing should have been trivial, but I've run up against a problem. There are several quick and dirty workarounds that would fix it, but I've been trying to fix it the "right" way (I know, I know, the right way would be to just store the data in mysql, but I actually need to be able to take the json file this produces and send it back to the platform that needs the data (In a ridiculously roundabout fashion), so it made sense to just have the php save it as a flat file in the first place. And It's already working, aside from this one issue, so I hate to reimpliment.
See... Because of the low memory on the platform I'm sending the json to my server from... I'm sending things one field at a time. Each call to the php script is only setting ONE field.
So basically what I'm doing is loading the file from disk if it exists, and running it through json_decode to get my storage object, and then the php file gets a key argument and a value argument, and if the key is something like "object1,object2", it explodes that, gets the length of the resulting array, and then stores the value in $data->$key[0]->$key[1].
Then it's saved back to disk with fwrite($file, json_encode($data));
This is all working perfectly. Except when $value is a simple string. If it's an array, it works perfectly. If it's a number, it works fine. If it's a string, I get null from json_decode. I have tried every way I can think of to force quotes on to the ends of the $value variable in the hopes of getting json_decode to recognize it. Nothing works.
I've tried setting $data->$key[0]->$key[1] = $value in cases where value is a string, and not an array or number. No dice, php just complains that I'm trying to set an object that doesn't exist. It's fine if I'm using the output of json_decode to set the field, but it simply will not accept a string on its own.
So I have no idea.
Does anyone know how I can either get json_decode to not choke on a string that's just a string, or add a new field to an existing php object without using the output of json_decode?
I'm sure there's something obvious I'm missing. It should be clear I'm no php guru. I've never really used arrays and objects in php, so their vagaries are not something I'm familiar with.
Solutions I'm already aware of, but would prefer to avoid, are: I could have the platform that's sending the post requests wrap single, non-numeric values with square braces, creating a single item array, but this shouldn't be necessary, as far as I'm aware, so doing this bothers me (And ends up costing me something like half a kilobyte of storage that shouldn't need to be used).
I could also change some of my json from objects to arrays in order to get php to let me add items more readily, but it seems like there should be a solution that doesn't require that, so I'd really prefer not to...
I skim through your post.
And I know this works for StdClass :
$yourClass->newField = $string;
Is this what you wanted ?
OK so... ultimately, as succinctly as possible, the problem was this:
Assuming we have this JSON in $data:
{
"key1":
{
"key2":["somedata","someotherdata"]
}
}
And we want it to be:
{
"key1":
{
"key2":["somedata","someotherdata"],
"key3":"key3data"
}
}
The php script has received "key=key1,key3&value=key3data" as its post data, and is initialized thusly:
$key = $_POST["key"];
$key = explode($key,",");
$value = $_POST["value"];
...which provides us with an array ($key) representing the nested json key we want to set as a field, and a variable ($value) holding the value we want to set it to.
Approach #1:
$data->$key[0]->$key[1] = json_decode($value);
...fails. It creates this JSON when we re-encode $data:
{
"key1":
{
"key2":["somedata","someotherdata"],
"key3":null
}
}
Approach #2:
$data->$key[0]->$key[1] = $value;
...also fails. It fails to insert the field into $data at all.
But then I realized... the problem with #2 is that it won't let me set the nonexistent field, and the problem with approach #1 is that it sets the field wrong.
So all I have to do is brute force it thusly:
$data->$key[0]->$key[1] = json_decode($value);
if (json_decode($value) == NULL)
{
$data->$key[0]->$key[1] = $value;
}
This works! Since Approach #1 has created the field (Albeit with the incorrect value), PHP now allows me to set the value of that field without complaint.
It's a very brute force sort of means of fixing the problem, and I'm sure there are better ones, if I understood PHP objects better. But this works, so at least I have my code working.
Using following code to convert as document to JSON is:
print( json_encode((new MongoClient())->db->col->findOne()));
//Output:{"_id":{"$id":"52838520f7c255c009000000"},"test":"test"}
Is there any way to set Mongo to return _id field as string instead of object? Is it safe to return _id value to client side script (as the response of a GET request)
I do not want manually convert _id to string and vice versa when implementing a REST api.
No, there is nothing you can do (mongod in comparison to SQL can not do modification of the fields it is outputting). Therefore you only resort is to do what you didn't want to do (manually convert). But it is not hard, all you need to do is one of these:
(string)$doc['_id'];
(string)$doc->_id;
$doc['_id']->{'$id'};
I have a whole suite of PHP scripts that interact with both the Android and iOS version of a mobile app. They all work the same: After the mobile app initiates a GET or POST, the PHP script typically returns a dash delimited string.
e.g.
If I want to get a list of the comments on a particular page, the PHP script would return something like
user1-comment1-user2-comment2
Is there a better way than this? Because if I ever want to return a new variable e.g.
user1-comment1-newValue1-user2-comment2-newValue2
then this will break all current versions of the mobile app.
Why not serialize the result and parse it in java? You could also use json_encode in PHP and decode it in your android app... see How to parse JSON in Android
You need to use a serializer. If you have a user name that contains a - you'll run into problems. Serializers take care of this for you. The current favorite is JSON, used to be XML.
JSON has excellent support in most web languages.
You can serialize your array of data into either a json string or a message pack string. Let's say your php array was:
$a = array(
"user1" => "comment1",
"user2" => "comment2",
"user3" => "comment3"
);
That would translate to this in json:
{
"user1": "comment1",
"user2": "comment2",
"user3": "comment3"
}
This json string can be easily converted to NSDictionaries on ios (using NSJSONSerialization) and JSONObjects on android (tutorial here).
A message packed string would be similar in structure to the json string above, but is less human readable because of its more compact nature. However, both Java and Objective-C have libraries to help translate messaged packed data into native objects.
Using JSON, you can make use of name/value pairs, so the order or inclusion of the parameters won't matter. JSON also provides hierarchy and limited typing, such as number versus string.
JSON also allows you to easily escape characters, so you could have any value you want (even with backslashes and quotes.
Im looking to see if anyone can shed some light on a problem im having.
In my collection Y, I have a field called ADJU, which has stored in it, the serialised PHP array of MongoIDs.
One example field is
"a:1:{i:0;a:1:{s:4:\"MBID\";C:7:\"MongoId\":24:{4f2c5b9bb9a21d5010000005}}}"
The parameter im passing in is
"4f2c5b9bb9a21d5010000005"
public function read_adjudicating(MongoID $account_identifier){
$regexObj = new MongoRegex("/".$account_identifier->__toString()."/");
var_dump($regexObj);
$result = $this->connection->X->Y->find(array('ADJU' => $regexObj), array('__id'));
var_dump($result);
Can anyone work out why it is giving me 0 records, when as you can see, one example definately has it?
Thanks for your help!
Well, it's not the query:
db.illogical.insert({'ADJU': "a:1:{i:0;a:1:{s:4:\"MBID\";C:7:\"MongoId\":24:{4f2c5b9bb9a21d5010000005}}}"})
db.illogical.find({'ADJU': /4f2c5b9bb9a21d5010000005/})
{ "_id" : ObjectId("4f605b9e5d2b96c06d2adb27"), "ADJU" : "a:1:{i:0;a:1:{s:4:\"MBID\";C:7:\"MongoId\":24:{4f2c5b9bb9a21d5010000005}}}" }
Which means the php code you've written doesn't correspond to the query you expect, or the data isn't in the format you expect.
Rather than investigate why though - you'd be better off IMO either updating the script you used to import the data from mysql to deserialize before inserting to mongo - or write a (php) script to read the already-serialized-in-mongo data, deserialize it - and save it again.