Symfony2 Doctrine query - datetime addition - php

I currently am facing a little problem : I have a table of events, and would like to get which events are upcoming or ongoing.
So for instance we are on a Monday at 12:00, we have 3 events planned for today :
Event A starting at 10:00 and lasting 1h
Event B starting at 11:00 and lasting 2h
Event C starting at 13:00 and lasting 2h
In the end I would like to get Event B (ongoing) and Event C (upcoming).
I tried doing this (didn't work) :
public function findAllPast(\Datetime $datetime)
{
$query = $this->createQueryBuilder('event')
->where('event.startTime + event.duration >= :time')
->setParameter('time', $datetime)
->getQuery();
return $query->getResult();
}
Searching around, I came onto the SQL ADDTIME() function. I'd pretty much like to do a where('ADDTIME(event.startTime, event.duration) >= :time'), but this isn't recognized by Doctrine.
Is there any proper way of doing this without brutal native SQL ?

You could use Doctrine's DATE_ADD() function :
public function findAllPast(\Datetime $datetime)
{
$query = $this->createQueryBuilder('event')
->where('DATE_ADD(event.startTime, event.duration, "days") >= :time')
->setParameter('time', $datetime)
->getQuery();
return $query->getResult();
}
This supposes that event.duration is in days, of course.
EDIT : Alternative in PHP working with DateTime objects
If $duration is in seconds, you can simply :
$datetime->sub(new DateInterval('PT' . $durationInSeconds . 'S')); // or ->add(), depending on what you wnat
and then just use :
public function findAllPast(\Datetime $datetime)
{
$datetime->sub(new DateInterval('PT' . $durationInSeconds . 'S'));
$query = $this->createQueryBuilder('event')
->where('event.startTime >= :time')
->setParameter('time', $datetime)
->getQuery();
return $query->getResult();
}

Alright, here's a working solution with $duration as a time field (much simpler for the form part of the problem) : a custom query
$entityManager = $this->getEntityManager();
$rsm = new ResultSetMappingBuilder($entityManager);
$rsm->addRootEntityFromClassMetadata('Ormindo\EventBundle\Entity\Event', 'event');
$sql = "
SELECT *
FROM events
WHERE ADDTIME(startTime, duration) > '" . $datetime->format("Y-m-d H:i:s") ."'"
;
$query = $entityManager->createNativeQuery($sql, $rsm);
return $query->getResult();
don't forget to use
use Doctrine\ORM\Query\ResultSetMappingBuilder;
Thank you tchap for your time and quick replies :)

Related

Laravel: Compare two dates against today with Eloquent

So I have events table which has start date and end date.
What I want to do is a comparison between today and start date + end date so if today is between start and end, return that collection which will be displayed on page, if it isn't ignore that event.
Problem is that when I retrieve an event I cannot access it as it is return that it doesn't exist in the collection, but it does after view is returned.
Here's my controller:
public function show($id)
{
$today = date("Y-m-d");
$today_dt = new DateTime($today);
$event = Event::with('businesses')
->get();
$test = $event->startdate;
$test2 = $event->enddate;
//something like if $today is not less that start date and not higher than end date, return that collection?
dd($test);
return view('events.showEvent', compact('event'));
}
use where date function like this
$today = Carbon::now();
$event = Event::with('businesses')
->whereDate('startdate', '<', $today->format('Y-m-d'))
->whereDate('enddate', '>', $today->format('Y-m-d'))
->get();
If I understood your problem correctly, I think this should suffice:
$today = Carbon::today();
$event = Event::whereDate('startdate', '>', $today->format('Y-m-d'))
->whereDate('enddate', '<', $today->format('Y-m-d'))
->with('businesses')
->get();
I hope you did search the internet for this problem in the first place
in Model
public function scopeOfToday($query){
$today = \Carbon\Carbon::today()->format('Y-m-d');
return $query->whereRaw("? BETWEEN startdate and enddate",$today);
}
in Controller
public function show($id)
{
$event = Event::ofToday()->with('businesses')->get();
$test = $event->startdate;
$test2 = $event->enddate;
//something like if $today is not less that start date and not higher than end date, return that collection?
dd($test);
return view('events.showEvent', compact('event'));
}

Laravel get entries in the database in given interval of time

