Laravel collection map function overrides default collection - php

I have a code where I use map to create a new collection of high scores.
The problem I have is that it overrides the default user collections. Which is not my intention.
Here is the code
$users = Users::all();
$highscore = $users->map(
function ($user) {
$calls = $user->calls->filter(
function ($call) {
$date = Carbon::parse($call->datetime)->format("Y-m-d");
$today = Carbon::now()->format("Y-m-d");
return $date == $today;
}
);
return [
'id' => $user->id,
'duration' => $calls->sum('duration'),
];
}
);
If i dump the first user after getting all the users I get the first user. Like this.
$users = Users::all();
dd($users->first());
If I dump the first user after the high score map. I get all Calls from that user which is another model. Which means that the users collection has been modified. Like this.
$highscore = $users->map(
function ($user) {
$calls = $user->calls->filter(
function ($call) {
$date = Carbon::parse($call->datetime)->format("Y-m-d");
$today = Carbon::now()->format("Y-m-d");
return $date == $today;
}
);
return [
'id' => $user->id,
'duration' => $calls->sum('duration'),
];
}
);
dd($users->first()):
Any idea on how to handle this behaviour?

The map function returns an array of [[$userId => $duration], ...]. What you want to do is to order your users by the sum of their calls.
I believe that, in order to do that easily, you should add to your User model:
public function getTodayCallSum() {
return $user->calls->filter(function($call) {
$date = Carbon::parse($call->datetime)->format("Y-m-d");
$today = Carbon::now()->format("Y-m-d");
return $date == $today;
})->sum('duration');
}
And then edit your query:
$users = User::all();
$firstUser = $users->sortBy('todayCallSum')->first();
I haven't tested this code, but I think it should help you towards the right direction.

Related

Pass argument to method

I have functions that I use in my Article model, they add likes to cookies for a specific article and record the time
public static function hasLikedToday($articleId, string $type)
{
$articleLikesJson = \Cookie::get('article_likes', '{}');
$articleLikes = json_decode($articleLikesJson, true);
// Check if there are any likes for this article
if (! array_key_exists($articleId, $articleLikes)) {
return false;
}
// Check if there are any likes with the given type
if (! array_key_exists($type, $articleLikes[$articleId])) {
return false;
}
$likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$articleId][$type]);
return ! $likeDatetime->addDay()->lt(now());
}
public static function setLikeCookie($articleId, string $type)
{
// Initialize the cookie default
$articleLikesJson = \Cookie::get('article_likes', '[]');
$articleLikes = json_decode($articleLikesJson, true);
// Update the selected articles type
$articleLikes[$articleId][$type] = today()->format('Y-m-d H:i:s');
$articleLikesJson = json_encode($articleLikes);
return cookie()->forever('article_likes', $articleLikesJson);
}
The php.blade page itself has buttons
Like Heart
Like Finger
Here are the routes web.php
Route::get('/article', function () {
$articleLikesJson = \Cookie::get('article_likes', '{}');
return view('article')->with([
'articleLikesJson' => $articleLikesJson,
]);
});
Route::get('article/{id}/like', 'App\Http\Controllers\ArticleController#postLike');
And the postLike() function itself in the controller
public function postLike($id) {
$article = Article::find($id);
$like = request('like');
if ($article->hasLikedToday($article->id, $like)) {
return response()
->json([
'message' => 'You have already liked the Article #'.$article->id.' with '.$like.'.',
]);
}
$cookie = $article->setLikeCookie($article->id, $like);
$article->increment('like_{$like}');
return response()
->json([
'message' => 'Liked the Article #'.$article->id.' with '.$like.'.',
'cookie_json' => $cookie->getValue(),
])
->withCookie($cookie);
}
In general, what is the problem, I have 2 types of likes that can be seen in php.blade, and the problem is to pass the choice of the type of like to the postLike() function, if in my function instead of $like I write 'heart', then everything will be work, but I need to determine which type we choose (heart or finger), tell me how this can be done?
You can use Laravel's Request object.
https://laravel.com/docs/8.x/requests#input
Like this:
use Illuminate\Http\Request;
public function postLike($id, Request $request)
{
$type = $request->input('type');
}

how to condition same time data to insert and update in laravel

