How can I make laravel casting array on the model? - php

I try like this
Data type of votes_detail in database is json
My model like this :
<?php
class Store extends Model{
protected $fillable = [ ...,'votes_detail',...];
protected $casts = [
'votes_detail' => 'array',
];
}
My controller like this :
$store = Store::find($id)
$votes_detail = $store->votes_detail;
dd($votes_detail);
The result of dd($votes_detail) is :
{"1": "1", "5": "2"}
Why the result is still json?
The result should be an array
Whereas I've set the array in cast model
How can I solve this problem?

You could use Laravel accessors. In you model define a method called exactly getVotesDetailAttribute($details):
public function getVotesDetailAttribute($details)
{
return json_decode($details, true);
}
then when you will call $store->votes_detail you will get the expected result.
After that you can use mutators to convert an array back to JSON when it is saved back in the DB. Define the method setVotesDetailAttribute($value) as follows:
public function setVotesDetailsAttribute($value)
{
$this->attributes['votes_detail'] = json_encode($value);
}

You can easily do it by converting your data to the array by using toArray() function. So it should be like
$store = Store::find($id)->toArray();
//$store contain a array.
$votes_detail = $store['votes_detail'];
make it dd($votes_detail) and get your desire result.

I think you are storing array data after json_encode() to a column which is not defined as json() in the migration like:
$table->text('votes_detail');
or
$table->integer('votes_detail');
And seems you have defined votes_detail as string, number or something else.
This is the reason behind your problem. So, define column type as json in migration like:
$table->json('votes_detail');
And then refresh your migration, your casting in the model will work and you will get your desired array.

Related

How to get value of only single column using eloquent model

This is my object
{
"id":1,
"name":"abc",
"tech":"PHP"
}
now i want to get value of tech using User eloquent model using laravel collection method first
this is my eloquent model query
$tech = User::select('tech')->first();
but it return data is form of object like this
{"tech":"PHP"}
i want only value in string formate not in object like it should return "PHP".
can any one help?
You can use the pluck function for this.
$tech = User::pluck('tech')->first();
This will return:
"php"
Your code
$tech = User::select('tech')->first();
as you said
Actually it will returns the object
{"tech":"PHP"}
try this to get the result the
$tech = User::select('tech')->first()->tech;
not as
$tech = User::select('tech')->first();

Laravel 5.6 Object of class stdClass could not be converted to string when updating a database value

Kindly note this is not a duplicate of this or this
I have a model page with json field called options.
in my page model, i have added the attribute options to the $cast variable and in the $fillable variable.
Then i have a function pageOptions() that's suppost to return a class PageOptions like so:
/*
*#return pageOptions
*/
public function pageOptions() : PageOption
{
$options = ($this->options) ? ($this->options) : [];
return new PageOption($options, $this);
}
the Page option class simply exposes functions of set() and get() to enable me set and get json data from the options field.
the set() method, simply sets data to a $options variable then calls the persist method that pushes data to the options field in the database.
/**
* Persist the options.
*
* #return mixed
*/
protected function persist()
{
return $this->model->update(['options' => $this->options]);
}
Instead
i get this error
Object of class stdClass could not be converted to string
i am not trying to echo any object or array anywhere in my code so i cannot really understand where the error is coming from . . I have tried to json_encode the options variable manually in the persist() method but i still get the same error. I also tried adding the TOString() magic method on the pages and PageOptions classes like so
public function __toString()
{
return $this->name;
}
but still does not solve it.
You should use the $casts property on the model.
protected $casts = [
'options' => 'array'
];
From the docs:
The array cast type is particularly useful when working with columns
that are stored as serialized JSON. For example, if your database has a JSON or TEXT field type that contains serialized JSON, adding the array cast to that attribute will automatically deserialize the attribute to a PHP array when you access it on your Eloquent model.

Laravel: array to Model with relationship tree

