【问题标题】:(Symfony 3.1) PHP Doctrine Group entities by datetime(Symfony 3.1) PHP Doctrine Group 实体按日期时间
【发布时间】:2016-08-11 19:14:45
【问题描述】:

我正在尝试按日期时间对我的实体进行分组。每个实体都有以下列:id、device、start、stop、ipaddress。

我希望能够获取某个日期范围内的实体,并按日期(天)对它们进行分组,然后是每天有多少小时。

这是我目前所拥有的

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
    ]);

到目前为止,我能够计算给定一天(仅一天)的总花费时间。现在我想获取所有实体,按相同的日期(天)对它们进行分组并返回具有间隔的数据。

示例 DB 表如下所示[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"]
]

时间间隔取决于 start 和 stop 都是 DateTime 类型

我曾尝试使用学说扩展: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,这可能是问题吗?

【问题讨论】:

    标签: php doctrine-orm grouping intervals symfony-3.1


    【解决方案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)
    

    请注意,第二个设备时间是正确的。现在,剩下的问题是如何在 Doctrine 中做到这一点。据我所知,TIMEDIFF 函数还不是 Doctrine 的一部分,所以我会提出 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
    

    【讨论】:

    • Tomislav 感谢您的回复,我会尝试一下,会告诉您进展如何
    • 您好,我已经尝试过了,但仍然无法正常工作,现在我收到一个预期错误:[2/2] QueryException: [Syntax Error] line 0, col 50: Error: Expected Unit is not valid用于 TIMESTAMPDIFF 函数。支持的单位有:"MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR", got 'stop'
    • 我加在上面,在下面
    • 很明显,TIMESTAMPDIFF 和 TIMEDIFF 不是同一个函数。您需要向 TIMESTAMPDIFF TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) 提供单位 示例:SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');见dev.mysql.com/doc/refman/5.5/en/…
    • @Jan Burger 我改变了我原来的答案。这会在几秒钟内给你答案。
    猜你喜欢
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    相关资源
    最近更新 更多