I will try If on today's date, any row insert Then update value use id
And if not any row today's date Then insert a new row. but the problem is update value is working but not insert a new row message is "Trying to get property 'Date' of non-object"
public function present($id){
$user = User::find($id);
$date = date('Y-m-d');
$id = $user->id;
$Attendance= Attendance::where('User_A_ID','=',$id)->first();
if($Attendance->Date == $date){
$Attendance->A_sts = '0';
$Attendance->Date = $date;
$Attendance->User_A_ID = $user->id;
$Attendance->save();
} else {
$Attendance= new Attendance();
$Attendance->A_sts = '0';
$Attendance->Date = $date;
$Attendance->User_A_ID = $user->id;
$Attendance->save();
}
return back();
}
If I understand you correctly you want to update the existing attendance that belongs to the user or create a new attendance if the user does not have one.
You can simplify your code:
public function present($id)
{
$user = User::findOrFail($id);
$date = date('Y-m-d');
$Attendance = Attendance::firstOrNew(['User_A_ID' => $user->id, 'Date', $date]);
$Attendance->User_A_ID = $user->id;
$Attendance->Date = $date;
$Attendance->A_sts = '0';
$Attendance->save();
return back();
}
Use findOrFail to check if the user exists, and then use firstOrNew to retrieve the existing attendance for today or create a new instance of it, this way you can get rid of your if statement.

Difference between dates always returns a default number(5) in the database

