From fe0b89903289f69eb0a99dd553ccc28880435f1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Noack?= <noack@data-quest.de>
Date: Mon, 25 Mar 2024 15:09:39 +0000
Subject: [PATCH] =?UTF-8?q?Resolve=20#3893=20"Performance=20des=20pers?=
 =?UTF-8?q?=C3=B6nlichen=20Kalenders=20/=20Gruppenkalender=20ist=20schlech?=
 =?UTF-8?q?t"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #3893

Merge request studip/studip!2746
---
 .../5.5.28_biest3893_performance_calendar.php | 25 +++++++++++++++
 .../calendar/CalendarDateAssignment.class.php | 32 +++++++++++--------
 2 files changed, 44 insertions(+), 13 deletions(-)
 create mode 100644 db/migrations/5.5.28_biest3893_performance_calendar.php

diff --git a/db/migrations/5.5.28_biest3893_performance_calendar.php b/db/migrations/5.5.28_biest3893_performance_calendar.php
new file mode 100644
index 00000000000..82a86fecbe5
--- /dev/null
+++ b/db/migrations/5.5.28_biest3893_performance_calendar.php
@@ -0,0 +1,25 @@
+<?php
+
+final class Biest3893PerformanceCalendar extends Migration
+{
+    public function description()
+    {
+        return 'add index to calendar tables';
+    }
+
+    public function up()
+    {
+        $db = DBManager::get();
+        $db->exec("DELETE FROM `calendar_date_exceptions` WHERE `date` = '1970-01-01'");
+        $db->exec("ALTER TABLE `calendar_date_exceptions` ADD INDEX(`calendar_date_id`)");
+        $db->exec("ALTER TABLE `calendar_dates` ADD INDEX `repetition_type` (`repetition_type`, `repetition_end`)");
+        $db->exec("ALTER TABLE `calendar_dates` ADD INDEX `begin` (`begin`)");
+        try {
+            $db->exec("ALTER TABLE `calendar_dates` DROP INDEX `uid`");
+        } catch (PDOException $exception) {}
+    }
+
+    public function down()
+    {
+    }
+}
diff --git a/lib/models/calendar/CalendarDateAssignment.class.php b/lib/models/calendar/CalendarDateAssignment.class.php
index 18cd6101cb3..fbd21a7d947 100644
--- a/lib/models/calendar/CalendarDateAssignment.class.php
+++ b/lib/models/calendar/CalendarDateAssignment.class.php
@@ -232,29 +232,35 @@ class CalendarDateAssignment extends SimpleORMap implements Event
         $sql = "JOIN `calendar_dates`
             ON calendar_date_id = `calendar_dates`.`id`
             WHERE
-            `calendar_date_assignments`.`range_id` = :range_id ";
+            `calendar_date_assignments`.`range_id` = :range_id
+            AND
+            `access` IN ( :access_levels ) ";
         if (!$with_declined) {
             $sql .= "AND `calendar_date_assignments`.`participation` <> 'DECLINED' ";
         }
-        $sql .= "AND (
-                `calendar_dates`.`begin` BETWEEN :begin AND :end
-                OR
-                (`calendar_dates`.`begin` <= :end AND `calendar_dates`.`repetition_type` <> ''
-                    AND `calendar_dates`.`repetition_end` > :begin)
-                OR
-                :begin BETWEEN `calendar_dates`.`begin` AND `calendar_dates`.`end`
-            )
-            AND
-            `access` IN ( :access_levels )
-            ORDER BY `calendar_dates`.`begin` ASC";
+        $sql_single = $sql . " AND
+                `calendar_dates`.`begin` < :end  AND :begin < `calendar_dates`.`end`
+            ";
 
-        $events = self::findBySql($sql, [
+        $events = self::findBySql($sql_single, [
             'range_id'      => $range_id,
             'begin'         => $begin->getTimestamp(),
             'end'           => $end->getTimestamp(),
             'access_levels' => $access_levels
         ]);
 
+
+        $sql_repetition = $sql . " AND `calendar_dates`.`begin` < :end AND `calendar_dates`.`repetition_type` IN ('DAYLY', 'WEEKLY', 'MONTHLY', 'YEARLY')
+                    AND `calendar_dates`.`repetition_end` > :begin
+            ";
+
+        $events = array_merge($events, self::findBySql($sql_repetition, [
+            'range_id'      => $range_id,
+            'begin'         => $begin->getTimestamp(),
+            'end'           => $end->getTimestamp(),
+            'access_levels' => $access_levels
+        ]));
+
         $m_start = clone $begin;
         $m_end = clone $end;
         $events_created = [];
-- 
GitLab