Store multiple objects in json column - laravel

I have table with some json column. I want to store multi objects in the json column in Laravel.
My json column look like this "position":[{"lat" : 500, "lon" : 5000, "date":"2020:04:21 16:58:23"}].
this is a function in a service that , i call in my controller
public static function savePositionCamion($id_tournee, $position)
{
$geoTour = GeoTournee::where('geo_tournee.id_tournee', $id_tournee)->first(['position']);
if (!$geoTour) {
$geoTournee = new self();
$geoTournee->id_tournee = $id_tournee;
$geoTournee->position = $position;
return $geoTournee->save() ? $geoTournee : false;
} else {
$arr_pos = json_decode($geoTour->position);
dd($arr_pos);
}
}
in the controller i call the function like this
$geoTourne = GeoTournee::savePositionCamion($request->id_tournee, json_encode($request->position));
anyone can help me to achieve this ! thank's

The array cast type is particularly useful when working with columns that are stored as serialized JSON. You have 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:
class GeoTournee extends Model
{
...
protected $casts = [
'position' => 'array',
];
...
}
So you can save this json field like this:
$geoTournee->position = $position;
$geoTournee->save();
Accessing the position attribute and it will automatically be deserialized from JSON into a PHP array. When you set the value of the position attribute, the given array will automatically be serialized back into JSON for storage:
And you don't need to create savePositionCamion function, you can use firstOrCreate instead:
GeoTournee::firstOrCreate(['id_tournee' => $id_tournee], [ 'position' => $position ]);

Related

Laravel 8.6 firstOrCreate on variable model from URL

In a URL i pass the table name with the where parameters en map this using a JSON. The problem is now is. I use DB::table($table) but this doesn't allow firstOrCreate so i wanted to try it by model, but $table::were doesn't see $table as a model name. Even if i change it from 'establisments' to 'Estalishment'. Maybe i need to put App\ before it? Because the model is not in use. How can i get the object using a model from model names as in the URL?
URL:
&spec_code=CHI&department=surgery&department_code=SUR
JSON:
{
"establishments": { // $table name, but want it to be model)
"from1": "spec_code", // from url
"to1": "abc_id" // to column in database
},
"departments": {
"from1": "department",
"to1": "name",
"from2": "department_code",
"to2": "abc_id"
},
}
Controller:
foreach(JSON as $table => $field){
if(isset($field['from2'])){
$output[$table] = DB::table($table)->where($field['to1'], $request->input($field['from1']))->where($field['to2'], $request->input($field['from2']))->first();
}elseif(isset($field['from1'])){
$output[$table] = DB::table($table)->where($field['to1'], $request->input($field['from1']))->first();
// $output[$table] = $table::where($field['to1'], $request->input($field['from1']))->firstOrCreate(); //i want this.
// $output[$table] = "\App\\".$table::where($field['to1'], $request->input($field['from1']))->firstOrCreate();
}else{
$output[$table] = null;
}
}
If someone knows how i can get it to use the model so i can firstOrCreate(), that would make my code a lot cleaner.
Kind regards,
Jeff
There are many ways to do this.
Create an array using which you can get model
$models = [
'establishments' => \App\Models\Establishment::class,
'departments' => \App\Models\Department::class,
]
Then within loop you can get the model from the array using
foreach(JSON as $table => $field){
$models[$table]::firstOrCreate(/* */)
}
As i said there are many ways to fulfill your requirement. this is one way i would do.
By Default laravel does't have out of the box method to get the Model FQN based on the table name.
Because you can have model under different namespace.
But however you can do a workaround
$tableClassToFind = 'users';
$models = [
\App\Models\User::class,
//add your model(s) here
];
$modelClass = collect($models)
->map(function($eachModelFqn){
return [
'modelClass' => $eachModelFqn,
'tableName' => app($eachModelFqn)->getTable(),
];
})
->mapWithKeys(fn($value) => [$value['tableName'] => $value['modelClass']])
->get($tableClassToFind);
dd($modelClass);
Basically it will get all the table name along with the Model FQN and changing the value of $tableClassToFind will get the appropriate Model class.
Please all the models to $models variable.

Protected cast not working after using getAttribute (laravel)