Hello I'm just having a little trouble with a function, to explain it first it's supposed to get the difference between two dates and take that number then subtract it from a field on the database and it works well or so I thought until I noticed that whatever date I put it always returns only the number 5
Leave Model
protected $dates = ['from', 'to'];
public function numberOfDays()
{
$datesx =Leave::where('user_id', auth()->user()->id)
->first();
$from =$datesx->from;
$to =$datesx->to;
$datetime1 = new DateTime($from);
$datetime2 = new DateTime($to);
$interval = $datetime1->diff($datetime2);
$days = $interval->format('%a');//now do whatever you like with $days
return $days;
}
User Model
public function leaveBalance()
{
$leave =new Leave;
$daysUsed= $leave->numberOfDays();
// $daysUsed = $this->leaves->map->numberOfDays()->sum();
// return $this->leave_days_granted - $daysUsed;
$days_granted = User::where('id', auth()->user()->id)
->first();
$leave_days_granted = $days_granted->leave_days_granted;
return $leave_days_granted - $daysUsed;
}
public function hasAvailableLeave()
{
return $this->leaveBalance() > 0;
}
public function leaves()
{
return $this->hasMany(\App\Leave::class);
}
Leave Controller
public function store(Request $request)
{
$this->validate($request,[
'from'=>'required',
'to'=>'required',
'description'=>'required',
'type'=>'required'
]);
$data=$request->all();
$data['user_id']=auth()->user()->id;
$data['message']='';
$data['status']=0;
$leave =Leave::create($data);
/** update users table with leaveBalance() return value*/
//get logged in user id
$user_id=auth()->user()->id;
//get the returned value from User model method
$leave_balance = new User;
// $leave_balance->leaveBalance();
// dd($leave_balance->leaveBalance());
// die();
DB::table('users')
->where('id', $user_id)
->update(['leave_days_granted' => $leave_balance->leaveBalance()]);
By only returns the number 5 I mean is that every time a leave is requested/stored it subtracts -5 from the field leave_days_granted but it's supposed to subtract the difference between the two dates that is given in the leave table, fields "from" and "to" which stores the date from and to a specific date

How to update in one to one relation in laravel?

In my user model, I have the following code
public function profile()
{
return $this->hasOne(UserProfile::class);
}
In profile model,
public function user()
{
return $this->belongsTo(User::class);
}
The create method is working, But when I try to update the profile with following code, It is creating a new profile and doesn’t update the profile information.
$profile = new UserProfile();
$profile->dob = '1999-03-20';
$profile->bio = 'A professional programmer.';
$profile->facebook = 'http://facebook.com/test/1';
$profile->github = 'http://github.com/test/1';
$profile->twitter = 'http://twitter.com/test/1';
$user = User::find($userId);
$res = $user->profile()->save($profile);
What is the correct method to update in One to One Relationship ?
I fixed it using push method. Here is the code.
$user = User::find($userId);
$user->name = "Alen";
$user->profile->dob = '1999-03-20';
$user->profile->bio = 'A professional programmer.';
$user->profile->facebook = 'http://facebook.com/test/1';
$user->profile->github = 'http://github.com/test/1';
$user->profile->twitter = 'http://twitter.com/test/1';
$user->push();
You're doing right, however i could suggest a little improvement
You may use the following
$user = User::with('profile')->findOrFail($userId);
if ($user->profile === null)
{
$profile = new UserProfile(['attr' => 'value', ....]);
$user->profile()->save($profile);
}
else
{
$user->profile()->update(['attr' => 'value', ....]);
}
you are using save method to save new record. use update query
//controller
$userObj=new User();
if(!empty($userId) && $userId!=null){
$userObj->updateByUserId($userId,[
'dob' = '1999-03-20';
'bio' = 'A professional programmer.';
'facebook' = 'http://facebook.com/test/1';
'github' = 'http://github.com/test/1';
'twitter' = 'http://twitter.com/test/1';
]);
}
//model
function updateByUserId($userId,$updateArray){
return $this->where('user_id',$userId)->update($updateArray);
}

Laravel events firing multiple times, should only be firining once

I have a model called Project, that has some model events setup like this,
class Project extends Eloquent {
public static function boot()
{
parent::boot();
// new project created
static::created(function($project)
{
// create the data informing the client to pull the new project information
$pullData = [
'id' => $project->id,
'item' => 'project',
'type' => 'created',
'interface' => '/project/basic/'.$project->id
];
foreach($project->organisation->users as $user) {
if ($user->id != $project->user_id)
Pusherer::trigger('private-user'.$user->id, 'project:createdPull', $pullData);
}
}
Event::subscribe(new ProjectEventHandler);
Event::fire('project.create', array($project));
Event::fire('project.create', array($project));
Event::forget('project.create');
Event::subscribe(new OrganisationEventHandler);
Event::fire('organisation.project.add', array($project, $project->organisation, $project->user));
Event::forget('organisation.project.add');
});
}
I create a project like this,
$project = new Project;
$project->name = $this->first_name . "'s example project";
$project->slug = Stringhelpers::_uriHash( time() . $project->name );
$project->uri_hash = Stringhelpers::_slugify($project->name);
$project->total_cost = "1000.00";
$project->start_date = date('Y-m-d H:i:s', time());
$project->finish_date = date('Y-m-d H:i:s', strtotime('+1 month'));
//$project->owner_id = $this->id;
$project->client_id = $client->id;
$project->status = 2;
$project->user_id = $this->id;
$project->organisation_id = $organisation->id;
$project->archived_at = "0000-00-00 00:00:00";
//$project->socketId = $this->socketId;
//Add the created user to the project as a just watcher.
//$project->flushEventListeners();
if($project->save()) {
$project->users()->attach(array($this->id => array('role' => 3, 'last_tab' => 'home')));
}
To my mind this this should fire the created event on the model once, and each of the subscribed events once, but it is firining the events, or the created event 3 times, would there be reason for this?
======= Further Details ======
I am saving multiple models in my process, I have noticed that I get multiple events firing when there have been a previous save, so I do the following, I get too Item events,
$project = new Project;
$project->name = $this->first_name . "'s example project";
$project->slug = Stringhelpers::_uriHash( time() . $project->name );
$project->uri_hash = Stringhelpers::_slugify($project->name);
$project->total_cost = "1000.00";
$project->start_date = date('Y-m-d H:i:s', time());
$project->finish_date = date('Y-m-d H:i:s', strtotime('+1 month'));
//$project->owner_id = $this->id;
$project->client_id = $client->id;
$project->status = 2;
$project->user_id = $this->id;
$project->organisation_id = $organisation->id;
$project->archived_at = "0000-00-00 00:00:00";
//$project->socketId = $this->socketId;
//Add the created user to the project as a just watcher.
//$project->flushEventListeners();
if($project->save()) {
$project->users()->attach(array($this->id => array('role' => 3, 'last_tab' => 'home')));
}
$item = new Item;
$item->name = $this->first_name . "'s example item";
$item->percentage_complete = 0;
$item->project_id = $project->id;
$item->workflow_id = 0;
$item->user_id = $this->id;
$item->start_date = $project->start_date;
$item->finish_date = $project->finish_date;
//$item->socketId = $this->socketId;
//$item->flushEventListeners();
$item->save();
my Item model looks like this,
public class Item extends Eloquent {
public static function boot() {
parent::boot();
// new item created
static::created(function($item) {
// fire project pusher events
Pusherer::trigger('project_'.$item->project_id, 'item:created', $item, $item->socketId);
Log::info("ITEM CREATE CALLBACK STARTED");
// fire off notifications and activity feeds
Event::subscribe( new ProjectEventHandler );
Event::fire('item.create', $item);
// Event::forget('item.created');
Log::info("ITEM CREATE CALLBACK FINISHED");
});
}
}
Why would it aggrege my events each time I save something?

Categories