Laravel eloquent query based on a given time - php

I have a simple list of tasks that need to be completed today, at various times. Each task has a reminder/notification that needs to be sent x amount of minutes before it is planned.
Simplified migration is as follows:
Schema::create('user_tasks', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->time('time'); // The time for when the task has been planned, i.e. 10:00
$table->string('minutes'); // The minutes before a reminder needs to be send, i.e. 30
$table->timestamps();
});
I want to query only the tasks that are due for a reminder, based on the current time and the minutes for the given task. So, for example, I have a task called sweep the floors with a value of 30 for the minutes. Which means, 30 minutes before the task is due, I want to send a reminder.
I could query all the tasks and then check for each task if it is due, but I want to query only the tasks that are due for a reminder, obviously.
This is my query so far:
$tasks = Task::whereTime('time', '<', Carbon::now()->addMinutes($task->minutes)->format('H:i'))->get();
Obviously $task->minutes doesn't exist, the value is in the database but I am unsure how to make my query. Any pointers?
Edit:
So I have changed the time column from a string to a time field, and the query below is the one I am using for testing:
$tasks = auth()->user()->tasks()
->whereRaw('time < DATE_ADD("' . now() . '", interval 60 minute)')
->get();
The outcome is this:
I am unsure why the time is displayed below as 0.4. When running the query multiple times I get different results for the time. But I am not sure if the query output is correct, hence the image.

You would need to compare column 'time' and current time + column 'minutes'. So basically you need to compare 2 columns. For this instead if whereTime you can use whereRaw(), for example something like this :
$tasks = Task::whereRaw('time < DATE_ADD("' . now() . '", interval minutes minute)')->get();
DATE_ADD is a MySQL function which adds time to it's first parameter.

For me, the best way to do this would be by refactoring your table schema to this:
$table->id();
$table->string('name');
$table->time('time'); // The time for when the task has been planned
$table->integer('minutes'); // The minutes before a reminder
$table->time('time_notification');//you can do the query only of this column
$table->timestamps();
So you would be able to get them by this query:
$tasks = Task::whereTime('time_notification', '<=', Carbon::now()->format('H:i'))->get();

Related

How to periodically update a database table's column for a million records in Laravel?

