(Symfony 3.1) Объекты PHP Doctrine Group по дате и времени

Я пытаюсь сгруппировать свои объекты по дате и времени. каждая сущность имеет следующие столбцы: идентификатор, устройство, запуск, остановка, IP-адрес.

Я хочу иметь возможность получать сущности в пределах диапазона дат и группировать их по дате (дням) по количеству часов в днях.

Это то, что я имею до сих пор

public function findAllGroupedByDate($from = null, $to = null)
{
$from = isset($from) && !is_null($from) ? $from : date('Y-m-d', time());
$to = isset($to) && !is_null($to) ? $to : date('Y-m-d', time());

$from = new \DateTime("-3 days");
$to = new \DateTime("1 days");

$from = date("Y-m-d", $from->getTimestamp());
$to = date("Y-m-d", $to->getTimestamp());

$q = $this->getEntityManager()->createQueryBuilder()
->select("timelog")
->from("AppBundle:Timelog", "timelog")
->where("timelog.start BETWEEN :from AND :to")
->setParameter("from", $from)
->setParameter("to", $to)
->orderBy("timelog.stop")
->getQuery();
return $q->getResult();
}

public function findFromToday()
{
$q = $this->createQueryBuilder('t')
->select('t.id', 't.start', 't.stop', 't.stop')
->where("t.start >= :today")
->setParameter("today", date('Y-m-d', time()))
->groupBy("t.id", "t.stop")
->orderBy("t.start", "asc")
->getQuery();

return $q->getResult();
}

Это код для моего класса репозитория.

и код для моего контроллера выглядит так:

$timelogsRepo = $this->getDoctrine()->getRepository('AppBundle:Timelog');

// Grab logs from today
$timelogsCollection = $timelogsRepo->findFromToday();
$tmpLogs = $timelogsRepo->findAllGroupedByDate();

// THIS SECTION IS FOR CALCULATING HOURS & MINUTES
$minutes = 0;
$hours = 0;
foreach($timelogsCollection as $log)
{
$time1 = $log['start'];
$time2 = $log['stop'];
$interval = date_diff($time1, $time2);

$hours += $interval->h;
$minutes += $interval->i;

}$minutes = $minutes >59 ? $minutes/60 : $minutes;return $this->render(':Timelog:index.html.twig', [
'timelogs' => $logsOut,
'hours' => $hours,
'minutes' => $minutes
]);

До сих пор я был в состоянии вычислить общее потраченное время для данного дня (только один день). Теперь я хотел бы получить все сущности, сгруппировать их по одной дате (дню) и вернуть данные с интервалом.

Пример таблицы БД выглядит следующим образом [id, device_id, start, stop, ipaddress]

1 1 2016-08-09 09:00:06 2016-08-09 12:00:06 127.0.0.1
2 1 2016-08-08 07:00:00 2016-08-08 13:00:00 127.0.0.1
3 1 2016-08-08 13:10:00 2016-08-08 15:05:00 127.0.0.1

Так что в этом случае мой вывод будет выглядеть примерно так:

[
0 => ["date" => "2016-08-09", "hours" => 9.00, "ipaddress" =>      "127.0.0.1"],
1 => ["date" => "2016-08-09", "hours" => 1.45, "ipaddress" => "127.0.0.1"]
]

интервал зависит от запуска и остановки, оба являются типом DateTime

Я пытался использовать doctrine-extensions: oro / doctrine-extensions, но теперь я получаю ошибку исключения:

[2/2] QueryException: [Syntax Error] line 0, col 50: Error: Expected Unit is not valid for TIMESTAMPDIFF function. Supported units are: "MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR", got 'stop'

Мой метод хранилища выглядит так:

public function findByToday()
{
$fields = array(
'DATE(stop) as stop',
'TIME(SUM(TIMESTAMPDIFF(stop, start))) AS tdiff',
'device_id',
'ipaddress'
);

$q = $this->createQueryBuilder('t')
->select($fields)
->where('DATE(stop) = :today')
->setParameter('today', date('Y-m-d', time()))
->groupBy('device_id')
->getQuery();

return $q->getResult();

}

моя таблица БД:

