update date to next day in laravel - php

I want to update my date to next day date. How Can I do it?
Now I do it using this.
$calendar = Calendar::find($id);
$calendar->update(['started_at' => $calendar->started_at->addDay(1)));
or I can do it
$calendar->started_at->addDay(1);
$calendar->save();
But this solutions is bad for me because there are 2 request in database. I wont do it using only one request.
Is there a way to dynamically update date to next day date?
For example
Calendar::where('id', $id)->updateToNextDay('started_at');
I find also sql equivalent
UPDATE `calendar` SET `started_at` = `started_at` - INTERVAL 1 DAY;
Thanks for attention.

Calendar::where('id', $id)->update() is just syntactical sugar. This proxies you to the Query Builder and is the same as running DB::table('calendar')->where('id', $id)->update();
The power of a model in an ORM is obtaining the data from the database, mapping it to properties in an object, and then manipulating that object. The overhead of a single select for an update is pretty small and if you're worried about that overhead in the development phase, you're probably overoptimizing.
If you wish to forego the select, you can use the Query Builder with a raw SQL expression. Either will call the Query Builder and run the same exact query:
Calendar::where('id', $id)
->update(['started_at' => DB::raw("started_at + INTERVAL 1 DAY")]);
or
DB::table('calendars')->where('id', $id)
->update(['started_at' => DB::raw("started_at + INTERVAL 1 DAY")]);

This should work
Calendar::where('id', $id)->update([
'started_at' => DB::raw("DATE_ADD(started_at, INTERVAL 1 DAY)")
]);
Let me know :)

$startDate = date_timestamp_get($calendar->started_at);
$date = date('Y-m-d H:i:s', strtotime('+1 day', $startDate));
$calendar->update(['started_at' => $date]);

You can write your own method in Calendar model like,
public function updateToNextDay(string $column)
{
$this->update([
$column => \Db::raw("$column + INTERVAL DAY 1");
]);
}
Not tested, but it should work.

Related

Matching rows by date on a Laravel 9 application using php-carbon objects

The background
I am building a Laravel application and I have an upsert method on a Booking Controller for updating/inserting bookings.
On upsert.blade.php I want to display a <select> element with a list of days into which a booking can be moved (or inserted).
There is a 'holidays' table with only one column: 'day' (of type datetime, precision 6). Each entry on this table means the system will be on holidays for that day, so bookings cannot be made or transfered into days that appear on this table.
Now, I want the <option>s in the above mentioned <select> to be disabled when they correspond to a holiday.
What I tried:
The view (upsert.blade.php)
<select>
<option value="" disabled selected>Select</option>
#foreach($days as $day)
<option value="{{ $day['value'] }}" #disabled($day['disabled'])>
{{ $day['display'] }}
</option>
#endforeach
</select>
The controller action:
public function upsert()
{
$now = Carbon::now();
$last = Carbon::now()->addDays(30);
$holidays = DB::table('holidays');
$days = [];
// Populate $days with dates from $now until $last
while($now->lte($last))
{
array_push($days, [
'value' => $now->toDateString(),
'display' => $now->format('l j F Y'),
/*
* Mark day as disabled if holidays matching current
* day is greater than 1
* DOESN'T WORK
*/
'disabled' => $holidays->whereDate('day', $now)->count()
]);
$now->addDay();
}
return view('upsert', [
'days' => $days,
]);
}
The problem
The line labelled 'DOESN'T WORK' doesn't work as expected (I expect the query to return 1 if there is a holiday for the current day in the loop, thus marking the day as disabled). It only matches the first day of the loop if it's a holliday, but it won't match any other days.
Note: I have cast the 'day' property of the Holiday model to 'datetime' so Laravel casts the value to a Carbon object when accessing it.
Attempts to solve it
I tried replacing
$holidays = DB::table('holidays');
with
$holidays = Holiday::all();
but that throws the following exception
Method Illuminate\Database\Eloquent\Collection::whereDate does not exist.
So I tried rewriting the query to (note whereDate was replaced by where):
'disabled' => $holidays->where('day', $now->toDateString().' 00:00:00.000000')->count()
But this would never match
The solution
After around 6 hours of fiddling about with this line, reading Laravel documentation and talking to ChatGPT, I couldn't come up with an answert to why this is happening so I replaced the problematic line with
'disabled' => Holiday::whereDate('day', $now)->count()
Which does the job but I think is terrible for performance due to so many (in my opinion unecessary) round trips to the database.
The question
Could anyone shed some light on this?
Although I've found a solution, I don't think it would scale and I also didn't learn a thing from the experience, I still have no idea why the first query is only matching the first day and no other days. Or why the second one using where() doesn't match any days at all when it is comparing strings and I am using the exact format the strings are stored in on the database.
Or maybe the problem is not on the query, but on the Carbon object?
If you want to reproduce it, follow steps on this gist:
https://gist.github.com/alvarezrrj/50cd3669914f52ce8a6188771fdeafcd
DB::table('holidays') instantiates an Illuminate\Database\Query\Builder object. The where method modifies that object in place.
So if you're looping from January 1st-3rd and are adding a new where condition on each loop, that's going to fail because now you are basically querying this. Obviously the day column cannot match 3 different dates.
SELECT * FROM holidays
WHERE DATE(day) = '2022-01-01'
AND DATE(day) = '2022-01-02'
AND DATE(day) = '2022-01-03'
That's also why it only worked on the first loop for you, because at that point there is only 1 where condition.
You would need to move the instantiation inside the while loop so that it gets reset on each loop. Which is basically what you did in your solution.
Re: performance, what you were trying to do would not have saved you any DB cycles anyway. Each time you call count() you are hitting the database, regardless of whether it's a new $holidays object or not.
If you're concerned about performance, one thing you could do is fetch all of the holidays between the start & end date in a single query.
// May need to call toDateString() on $now and $last
$holidays = Holiday::whereBetween('day', [$now, $last])
->get()
->pluck('id', 'day'); // Assuming day is a DATE column not DATETIME or TIMESTAMP
// This will give you a collection with an underlying array like this:
// ['2022-07-04' => 1, '2022-12-25' => 2]
while($now->lte($last))
{
array_push($days, [
// Now you can instantly look it up in the array by the date
'disabled' => isset($holidays[$now->toDateString()]),
]);
$now->addDay();
}

Attempting to return users registered per month, but not getting a correct count in CakePHP 3?

I am attempting to fetch a count of users who have registered each month, separated by month in the results - so, January - 22, February - 36, March- 56, so on and so forth limited to this month and the last five.
However, I can't seem to get the query correct as it relates to CakePHP 3's query builder. This is what I have so far:
$query = $this->find('all');
$query->select(['count' => $query->func()->count('id'), 'day' => 'DAY(dateRegistered)']);
$query->where(['YEAR(dateRegistered)' => date('Y')]);
$query->group(['MONTH(dateRegistered)']);
$query->enableHydration(false);
return $query->all();
This seems to return the user count for the month, but that's all, and not in an easily graph-able format. I have seen some queries in raw SQL so it should be possible, but I would like to use the native query controls in Cake. Could someone help fix this?
Try this:
$query = $this->find();
$res = $query
->select([
'month'=>'monthname(created)',
'count'=>$query->func()->count('*'),
])
->where('year(created) = year(curdate())')
->group('month')
->enableHydration(false);
pr($res->toArray());

Phalcon datetime in model query error

I am trying to execute a query like this:
Select * from table where created_at > DATE_SUB(NOW(), INTERVAL 1 DAY) in phalcon model query form. But i keep getting the following error:
Syntax error, unexpected token INTEGER(1), near to ' DAY)',
By query building is like below
$donations = Donations::query()
->where('created_at > DATE_SUB(NOW(), INTERVAL 1 DAY)')
->execute();
The above code gives me that error. Now i have tried like below
$donations = Donations::query()
->where('created_at > :holder:')
->bind(["holder" => 'DATE_SUB(NOW(), INTERVAL 1 DAY)'])
->execute();
Although this binding does not give me an error, it gives me a 0 result but i have a few rows inserted into the table to check this and when i execute the query in phpmyadmin it works correctly, So i assumed there might be a datetime mix up in the phalcon library setup of mine but when i changed from 1 DAY to 1 MONTH there is still not result. Can someone guide me on this.
INTERVAL, DATE_SUB, NOW() and other similar are MySQL only features and are not supported by PHQL.
You have two options:
1) Rewrite your WHERE condition by using PHP date:
$date = date('Y-m-d', strtotime('-1 DAY')); // Modify according to your date format
$donations = Donations::query()
->where('created_at > :holder:')
->bind(["holder" => $date)
->execute();
2) Extend MySQL with a dialect class:
$di->set('db', function() use ($config) {
return new \Phalcon\Db\Adapter\Pdo\Mysql(array(
"host" => $config->database->host,
"username" => $config->database->username,
"password" => $config->database->password,
"dbname" => $config->database->name,
"dialectClass" => '\Phalcon\Db\Dialect\MysqlExtended'
));
});
More info in the following links:
How to extend: https://forum.phalconphp.com/discussion/1748/date-sub-interval-mysql#C6291
The dialect class itself: https://github.com/phalcon/incubator/blob/master/Library/Phalcon/Db/Dialect/MysqlExtended.php

MongoDB using timestamps to sort

I have a mongodb that will be storing visitor data. I need to delete the data after ten minutes of not being active and will run a command through a cron. How would I do this?
Currently the collection is setup like so:
{ "_id" : ObjectId("4fd33e0b0feeda3b2406f6be"), "name" : "Dugley Reanimator", "updated" : "Some form of timestmap" }
How should I go about storing a timestamp that I search the collection with I.E for my MySql version:
$sql = mysql_query('DELETE FROM `visitors` WHERE NOW() > DATE_ADD(`last_seen`, INTERVAL 10 MINUTE)');
The ObjectId has a timestamp component to it. see the docs here. This essentially gives you a free insert time that you can use for sorting and querying.
The mongodb drives should give you a way to created an ObjectId off of a timestamp.
In Python:
gen_time = datetime.datetime(2010, 1, 1)
dummy_id = ObjectId.from_datetime(gen_time)
In Java:
Date d = new Date(some timestamp in ms);
ObjectId id = new ObjectId(d)
So once you've created an ObjectId based on "10 minutes ago" you can do a delete query using $lt
in the js console it would be:
db.collectionName.remove({_id: {$lt: <Your Object Id that represents 10 minutes ago>})
The best way to do it (if the timestamp is the same when you insert) its by using the _id field.
The _id field can indicate you the time, and you can do a $lte query to delete old values.
I've written about it here: http://blog.dicarsio.com/post/10739857186/quick-snippet-get-creation-time-from-id-on-mongodb
Your driver will use a MongoDate time (this may map to a more native representation in PHP).
You can then query using something like the following mongo statement:
db.myCollection.find({updated : { $lte : new ISODate("2012-06-09T16:22:50Z") } })
A rough translation for PHP would be:
$search = array(
'updated' => array(
'$lte' => new MongoDate($tenMinutesAgo))
);
$collection->find($search)
Or (Caveat: not tested):
$tenMinutesAgo = new DateTime();
$tenMinutesAgo->modify('-10 minutes');
$search = array('updated' => array('$lte' => $tenMinutesAgo));
$collection->find($search)

How to set current date and time in table field using zend

I am having table called users with following fields ,
is_login(tinyint(1)) and last_login(datetime).
Below is the piece of code to update when user is online using Zend,
public function updateLastLoginDetails($id){
$currentDateTime = date('Y-m-d H:i:s');
$data = array('is_online' => 1,'last_login'=>$currentDateTime);
$this->_db->update( 'users', $data,'id = '.$id);
}
Here i am using $currentDateTime = date('Y-m-d H:i:s'); to store current data and time. But it seems not ok with time.
Kindly suggest me the best way to store current data and time using Zend .
Thanks in Advance,
Dinesh Kumar Manoharan
I'm not exactly sure what's causing your problem, but I find using NOW() to be easier. Also, you should ensure the variable $id gets quoted in the update's where condition.
public function updateLastLoginDetails($id){
$data = array('is_online' => 1, 'last_login' => new Zend_Db_Expr('NOW()'));
$this->_db->update('users', $data, array('id = ?' => $id));
}
It looks like you forgot to use $data anywhere in your code!
public function updateLastLoginDetails($id){
$currentDateTime = date('Y-m-d H:i:s');
$data = array('is_online' => 1, 'last_login'=>$currentDateTime);
$this->_db->update('users', $data, 'id = '. (int)$id);
}
You might want to consider using a TIMESTAMP field in place of a DATETIME for last_login and have MySQL update it automagically.
Hi am I understanding correctly that the year month and day are being inserted correctly but not the hour minutes and seconds? If that is the case can you please provide use with a describe of the users table. Just execute "DESCRIBE users" in phpMyAdmin.
If that is the case it could be that the field is of type DATE and not DATETIME.

Categories