In my users' table, I will require to revert the 'daily' column back to the default value '1' on the dot at 12AM.
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name', 50);
$table->string('email')->unique();
$table->unsignedTinyInteger('daily')->default('1');
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Is there a way where I can revert the value back to default value 1 or update the value to 1 for a million records with no time delay(meaning all the user's 'daily' column will be updated at the same time) at 12AM daily?
Note: The 'daily' column is to determine if user has 'use up' their daily click. User will have 1 chance to click on a button(sort of like a reward box) daily. Once they have clicked on the button, the daily will be updated to '0' and they will not be able to click the button again until the next day.
You need to do the update within a transaction with serialization level of serializable to ensure it's done at once and no other transaction interferes with the update. As for the timing, I do not know how you can get the update done exactly at 00:00. It will either happen before or after midnight no matter what you do. The other solution is to have a time stamp for each row and use a trigger upon update to check if the timestamp is before midnight and if the time is after midnight set the column you want to one on that particular row. This should also be done in a transaction.

Mysql Query in Laravel active records

after a little bit search in stackoverflow I came up with this query which I wanted, and its like this:
SELECT * FROM workers where TIMESTAMPDIFF(SECOND, last_activity_time, NOW()) >= (60/per_hour*60)
each record is consist of these fields:
id worker_name last_activity_time per_hour
so each worker has a per_hour field that will determined as actions number per hour.
last activity is the last time worker was doing an action.
It will get records that are qualified to run at current time.
so it will determine time interval with 60/per_hour in seconds and selects the records which time passed from their last_activity_time till now is more than this calculated interval.
this works okay, But I want to know two things.
1: is this query a good approach for this problem or its slow?
2: how can I do this query in laravel 5.5 active records or query builder? and also it should return one record at a time.
thanks in advance
i think your query is fine because there were no joins and no subquerires just only condition is there. You can fire raw queries on laravel to -
$workers = DB::select('SELECT * FROM workers where TIMESTAMPDIFF(SECOND, last_activity_time, NOW()) >= (60/per_hour*60)');
// or you can make use of query builder as follows
$workers = DB::table('workers')->whereRaw('TIMESTAMPDIFF(SECOND, last_activity_time, NOW()) >= (60/per_hour*60')->first();
this should work
\DB::table('workers')->whereRaw(...)->first();
https://laravel.com/docs/5.6/queries
1: is this query a good approach for this problem or its slow?
It will depend on how many workers you have, you should try and see

notification one day before the selected date in laravel 5

i am working on laravel dates and i want laravel to give notification a day before or the same selected day in database how can i do that here is a part of my code :
here is my controller i save remember_date in phonebook model
public function index()
{
$current_time = Verta::now();
$phonebooks = Phonebook::with('client')->get();
return view('admin.phonebooks.index', compact('phonebooks'))->with('current_time',$current_time);
}
and here is the migration of my phonebooks table
public function up()
{
Schema::create('phonebooks', function (Blueprint $table) {
$table->increments('id');
$table->text('title');
$table->longText('description');
$table->integer('client_id');
$table->dateTime('calldate');
$table->dateTime('rememberdate');
$table->timestamps();
});
}
now i want to give notification to call the client 1 day before or the day which is stored in rememberdate .
In case: If you just want static notification section on you page
If you just wanna show something on the page as notification then just fetch data based on your condition that matches with the notification rule.
Steps:
Get current date (php current date)
Calculated date: Add a day to the current date (current date+1 day)
fetch record by matching the Calculated date with the rememberdate in DB
display your notification if any record found in DB, if record not found then "No notification found"
For date operations you can use core php and add one day to current date. But I would recommend you to use Carbon lib in laravel.
Examples using Carbon to add days in current date time Link
Update based on your comment:
I am sorry, actually I dont understand that calendar (jalali calendar) but simply adding one day will work for any calendar. First explore Carbon if that support your calendar.
But I had similar problem in past. Nepal got its own dates and calendar system and I had to develop an application. What I did is I did all the operations/calculations and storing data in DB in standard time (English date-time) that servers and mysql default and then on application only at the time of displaying data, I display date-time in local format (Nepal's Local Calendar).
At the time of displaying data on web page (UI), I used date converter class that I had written to convert date-time from Nepal date-time to English date-time and vise versa.
you can use Carbon which gives you a lot of functionality working with date and Time
$currentTime = Carbon::now();
$clientsToNotif = Phonebook::with('client')->whereDate('rememberdate' , $currentTime->addDays(1))->get();
you can do any kind of notification to users now

How to set Task Scheduler in Laravel to run only once at given timestamp?

How do I execute a function at a specific timestamp only once instead of making it run periodically?
Here is my application:
I have a table with 2 rows: id(primary key) and time(epoch timestamp stored as integer). Now, for each of the entries I want to call a function that will execute at the timestamp stored in table. How do I achieve this?
Are there any better alternatives to Task Scheduler?
I'm using Laravel 5.4 (if it matters)
EDIT: I do know a workaround, but I am looking for most efficient solution.
The concept is to run the scheduler every minute and you select the records on that time period & execute the function. With the assumption the seconds doesn't matter I wrote the below code. If the seconds matters, you have to check how to run the scheduler every seconds, but the concept is same.
Hope this will help you
use Carbon\Carbon;
...
$schedule->call(function() {
// Look in your table for `time` in current minute, between 0-59s
$entries = TheTable::where([
['time', '>=', Carbon::now()->second(0)->timestamp],
['time', '<=', Carbon::now()->second(59)->timestamp]
]);
// Loop through the results & call the function
})->everyMinute();

Randomized cron jobs in Laravel 5.1

I am using Laravel's artisan scheduler to manage cron jobs for an application. One of the features of this app are virtual shops that "restock" at an interval that's logged in the database (i.e stock_min = 5 and stock_max = 15 would mean the shop would restock every 5-15 minutes). These values can change at any time.
How would I go about setting up the cron in Laravel so it would adhere to the interval given with a sufficient amount of randomness and look to see if the interval has changed since the last restock?
You'd need to create a model called 'stock_update_tracking' or something similar, to log when the next time the stock should be restocked.
stock_update_tracking
next_update
Then, you can call a cron job every minute and simply do a check to see if the next_update value is more than the current timestamp.
$schedule->call(function() {
$nextUpdate = DB::table('stock_update_tracking')
->select('next_update')
->where('next_update', '<' Carbon::now())
->count();
if($nextUpdate) {
// Update the stock
// Calculate a new next update time
$newNextUpdate = Carbon::now();
$newNextUpdate = $newNextUpdate->addMinutes(rand(5,15));
// Save the newNextUpdate value in the stock_update_tracking table
DB::table('stock_update_tracking')->update(['next_update' => $newNextUpdate])
}
})->everyMinute()->withoutOverlapping()

Categories