I want to display in the admin panel statitics about users and other things in the database.
For example to show how many users were registered today, this month etc.
For now I am doing this with the users for today the following way:
$users = User::where('admin', 0)->get();
$usersRegisteredToday = array_filter($users->toArray(), function ($user) {
$registerDate = \DateTime::createFromFormat('Y-m-d H:i:s', $user['created_at']);
$registerDate->setTime(0,0,0);
$today = new \DateTime();
$today->setTime(0,0,0);
$diff = $today->diff($registerDate);
$diffDays = (integer)$diff->format("%R%a"); // Extract days count in interval
return $diffDays == 0;
});
return view('admin.index', compact("users", "usersRegisteredToday"));
And in the view:
<p class="text-no">Today: {{ count($usersRegisteredToday) }} </p>
I wonder if there is a better, simpler and faster way to do this, because I think if I get the information for the other things that way it will be very slow and heavy. So i want to know the best and lightest way to do this.
As of Laravel 5.3 we can use whereDate / whereMonth / whereDay / whereYear
For example to get records created today:
$users = User::whereDate('created_at', DB::raw('CURDATE()'))->get();
Possibly a similar question is asked here: Get only records created today in laravel
$todayStart = (new Carbon())->setTime(0, 0);
$todayEnd = (new Carbon())->setTime(23, 59, 59);
$users = User::where('admin', 0)
->where('created_at', '>=', $todayStart)
->where('created_at', '<=', $todayEnd)
->get();
You could use query scopes which would make it even better. Inside User model:
class User extends Model
{
public function scopeCreatedBefore(Carbon $date)
{
return $this->where('created_at', '<=', $date);
}
public function scopeCreatedAfter(Carbon $date)
{
return $this->where('created_at', '>=', $date);
}
}
And for the usage:
$todayStart = (new Carbon())->setTime(0, 0);
$todayEnd = (new Carbon())->setTime(23, 59, 59);
$users = User::where('admin', 0)
->createdAfter($todayStart)
->createdBefore($todayEnd)
->get();
Its quite easy to do it. Im doing this in laravel 5.6
We are working in controller here. Lets say $date1 and $date2 is your range.
First, parse the date to carbon
$olddate = Carbon::parse($date1)->format('Y-m-d');
$newdate = Carbon::parse($date2)->format('Y-m-d');
Now, we get the users within that date range.
$users = Users::latest()
->whereBetween('created_at', array($olddate, $newdate))
->orderBy('id', 'desc')
->get(); // or count if you just want to count
basically, the function will look like below
public function betweendates(Request $request)
{
// get dates from request
$date1= $request->olddate;
$date2= $request->newdate;
// parse date to carbon
$olddate = Carbon::parse($date1)->format('Y-m-d');
$newdate = Carbon::parse($date2)->format('Y-m-d');
// the magic stuff
$users = Users::latest()
->whereBetween('created_at', array($olddate, $newdate))
->orderBy('id', 'desc')
->count();
return view('users.dashboard', compact('users'));
}

doctrine2 with php Datetime month

I have some events stored in a database using doctrine and Symfony2, and those events have a two datetime parameters, start and end of the event. I need to know if those events are active during a certain month, but i cant find a way. I tried with :
$now = new \Datetime('now');
$qb = $this->createQueryBuilder('e');
$qb->where('e.start <= :now AND e.end >= :now')
->setParameter('now', $now);
return $qb->getQuery()
->getArrayResult();
but it limits to the day, and not to the month. Is there a way to check it ? Thanks a lot !
You can use the following code
$monthStart = new DateTime(date('Y-m-01') . " 00:00:00");
$monthEnd = new DateTime(date('Y-m-t'). " 23:59:59");
$qb = $this->createQueryBuilder('e');
$qb
->where('e.start <= :end AND e.end >= :start')
->setParameter('start', $monthStart)
->setParameter('end', $monthEnd);
return $qb->getQuery()
->getArrayResult();

Date Query with Doctrine

I have fields in my table for date, but they contain everything - day, year and month. Can I write a query to get only the records, which has month equal to the current month? I can do this:
$today = new \DateTime();
$month = $today->format('m');
$cat = $em->getRepository('EMBudgetTrackerBundle:Expense')->find(1);
$ex_date = $cat->getDate();
and compare $month and $ex_date, but can I write some kind of query? Something like this:
public function getExpensesByMonth($month)
{
$q = $this->createQueryBuilder('e');
$q->select('e')
->where('e.date = :date')
->setParameter('date', $month);
return $q->getQuery()->getResult();
}
Thank you in advance! :)
If you database column is in DateTime format you can use the DateTime object in your query. As far as I know you can only query for time ranges though.
public function getExpensesByMonth($beginning, $end)
{
$q = $this->createQueryBuilder('e');
$q->select('e')
->where('e.date > :beginning')
->andWhere('e.date < :end')
->setParameter('beginning', $beginning)
->setParameter('end', $end);
return $q->getQuery()->getResult();
}

