mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 00:46:50 +02:00
MDL-57730 core_calendar: Allow modules to control event visibility
By implementing the mod_{modname}_core_calendar_is_event_visible callback a module can decide whether or not a user should see an event. Part of MDL-55611 epic.
This commit is contained in:
parent
5df117d438
commit
2a5cce61ba
5 changed files with 185 additions and 45 deletions
|
@ -74,14 +74,13 @@ class core_container {
|
||||||
*/
|
*/
|
||||||
private static function init() {
|
private static function init() {
|
||||||
if (empty(self::$eventfactory)) {
|
if (empty(self::$eventfactory)) {
|
||||||
|
$identity = function(event_interface $event) {
|
||||||
|
return $event;
|
||||||
|
};
|
||||||
self::$actionfactory = new action_factory();
|
self::$actionfactory = new action_factory();
|
||||||
self::$actioneventfactory = new action_event_factory();
|
self::$actioneventfactory = new action_event_factory();
|
||||||
self::$eventmapper = new event_mapper(
|
self::$eventmapper = new event_mapper(
|
||||||
new event_factory(
|
new event_factory($identity, $identity)
|
||||||
function(event_interface $event) {
|
|
||||||
return $event;
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
self::$eventfactory = new event_factory(
|
self::$eventfactory = new event_factory(
|
||||||
function(event_interface $event) {
|
function(event_interface $event) {
|
||||||
|
@ -96,6 +95,23 @@ class core_container {
|
||||||
);
|
);
|
||||||
|
|
||||||
return $action ? self::$actioneventfactory->create_instance($event, $action) : $event;
|
return $action ? self::$actioneventfactory->create_instance($event, $action) : $event;
|
||||||
|
},
|
||||||
|
function(event_interface $event) {
|
||||||
|
$mapper = self::$eventmapper;
|
||||||
|
$eventvisible = component_callback(
|
||||||
|
'mod_' . $event->get_course_module()->get('modname'),
|
||||||
|
'core_calendar_is_event_visible',
|
||||||
|
[
|
||||||
|
$mapper->from_event_to_legacy_event($event)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Module does not implement the callback, event should be visible.
|
||||||
|
if (is_null($eventvisible)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $eventvisible ? true : false;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,14 @@ use core_calendar\local\interfaces\event_interface;
|
||||||
*/
|
*/
|
||||||
abstract class event_abstract_factory implements event_factory_interface {
|
abstract class event_abstract_factory implements event_factory_interface {
|
||||||
/**
|
/**
|
||||||
* @var callable $callbackapplier Function to apply component callbacks.
|
* @var callable $actioncallbackapplier Function to apply component action callbacks.
|
||||||
*/
|
*/
|
||||||
protected $callbackapplier;
|
protected $actioncallbackapplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var callable $visibilitycallbackapplier Function to apply component visibility callbacks.
|
||||||
|
*/
|
||||||
|
protected $visibilitycallbackapplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies component actions to the event.
|
* Applies component actions to the event.
|
||||||
|
@ -55,13 +60,23 @@ abstract class event_abstract_factory implements event_factory_interface {
|
||||||
*/
|
*/
|
||||||
protected abstract function apply_component_action(event_interface $event);
|
protected abstract function apply_component_action(event_interface $event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes the event (or not)
|
||||||
|
*
|
||||||
|
* @param event_interface $event The event to potentially expose.
|
||||||
|
* @return event_interface|null The exposed event or null.
|
||||||
|
*/
|
||||||
|
protected abstract function expose_event(event_interface $event);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
*
|
*
|
||||||
* @param callable $callbackapplier Function to apply component callbacks.
|
* @param callable $actioncallbackapplier Function to apply component action callbacks.
|
||||||
|
* @param callable $visibilitycallbackapplier Function to apply component visibility callbacks.
|
||||||
*/
|
*/
|
||||||
public function __construct(callable $callbackapplier) {
|
public function __construct(callable $actioncallbackapplier, callable $visibilitycallbackapplier) {
|
||||||
$this->callbackapplier = $callbackapplier;
|
$this->actioncallbackapplier = $actioncallbackapplier;
|
||||||
|
$this->visibilitycallbackapplier = $visibilitycallbackapplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create_instance(\stdClass $dbrow) {
|
public function create_instance(\stdClass $dbrow) {
|
||||||
|
@ -108,7 +123,8 @@ abstract class event_abstract_factory implements event_factory_interface {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->apply_component_action(
|
return $this->expose_event(
|
||||||
|
$this->apply_component_action(
|
||||||
new event(
|
new event(
|
||||||
$dbrow->id,
|
$dbrow->id,
|
||||||
$dbrow->name,
|
$dbrow->name,
|
||||||
|
@ -128,6 +144,7 @@ abstract class event_abstract_factory implements event_factory_interface {
|
||||||
!empty($dbrow->visible),
|
!empty($dbrow->visible),
|
||||||
$subscription
|
$subscription
|
||||||
)
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,17 +38,25 @@ use core_calendar\local\interfaces\event_interface;
|
||||||
*/
|
*/
|
||||||
class event_factory extends event_abstract_factory {
|
class event_factory extends event_abstract_factory {
|
||||||
protected function apply_component_action(event_interface $event) {
|
protected function apply_component_action(event_interface $event) {
|
||||||
if (!$event->get_course_module()) {
|
$callbackapplier = $this->actioncallbackapplier;
|
||||||
return $event;
|
|
||||||
}
|
|
||||||
|
|
||||||
$callbackapplier = $this->callbackapplier;
|
|
||||||
$callbackresult = $callbackapplier($event);
|
$callbackresult = $callbackapplier($event);
|
||||||
|
|
||||||
if (!$callbackresult instanceof event_interface) {
|
if (!$callbackresult instanceof event_interface) {
|
||||||
throw new invalid_callback_exception('Event factory callback applier must return an instance of action_interface');
|
throw new invalid_callback_exception(
|
||||||
|
'Event factory action callback applier must return an instance of event_interface');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $callbackresult;
|
return $callbackresult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function expose_event(event_interface $event) {
|
||||||
|
$callbackapplier = $this->visibilitycallbackapplier;
|
||||||
|
$callbackresult = $callbackapplier($event);
|
||||||
|
|
||||||
|
if (!is_bool($callbackresult)) {
|
||||||
|
throw new invalid_callback_exception('Event factory visibility callback applier must return true or false');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $callbackresult === true ? $event : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,10 @@ class core_calendar_container_testcase extends advanced_testcase {
|
||||||
$dbrow->id = $legacyevent->id;
|
$dbrow->id = $legacyevent->id;
|
||||||
$event = $factory->create_instance($dbrow);
|
$event = $factory->create_instance($dbrow);
|
||||||
|
|
||||||
|
if (is_null($event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$this->assertInstanceOf(event_interface::class, $event);
|
$this->assertInstanceOf(event_interface::class, $event);
|
||||||
$this->assertTrue($event instanceof event || $event instanceof action_event);
|
$this->assertTrue($event instanceof event || $event instanceof action_event);
|
||||||
|
|
||||||
|
|
|
@ -38,36 +38,98 @@ class core_calendar_event_factory_testcase extends advanced_testcase {
|
||||||
* Test event class getters.
|
* Test event class getters.
|
||||||
*
|
*
|
||||||
* @dataProvider create_instance_testcases()
|
* @dataProvider create_instance_testcases()
|
||||||
* @param array $instanceparams Associative array of instance parameters.
|
* @param \stdClass $dbrow Row from the event table.
|
||||||
|
* @param callable $actioncallbackapplier Action callback applier.
|
||||||
|
* @param callable $visibilitycallbackapplier Visibility callback applier.
|
||||||
|
* @param string $expectedclass Class the factory is expected to produce.
|
||||||
|
* @param mixed $expectedattributevalue Expected value of the modified attribute.
|
||||||
*/
|
*/
|
||||||
public function test_create_instance(
|
public function test_create_instance(
|
||||||
$dbrow,
|
$dbrow,
|
||||||
callable $callbackapplier,
|
callable $actioncallbackapplier,
|
||||||
|
callable $visibilitycallbackapplier,
|
||||||
|
$expectedclass,
|
||||||
$expectedattributevalue
|
$expectedattributevalue
|
||||||
) {
|
) {
|
||||||
$this->resetAfterTest(true);
|
$this->resetAfterTest(true);
|
||||||
$this->setAdminUser();
|
$this->setAdminUser();
|
||||||
$event = $this->create_event();
|
$event = $this->create_event();
|
||||||
|
|
||||||
$factory = new event_factory($callbackapplier);
|
$factory = new event_factory($actioncallbackapplier, $visibilitycallbackapplier);
|
||||||
$dbrow->id = $event->id;
|
$dbrow->id = $event->id;
|
||||||
$instance = $factory->create_instance($dbrow);
|
$instance = $factory->create_instance($dbrow);
|
||||||
|
|
||||||
|
if ($expectedclass) {
|
||||||
|
$this->assertInstanceOf($expectedclass, $instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_null($expectedclass)) {
|
||||||
|
$this->assertNull($instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($expectedattributevalue) {
|
||||||
$this->assertEquals($instance->testattribute, $expectedattributevalue);
|
$this->assertEquals($instance->testattribute, $expectedattributevalue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test invalid callback exception.
|
* Test invalid callback exception.
|
||||||
*
|
*
|
||||||
* @expectedException \core_calendar\local\event\exceptions\invalid_callback_exception
|
* @expectedException \core_calendar\local\event\exceptions\invalid_callback_exception
|
||||||
*/
|
*/
|
||||||
public function test_invalid_callback() {
|
public function test_invalid_action_callback() {
|
||||||
$this->resetAfterTest(true);
|
$this->resetAfterTest(true);
|
||||||
$this->setAdminUser();
|
$this->setAdminUser();
|
||||||
$event = $this->create_event();
|
$event = $this->create_event();
|
||||||
$factory = new event_factory(function () {
|
$factory = new event_factory(
|
||||||
|
function () {
|
||||||
return 'hello';
|
return 'hello';
|
||||||
});
|
},
|
||||||
|
function () {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$factory->create_instance(
|
||||||
|
(object)[
|
||||||
|
'id' => $event->id,
|
||||||
|
'name' => 'test',
|
||||||
|
'description' => 'Test description',
|
||||||
|
'format' => 2,
|
||||||
|
'courseid' => 1,
|
||||||
|
'groupid' => 1,
|
||||||
|
'userid' => 1,
|
||||||
|
'repeatid' => 1,
|
||||||
|
'modulename' => 'assign',
|
||||||
|
'instance' => 1,
|
||||||
|
'eventtype' => 'due',
|
||||||
|
'timestart' => 123456789,
|
||||||
|
'timeduration' => 12,
|
||||||
|
'timemodified' => 123456789,
|
||||||
|
'timesort' => 123456789,
|
||||||
|
'visible' => 1,
|
||||||
|
'subscriptionid' => 1
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test invalid callback exception.
|
||||||
|
*
|
||||||
|
* @expectedException \core_calendar\local\event\exceptions\invalid_callback_exception
|
||||||
|
*/
|
||||||
|
public function test_invalid_visibility_callback() {
|
||||||
|
$this->resetAfterTest(true);
|
||||||
|
$this->setAdminUser();
|
||||||
|
$event = $this->create_event();
|
||||||
|
$factory = new event_factory(
|
||||||
|
function ($event) {
|
||||||
|
return $event;
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
return 'asdf';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$factory->create_instance(
|
$factory->create_instance(
|
||||||
(object)[
|
(object)[
|
||||||
|
@ -94,7 +156,7 @@ class core_calendar_event_factory_testcase extends advanced_testcase {
|
||||||
|
|
||||||
public function create_instance_testcases() {
|
public function create_instance_testcases() {
|
||||||
return [
|
return [
|
||||||
'Sample event record' => [
|
'Sample event record with event exposed' => [
|
||||||
'dbrow' => (object)[
|
'dbrow' => (object)[
|
||||||
'name' => 'Test event',
|
'name' => 'Test event',
|
||||||
'description' => 'Hello',
|
'description' => 'Hello',
|
||||||
|
@ -113,11 +175,44 @@ class core_calendar_event_factory_testcase extends advanced_testcase {
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'subscriptionid' => 1
|
'subscriptionid' => 1
|
||||||
],
|
],
|
||||||
'callbackapplier' => function(event_interface $event) {
|
'actioncallbackapplier' => function(event_interface $event) {
|
||||||
$event->testattribute = 'Hello';
|
$event->testattribute = 'Hello';
|
||||||
return $event;
|
return $event;
|
||||||
},
|
},
|
||||||
|
'visibilitycallbackapplier' => function(event_interface $event) {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
event_interface::class,
|
||||||
'Hello'
|
'Hello'
|
||||||
|
],
|
||||||
|
'Sample event record with event hidden' => [
|
||||||
|
'dbrow' => (object)[
|
||||||
|
'name' => 'Test event',
|
||||||
|
'description' => 'Hello',
|
||||||
|
'format' => 1,
|
||||||
|
'courseid' => 1,
|
||||||
|
'groupid' => 1,
|
||||||
|
'userid' => 1,
|
||||||
|
'repeatid' => null,
|
||||||
|
'modulename' => 'Test module',
|
||||||
|
'instance' => 1,
|
||||||
|
'eventtype' => 'Due',
|
||||||
|
'timestart' => 123456789,
|
||||||
|
'timeduration' => 123456789,
|
||||||
|
'timemodified' => 123456789,
|
||||||
|
'timesort' => 123456789,
|
||||||
|
'visible' => true,
|
||||||
|
'subscriptionid' => 1
|
||||||
|
],
|
||||||
|
'actioncallbackapplier' => function(event_interface $event) {
|
||||||
|
$event->testattribute = 'Hello';
|
||||||
|
return $event;
|
||||||
|
},
|
||||||
|
'visibilitycallbackapplier' => function(event_interface $event) {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
null
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue