Best way to store and load JSON from database in Laravel - php

I'm trying to store json into a db and load it back
I tried to store
{name: "John", age: 31, city: "New York"}
It stored correctly. I checked the db, it showed correctly.
{name: "John", age: 31, city: "New York"}
I kept getting on the view
"{name: \"John\", age: 31, city: \"New York\"}"
This is my code.
public function store()
{
$paste = new Paste;
$paste->uuid = Str::uuid()->toString();
$paste->data = trim(Request::get('data',''));
$paste->save();
return Redirect::to('/paste/'.$paste->uuid)->with('success', 'Created');
}
public function show($uuid)
{
$paste = Paste::where('uuid',$uuid)->first();
return response()->json($paste->data);
}
Any hints for me ?
Reproducible here
https://www.bunlongheng.com/paste
Try # 2
If I did this
public function show($uuid)
{
$paste = Paste::where('uuid',$uuid)->first();
return View::make('layouts.fe.pastes.show', get_defined_vars());
}
and in my view, I only have this 1 line
{!!$paste->data!!}
I get the same data as what I submitted now.
{name: "John", age: 31, city: "New York"}
BUT the browser detected it as text, not a response JSON which defeated the purpose of what I am trying to do.
Try # 3
public function show($uuid)
{
$paste = Paste::where('uuid',$uuid)->first();
return response()->json(stripslashes($paste->data));
}
result
"{name: \"John\", age: 31, city: \"New York\"}"
Try # 4
public function show($uuid)
{
$paste = Paste::where('uuid',$uuid)->first();
return View::make('layouts.fe.pastes.show', get_defined_vars());
}
view
{{ json_encode($paste->data, JSON_UNESCAPED_SLASHES) }}
result
"{name: \"John\", age: 31, city: \"New York\"}"
Try #5
I think the issue is lying on the storing ... not the loading and rendering.
I tried
return response()->json($paste);
My JSON parser detected it ...
{
"id": 11,
"status": 0,
"uuid": "0c40f97d-7d98-42c6-864e-71d3ed81eed3",
"name": "n6ou",
"password": "",
"expiration": "",
"type": "json",
"data": "{name: \"John\", age: 31, city: \"New York\"}",
"created_at": "2021-04-22T22:53:11.000000Z",
"updated_at": "2021-04-22T22:53:11.000000Z"
}
This is what I used to store
$paste->data = trim(Request::get('data',''));
$paste->save();
Try #6
For those of you that doubt my data/content
I've tried pasting the same line in Pastebin
It's cleaned, you can see below.
https://pastebin.com/raw/r9akUK1v

Database
In your database migrations add:
$table->json('data'); // Recommended. Supported in MySQL since version 5.7.8
or
$table->text('data');
The JSON column type is recommended as it allows you to do SQL queries on JSON data. See MySQL JSON Data Type
Model: Casting the Attribute
The next issue is that you need to be able to cast your data into a PHP array.
This is done by modifying the casts attribute in the model:
class Paste extends Model {
protected $casts = [
'data' => 'array'
];
}
See Array and JSON Casting for more information.
Now you can save data onto the attribute as a PHP array, and also assign it a PHP array.
$paste = Paste::first();
dump($paste); // Returns a PHP array
$paste->data = ['some-data' => 20, 'score' => 500];
$paste->save();
Internally, when it saves the data, it automatically would convert it into a JSON string and save it in the database in the correct format.
Store Method
When taking in input as JSON, it highly depends in how you want to pass the data,
1. Sending form data with JSON content type (recommended)
My recommendation is to send the entire data as JSON in the POST body like so:
Content-Type: application/json
Body:
{
"data": {
"name": "John",
"age": 31,
"city": "New York"
},
"someOtherField": "Hello!"
}
Your store() method should now be (I've also added validation code):
public function store()
{
$this->validate($request, [
'data' => ['required', 'array'],
'data.*.name' => ['required', 'string'],
'data.*.age' => ['required', 'int'],
'data.*.city' => ['required', 'string'],
]);
$paste = new Paste();
$paste->uuid = Str::uuid()->toString();
$paste->data = $request->post('data'); // No need to decode as it's already an array
$paste->save();
return Redirect::to("/paste/{$paste->uuid}")
->with('success', 'Created');
}
2. Sending form data with form params
If however you insist in sending data through query params or form params, note these can only send strings. Therefore you need to send an encoded version of the JSON string to persists data types, as follows:
Form Params:
- data: '{"name": "John", "age": 31, "city": "New York"}'
- someOtherField: "Hello!"
The store method will now look like this:
$this->validate($request, [
'data' => ['required', 'json'], // I'm unsure if data is required
]);
$data = json_decode($request->post('data'), true, JSON_THROW_ON_ERROR); // Needs to be decoded
// validate $data is correct
Validator::make($data, [
'name' => ['required', 'string'],
'age' => ['required', 'int'],
'city' => ['required', 'string'],
])->validate();
$paste = new Paste();
$paste->uuid = Str::uuid()->toString();
$paste->data = $data;
$paste->save();
return Redirect::to("/paste/{$paste->uuid}")
->with('success', 'Created');
Show Method
Your show method needs no changes:
public function show($uuid)
{
$paste = Paste::where('uuid', $uuid)->first();
return response()->json($paste->data);
}

1- Your column need to be of type json type
$table->json('data');
2- in your Model you need to cast your column to an array
protected $casts = ['data' => 'array'];
3- sending data value to your controller must be an array so you can use array Laravel validation on it:
[
'data' => 'required|array',
'data.*.name' => 'required'
....
]
4- when you store your data it will be parsed automatically and the same when you retrieve your data column it will be converted to an array

Using ->json() as the migration method to store JSON data (https://laravel.com/docs/8.x/migrations#column-method-json)
Refer to "Array & JSON Casting" (https://laravel.com/docs/8.x/eloquent-mutators#array-and-json-casting) for how do you prepare the data
I know the answer is not in paragraphs as others, but I like to make it simple and straight. Is it the best solution? No one can tell you that nor prove that? Is this method going to work, no one can tell you that nor prove that, but at least it boosts up your success rate. Let me know if there is anything else I could help with! Good Luck

If you want to store data as json on DB and restore it just do the following (I always use this way):
1- Add your data to array:
$data["name"] = "John";
$data["age"] = 31;
$data["city"] = "New York";
2- Encode the array and add it to the database (you can store it as text)
$encodedData = json_encode($data);
3- If you want to add nested json data just make your array nested array.
4- When you restore the data just use json_decode to decode it

Just add this to your Model.
protected $casts = [
'data' => 'object'
];
Then you can get in your view like this:
{{ $data->data->name }}

Related

Insert multiple json data into mysql database from postman using codeigniter api

I am tring to insert multiple data in db using postman but only single data is insetred successfully ,when inserting multiple data getting 500 error.Please help me on how can i insert multiple data in db.Any help would be highly appreciated.Thank you.
PostMan raw data:
[{
"total_sales":"14",
"total_product":"21",
"total_profit":"5099",
"total_distributor":14,
"total_ratail":40 },
{
"total_sales":14,
"total_product":21,
"total_profit":50,
"total_distributors":14,
"total_ratail":40 }
]
Below is my code:
public function create()
{
$model = new AdminModel();
print_r("total_sales");
$data = array(
'total_sales'=>$this->request->getVar('total_sales'),
'total_product'=>$this->request->getVar('total_product'),
'total_profit'=>$this->request->getVar('total_profit'),
'total_distributors'=>$this->request->getVar('total_distributors'),
'total_ratail'=>$this->request->getVar('total_ratail'),
);
$query = $model->where('id', $data['total_sales'])->find();
if(count($query)>0){
$model->update->where('id', $data['total_sales'])->find();
}
else{
$model->insert($data);
}
//$model->insert($data);
$response = [
'status' => 200,
'error' => null,
'messages' => [
'success' => 'Data Saved'
]
];
return $this->respondCreated($response);
}
You are adding an array of objects but the code is expecting only one object. That's why you are getting the error.
You have to modify your php code to accept an array and loop through them.

Laravel 8 Unit Testing - assertJson() how to capture it in controller

I have a laravel 8 Unit Test which looks like this:
public function testAddingTwoCars()
{
$response = $this->postJson('api/basket', ['cars' => [['name' => 'car one'], ['name' => 'car two']]]);
$response
->assertStatus(200)
->assertJson(['total' => 40]);
}
In my route I have:
Route::post('/api/basket',[basketController::class, 'store']);
In my controller I have:
public function store(Request $request)
{
$data = $request->all();
return response()->json($data);
}
when I run the test with php artisan test it shows this:
• Tests\Unit\BasketTest > adding two cars
Unable to find JSON:
[{
"total": 40
}]
within response JSON:
[{
"cars": [
{
"name": "car one"
},
{
"name": "car two"
}
]
}].
How do I:grab the total as its not in $request so that I could do something like this in my controller:
$public function store(Request $request)
{
$data = $request->all();
$data['total'] = 40;
return response()->json($data);
}
The above works, but it is hard coded so is not the best way to do it
assertJson
Assert that the response contains the given JSON data:
$response->assertJson(array $data, $strict = false);
The assertJson method converts the response to an array and utilizes PHPUnit::assertArraySubset to verify that the given array exists within the JSON response returned by the application. So, if there are other properties in the JSON response, this test will still pass as long as the given fragment is present.
You can read about it at this link
https://laravel.com/docs/8.x/http-tests#assert-json
and Here
https://laravel.com/docs/5.4/http-tests#testing-json-apis
and you can check this video too
https://adamwathan.me/2016/11/16/the-only-json-assertion-youll-ever-need/
->assertJson(['total' => 40]) is non-sense; this will not pass unless the JSON has it:
return response()->json(['data' => $data, 'total' => 40]);

How to insert nested objects into MongoDB with Laravel 5?

I'm using Laravel 5 and MongoDB based Eloquent Jenssegers to develop an API to save and get data. I have a object called Player and inside I have other nested objects.
For example:
{
"idPlayer": "1",
"name": "John",
"lastname": "Doe",
"stats": {
"position": "lorem",
"profile": "ipsum",
"technique": {
"skill": 1
}
}
}
Using Postman to test I've could insert "idPlayer", "name" and "lastname" without problems, but I couldn't figure out how to insert stats inside the Player object.
This is what I've tried:
PlayerController.php
public function store(Request $request)
{
$player->name= $request->input('name');
$player->lastname = $request->input('lastname');
$player->save();
return response()->json($player);
}
And to insert stats I've tried to do something like this inside the store function:
$player->stats = $request->input('position');
$player->stats = $request->input('profile');
But I get "Stats:null" on response and the name and lastname inserts ok.
I expect to insert the data just as the Player object shown above.
Make an array with keys.
public function store(Request $request)
{
$player->name = $request->input('name');
$player->lastname = $request->input('lastname');
$player->stats = [
'position' => $request->input('stats.position'),
'profile' => $request->input('stats.profile'),
];
$player->save();
return response()->json($player);
}
More data about PHP arrays.
Retrieving input from Laravel Requests.

Laravel - Creating an object from a JSON array to save it in a SQL database

What I am trying to do is to send a JSON array (that was gotten from Guzzle) to my SQL database. I have gotten to the point where I am able to get the response and display the gotten JSON array on a webpage. The array is defined as the $data variable. The $data variable gets decoded using this:
$data = json_decode($response->getBody()->getContents());
This is able to get the JSON and decode it with no problem. The part I am stuck on is taking the $data variable, processing it and sending it to my database. From what I understand is that you are required to convert the JSON into an array and then send it to the database.
The JSON format is like this:
[{
"INTLDES": "2017-042Z",
"NORAD_CAT_ID": "42848",
"OBJECT_TYPE": "TBA",
"SATNAME": "OBJECT Z",
"COUNTRY": "TBD",
"LAUNCH": "2017-07-14",
"SITE": "TTMTR",
"DECAY": null,
"PERIOD": "96.52",
"INCLINATION": "97.61",
"APOGEE": "597",
"PERIGEE": "586",
"COMMENT": null,
"COMMENTCODE": null,
"RCSVALUE": "0",
"RCS_SIZE": null,
"FILE": "6242",
"LAUNCH_YEAR": "2017",
"LAUNCH_NUM": "42",
"LAUNCH_PIECE": "Z",
"CURRENT": "Y",
"OBJECT_NAME": "OBJECT Z",
"OBJECT_ID": "2017-042Z",
"OBJECT_NUMBER": "42848"
}]
My Satellite Model goes like this:
protected $fillable = [
'intldes',
'norad_cat_id',
'object_type',
'satname',
'country',
'launch',
'site',
'decay',
'period',
'inclination',
'apogee',
'perigee',
'comment',
'commentcode',
'rcsvalue',
'rcs_size',
'file',
'launch_year',
'launch_num',
'launch_piece',
'current',
'object_name',
'object_id',
'object_number'
];
My migrations file:
Schema::create('satellites', function (Blueprint $table) {
$table->increments('id');
$table->string('intldes');
$table->string('norad_cat_id');
$table->string('object_type');
$table->string('satname');
$table->string('country');
$table->string('launch')->nullable();
$table->string('site')->nullable();
$table->string('decay')->nullable();
$table->string('period')->nullable();
$table->string('inclination')->nullable();
$table->string('apogee')->nullable();
$table->string('perigee')->nullable();
$table->string('comment')->nullable();
$table->string('commentcode')->nullable();
$table->string('rcsvalue')->nullable();
$table->string('rcs_size')->nullable();
$table->string('file')->nullable();
$table->string('launch_year')->nullable();
$table->string('launch_num')->nullable();
$table->string('launch_piece')->nullable();
$table->string('current')->nullable();
$table->string('object_name');
$table->string('object_id');
$table->string('object_number');
$table->timestamps();
});
I tried making an $object array, which did not work.
TL;DR: I want to take the $data variable, which contains the decoded JSON and create something that allows it to get saved into my 'satellites' SQL database.
EDIT: Here is the full Satellite controller:
public function displayer(){
$api = new Client([
'base_uri' => 'https://www.space-track.org',
'cookies' => true,
]); $api->post('ajaxauth/login', [
'form_params' => [
'identity' => '#',
'password' => '#',
],
]);
$response = $api->get('basicspacedata/query/class/satcat/orderby/INTLDES%20desc/limit/5/metadata/false');
$data = json_decode($response->getBody()->getContents(), true);
$data = array_change_key_case($data, CASE_LOWER);
$model = Satellite::create($data);
dd($data);
}
It looks like your JSON key names match up nicely with your model attributes, with the exception of being capitalised.
Try mapping the data keys to lowercase and then creating your model instance.
Per #OmisakinOluwatobi suggestion, you can use pass true to json_decode to retrieve the data as an array.
Edit - I missed that your response data was an array of objects. The following update will iterate over the response data and create a new Satellite for each.
// Retrieve data from response
$data = json_decode($response->getBody()->getContents(), true);
// Iterate over response data
foreach ($data as $attributes) {
// Change attribute keys to lowercase
$attributes = array_change_key_case($attributes, CASE_LOWER);
// Create satellite model
Satellite::create($attributes);
}
It is actually as simple as $encoded = json_encode($request->your_array);. This $encoded will now be "savable" to sql database. When you later access the encoded data, you can use a JSON parser to convert back to a json array. Example using jQuery var your_array = $.parseJSON($response.body);

Symfony2 form to JSON structure

How can the Symfony2 form be transformed to JSON data structure? Looking for proper bundle gave me no results;
Example:
$builder
->add('name', 'text')
->add('password', 'password')
;
Would result in something like that:
{
fields: {
name: {
type: 'text'
},
password: {
type: 'password'
}
}
}
Iterating over each element in form after $form = $this->createForm(new FormType(), new Entity()) was not helpful, could not find some properties that could be defined in form builder.
I assume that you want to get this information in a controller once you have posted the form, in which case you can easily get the underlying entity from the form object, like so:
$entity = $form->getData();
At this point you can either manually pull out the fields you want into an array and json_encode() that, or... implement the JsonSerializable interface in your entity and then directly json_encode() the object itself.
For example:
<?php
namespace FooApp/BarBundle/Entity;
use JsonSerializable;
class Baz implements JsonSerializable
{
private $name;
private $password;
// ...
function jsonSerialize()
{
return [
'fields' => [
'name' => ['type' => $this->name],
'password' => ['type' => $this->password],
],
];
}
}
Then, in your controller:
$entity = $form->getData();
$json = json_encode($entity);
Calling json_encode() will automatically invoke Baz::jsonSerialize() and return the array structure you defined, which in turn is JSON-encoded.
Update 2016-06-23
I happened across this question again by chance - and... I realise that I didn't answer your actual question.
You didn't want to convert the form's underlying entity to JSON - instead you want to represent form structure as data. My apologies for misunderstanding - hopefully I can rectify that with an update.
This is a proof-of-concept that should work for a non-nested form (although it should be straightforward to create a recursive version or something for that case). But, assuming a scenario where you have instantiated a form, comprising of fields name and password, like so:
$form = $this->createForm(FooType::class, $foo);
It should then possible to iterate over the instance and derive a representation of the structure; e.g:
$fields = ['fields' => []];
foreach ($form->all() as $field) {
$name = $field->getName();
$type = $field->getConfig()->getType()->getBlockPrefix();
$fields['fields'][$name] = ['type' => $type];
}
echo json_encode($fields, JSON_PRETTY_PRINT);
Yields:
{
"fields": {
"name": {
"type": "text"
},
"password": {
"type": "password"
}
}
}
Hope this helps :)
If you need to get the JSON representation of the form object, you can get the entity object and encode it:
$jsonStr =json_encode($builder->getData());
Take a look on http://jmsyst.com/libs/serializer#installation
and fosrestbundle
$view = $this->view( $form->createView() );
return $this->handleView( $view );
Does what you are looking for.

Categories