diff --git a/lib/classes/event/base.php b/lib/classes/event/base.php index e0034bd6674..c77e0ab5ae5 100644 --- a/lib/classes/event/base.php +++ b/lib/classes/event/base.php @@ -478,6 +478,69 @@ abstract class base implements \IteratorAggregate { return $event; } + /** + * Get static information about an event. + * This is used in reports and is not for general use. + * + * @return array Static information about the event. + */ + public static final function get_static_info() { + /** Var \core\event\base $event. */ + $event = new static(); + // Set static event data specific for child class. + $event->init(); + return array( + 'eventname' => $event->data['eventname'], + 'component' => $event->data['component'], + 'target' => $event->data['target'], + 'action' => $event->data['action'], + 'crud' => $event->data['crud'], + 'edulevel' => $event->data['edulevel'], + 'objecttable' => $event->data['objecttable'], + ); + } + + /** + * Get an explanation of what the class does. + * By default returns the phpdocs from the child event class. Ideally this should + * be overridden to return a translatable get_string style markdown. + * e.g. return new lang_string('eventyourspecialevent', 'plugin_type'); + * + * @return string An explanation of the event formatted in markdown style. + */ + public static function get_explanation() { + $ref = new \ReflectionClass(get_called_class()); + $docblock = $ref->getDocComment(); + + // Check that there is something to work on. + if (empty($docblock)) { + return null; + } + + $docblocklines = explode("\n", $docblock); + // Remove the bulk of the comment characters. + $pattern = "/(^\s*\/\*\*|^\s+\*\s|^\s+\*)/"; + $cleanline = array(); + foreach ($docblocklines as $line) { + $templine = preg_replace($pattern, '', $line); + // If there is nothing on the line then don't add it to the array. + if (!empty($templine)) { + $cleanline[] = rtrim($templine); + } + // If we get to a line starting with an @ symbol then we don't want the rest. + if (preg_match("/^@|\//", $templine)) { + // Get rid of the last entry (it contains an @ symbol). + array_pop($cleanline); + // Break out of this foreach loop. + break; + } + } + // Add a line break to the sanitised lines. + $explanation = implode("\n", $cleanline); + + return $explanation; + } + /** * Returns event context. * @return \context diff --git a/lib/classes/event/manager.php b/lib/classes/event/manager.php index 879b4a636ea..28f9d13583f 100644 --- a/lib/classes/event/manager.php +++ b/lib/classes/event/manager.php @@ -215,15 +215,16 @@ class manager { self::$allobservers = array(); $plugintypes = \core_component::get_plugin_types(); + $plugintypes = array_merge(array('core' => 'not used'), $plugintypes); $systemdone = false; foreach ($plugintypes as $plugintype => $ignored) { - $plugins = \core_component::get_plugin_list($plugintype); - if (!$systemdone) { - $plugins[] = "$CFG->dirroot/lib"; - $systemdone = true; + if ($plugintype === 'core') { + $plugins['core'] = "$CFG->dirroot/lib"; + } else { + $plugins = \core_component::get_plugin_list($plugintype); } - foreach ($plugins as $fulldir) { + foreach ($plugins as $plugin => $fulldir) { if (!file_exists("$fulldir/db/events.php")) { continue; } @@ -232,7 +233,7 @@ class manager { if (!is_array($observers)) { continue; } - self::add_observers($observers, "$fulldir/db/events.php"); + self::add_observers($observers, "$fulldir/db/events.php", $plugintype, $plugin); } } @@ -248,8 +249,10 @@ class manager { * Add observers. * @param array $observers * @param string $file + * @param string $plugintype Plugin type of the observer. + * @param string $plugin Plugin of the observer. */ - protected static function add_observers(array $observers, $file) { + protected static function add_observers(array $observers, $file, $plugintype = null, $plugin = null) { global $CFG; foreach ($observers as $observer) { @@ -292,6 +295,8 @@ class manager { } $o->includefile = $observer['includefile']; } + $o->plugintype = $plugintype; + $o->plugin = $plugin; self::$allobservers[$observer['eventname']][] = $o; } } @@ -306,6 +311,17 @@ class manager { } } + /** + * Returns all observers in the system. This is only for use for reporting on the list of observers in the system. + * + * @access private + * @return array An array of stdClass with all core observer details. + */ + public static function get_all_observers() { + self::init_all_observers(); + return self::$allobservers; + } + /** * Replace all standard observers. * @param array $observers diff --git a/lib/tests/event_test.php b/lib/tests/event_test.php index fe79d577c13..ad84112678a 100644 --- a/lib/tests/event_test.php +++ b/lib/tests/event_test.php @@ -159,12 +159,16 @@ class core_event_testcase extends advanced_testcase { $observer->priority = 200; $observer->internal = false; $observer->includefile = null; + $observer->plugintype = null; + $observer->plugin = null; $expected[0] = $observer; $observer = new stdClass(); $observer->callable = '\core_tests\event\unittest_observer::observe_one'; $observer->priority = 0; $observer->internal = true; $observer->includefile = $CFG->dirroot.'/lib/tests/fixtures/event_fixtures.php'; + $observer->plugintype = null; + $observer->plugin = null; $expected[1] = $observer; $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']); @@ -175,6 +179,8 @@ class core_event_testcase extends advanced_testcase { $observer->priority = 100; $observer->internal = true; $observer->includefile = null; + $observer->plugintype = null; + $observer->plugin = null; $expected[0] = $observer; $this->assertEquals($expected, $result['\core\event\unknown_executed']); @@ -185,12 +191,16 @@ class core_event_testcase extends advanced_testcase { $observer->priority = 10; $observer->internal = true; $observer->includefile = null; + $observer->plugintype = null; + $observer->plugin = null; $expected[0] = $observer; $observer = new stdClass(); $observer->callable = array('\core_tests\event\unittest_observer', 'observe_all_alt'); $observer->priority = 0; $observer->internal = true; $observer->includefile = null; + $observer->plugintype = null; + $observer->plugin = null; $expected[1] = $observer; $this->assertEquals($expected, $result['\core\event\base']); @@ -213,6 +223,8 @@ class core_event_testcase extends advanced_testcase { $observer->priority = 0; $observer->internal = true; $observer->includefile = $CFG->dirroot.'/lib/tests/fixtures/event_fixtures.php'; + $observer->plugintype = null; + $observer->plugin = null; $expected[0] = $observer; $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']); @@ -749,4 +761,72 @@ class core_event_testcase extends advanced_testcase { phpunit_event_mock::testable_set_event_context($event, null); $this->assertEventContextNotUsed($event); } + + /** + * Test that all observer information is returned correctly. + */ + public function test_get_all_observers() { + // Retrieve all observers. + $observers = \core\event\manager::get_all_observers(); + + // Expected information from the workshop allocation scheduled observer. + $expected = array(); + $observer = new stdClass(); + $observer->callable = '\workshopallocation_scheduled\observer::workshop_viewed'; + $observer->priority = 0; + $observer->internal = true; + $observer->includefile = null; + $observer->plugintype = 'workshopallocation'; + $observer->plugin = 'scheduled'; + $expected[0] = $observer; + + $this->assertEquals($expected, $observers['\mod_workshop\event\course_module_viewed']); + } + + /** + * Test formatting of the get_explanation method. + * This formats the information from an events class docblock. + */ + public function test_get_explanation() { + $explanation = \core_tests\event\full_docblock::get_explanation(); + + $expected = "This is an explanation of the event. + - I'm making a point here. + - I have a second {@link something} point here. + - whitespace is intentional to test it's removal. +I have something else *Yeah* that."; + + $this->assertEquals($explanation, $expected); + + $explanation = \core_tests\event\docblock_test2::get_explanation(); + + $expected = "We have only the description in the docblock +and nothing else."; + + $this->assertEquals($explanation, $expected); + + $explanation = \core_tests\event\docblock_test3::get_explanation(); + $expected = "Calendar event created event."; + $this->assertEquals($explanation, $expected); + + } + + /** + * Test that general information about an event is returned + * by the get_static_info() method. + */ + public function test_get_static_info() { + $staticinfo = \core_tests\event\static_info_viewing::get_static_info(); + + $expected = array( + 'eventname' => '\\core_tests\\event\\static_info_viewing', + 'component' => 'core_tests', + 'target' => 'static_info', + 'action' => 'viewing', + 'crud' => 'r', + 'edulevel' => 0, + 'objecttable' => 'mod_unittest' + ); + $this->assertEquals($staticinfo, $expected); + } } diff --git a/lib/tests/fixtures/event_fixtures.php b/lib/tests/fixtures/event_fixtures.php index 885a3f0927a..cc8de0b22a7 100644 --- a/lib/tests/fixtures/event_fixtures.php +++ b/lib/tests/fixtures/event_fixtures.php @@ -276,3 +276,66 @@ class context_used_in_event extends \core\event\base { return array($this->data['courseid'], 'core_unittest', 'view', 'unittest.php?id=' . $this->context->instanceid); } } + +/** + * This is an explanation of the event. + * - I'm making a point here. + * - I have a second {@link something} point here. + * - whitespace is intentional to test it's removal. + * + * + * I have something else *Yeah* that. + * + * + * + * @package core + * @category phpunit + * @copyright 2014 Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class full_docblock extends \core\event\base { + + protected function init() { + + } +} + +/** + * We have only the description in the docblock + * and nothing else. + */ +class docblock_test2 extends \core\event\base { + + protected function init() { + + } +} + +/** + * Calendar event created event. + * + * @property-read array $other Extra information about the event. + * -int timestart: timestamp for event time start. + * -string name: Name of the event. + * -int repeatid: Id of the parent event if present, else 0. + * + * @package core + * @since Moodle 2.7 + * @copyright 2014 onwards Adrian Greeve + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class docblock_test3 extends \core\event\base { + + protected function init() { + + } +} + +class static_info_viewing extends \core\event\base { + + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_OTHER; + $this->data['objecttable'] = 'mod_unittest'; + } +}