MDL-60958 calendar: stop db query in repeat collection constructor

Stop loading the parent record in the constructor because it is an
unnecessary DB query for each event instantiation.

Return null on get_repeats() for events that don't have repeats.
This commit is contained in:
Ryan Wyllie 2017-11-08 06:20:02 +00:00
parent 315a0a3aaf
commit 28852998f6
8 changed files with 72 additions and 65 deletions

View file

@ -127,7 +127,7 @@ class event implements event_interface {
proxy_interface $course = null, proxy_interface $course = null,
proxy_interface $group = null, proxy_interface $group = null,
proxy_interface $user = null, proxy_interface $user = null,
event_collection_interface $repeats, event_collection_interface $repeats = null,
proxy_interface $coursemodule = null, proxy_interface $coursemodule = null,
$type, $type,
times_interface $times, times_interface $times,

View file

@ -106,9 +106,10 @@ interface event_interface {
public function get_times(); public function get_times();
/** /**
* Get repeats of this event. * Get repeats of this event or null if the event has no
* repeats.
* *
* @return event_collection_interface * @return event_collection_interface|null
*/ */
public function get_repeats(); public function get_repeats();

View file

@ -27,7 +27,6 @@ namespace core_calendar\local\event\entities;
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
use core_calendar\local\event\factories\event_factory_interface; use core_calendar\local\event\factories\event_factory_interface;
use core_calendar\local\event\exceptions\no_repeat_parent_exception;
/** /**
* Class representing a collection of repeat events. * Class representing a collection of repeat events.
@ -64,18 +63,27 @@ class repeat_event_collection implements event_collection_interface {
/** /**
* Constructor. * Constructor.
* *
* @param int $parentid ID of the parent event. * @param stdClass $dbrow The event dbrow that is being repeated.
* @param int $repeatid If non-zero this will be used as the parent id.
* @param event_factory_interface $factory Event factory. * @param event_factory_interface $factory Event factory.
* @throws no_repeat_parent_exception If the parent record can't be loaded.
*/ */
public function __construct($parentid, $repeatid, event_factory_interface $factory) { public function __construct($dbrow, event_factory_interface $factory) {
$this->parentid = $repeatid ? $repeatid : $parentid; $eventid = $dbrow->id;
$this->factory = $factory; $repeatid = $dbrow->repeatid;
if (!$this->get_parent_record()) { if (empty($repeatid)) {
throw new no_repeat_parent_exception(sprintf('No record found for id %d', $parentid)); $this->parentrecord = $dbrow;
$this->parentid = $eventid;
} else {
$this->parentid = $repeatid;
} }
if ($eventid === $repeatid) {
// This means the record we've been given is the parent
// record.
$this->parentrecord = $dbrow;
}
$this->factory = $factory;
} }
public function get_id() { public function get_id() {
@ -109,11 +117,11 @@ class repeat_event_collection implements event_collection_interface {
protected function get_parent_record() { protected function get_parent_record() {
global $DB; global $DB;
if (isset($this->parentrecord)) { if (!isset($this->parentrecord)) {
return $this->parentrecord; $this->parentrecord = $DB->get_record('event', ['id' => $this->parentid]);
} }
return $DB->get_record('event', ['id' => $this->parentid]); return $this->parentrecord;
} }
/** /**

View file

@ -1,36 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* No repeat parent exception.
*
* @package core_calendar
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_calendar\local\event\exceptions;
defined('MOODLE_INTERNAL') || die();
/**
* No repeat parent exception.
*
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class no_repeat_parent_exception extends \moodle_exception {
}

View file

@ -165,6 +165,12 @@ abstract class event_abstract_factory implements event_factory_interface {
}); });
} }
if (!empty($dbrow->repeatid)) {
$repeatcollection = new repeat_event_collection($dbrow, $this);
} else {
$repeatcollection = null;
}
$event = new event( $event = new event(
$dbrow->id, $dbrow->id,
$dbrow->name, $dbrow->name,
@ -173,7 +179,7 @@ abstract class event_abstract_factory implements event_factory_interface {
$course, $course,
$group, $group,
$user, $user,
new repeat_event_collection($dbrow->id, $dbrow->repeatid, $this), $repeatcollection,
$module, $module,
$dbrow->eventtype, $dbrow->eventtype,
new event_times( new event_times(

View file

@ -98,6 +98,7 @@ class event_mapper implements event_mapper_interface {
$properties->userid = empty($properties->userid) ? 0 : $properties->userid; $properties->userid = empty($properties->userid) ? 0 : $properties->userid;
$properties->modulename = empty($properties->modulename) ? 0 : $properties->modulename; $properties->modulename = empty($properties->modulename) ? 0 : $properties->modulename;
$properties->instance = empty($properties->instance) ? 0 : $properties->instance; $properties->instance = empty($properties->instance) ? 0 : $properties->instance;
$properties->repeatid = empty($properties->repeatid) ? 0 : $properties->repeatid;
return new \calendar_event($properties); return new \calendar_event($properties);
} }
@ -122,7 +123,7 @@ class event_mapper implements event_mapper_interface {
'categoryid' => $event->get_category() ? $event->get_category()->get('id') : null, 'categoryid' => $event->get_category() ? $event->get_category()->get('id') : null,
'groupid' => $event->get_group() ? $event->get_group()->get('id') : null, 'groupid' => $event->get_group() ? $event->get_group()->get('id') : null,
'userid' => $event->get_user() ? $event->get_user()->get('id') : null, 'userid' => $event->get_user() ? $event->get_user()->get('id') : null,
'repeatid' => $event->get_repeats()->get_id(), 'repeatid' => $event->get_repeats() ? $event->get_repeats()->get_id() : null,
'modulename' => $event->get_course_module() ? $event->get_course_module()->get('modname') : null, 'modulename' => $event->get_course_module() ? $event->get_course_module()->get('modname') : null,
'instance' => $event->get_course_module() ? $event->get_course_module()->get('instance') : null, 'instance' => $event->get_course_module() ? $event->get_course_module()->get('instance') : null,
'eventtype' => $event->get_type(), 'eventtype' => $event->get_type(),

View file

@ -108,7 +108,7 @@ class core_calendar_container_testcase extends advanced_testcase {
} }
$this->assertEquals($dbrow->userid, $event->get_user()->get('id')); $this->assertEquals($dbrow->userid, $event->get_user()->get('id'));
$this->assertEquals($legacyevent->id, $event->get_repeats()->get_id()); $this->assertEquals(null, $event->get_repeats());
$this->assertEquals($dbrow->modulename, $event->get_course_module()->get('modname')); $this->assertEquals($dbrow->modulename, $event->get_course_module()->get('modname'));
$this->assertEquals($dbrow->instance, $event->get_course_module()->get('instance')); $this->assertEquals($dbrow->instance, $event->get_course_module()->get('instance'));
$this->assertEquals($dbrow->timestart, $event->get_times()->get_start_time()->getTimestamp()); $this->assertEquals($dbrow->timestart, $event->get_times()->get_start_time()->getTimestamp());

View file

@ -44,15 +44,35 @@ use core_calendar\local\event\factories\event_factory_interface;
*/ */
class core_calendar_repeat_event_collection_testcase extends advanced_testcase { class core_calendar_repeat_event_collection_testcase extends advanced_testcase {
/** /**
* Test that creating a repeat collection for a parent that doesn't * Test that the collection id is set to the parent id if the repeat id
* exist throws an exception. * is falsey.
*/ */
public function test_no_parent_collection() { public function test_parent_id_no_repeat_id() {
$this->resetAfterTest(true); $this->resetAfterTest(true);
$parentid = 123122131; $dbrow = (object) [
'id' => 123122131,
'repeatid' => null
];
$factory = new core_calendar_repeat_event_collection_event_test_factory(); $factory = new core_calendar_repeat_event_collection_event_test_factory();
$this->expectException('\core_calendar\local\event\exceptions\no_repeat_parent_exception'); $collection = new repeat_event_collection($dbrow, $factory);
$collection = new repeat_event_collection($parentid, null, $factory);
$this->assertEquals($dbrow->id, $collection->get_id());
}
/**
* Test that the repeat id is set to the parent id if the repeat id
* is not falsey (even if the parent id is provided).
*/
public function test_parent_id_and_repeat_id() {
$this->resetAfterTest(true);
$dbrow = (object) [
'id' => 123122131,
'repeatid' => 5647839
];
$factory = new core_calendar_repeat_event_collection_event_test_factory();
$collection = new repeat_event_collection($dbrow, $factory);
$this->assertEquals($dbrow->repeatid, $collection->get_id());
} }
/** /**
@ -68,13 +88,16 @@ class core_calendar_repeat_event_collection_testcase extends advanced_testcase {
'repeat' => 1, 'repeat' => 1,
'repeats' => 0 'repeats' => 0
]); ]);
$parentid = $event->id; $dbrow = (object) [
'id' => $event->id,
'repeatid' => null
];
$factory = new core_calendar_repeat_event_collection_event_test_factory(); $factory = new core_calendar_repeat_event_collection_event_test_factory();
// Event collection with no repeats. // Event collection with no repeats.
$collection = new repeat_event_collection($parentid, null, $factory); $collection = new repeat_event_collection($dbrow, $factory);
$this->assertEquals($parentid, $collection->get_id()); $this->assertEquals($event->id, $collection->get_id());
$this->assertEquals(0, $collection->get_num()); $this->assertEquals(0, $collection->get_num());
$this->assertNull($collection->getIterator()->next()); $this->assertNull($collection->getIterator()->next());
} }
@ -94,6 +117,10 @@ class core_calendar_repeat_event_collection_testcase extends advanced_testcase {
'repeats' => 0 'repeats' => 0
]); ]);
$parentid = $event->id; $parentid = $event->id;
$dbrow = (object) [
'id' => $parentid,
'repeatid' => null
];
$repeats = []; $repeats = [];
for ($i = 1; $i < 4; $i++) { for ($i = 1; $i < 4; $i++) {
@ -108,7 +135,7 @@ class core_calendar_repeat_event_collection_testcase extends advanced_testcase {
} }
// Event collection with no repeats. // Event collection with no repeats.
$collection = new repeat_event_collection($parentid, null, $factory); $collection = new repeat_event_collection($dbrow, $factory);
$this->assertEquals($parentid, $collection->get_id()); $this->assertEquals($parentid, $collection->get_id());
$this->assertEquals(count($repeats), $collection->get_num()); $this->assertEquals(count($repeats), $collection->get_num());
@ -167,7 +194,7 @@ class core_calendar_repeat_event_collection_event_test_factory implements event_
new std_proxy($dbrow->courseid, $identity), new std_proxy($dbrow->courseid, $identity),
new std_proxy($dbrow->groupid, $identity), new std_proxy($dbrow->groupid, $identity),
new std_proxy($dbrow->userid, $identity), new std_proxy($dbrow->userid, $identity),
new repeat_event_collection($dbrow->id, null, $this), $dbrow->repeatid ? new repeat_event_collection($dbrow, $this) : null,
new std_proxy($dbrow->instance, $identity), new std_proxy($dbrow->instance, $identity),
$dbrow->type, $dbrow->type,
new event_times( new event_times(