How can I format the array on a specific format in my laravel controller function? - json

I'm currently creating a laravel vue spa, and just wondering on how can I get designation names with these designation id's with the same structure. This is the json of designation id's:
[
[
1,
5
],
[
1,
3
]
]
This is my getDesignations function in EmployeesController.php:
public function getDesignations($id) {
$employee_designation_ids = Employees::find($id)->pluck('designation_id')->toArray();
$designation_name = [];
foreach ($employee_designation_ids as $employee_designation_id) {
$designation = Designations::where('id', '=', $employee_designation_id);
//$designation_name[] = $designation;
}
return $employee_designation_ids;
}

If you want specifically that format, you can do it like this (with a lot of guesses in my part since you did not share your Tables structures)
public function getDesignations($id) {
$employee_designation_ids = Employees::find($id)->designation_id;
return [[$id, $employee_designation_ids]];
}
But why are you returning a double table for a single row result.

Thanks for all your help! I've managed to fix it with this method in my controller:
public function getDesignations(Request $request, $id) {
$employee_designation_ids = Employees::where('id', $id)->pluck('designation_id');
return Designations::whereIn('id', $employee_designation_ids[0])->pluck('name');
}

Related

How to fetch data from single column stored in array using laravel?

I need to fetch the each and every column individually from the field array_payout can anyone solve it
$currentMonth_start_Date = Carbon::now()->startOfMonth()->subMonth(1);
$currentMonth_end_date = Carbon::now()->subMonth()->endOfMonth();
$clients_referral_tree = DB::table('mam_referral_payout')
->select('clients.id', 'mam_referral_payout.*')
//->addSelect(DB::raw('SUM(mam_referral_payout.Final_amount) as referral_amount'))
->leftjoin('clients', 'clients.id', '=', 'mam_referral_payout.to_id')
->where('clients.id', '=', (Auth::user()->id))
->whereBetween('mam_referral_payout.created_at', [$currentMonth_start_Date, $currentMonth_end_date])->get();
$clientTree = [];
foreach ($clients_referral_tree as $tree) {
$clientThree = $tree;
$clientTree[] = $clientThree;
}
dd($clientTree);
You can add the following to your Model:
protected $casts = [
"array_payout" => "object"
];
Add an accessor for each attribute in your json like this for example:
public function getTotalAmountAttribute(){
return optional($this->array_payout)->total_amount;
}
You can use them like this:
$clientTree1->total_amount;

I can't get the data in appends with json in Laravel

I have two models in laravel project Item and ItemImgs
Item.php
class Item extends Model
{
protected $appends = [
'photo',
];
public function imgs()
{
return $this->hasMany(ItemImage::class);
}
public function getPhotoAttribute()
{
$img = $this->imgs->first();
return $img.src;
}
}
it's worked in views
dd(Item::all()); //worked
{{ $cane->photo}}; //worked
but when I try to get json
return response()->json([
'items' => Item::with('imgs')->get(),
]);
// not worked. Got timeout 500
You cannot use dot notation in PHP.
public function getPhotoAttribute()
{
$img = $this->imgs->first();
return $img.src; // Dot notation is not allowed
}
but you've to use:
public function getPhotoAttribute()
{
$img = $this->imgs->first();
return $img->src;
}
if what you're trying to do is to get the items that have imgs() then what you should do is query by relationship existence, as mentioned in the docs
https://laravel.com/docs/5.8/eloquent-relationships#querying-relationship-existence
'items' => Item::has('imgs')->get()
It is not possible to refer to the linked model tables in attributes. It works in views but gives out a memory error when outputting an array through json.
public function getPhotoAttribute(){
$img = ItemImage::where('item', $this->id)-
>first();
}
It works that way, but it's not elegant.

How to improve performance of multiple count queries in a laravel view