find the upcomming birthday in week [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How would I get the birthdays of friends who are celebrating their birthday this week, this month and next month using MYSQL and PHP?
I have a mysql table of users with fields UserId, Username, Birthdate (format YYYY-MM-DD). I want to display something on my homepage like this:
Upcoming birthdays:
Fred Smith 24 Aug
Bill Jones 27 Aug
Sarah Connor 1 Sep
David Cassidy 5 Sep
You get the idea - it generates a short list of which birthdays are coming up next, ignoring the year, just based on the day and month. I just have no idea how to do the query - any help would be appreciated!
You can use the mysql DATE_FORMAT() function. This should give you all the birthdays between the current day, and 7 days from now:
SELECT username, DATE_FORMAT(Birthdate,'%M %d') as 'birthday' FROM table WHERE DATE_FORMAT(Birthdate,'%m-%d') BETWEEN DATE_FORMAT(CURDATE(),'%m-%d') AND DATE_FORMAT(ADDDATE(NOW(), INTERVAL 7 DAY), '%m-%d') ORDER BY DATE_FORMAT(Birthdate,'%m-%d');
Another option is to create a function that will sit in a helper class, or go into your user class perhaps:-
/**
* Fetches a list of birthdays coming up in the following week
* #return array an array user's birthdays
*/
public function getBirthdays()
{
$date = new DateTime();
$date->setTime(0, 0, 1);
$today = $date->getTimestamp();
$week = new DateInterval('P7D');
$date->add($week);
$date->setTime(23, 59, 59);
$nextWeek = $date->getTimestamp();
$select = new Zend_Db_Select(Zend_Db_Table::getDefaultAdapter());
$select ->from('users', array('user_name', 'user_dob'))
->where('user_dob > ?', $today)
->where('user_dob < ?', $nextWeek);
return $select->query()->fetchAll();
}
Then you just do:-
$birthdays = $classYouMade->getBirthdays();
$html = '';
foreach($birthdays as $bday){
$html .= "Happy Birthday to {$bday['user_name']} on ";
$html .= date('jS F', $bday['user_dob']) . '<br/>';
}
echo $html;
It's quite long, but is self documenting (I think) and you can come back to it in a year's time and see exactly what is happening at a glance.
I have ofcourse made some assumptions about how you are storing date etc (I always use unix timestamps), but I'm sure you can adapt it to your use case if you wish to use it.
First, you need to retrieve a list of your users as follow:
$adapter = Zend_Db_Table::getDefaultAdapter()
$table = $adapter->getDbTable()
$select = $table->select();
$select->where('active = ?', true); // if needed
$user = $table->fetchAll($select);
Your getDbTable would be something very similar to the one in Zend Quickstart :
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (! $dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('My_Users_DbTable_User');
}
return $this->_dbTable;
}
And in My/Users/DbTable/User a simpla class that contains:
class My_Users_DbTable_User extends Zend_Db_Table_Abstract
{
protected $_name = 'users';
}
Finally, when you retrieved your data from the database, you can iterate through each row you fetched using current() and toArray()methods. See Zend_Db_Table_Row documentation for more details.
In order to display only the day and month of a birthdate, you can use Zend_Date which is pretty useful.
$date = "1970-12-10";
$d = new Zend_Date($date);
echo $d->toString(Zend_Date::DAY) . " " . $d->toString(Zend_Date::MONTH_NAME_SHORT);
// output: 10 Dec
You can query this with something like:
SELECT username, birthdate FROM table WHERE birthdate >= beginning_of_week AND birthdate <= end_of_week
You'd probably have to calculate the week range you want in whatever script you're querying from.
You should be able to get the list with a simple SQL query:
select UserId, Username, Birthdate from Users where Birthdate >= CURDATE() and Birthdate <= DATE_ADD(CURDATE(), INTERVAL + 2 WEEK) order by Birthdate ASC
Then you can format the text using DateTime::format() in PHP.
while ($row = mysql_fetch_assoc($res))
{
$birthday = new DateTime($row['Birthdate']);
print $row['Username']." ".$birthday->format('d M')."\n";
}

Categories