mirror of
https://github.com/moodle/moodle.git
synced 2025-03-24 09:30:17 +01:00
Merge branch 'MDL-56516-master' of git://github.com/andrewnicols/moodle
This commit is contained in:
commit
8823be0b60
135
admin/tool/usertours/classes/cache.php
Normal file
135
admin/tool/usertours/classes/cache.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Cache manager.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_usertours;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Cache manager.
|
||||
*
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache {
|
||||
/**
|
||||
* @var CACHENAME_TOUR The name of the cache used for storing tours.
|
||||
*/
|
||||
const CACHENAME_TOUR = 'tourdata';
|
||||
|
||||
/**
|
||||
* @var CACHEKEY_TOUR The name of the key used for storing tours.
|
||||
*/
|
||||
const CACHEKEY_TOUR = 'tours';
|
||||
|
||||
/**
|
||||
* @var CACHENAME_STEP The name of the cache used for storing steps.
|
||||
*/
|
||||
const CACHENAME_STEP = 'stepdata';
|
||||
|
||||
/**
|
||||
* Fetch all enabled tours.
|
||||
*/
|
||||
public static function get_enabled_tourdata() {
|
||||
global $DB;
|
||||
|
||||
$cache = \cache::make('tool_usertours', self::CACHENAME_TOUR);
|
||||
|
||||
$data = $cache->get(self::CACHEKEY_TOUR);
|
||||
if ($data === false) {
|
||||
$sql = <<<EOF
|
||||
SELECT t.*
|
||||
FROM {tool_usertours_tours} t
|
||||
INNER JOIN {tool_usertours_steps} s ON s.tourid = t.id
|
||||
WHERE t.enabled = 1
|
||||
GROUP BY t.id
|
||||
HAVING COUNT(s.id) > 0
|
||||
ORDER BY t.sortorder ASC
|
||||
EOF;
|
||||
|
||||
$data = $DB->get_records_sql($sql);
|
||||
$cache->set('tours', $data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all enabled tours matching the specified target.
|
||||
*
|
||||
* @param string $targetmatch The URL to match.
|
||||
*/
|
||||
public static function get_matching_tourdata($targetmatch) {
|
||||
$tours = self::get_enabled_tourdata();
|
||||
|
||||
return array_filter($tours, function($tour) use ($targetmatch) {
|
||||
$pattern = preg_quote($tour->pathmatch, '@');
|
||||
$pattern = str_replace('%', '.*', $pattern);
|
||||
return !!preg_match("@{$pattern}@", $targetmatch);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify of changes to any tour to clear the tour cache.
|
||||
*/
|
||||
public static function notify_tour_change() {
|
||||
$cache = \cache::make('tool_usertours', self::CACHENAME_TOUR);
|
||||
$cache->delete(self::CACHEKEY_TOUR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the tour data for the specified tour.
|
||||
*
|
||||
* @param int $tourid The ID of the tour to fetch steps for
|
||||
*/
|
||||
public static function get_stepdata($tourid) {
|
||||
global $DB;
|
||||
|
||||
$cache = \cache::make('tool_usertours', self::CACHENAME_STEP);
|
||||
|
||||
$data = $cache->get($tourid);
|
||||
if ($data === false) {
|
||||
$sql = <<<EOF
|
||||
SELECT s.*
|
||||
FROM {tool_usertours_steps} s
|
||||
WHERE s.tourid = :tourid
|
||||
ORDER BY s.sortorder ASC
|
||||
EOF;
|
||||
|
||||
$data = $DB->get_records_sql($sql, ['tourid' => $tourid]);
|
||||
$cache->set($tourid, $data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
/**
|
||||
* Notify of changes to any step to clear the step cache for that tour.
|
||||
*
|
||||
* @param int $tourid The ID of the tour to clear the step cache for
|
||||
*/
|
||||
public static function notify_step_change($tourid) {
|
||||
$cache = \cache::make('tool_usertours', self::CACHENAME_STEP);
|
||||
$cache->delete($tourid);
|
||||
}
|
||||
}
|
@ -432,6 +432,11 @@ class helper {
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
|
||||
// Notify the cache that a tour has changed.
|
||||
// Tours are only stored in the cache if there are steps.
|
||||
// If there step count has changed for some reason, this will change the potential cache results.
|
||||
cache::notify_tour_change();
|
||||
}
|
||||
|
||||
|
||||
@ -442,11 +447,8 @@ class helper {
|
||||
* @return stdClass[]
|
||||
*/
|
||||
public static function get_steps($tourid) {
|
||||
global $DB;
|
||||
$steps = cache::get_stepdata($tourid);
|
||||
|
||||
$order = 'sortorder ASC';
|
||||
|
||||
$steps = $DB->get_records('tool_usertours_steps', array('tourid' => $tourid), $order);
|
||||
$return = [];
|
||||
foreach ($steps as $step) {
|
||||
$return[$step->id] = step::load_from_record($step);
|
||||
|
@ -559,22 +559,14 @@ class manager {
|
||||
* @return tour
|
||||
*/
|
||||
public static function get_matching_tours(\moodle_url $pageurl) {
|
||||
global $DB, $PAGE;
|
||||
global $PAGE;
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT * FROM {tool_usertours_tours}
|
||||
WHERE enabled = 1
|
||||
AND ? LIKE pathmatch
|
||||
ORDER BY sortorder ASC
|
||||
EOF;
|
||||
|
||||
$tours = $DB->get_records_sql($sql, array(
|
||||
$pageurl->out_as_local_url(),
|
||||
));
|
||||
$tours = cache::get_matching_tourdata($pageurl->out_as_local_url());
|
||||
|
||||
foreach ($tours as $record) {
|
||||
$tour = tour::load_from_record($record);
|
||||
if ($tour->is_enabled() && $tour->matches_all_filters($PAGE->context) && $tour->count_steps() > 0) {
|
||||
if ($tour->is_enabled() && $tour->matches_all_filters($PAGE->context)) {
|
||||
return $tour;
|
||||
}
|
||||
}
|
||||
|
@ -485,8 +485,19 @@ class step {
|
||||
$this->id = $DB->insert_record('tool_usertours_steps', $record);
|
||||
}
|
||||
|
||||
$this->get_tour()->reset_step_sortorder();
|
||||
|
||||
$this->reload();
|
||||
|
||||
// Notify of a change to the step configuration.
|
||||
// This must be done separately to tour change notifications.
|
||||
cache::notify_step_change($this->get_tourid());
|
||||
|
||||
// Notify the cache that a tour has changed.
|
||||
// Tours are only stored in the cache if there are steps.
|
||||
// If there step count has changed for some reason, this will change the potential cache results.
|
||||
cache::notify_tour_change();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -502,6 +513,15 @@ class step {
|
||||
|
||||
$DB->delete_records('tool_usertours_steps', array('id' => $this->id));
|
||||
$this->get_tour()->reset_step_sortorder();
|
||||
|
||||
// Notify of a change to the step configuration.
|
||||
// This must be done separately to tour change notifications.
|
||||
cache::notify_step_change($this->get_id());
|
||||
|
||||
// Notify the cache that a tour has changed.
|
||||
// Tours are only stored in the cache if there are steps.
|
||||
// If there step count has changed for some reason, this will change the potential cache results.
|
||||
cache::notify_tour_change();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -523,6 +523,9 @@ class tour {
|
||||
|
||||
$this->reload();
|
||||
|
||||
// Notify the cache that a tour has changed.
|
||||
cache::notify_tour_change();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -566,6 +569,10 @@ class tour {
|
||||
$index++;
|
||||
}
|
||||
|
||||
// Notify of a change to the step configuration.
|
||||
// Note: Do not notify of a tour change here. This is only a step change for a tour.
|
||||
cache::notify_step_change($this->get_id());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
42
admin/tool/usertours/db/caches.php
Normal file
42
admin/tool/usertours/db/caches.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Plugin cache definitions.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$definitions = array(
|
||||
'tourdata' => array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'simplekeys' => true,
|
||||
'simpledata' => true,
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 1,
|
||||
),
|
||||
'stepdata' => array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'simplekeys' => true,
|
||||
'simpledata' => true,
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 1,
|
||||
),
|
||||
);
|
@ -27,6 +27,8 @@ $string['appliesto'] = 'Applies to';
|
||||
$string['block'] = 'Block';
|
||||
$string['block_named'] = 'Block named \'{$a}\'';
|
||||
$string['bottom'] = 'Bottom';
|
||||
$string['cachedef_stepdata'] = 'List of User Tour steps';
|
||||
$string['cachedef_tourdata'] = 'List of enabled User Tours information which are fetched on every page';
|
||||
$string['description'] = 'Description';
|
||||
$string['confirmstepremovalquestion'] = 'Are you sure that you wish to remove this step?';
|
||||
$string['confirmstepremovaltitle'] = 'Confirm step removal';
|
||||
|
340
admin/tool/usertours/tests/cache_test.php
Normal file
340
admin/tool/usertours/tests/cache_test.php
Normal file
@ -0,0 +1,340 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Tests for cache.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once(__DIR__ . '/helper_trait.php');
|
||||
|
||||
/**
|
||||
* Tests for cache.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cache_testcase extends advanced_testcase {
|
||||
// There are shared helpers for these tests in the helper trait.
|
||||
use tool_usertours_helper_trait;
|
||||
|
||||
/**
|
||||
* Test that get_enabled_tourdata does not return disabled tours.
|
||||
*/
|
||||
public function test_get_enabled_tourdata_disabled() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour = $this->helper_create_tour((object)['enabled' => false]);
|
||||
$this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEmpty($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_enabled_tourdata does not return an enabled but empty tour.
|
||||
*/
|
||||
public function test_get_enabled_tourdata_enabled_no_steps() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->helper_create_tour();
|
||||
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEmpty($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_enabled_tourdata returns a tour with steps.
|
||||
*/
|
||||
public function test_get_enabled_tourdata_enabled() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create two tours. Only the second has steps.
|
||||
$this->helper_create_tour();
|
||||
$tour2 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour2->get_id()]);
|
||||
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertNotEmpty($matches);
|
||||
$this->assertCount(1, $matches);
|
||||
|
||||
$match = array_shift($matches);
|
||||
$this->assertEquals($tour2->get_id(), $match->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_enabled_tourdata returns tours in the correct sortorder
|
||||
*/
|
||||
public function test_get_enabled_tourdata_enabled_sortorder() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour1 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour1->get_id()]);
|
||||
$tour2 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour2->get_id()]);
|
||||
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertNotEmpty($matches);
|
||||
$this->assertCount(2, $matches);
|
||||
|
||||
$match = array_shift($matches);
|
||||
$this->assertEquals($tour1->get_id(), $match->id);
|
||||
$match = array_shift($matches);
|
||||
$this->assertEquals($tour2->get_id(), $match->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that caching prevents additional DB reads.
|
||||
*/
|
||||
public function test_get_enabled_tourdata_single_fetch() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour1 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour1->get_id()]);
|
||||
$tour2 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour2->get_id()]);
|
||||
|
||||
// Only one read for the first call.
|
||||
$startreads = $DB->perf_get_reads();
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
// No subsequent reads for any further calls.
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for get_matching_tourdata.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_matching_tourdata_provider() {
|
||||
$tourconfigs = [
|
||||
(object) [
|
||||
'name' => 'my_exact_1',
|
||||
'pathmatch' => '/my/view.php'
|
||||
],
|
||||
(object) [
|
||||
'name' => 'my_failed_regex',
|
||||
'pathmatch' => '/my/*.php'
|
||||
],
|
||||
(object) [
|
||||
'name' => 'my_glob_1',
|
||||
'pathmatch' => '/my/%'
|
||||
],
|
||||
(object) [
|
||||
'name' => 'my_glob_2',
|
||||
'pathmatch' => '/my/%'
|
||||
],
|
||||
];
|
||||
|
||||
return [
|
||||
'Matches expected glob' => [
|
||||
$tourconfigs,
|
||||
'/my/index.php',
|
||||
['my_glob_1', 'my_glob_2'],
|
||||
],
|
||||
'Matches expected glob and exact' => [
|
||||
$tourconfigs,
|
||||
'/my/view.php',
|
||||
['my_exact_1', 'my_glob_1', 'my_glob_2'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for the get_matching_tourdata function.
|
||||
*
|
||||
* @dataProvider get_matching_tourdata_provider
|
||||
* @param array $tourconfigs The configuration for the tours to create
|
||||
* @param string $targetmatch The match to be tested
|
||||
* @param array $expected An array containing the ordered names of the expected tours
|
||||
*/
|
||||
public function test_get_matching_tourdata($tourconfigs, $targetmatch, $expected) {
|
||||
$this->resetAfterTest();
|
||||
foreach ($tourconfigs as $tourconfig) {
|
||||
$tour = $this->helper_create_tour($tourconfig);
|
||||
$this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
}
|
||||
|
||||
$matches = \tool_usertours\cache::get_matching_tourdata((new moodle_url($targetmatch))->out_as_local_url());
|
||||
$this->assertCount(count($expected), $matches);
|
||||
|
||||
for ($i = 0; $i < count($matches); $i++) {
|
||||
$match = array_shift($matches);
|
||||
$this->assertEquals($expected[$i], $match->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that notify_tour_change clears the cache.
|
||||
*/
|
||||
public function test_notify_tour_change() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour1 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour1->get_id()]);
|
||||
$tour2 = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour2->get_id()]);
|
||||
|
||||
// Only one read for the first call.
|
||||
$startreads = $DB->perf_get_reads();
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
// No subsequent reads for any further calls.
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
// Reset.
|
||||
\tool_usertours\cache::notify_tour_change();
|
||||
|
||||
// An additional DB read now.
|
||||
$startreads = $DB->perf_get_reads();
|
||||
$matches = \tool_usertours\cache::get_enabled_tourdata();
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_stepdata returns an empty array when no steps were found.
|
||||
*/
|
||||
public function test_get_stepdata_no_steps() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour = $this->helper_create_tour((object)['enabled' => false]);
|
||||
|
||||
$data = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertInternalType('array', $data);
|
||||
$this->assertEmpty($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_stepdata returns an empty array when no steps were found.
|
||||
*/
|
||||
public function test_get_stepdata_correct_tour() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour1 = $this->helper_create_tour((object)['enabled' => false]);
|
||||
$this->helper_create_step((object) ['tourid' => $tour1->get_id()]);
|
||||
$this->helper_create_step((object) ['tourid' => $tour1->get_id()]);
|
||||
$this->helper_create_step((object) ['tourid' => $tour1->get_id()]);
|
||||
$tour2 = $this->helper_create_tour((object)['enabled' => false]);
|
||||
|
||||
$data = \tool_usertours\cache::get_stepdata($tour1->get_id());
|
||||
$this->assertInternalType('array', $data);
|
||||
$this->assertCount(3, $data);
|
||||
|
||||
$data = \tool_usertours\cache::get_stepdata($tour2->get_id());
|
||||
$this->assertInternalType('array', $data);
|
||||
$this->assertEmpty($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get_stepdata returns an array containing multiple steps in
|
||||
* the same order.
|
||||
*
|
||||
* This is very difficult to determine because the act of changing the
|
||||
* order will likely change the DB natural sorting.
|
||||
*/
|
||||
public function test_get_stepdata_ordered_steps() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour = $this->helper_create_tour((object)['enabled' => false]);
|
||||
$steps = [];
|
||||
$steps[] = $this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
$steps[] = $this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
$steps[] = $this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
$steps[] = $this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
$steps[0]->set_sortorder(10)->persist();
|
||||
|
||||
$data = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertInternalType('array', $data);
|
||||
$this->assertCount(4, $data);
|
||||
|
||||
// Re-order the steps.
|
||||
usort($steps, function($a, $b) {
|
||||
return ($a->get_sortorder() < $b->get_sortorder()) ? -1 : 1;
|
||||
});
|
||||
|
||||
for ($i = 0; $i < count($data); $i++) {
|
||||
$step = array_shift($data);
|
||||
$this->assertEquals($steps[$i]->get_id(), $step->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that caching prevents additional DB reads.
|
||||
*/
|
||||
public function test_get_stepdata_single_fetch() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
|
||||
// Only one read for the first call.
|
||||
$startreads = $DB->perf_get_reads();
|
||||
$matches = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
// No subsequent reads for any further calls.
|
||||
$matches = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that notify_step_change clears the cache.
|
||||
*/
|
||||
public function test_notify_step_change() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$tour = $this->helper_create_tour();
|
||||
$this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
|
||||
// Only one read for the first call.
|
||||
$startreads = $DB->perf_get_reads();
|
||||
$matches = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
// No subsequent reads for any further calls.
|
||||
$matches = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
|
||||
// Reset.
|
||||
\tool_usertours\cache::notify_step_change($tour->get_id());
|
||||
|
||||
// An additional DB read now.
|
||||
$startreads = $DB->perf_get_reads();
|
||||
$matches = \tool_usertours\cache::get_stepdata($tour->get_id());
|
||||
$this->assertEquals(1, $DB->perf_get_reads() - $startreads);
|
||||
}
|
||||
}
|
105
admin/tool/usertours/tests/helper_trait.php
Normal file
105
admin/tool/usertours/tests/helper_trait.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Helpers for unit tests.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Helpers for unit tests.
|
||||
*
|
||||
* @package tool_usertours
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
trait tool_usertours_helper_trait {
|
||||
/**
|
||||
* A helper to create an empty tour.
|
||||
*
|
||||
* @param stdClass $tourconfig The configuration for the new tour
|
||||
* @param bool $persist Whether to persist the data
|
||||
* @return \tool_usertours\tour
|
||||
*/
|
||||
public function helper_create_tour(\stdClass $tourconfig = null, $persist = true) {
|
||||
$minvalues = [
|
||||
'id' => null,
|
||||
'pathmatch' => '/my/%',
|
||||
'enabled' => true,
|
||||
'name' => '',
|
||||
'description' => '',
|
||||
'configdata' => '',
|
||||
];
|
||||
|
||||
if ($tourconfig === null) {
|
||||
$tourconfig = new \stdClass();
|
||||
}
|
||||
|
||||
foreach ($minvalues as $key => $value) {
|
||||
if (!isset($tourconfig->$key)) {
|
||||
$tourconfig->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$tour = \tool_usertours\tour::load_from_record($tourconfig, true);
|
||||
if ($persist) {
|
||||
$tour->persist(true);
|
||||
}
|
||||
|
||||
return $tour;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to create an empty step for the specified tour.
|
||||
*
|
||||
* @param stdClass $stepconfig The configuration for the new step
|
||||
* @param bool $persist Whether to persist the data
|
||||
* @return \tool_usertours\step
|
||||
*/
|
||||
public function helper_create_step(\stdClass $stepconfig = null, $persist = true) {
|
||||
$minvalues = [
|
||||
'id' => null,
|
||||
'title' => '',
|
||||
'content' => '',
|
||||
'targettype' => \tool_usertours\target::TARGET_UNATTACHED,
|
||||
'targetvalue' => '',
|
||||
'sortorder' => 0,
|
||||
'configdata' => '',
|
||||
];
|
||||
|
||||
if ($stepconfig === null) {
|
||||
$stepconfig = new \stdClass();
|
||||
}
|
||||
|
||||
foreach ($minvalues as $key => $value) {
|
||||
if (!isset($stepconfig->$key)) {
|
||||
$stepconfig->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$step = \tool_usertours\step::load_from_record($stepconfig, true);
|
||||
if ($persist) {
|
||||
$step->persist(true);
|
||||
}
|
||||
|
||||
return $step;
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
require_once(__DIR__ . '/helper_trait.php');
|
||||
|
||||
/**
|
||||
* Tests for step.
|
||||
@ -34,7 +35,9 @@ require_once($CFG->libdir . '/formslib.php');
|
||||
* @copyright 2016 Andrew Nicols <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class manager_testcase extends advanced_testcase {
|
||||
class tool_usertours_manager_testcase extends advanced_testcase {
|
||||
// There are shared helpers for these tests in the helper trait.
|
||||
use tool_usertours_helper_trait;
|
||||
|
||||
/**
|
||||
* @var moodle_database
|
||||
@ -243,25 +246,14 @@ class manager_testcase extends advanced_testcase {
|
||||
$tourconfig->id = null;
|
||||
$tour = \tool_usertours\tour::load_from_record($tourconfig, true);
|
||||
$tour->persist(true);
|
||||
|
||||
$stepconfig = (object) [
|
||||
'id' => null,
|
||||
'tourid' => $tour->get_id(),
|
||||
'title' => '',
|
||||
'content' => '',
|
||||
'targettype' => \tool_usertours\target::TARGET_UNATTACHED,
|
||||
'targetvalue' => '',
|
||||
'sortorder' => 0,
|
||||
'configdata' => '',
|
||||
];
|
||||
$step = \tool_usertours\step::load_from_record($stepconfig, true);
|
||||
$step->persist(true);
|
||||
$this->helper_create_step((object) ['tourid' => $tour->get_id()]);
|
||||
}
|
||||
|
||||
$match = \tool_usertours\manager::get_matching_tours(new moodle_url($url));
|
||||
if ($expected === null) {
|
||||
$this->assertNull($match);
|
||||
} else {
|
||||
$this->assertNotNull($match);
|
||||
$this->assertEquals($expected, $match->get_name());
|
||||
}
|
||||
}
|
||||
@ -289,5 +281,4 @@ class manager_testcase extends advanced_testcase {
|
||||
|
||||
$this->assertNull(\tool_usertours\manager::get_matching_tours(new moodle_url($url)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -551,6 +551,11 @@ class step_testcase extends advanced_testcase {
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, true);
|
||||
|
||||
$tour = $this->createMock(\tool_usertours\tour::class);
|
||||
$rcp = $rc->getProperty('tour');
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, $tour);
|
||||
|
||||
$this->assertSame($step, $step->persist());
|
||||
}
|
||||
|
||||
@ -590,6 +595,12 @@ class step_testcase extends advanced_testcase {
|
||||
->method('reload')
|
||||
;
|
||||
|
||||
$tour = $this->createMock(\tool_usertours\tour::class);
|
||||
$rc = new \ReflectionClass(\tool_usertours\step::class);
|
||||
$rcp = $rc->getProperty('tour');
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, $tour);
|
||||
|
||||
$this->assertSame($step, $step->persist(true));
|
||||
}
|
||||
|
||||
@ -635,6 +646,11 @@ class step_testcase extends advanced_testcase {
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, true);
|
||||
|
||||
$tour = $this->createMock(\tool_usertours\tour::class);
|
||||
$rcp = $rc->getProperty('tour');
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, $tour);
|
||||
|
||||
$this->assertSame($step, $step->persist());
|
||||
}
|
||||
|
||||
@ -678,6 +694,11 @@ class step_testcase extends advanced_testcase {
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, 42);
|
||||
|
||||
$tour = $this->createMock(\tool_usertours\tour::class);
|
||||
$rcp = $rc->getProperty('tour');
|
||||
$rcp->setAccessible(true);
|
||||
$rcp->setValue($step, $tour);
|
||||
|
||||
$this->assertSame($step, $step->persist(true));
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2016101800; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2016102001; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2016052300; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_usertours'; // Full name of the plugin (used for diagnostics).
|
||||
|
Loading…
x
Reference in New Issue
Block a user