I want to create an Eloquent Model from an Array() fetched from database which is already toArray() of some model stored in database. I am able to do that using this code:
$model = Admin::hydrate($notification->data);
$notification->data = [
"name" => "abcd"
"email" => "abcd#yahoo.com"
"verified" => 0
"shopowner_id" => 1
"id" => 86
"shopowner" => [
"id" => 1
"name" => "Owner1"
"email" => "owner1#owner.com"
]
];
But i can't access the $model->shopowner->name
I have to use $model->shopowner['name']
I want to use the same class of notification without any specific change to access the data.
If you want to access shopowner as a relationship, you have to hydrate it manually:
$data = $notification->data;
$model = Notification::hydrate([$data])[0];
$model->setRelation('shopowner', ShopOwner::hydrate([$data['shopowner']])[0]);
Solution:
Thanks to #Devon & #Junas. by combining their code I landed to this solution
$data = $notification->data;
$data['shopowner'] = (object) $data['shopowner'];
$model = Admin::hydrate([$data])[0];
I see this as an invalid use of an ORM model. While you could mutate the array to fit your needs:
$notification->data['shopowner'] = (object) $notification->data['shopowner'];
$model = Admin::hydrate($notification->data);
Your model won't be functional because 'shopowner' will live as an attribute instead of a relationship, so when you try to use this model for anything other than retrieving data, it will cause an exception.
You cannot access array data as object, what you can do is override the attribute and create an instance of the object in your model, so then you can use it like that. For example:
public function getShopownerAttribute($value)
{
return new Notification($value); // or whatever object here
}
class Notification {
public function __construct($data)
{
// here get the values from your array and make them as properties of the object
}
}
It has been a while since I used laravel but to my understanding once you use hydrate your getting a Illuminate\Database\Eloquent\Collection Object, which then holds Model classes.
These however could have attributes that are lazy loaded when nested.
Using the collections fresh method could help getting a Full database object as using load missing

Perform action on Laravel model once it has been filled with data

So I have a model that has a json field as an attribute. When it is retrieved, I'd like to convert that field into an array so I can do some other things with it.
For example, if the json has data like this {name:bob,email:sue} in a parameter called json, when the model object is built, I'd like it to something like this:
public function setJsonAttribute($value)
{
$this->attributes['json'] = $value;
$jsonInfo = json_decode($value, true);
$this->name = $jsonInfo['email'];
$this->email = $jsonInfo['name'];
}
This is an example of an attempt I did with a mutator, but it's not optimal. Is there any way to do this kind of thing automatically once the model has been loaded with data from the database?
Laravel 5.4
Eloquent includes a feature called array casting which converts a field from JSON to an array property on retrieval and converts the array back to a JSON string on saving.
You can enable this by adding a $casts property to your Model with the field name as the key and array as the value:
protected $casts = [
'options' => 'array',
];
https://laravel.com/docs/5.4/eloquent-mutators#array-and-json-casting
If you had options as {name:bob,email:sue} in the database, you would then access them as $model->options['name'] and $model->options['email'].

JSON string in MySQL to json response

I have a JSON formatted string stored in a column (meta_data) in a mysql database, stored in the table it looks something like this for example:
{"Format":"JPEG","Geometry":"3216x2136","size":{"width":3216,"height":2136}}
Now if I use the following:
$meta_data = DB::query->get();
return $meta_data;
I get:
[
{
"meta_data": "{\"Format\":\"JPEG\",\"Geometry\":\"3216x2136\",\"size\":{\"width\":3216,\"height\":2136}
}
]
I also get the same result if I use:
$meta_data = json_decode(DB::query->get());
return $meta_data;
Similarly, using response()->json($meta_data); returns it as a string.
It seems to me that it needs to go the next step down but I haven't been able to get anything close to what I'm after, which is ideally:
[
{
"meta_data":
{
"Format":"JPEG",
"Geometry":"3216x2136",
"size":
{
"width":3216,
"height":2136
}
}
}
]
DB::query->get() will return an array of stdClass objects (assuming query is just shorthand for your query conditions). You will need to loop through the array and convert the meta_data field of each entry to a json object manually.
$records = DB::query->get();
foreach ($records as $record) {
$record->meta_data = json_decode($record->meta_data);
}
return $records;
Another option would be to create a Model for the table, and then add the meta_data field to the $casts property to automatically cast it to json.
Model:
class Attachment extends Model
{
protected $casts = [
'meta_data' => 'json',
];
}
Controller:
// assume "query" is shorthand for your query conditions
$records = Attachment::query->get();
return $records;

Categories