id  device_id   start   stop    ipaddress
5   1   2016-08-09 09:00:06 2016-08-09 12:00:06 127.0.0.1
6   1   2016-08-08 07:00:00 2016-08-08 13:00:00 127.0.0.1
7   1   2016-08-08 13:10:00 2016-08-08 15:05:00 127.0.0.1

Кстати, я использую Symfony 3, это может быть проблемой?

1

Решение

Исходя из вашей таблицы выше (если я правильно понял), я бы попытался получить данные напрямую с помощью MYSQL, а затем перейти к Doctrine.

Если у вас есть таблица ниже:

CREATE TABLE `testdevices` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`device` INT(11) NULL DEFAULT NULL,
`dstart` DATETIME NULL DEFAULT NULL,
`dend` DATETIME NULL DEFAULT NULL,
`ip` TINYTEXT NULL,
PRIMARY KEY (`id`)
);

И заполняется тестовыми данными ниже (я создал два устройства, второе из которых было удобно активным в течение точных 3 часов на сегодняшнюю дату):

mysql> select * from testdevices;
+----+--------+---------------------+---------------------+-----------+
| id | device | dstart              | dend                | ip        |
+----+--------+---------------------+---------------------+-----------+
|  1 |      1 | 2016-08-09 09:00:06 | 2016-08-09 12:00:06 | 127.0.0.1 |
|  2 |      1 | 2016-08-08 07:00:00 | 2016-08-08 13:00:00 | 127.0.0.1 |
|  3 |      1 | 2016-08-08 13:10:00 | 2016-08-11 22:14:46 | 127.0.0.1 |
|  4 |      2 | 2016-08-11 13:00:00 | 2016-08-11 14:00:00 | 127.0.0.1 |
|  5 |      2 | 2016-08-11 15:00:00 | 2016-08-11 16:00:00 | 127.0.0.1 |
|  6 |      2 | 2016-08-11 17:00:00 | 2016-08-11 18:00:00 | 127.0.0.1 |
+----+--------+---------------------+---------------------+-----------+
6 rows in set (0.00 sec)

Следуя запросу MYSQL, я считаю, что выведите нужные данные:

SELECT DATE(dend) as dend, TIME(SUM(TIMEDIFF(dend, dstart))) AS tdiff, device, ip
FROM testdevices WHERE DATE(dend) = '2016-08-11'
GROUP BY device ;

И результат будет выглядеть так:

+------------+----------+--------+-----------+
| dend       | tdiff    | device | ip        |
+------------+----------+--------+-----------+
| 2016-08-11 | 81:04:46 |      1 | 127.0.0.1 |
| 2016-08-11 | 03:00:00 |      2 | 127.0.0.1 |
+------------+----------+--------+-----------+
2 rows in set (0.01 sec)

Обратите внимание, что время второго устройства правильное. Теперь остается вопрос, как это сделать в Учении. Насколько я знаю TIMEDIFF функция еще не является частью доктрины, поэтому я бы предложил 2 разных подхода:

  1. Напишите свою собственную функцию как в
    http://www.doctrine-project.org/2010/03/29/doctrine2-custom-dql-udfs.html#date-diff (В этой ссылке есть пример DATEDIFF, поэтому его легко настроить), или
  2. использование https://packagist.org/packages/oro/doctrine-extensions

Ваша последняя функция репозитория в Doctrine / Symfony2 с установленными oro / doctrine-extensions будет выглядеть примерно так:

 $fields = array(
'DATE(dend) as dend',
'SUM(TIMESTAMPDIFF(SECOND, dend, dstart)) AS tdiff',
'device',
'ip'
);

public function findFromToday()
{
$q = $this->createQueryBuilder('t')
->select($fields)
->where('DATE(dend) = :today')
->setParameter('today', date('Y-m-d', time()))
->groupBy('device')
->getQuery();

return $q->getResult();

Я написал эту функцию, не проверяя ее вообще и от всей головы. Вы, вероятно, обнаружите, что это не удается. Это даст разницу во времени в секундах как TIMESTAMPDIFF требует указания единиц измерения.
Установите oro / doctrine-extensions с помощью

composer require oro/doctrine-extensions
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]