Here is how defined inside th model. The total does not return in array form after getTotalAttribute is used
protected $casts = [
'total' => 'array'
];
public function getTotalAttribute($value)
{
return $this->_auth($value);
}
You have to make sure “total” in database is a valid JSON format.
The array cast is particularly useful when working with columns that are stored as serialized JSON.
For more info: https://laravel.com/docs/8.x/eloquent-mutators#array-and-json-casting

Laravel: Trying to push url strings to array in database

I have a field in my AppSetup table called reference_images that is added as follows in the migration: $table->json('reference_images')->nullable(); and casted as an array in the AppSetup model. I have a method that adds image urls to the database. If it's for the reference_image field, I am trying to push it to the array but I keep getting an "Array to String conversion" error in Laravel.
public function addImagesToAppSetup($imageType=null, $image=null)
{
$appSetup = AppSetup::where('store', '=', id())->first();
if ($image) {
if ($imageType == "reference_images") {
$originalArray = $appSetup->$imageType;
$originalArray[] = $image;
$appSetup->$imageType = array_values(array_unique($originalArray));
} else {
$appSetup->$imageType = $image;
}
}
$appSetup->save();
return response()->json(['status' => 1, 'data' => $appSetup]);
}
Since reference_images is of type json, doing array_values(array_unique($originalArray)); is still an Array. You will have to convert it to json.
e.g. using collect()->json() docs
$appSetup->$imageType = collect($originalArray)->unique()->values()->toJson();

Fractal Transformer Laravel?

I tried to transform object like as:
$objects = Object::all();
$objects = (new ObjectTransformer)->transform($objects);
Where ObjectTransformer is:
class ObjectTransformer extends TransformerAbstract {
public function transform(Object $obj)
{
return [
'id' => (int) $obj->id,
'name' => $obj->prefix
];
}
}
I get an error:
Type error: Argument 1 passed to App\Http\Controllers\API\ObjectTransformer::transform() must be an instance of App\Http\Controllers\API\Object, instance of Illuminate\Database\Eloquent\Collection given
The function expects an Object and you are passing a Collection of Objects...
But if what you want is just to transform a collection, you don't need to create a specific class, just use the transform Collection method with an anonymous function that does the job:
$objects = Object::all();
$objects->transform(function($object,$key){
return [
'id'=>(int)$object->id,
'name'=>$object->prefix
];
});

Sending an array to index via Algolia's Laravel Search Framework

I'm having some difficulty sending an array to be indexed in Algolia because I have to encode it to save it to the database first.
$algoliaAgent = AlgoliaAgent::firstOrCreate([
'FirstName' => $item->FirstName,
'LastName' => $item->LastName,
'AgentRecId' => $item->AgentRecId,
'Style' => json_encode(explode(',', $item->Style))
]);
$algoliaAgent->pushToIndex();
The resulting index in Algolia looks like this:
"[\"value1\",\"value2\",\"value3\"]"
Is there a method to decode the value before sending it to Algolia?
I believe you are looking for the json_encode and json_decode methods.
Also, see the Laravel Scout documenation for more information about what is indexed.
By default, the entire toArray form of a given model will be persisted to its search index. If you would like to customize the data that is synchronized to the search index, you may override the toSearchableArray method on the model:
The final solution was to modify the pushToIndex() method to intercept the the loop that sends the object to Algolia.
Something like this:
public function pushToIndex()
{
/** #var \AlgoliaSearch\Laravel\ModelHelper $modelHelper */
$modelHelper = App::make('\AlgoliaSearch\Laravel\ModelHelper');
$indices = $modelHelper->getIndices($this);
/** #var \AlgoliaSearch\Index $index */
foreach ($indices as $index) {
if ($modelHelper->indexOnly($this, $index->indexName)) {
$temp = $this->getAlgoliaRecordDefault($index->indexName);
$temp['Style'] = $this->castArray($temp['Style']);
//$index->addObject($this->getAlgoliaRecordDefault($index->indexName));
$index->addObject($temp);
}
}
}
public function castArray($raw) {
$arrayString = '';
if(is_string($raw)) {
$arrayString = explode(",",$raw);
}
return $arrayString;
}

Resources