I'm working on a marketing application that allows users to message their contacts. When a message is sent, a new "processed_message" database entry is created. There is a list view that displays all campaigns and the number of messages sent, blocked and failed for each campaign. My problem is that this list view takes way too long to load after there are > 50 campaigns with lots of messages.
Currently each campaign has 3 computed attributes (messages_sent, messages_failed and messages_blocked) that are all in the Campaign model's "appends" array. Each attribute queries the count of processed_messages of the given type for the given campaign.
namespace App;
class Campaign
{
protected $appends = [
'messages_sent',
'messages_blocked',
'messages_failed'
];
/**
* #relationship
*/
public function processed_messages()
{
return $this->hasMany(ProcessedMessage::class);
}
public function getMessagesSentAttribute()
{
return $this->processed_messages()->where('status', 'sent')->count();
}
public function getMessagesFailedAttribute()
{
return $this->processed_messages()->where('status', 'failed')->count();
}
public function getMessagesBlockedAttribute()
{
return $this->processed_messages()->where('status', 'blocked')->count();
}
}
I also tried to query all of the messages at once or in chunks to reduce the number of queries but getting all of the processed_messages for a campaing at once will overflow memory and the chunking method is way too slow since it has to use offset. I considered using eager loading the campaigns with processed_messages but that would obviously use way too much memory as well.
namespace App\Http\Controllers;
class CampaignController extends Controller
{
public function index()
{
$start = now();
$campaigns = Campaign::where('user_id', Auth::user()->id)->orderBy('updated_at', 'desc')->get();
$ids = $campaigns->map(function($camp) {
return $camp->id;
});
$statistics = ProcessedMessage::whereIn('campaign_id', $ids)->select(['campaign_id', 'status'])->get();
foreach($statistics->groupBy('campaign_id') as $group) {
foreach($group->groupBy('status') as $messages) {
$status = $messages->first()->status;
$attr = "messages_$status";
$campaign = $campaigns->firstWhere('id', $messages->first()->campaign_id);
$campaign->getStatistics()->$attr = $status;
}
}
return view('campaign.index', [
'campaigns' => $campaigns
]);
}
}
My main goal is to reduce the current page load time considerably (which can take anywhere from 30 seconds to 5 minutes when there are a bunch of campaigns).
You could use the withCount method to count all the objects without loading the relation.
Reference:
If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
In your controller you could do this:
$count = Campaign::withCount(['processed_messages' => function ($query) {
$query->where('content', 'sent');
}])->get();
You could do multiple counts in the same relationship too:
$campaigns = Campaign::withCount([
'processed_messages',
'processed_messages as sent_message_count' => function ($query) {
$query->where('content', 'sent');
}],
'processed_messages as failed_message_count' => function ($query) {
$query->where('status', 'failed');
}],
'processed_messages as blocked_message_count' => function ($query) {
$query->where('status', 'blocked');
}])->get();
You can access the count with this:
echo $campaigns[0]->sent_message_count
Docs

Passing Laravel Collection to Vue

I am trying to return customers from model Customer where id < 10. I do have some in the database.
$customers = Customer::where('id', '<', 10)->get();
return json_encode(['customers' => $customers]);
The above code will error out "Trailing data"
and when I try to dd($customers), I get a list of the collection Customer
I have no idea why I keep getting that and why the model is returning raw collection and not an object of the list of customers???
It seems like a null date "updated_at" field is causing the error. don't know why!
Solved By:
on the Customer model I had to do:
//ask Laravel to not manage default date columns
public $timestamps = false;
also I to mutate those columns:
public function setDateRemindedAttribute($value)
{
if (strlen($value)) {
$this->attributes['date_reminded'] = Carbon::createFromFormat('d/m/Y', $value);
} else {
$this->attributes['date_reminded'] = null;
}
}
public function setUpdatedAtAttribute($value)
{
if (strlen($value)) {
$this->attributes['updated_at'] = Carbon::createFromFormat('d/m/Y', $value);
} else {
$this->attributes['updated_at'] = $_SERVER['REQUEST_TIME'];
}
}
Use response()->json() like this
$customers = Customer::where('id', '<', 10)->get();
return response()->json(['customers' => $customers]);

Laravel return one model + association as JSON

I'm looking for a way to return a model as JSON including an association model after save (within a controller).
I know how to respond as JSON with associations by doing the following :
$objects = MyModel::with(['assocation1', 'association2.dependencies'])->get();
return response()->json($objects, 200);
But in a case of an object already found ? I've tried to use the same concept as above but it returns every rows.
$object = MyModel::first();
$object->with(['assocation1', 'association2.dependencies'])->get();
Laravel's documentation unfortunately does says much about it. What I'm trying to do is to return a JSON object including an association after save, within a controller :
class ExampleController extends Controller {
public function store()
{
$object = new MyModel($request->input('object'));
$response = DB::transaction(function () use ($object) {
if (object()->save()) {
// Here I want to return the object with association1 as JSON
return response()->json($object->with('association1')->get(), 201);
}
});
return $response;
}
}
Edit
More clarification about this case. Using either with or load seems to produce the same result: returning all rows from the Object object including associations. My goal here is to only return ONE object with it's association as JSON, not all of them.
I believe you aren't as far off as you think. In your second example, you shouldn't call get(). Try this instead:
if ( $object = $object->save() )
{
$object->load(['assocation1', 'association2.dependencies']);
return response()->json($object, 201);
}