Merge branch 'MDL-48621_master' of git://github.com/dmonllao/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Tue, 19 Jan 2016 07:47:12 +0000 (15:47 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Tue, 19 Jan 2016 07:47:12 +0000 (15:47 +0800)
admin/index.php
admin/renderer.php
lang/en/admin.php
lib/deprecatedlib.php
lib/eventslib.php
lib/phpunit/classes/advanced_testcase.php
lib/tests/event_test.php
lib/tests/eventslib_test.php
lib/upgrade.txt

index b8de2e6..1000f93 100644 (file)
@@ -843,6 +843,8 @@ $buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', '
 $registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
 // Check if there are any cache warnings.
 $cachewarnings = cache_helper::warnings();
+// Check if there are events 1 API handlers.
+$eventshandlers = $DB->get_records_sql('SELECT DISTINCT component FROM {events_handlers}');
 
 admin_externalpage_setup('adminnotifications');
 
@@ -850,4 +852,4 @@ $output = $PAGE->get_renderer('core', 'admin');
 
 echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
                                        $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
-                                       $registered, $cachewarnings);
+                                       $registered, $cachewarnings, $eventshandlers);
index 12d9dc3..7c0dfe2 100644 (file)
@@ -275,12 +275,13 @@ class core_admin_renderer extends plugin_renderer_base {
      * @param array|null $availableupdates array of \core\update\info objects or null
      * @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
      * @param string[] $cachewarnings An array containing warnings from the Cache API.
+     * @param array $eventshandlers Events 1 API handlers.
      *
      * @return string HTML to output.
      */
     public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
             $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
-            $buggyiconvnomb, $registered, array $cachewarnings = array()) {
+            $buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0) {
         global $CFG;
         $output = '';
 
@@ -294,6 +295,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $output .= $this->db_problems($dbproblems);
         $output .= $this->maintenance_mode_warning($maintenancemode);
         $output .= $this->cache_warnings($cachewarnings);
+        $output .= $this->events_handlers($eventshandlers);
         $output .= $this->registration_warning($registered);
 
         //////////////////////////////////////////////////////////////////////////////////////////////////
@@ -594,6 +596,23 @@ class core_admin_renderer extends plugin_renderer_base {
         return join("\n", array_map(array($this, 'warning'), $cachewarnings));
     }
 
+    /**
+     * Renders events 1 API handlers warning.
+     *
+     * @param array $eventshandlers
+     * @return string
+     */
+    public function events_handlers($eventshandlers) {
+        if ($eventshandlers) {
+            $components = '';
+            foreach ($eventshandlers as $eventhandler) {
+                $components .= $eventhandler->component . ', ';
+            }
+            $components = rtrim($components, ', ');
+            return $this->warning(get_string('eventshandlersinuse', 'admin', $components));
+        }
+    }
+
     /**
      * Render an appropriate message if the site in in maintenance mode.
      * @param bool $maintenancemode
index 1ecd467..5f81af9 100644 (file)
@@ -504,6 +504,7 @@ $string['environmentxmlerror'] = 'Error reading environment data ({$a->error_cod
 $string['errordeletingconfig'] = 'An error occurred while deleting the configuration records for plugin \'{$a}\'.';
 $string['errorsetting'] = 'Could not save setting:';
 $string['errorwithsettings'] = 'Some settings were not changed due to an error.';
+$string['eventshandlersinuse'] = 'The following plugins in your system are using Events 1 API deprecated handlers: \'{$a}\'. Please, update them to use Events 2 API. See https://docs.moodle.org/dev/Event_2#Event_dispatching_and_observers.';
 $string['everyonewhocan'] = 'Everyone who can \'{$a}\'';
 $string['exceptions'] = 'exceptions';
 $string['execpathnotallowed'] = 'Setting executable and local paths disabled in config.php';
index df0bc92..21c56f5 100644 (file)
@@ -3882,3 +3882,497 @@ function tag_cloud_sort($a, $b) {
         return 0;
     }
 }
+
+/**
+ * Loads the events definitions for the component (from file). If no
+ * events are defined for the component, we simply return an empty array.
+ *
+ * @access protected To be used from eventslib only
+ * @deprecated since Moodle 3.1
+ * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
+ * @return array Array of capabilities or empty array if not exists
+ */
+function events_load_def($component) {
+    global $CFG;
+    if ($component === 'unittest') {
+        $defpath = $CFG->dirroot.'/lib/tests/fixtures/events.php';
+    } else {
+        $defpath = core_component::get_component_directory($component).'/db/events.php';
+    }
+
+    $handlers = array();
+
+    if (file_exists($defpath)) {
+        require($defpath);
+    }
+
+    // make sure the definitions are valid and complete; tell devs what is wrong
+    foreach ($handlers as $eventname => $handler) {
+        if ($eventname === 'reset') {
+            debugging("'reset' can not be used as event name.");
+            unset($handlers['reset']);
+            continue;
+        }
+        if (!is_array($handler)) {
+            debugging("Handler of '$eventname' must be specified as array'");
+            unset($handlers[$eventname]);
+            continue;
+        }
+        if (!isset($handler['handlerfile'])) {
+            debugging("Handler of '$eventname' must include 'handlerfile' key'");
+            unset($handlers[$eventname]);
+            continue;
+        }
+        if (!isset($handler['handlerfunction'])) {
+            debugging("Handler of '$eventname' must include 'handlerfunction' key'");
+            unset($handlers[$eventname]);
+            continue;
+        }
+        if (!isset($handler['schedule'])) {
+            $handler['schedule'] = 'instant';
+        }
+        if ($handler['schedule'] !== 'instant' and $handler['schedule'] !== 'cron') {
+            debugging("Handler of '$eventname' must include valid 'schedule' type (instant or cron)'");
+            unset($handlers[$eventname]);
+            continue;
+        }
+        if (!isset($handler['internal'])) {
+            $handler['internal'] = 1;
+        }
+        $handlers[$eventname] = $handler;
+    }
+
+    return $handlers;
+}
+
+/**
+ * Puts a handler on queue
+ *
+ * @access protected To be used from eventslib only
+ * @deprecated since Moodle 3.1
+ * @param stdClass $handler event handler object from db
+ * @param stdClass $event event data object
+ * @param string $errormessage The error message indicating the problem
+ * @return int id number of new queue handler
+ */
+function events_queue_handler($handler, $event, $errormessage) {
+    global $DB;
+
+    if ($qhandler = $DB->get_record('events_queue_handlers', array('queuedeventid'=>$event->id, 'handlerid'=>$handler->id))) {
+        debugging("Please check code: Event id $event->id is already queued in handler id $qhandler->id");
+        return $qhandler->id;
+    }
+
+    // make a new queue handler
+    $qhandler = new stdClass();
+    $qhandler->queuedeventid  = $event->id;
+    $qhandler->handlerid      = $handler->id;
+    $qhandler->errormessage   = $errormessage;
+    $qhandler->timemodified   = time();
+    if ($handler->schedule === 'instant' and $handler->status == 1) {
+        $qhandler->status     = 1; //already one failed attempt to dispatch this event
+    } else {
+        $qhandler->status     = 0;
+    }
+
+    return $DB->insert_record('events_queue_handlers', $qhandler);
+}
+
+/**
+ * trigger a single event with a specified handler
+ *
+ * @access protected To be used from eventslib only
+ * @deprecated since Moodle 3.1
+ * @param stdClass $handler This shoudl be a row from the events_handlers table.
+ * @param stdClass $eventdata An object containing information about the event
+ * @param string $errormessage error message indicating problem
+ * @return bool|null True means event processed, false means retry event later; may throw exception, NULL means internal error
+ */
+function events_dispatch($handler, $eventdata, &$errormessage) {
+    global $CFG;
+
+    debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.', DEBUG_DEVELOPER);
+
+    $function = unserialize($handler->handlerfunction);
+
+    if (is_callable($function)) {
+        // oki, no need for includes
+
+    } else if (file_exists($CFG->dirroot.$handler->handlerfile)) {
+        include_once($CFG->dirroot.$handler->handlerfile);
+
+    } else {
+        $errormessage = "Handler file of component $handler->component: $handler->handlerfile can not be found!";
+        return null;
+    }
+
+    // checks for handler validity
+    if (is_callable($function)) {
+        $result = call_user_func($function, $eventdata);
+        if ($result === false) {
+            $errormessage = "Handler function of component $handler->component: $handler->handlerfunction requested resending of event!";
+            return false;
+        }
+        return true;
+
+    } else {
+        $errormessage = "Handler function of component $handler->component: $handler->handlerfunction not callable function or class method!";
+        return null;
+    }
+}
+
+/**
+ * given a queued handler, call the respective event handler to process the event
+ *
+ * @access protected To be used from eventslib only
+ * @deprecated since Moodle 3.1
+ * @param stdClass $qhandler events_queued_handler row from db
+ * @return boolean true means event processed, false means retry later, NULL means fatal failure
+ */
+function events_process_queued_handler($qhandler) {
+    global $DB;
+
+    // get handler
+    if (!$handler = $DB->get_record('events_handlers', array('id'=>$qhandler->handlerid))) {
+        debugging("Error processing queue handler $qhandler->id, missing handler id: $qhandler->handlerid");
+        //irrecoverable error, remove broken queue handler
+        events_dequeue($qhandler);
+        return NULL;
+    }
+
+    // get event object
+    if (!$event = $DB->get_record('events_queue', array('id'=>$qhandler->queuedeventid))) {
+        // can't proceed with no event object - might happen when two crons running at the same time
+        debugging("Error processing queue handler $qhandler->id, missing event id: $qhandler->queuedeventid");
+        //irrecoverable error, remove broken queue handler
+        events_dequeue($qhandler);
+        return NULL;
+    }
+
+    // call the function specified by the handler
+    try {
+        $errormessage = 'Unknown error';
+        if (events_dispatch($handler, unserialize(base64_decode($event->eventdata)), $errormessage)) {
+            //everything ok
+            events_dequeue($qhandler);
+            return true;
+        }
+    } catch (Exception $e) {
+        // the problem here is that we do not want one broken handler to stop all others,
+        // cron handlers are very tricky because the needed data might have been deleted before the cron execution
+        $errormessage = "Handler function of component $handler->component: $handler->handlerfunction threw exception :" .
+                $e->getMessage() . "\n" . format_backtrace($e->getTrace(), true);
+        if (!empty($e->debuginfo)) {
+            $errormessage .= $e->debuginfo;
+        }
+    }
+
+    //dispatching failed
+    $qh = new stdClass();
+    $qh->id           = $qhandler->id;
+    $qh->errormessage = $errormessage;
+    $qh->timemodified = time();
+    $qh->status       = $qhandler->status + 1;
+    $DB->update_record('events_queue_handlers', $qh);
+
+    debugging($errormessage);
+
+    return false;
+}
+
+/**
+ * Updates all of the event definitions within the database.
+ *
+ * Unfortunately this isn't as simple as removing them all and then readding
+ * the updated event definitions. Chances are queued items are referencing the
+ * existing definitions.
+ *
+ * Note that the absence of the db/events.php event definition file
+ * will cause any queued events for the component to be removed from
+ * the database.
+ *
+ * @category event
+ * @deprecated since Moodle 3.1
+ * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
+ * @return boolean always returns true
+ */
+function events_update_definition($component='moodle') {
+    global $DB;
+
+    // load event definition from events.php
+    $filehandlers = events_load_def($component);
+
+    if ($filehandlers) {
+        debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.', DEBUG_DEVELOPER);
+    }
+
+    // load event definitions from db tables
+    // if we detect an event being already stored, we discard from this array later
+    // the remaining needs to be removed
+    $cachedhandlers = events_get_cached($component);
+
+    foreach ($filehandlers as $eventname => $filehandler) {
+        if (!empty($cachedhandlers[$eventname])) {
+            if ($cachedhandlers[$eventname]['handlerfile'] === $filehandler['handlerfile'] &&
+                $cachedhandlers[$eventname]['handlerfunction'] === serialize($filehandler['handlerfunction']) &&
+                $cachedhandlers[$eventname]['schedule'] === $filehandler['schedule'] &&
+                $cachedhandlers[$eventname]['internal'] == $filehandler['internal']) {
+                // exact same event handler already present in db, ignore this entry
+
+                unset($cachedhandlers[$eventname]);
+                continue;
+
+            } else {
+                // same event name matches, this event has been updated, update the datebase
+                $handler = new stdClass();
+                $handler->id              = $cachedhandlers[$eventname]['id'];
+                $handler->handlerfile     = $filehandler['handlerfile'];
+                $handler->handlerfunction = serialize($filehandler['handlerfunction']); // static class methods stored as array
+                $handler->schedule        = $filehandler['schedule'];
+                $handler->internal        = $filehandler['internal'];
+
+                $DB->update_record('events_handlers', $handler);
+
+                unset($cachedhandlers[$eventname]);
+                continue;
+            }
+
+        } else {
+            // if we are here, this event handler is not present in db (new)
+            // add it
+            $handler = new stdClass();
+            $handler->eventname       = $eventname;
+            $handler->component       = $component;
+            $handler->handlerfile     = $filehandler['handlerfile'];
+            $handler->handlerfunction = serialize($filehandler['handlerfunction']); // static class methods stored as array
+            $handler->schedule        = $filehandler['schedule'];
+            $handler->status          = 0;
+            $handler->internal        = $filehandler['internal'];
+
+            $DB->insert_record('events_handlers', $handler);
+        }
+    }
+
+    // clean up the left overs, the entries in cached events array at this points are deprecated event handlers
+    // and should be removed, delete from db
+    events_cleanup($component, $cachedhandlers);
+
+    events_get_handlers('reset');
+
+    return true;
+}
+
+/**
+ * Events cron will try to empty the events queue by processing all the queued events handlers
+ *
+ * @access public Part of the public API
+ * @deprecated since Moodle 3.1
+ * @category event
+ * @param string $eventname empty means all
+ * @return int number of dispatched events
+ */
+function events_cron($eventname='') {
+    global $DB;
+
+    $failed = array();
+    $processed = 0;
+
+    if ($eventname) {
+        $sql = "SELECT qh.*
+                  FROM {events_queue_handlers} qh, {events_handlers} h
+                 WHERE qh.handlerid = h.id AND h.eventname=?
+              ORDER BY qh.id";
+        $params = array($eventname);
+    } else {
+        $sql = "SELECT *
+                  FROM {events_queue_handlers}
+              ORDER BY id";
+        $params = array();
+    }
+
+    $rs = $DB->get_recordset_sql($sql, $params);
+    if ($rs->valid()) {
+        debugging('Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.', DEBUG_DEVELOPER);
+    }
+
+    foreach ($rs as $qhandler) {
+        if (isset($failed[$qhandler->handlerid])) {
+            // do not try to dispatch any later events when one already asked for retry or ended with exception
+            continue;
+        }
+        $status = events_process_queued_handler($qhandler);
+        if ($status === false) {
+            // handler is asking for retry, do not send other events to this handler now
+            $failed[$qhandler->handlerid] = $qhandler->handlerid;
+        } else if ($status === NULL) {
+            // means completely broken handler, event data was purged
+            $failed[$qhandler->handlerid] = $qhandler->handlerid;
+        } else {
+            $processed++;
+        }
+    }
+    $rs->close();
+
+    // remove events that do not have any handlers waiting
+    $sql = "SELECT eq.id
+              FROM {events_queue} eq
+              LEFT JOIN {events_queue_handlers} qh ON qh.queuedeventid = eq.id
+             WHERE qh.id IS NULL";
+    $rs = $DB->get_recordset_sql($sql);
+    foreach ($rs as $event) {
+        //debugging('Purging stale event '.$event->id);
+        $DB->delete_records('events_queue', array('id'=>$event->id));
+    }
+    $rs->close();
+
+    return $processed;
+}
+
+/**
+ * Do not call directly, this is intended to be used from new event base only.
+ *
+ * @private
+ * @deprecated since Moodle 3.1
+ * @param string $eventname name of the event
+ * @param mixed $eventdata event data object
+ * @return int number of failed events
+ */
+function events_trigger_legacy($eventname, $eventdata) {
+    global $CFG, $USER, $DB;
+
+    $failedcount = 0; // number of failed events.
+
+    // pull out all registered event handlers
+    if ($handlers = events_get_handlers($eventname)) {
+        foreach ($handlers as $handler) {
+            $errormessage = '';
+
+            if ($handler->schedule === 'instant') {
+                if ($handler->status) {
+                    //check if previous pending events processed
+                    if (!$DB->record_exists('events_queue_handlers', array('handlerid'=>$handler->id))) {
+                        // ok, queue is empty, lets reset the status back to 0 == ok
+                        $handler->status = 0;
+                        $DB->set_field('events_handlers', 'status', 0, array('id'=>$handler->id));
+                        // reset static handler cache
+                        events_get_handlers('reset');
+                    }
+                }
+
+                // dispatch the event only if instant schedule and status ok
+                if ($handler->status or (!$handler->internal and $DB->is_transaction_started())) {
+                    // increment the error status counter
+                    $handler->status++;
+                    $DB->set_field('events_handlers', 'status', $handler->status, array('id'=>$handler->id));
+                    // reset static handler cache
+                    events_get_handlers('reset');
+
+                } else {
+                    $errormessage = 'Unknown error';
+                    $result = events_dispatch($handler, $eventdata, $errormessage);
+                    if ($result === true) {
+                        // everything is fine - event dispatched
+                        continue;
+                    } else if ($result === false) {
+                        // retry later - set error count to 1 == send next instant into cron queue
+                        $DB->set_field('events_handlers', 'status', 1, array('id'=>$handler->id));
+                        // reset static handler cache
+                        events_get_handlers('reset');
+                    } else {
+                        // internal problem - ignore the event completely
+                        $failedcount ++;
+                        continue;
+                    }
+                }
+
+                // update the failed counter
+                $failedcount ++;
+
+            } else if ($handler->schedule === 'cron') {
+                //ok - use queueing of events only
+
+            } else {
+                // unknown schedule - ignore event completely
+                debugging("Unknown handler schedule type: $handler->schedule");
+                $failedcount ++;
+                continue;
+            }
+
+            // if even type is not instant, or dispatch asked for retry, queue it
+            $event = new stdClass();
+            $event->userid      = $USER->id;
+            $event->eventdata   = base64_encode(serialize($eventdata));
+            $event->timecreated = time();
+            if (debugging()) {
+                $dump = '';
+                $callers = debug_backtrace();
+                foreach ($callers as $caller) {
+                    if (!isset($caller['line'])) {
+                        $caller['line'] = '?';
+                    }
+                    if (!isset($caller['file'])) {
+                        $caller['file'] = '?';
+                    }
+                    $dump .= 'line ' . $caller['line'] . ' of ' . substr($caller['file'], strlen($CFG->dirroot) + 1);
+                    if (isset($caller['function'])) {
+                        $dump .= ': call to ';
+                        if (isset($caller['class'])) {
+                            $dump .= $caller['class'] . $caller['type'];
+                        }
+                        $dump .= $caller['function'] . '()';
+                    }
+                    $dump .= "\n";
+                }
+                $event->stackdump = $dump;
+            } else {
+                $event->stackdump = '';
+            }
+            $event->id = $DB->insert_record('events_queue', $event);
+            events_queue_handler($handler, $event, $errormessage);
+        }
+    } else {
+        // No handler found for this event name - this is ok!
+    }
+
+    return $failedcount;
+}
+
+/**
+ * checks if an event is registered for this component
+ *
+ * @access public Part of the public API
+ * @deprecated since Moodle 3.1
+ * @param string $eventname name of the event
+ * @param string $component component name, can be mod/data or moodle
+ * @return bool
+ */
+function events_is_registered($eventname, $component) {
+    global $DB;
+
+    debugging('events_is_registered() has been deprecated along with all Events 1 API in favour of Events 2 API,' .
+        ' please use it instead.', DEBUG_DEVELOPER);
+
+    return $DB->record_exists('events_handlers', array('component'=>$component, 'eventname'=>$eventname));
+}
+
+/**
+ * checks if an event is queued for processing - either cron handlers attached or failed instant handlers
+ *
+ * @access public Part of the public API
+ * @deprecated since Moodle 3.1
+ * @param string $eventname name of the event
+ * @return int number of queued events
+ */
+function events_pending_count($eventname) {
+    global $DB;
+
+    debugging('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2 API,' .
+        ' please use it instead.', DEBUG_DEVELOPER);
+
+    $sql = "SELECT COUNT('x')
+              FROM {events_queue_handlers} qh
+              JOIN {events_handlers} h ON h.id = qh.handlerid
+             WHERE h.eventname = ?";
+
+    return $DB->count_records_sql($sql, array($eventname));
+}
index 567cc6c..2474aa1 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-/**
- * Loads the events definitions for the component (from file). If no
- * events are defined for the component, we simply return an empty array.
- *
- * @access protected To be used from eventslib only
- *
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @return array Array of capabilities or empty array if not exists
- */
-function events_load_def($component) {
-    global $CFG;
-    if ($component === 'unittest') {
-        $defpath = $CFG->dirroot.'/lib/tests/fixtures/events.php';
-    } else {
-        $defpath = core_component::get_component_directory($component).'/db/events.php';
-    }
-
-    $handlers = array();
-
-    if (file_exists($defpath)) {
-        require($defpath);
-    }
-
-    // make sure the definitions are valid and complete; tell devs what is wrong
-    foreach ($handlers as $eventname => $handler) {
-        if ($eventname === 'reset') {
-            debugging("'reset' can not be used as event name.");
-            unset($handlers['reset']);
-            continue;
-        }
-        if (!is_array($handler)) {
-            debugging("Handler of '$eventname' must be specified as array'");
-            unset($handlers[$eventname]);
-            continue;
-        }
-        if (!isset($handler['handlerfile'])) {
-            debugging("Handler of '$eventname' must include 'handlerfile' key'");
-            unset($handlers[$eventname]);
-            continue;
-        }
-        if (!isset($handler['handlerfunction'])) {
-            debugging("Handler of '$eventname' must include 'handlerfunction' key'");
-            unset($handlers[$eventname]);
-            continue;
-        }
-        if (!isset($handler['schedule'])) {
-            $handler['schedule'] = 'instant';
-        }
-        if ($handler['schedule'] !== 'instant' and $handler['schedule'] !== 'cron') {
-            debugging("Handler of '$eventname' must include valid 'schedule' type (instant or cron)'");
-            unset($handlers[$eventname]);
-            continue;
-        }
-        if (!isset($handler['internal'])) {
-            $handler['internal'] = 1;
-        }
-        $handlers[$eventname] = $handler;
-    }
-
-    return $handlers;
-}
-
 /**
  * Gets the capabilities that have been cached in the database for this
  * component.
@@ -116,83 +54,6 @@ function events_get_cached($component) {
     return $cachedhandlers;
 }
 
-/**
- * Updates all of the event definitions within the database.
- *
- * Unfortunately this isn't as simple as removing them all and then readding
- * the updated event definitions. Chances are queued items are referencing the
- * existing definitions.
- *
- * Note that the absence of the db/events.php event definition file
- * will cause any queued events for the component to be removed from
- * the database.
- *
- * @category event
- * @param string $component examples: 'moodle', 'mod_forum', 'block_quiz_results'
- * @return boolean always returns true
- */
-function events_update_definition($component='moodle') {
-    global $DB;
-
-    // load event definition from events.php
-    $filehandlers = events_load_def($component);
-
-    // load event definitions from db tables
-    // if we detect an event being already stored, we discard from this array later
-    // the remaining needs to be removed
-    $cachedhandlers = events_get_cached($component);
-
-    foreach ($filehandlers as $eventname => $filehandler) {
-        if (!empty($cachedhandlers[$eventname])) {
-            if ($cachedhandlers[$eventname]['handlerfile'] === $filehandler['handlerfile'] &&
-                $cachedhandlers[$eventname]['handlerfunction'] === serialize($filehandler['handlerfunction']) &&
-                $cachedhandlers[$eventname]['schedule'] === $filehandler['schedule'] &&
-                $cachedhandlers[$eventname]['internal'] == $filehandler['internal']) {
-                // exact same event handler already present in db, ignore this entry
-
-                unset($cachedhandlers[$eventname]);
-                continue;
-
-            } else {
-                // same event name matches, this event has been updated, update the datebase
-                $handler = new stdClass();
-                $handler->id              = $cachedhandlers[$eventname]['id'];
-                $handler->handlerfile     = $filehandler['handlerfile'];
-                $handler->handlerfunction = serialize($filehandler['handlerfunction']); // static class methods stored as array
-                $handler->schedule        = $filehandler['schedule'];
-                $handler->internal        = $filehandler['internal'];
-
-                $DB->update_record('events_handlers', $handler);
-
-                unset($cachedhandlers[$eventname]);
-                continue;
-            }
-
-        } else {
-            // if we are here, this event handler is not present in db (new)
-            // add it
-            $handler = new stdClass();
-            $handler->eventname       = $eventname;
-            $handler->component       = $component;
-            $handler->handlerfile     = $filehandler['handlerfile'];
-            $handler->handlerfunction = serialize($filehandler['handlerfunction']); // static class methods stored as array
-            $handler->schedule        = $filehandler['schedule'];
-            $handler->status          = 0;
-            $handler->internal        = $filehandler['internal'];
-
-            $DB->insert_record('events_handlers', $handler);
-        }
-    }
-
-    // clean up the left overs, the entries in cached events array at this points are deprecated event handlers
-    // and should be removed, delete from db
-    events_cleanup($component, $cachedhandlers);
-
-    events_get_handlers('reset');
-
-    return true;
-}
-
 /**
  * Remove all event handlers and queued events
  *
@@ -233,141 +94,6 @@ function events_cleanup($component, $cachedhandlers) {
     return $deletecount;
 }
 
-/****************** End of Events handler Definition code *******************/
-
-/**
- * Puts a handler on queue
- *
- * @access protected To be used from eventslib only
- *
- * @param stdClass $handler event handler object from db
- * @param stdClass $event event data object
- * @param string $errormessage The error message indicating the problem
- * @return int id number of new queue handler
- */
-function events_queue_handler($handler, $event, $errormessage) {
-    global $DB;
-
-    if ($qhandler = $DB->get_record('events_queue_handlers', array('queuedeventid'=>$event->id, 'handlerid'=>$handler->id))) {
-        debugging("Please check code: Event id $event->id is already queued in handler id $qhandler->id");
-        return $qhandler->id;
-    }
-
-    // make a new queue handler
-    $qhandler = new stdClass();
-    $qhandler->queuedeventid  = $event->id;
-    $qhandler->handlerid      = $handler->id;
-    $qhandler->errormessage   = $errormessage;
-    $qhandler->timemodified   = time();
-    if ($handler->schedule === 'instant' and $handler->status == 1) {
-        $qhandler->status     = 1; //already one failed attempt to dispatch this event
-    } else {
-        $qhandler->status     = 0;
-    }
-
-    return $DB->insert_record('events_queue_handlers', $qhandler);
-}
-
-/**
- * trigger a single event with a specified handler
- *
- * @access protected To be used from eventslib only
- *
- * @param stdClass $handler This shoudl be a row from the events_handlers table.
- * @param stdClass $eventdata An object containing information about the event
- * @param string $errormessage error message indicating problem
- * @return bool|null True means event processed, false means retry event later; may throw exception, NULL means internal error
- */
-function events_dispatch($handler, $eventdata, &$errormessage) {
-    global $CFG;
-
-    $function = unserialize($handler->handlerfunction);
-
-    if (is_callable($function)) {
-        // oki, no need for includes
-
-    } else if (file_exists($CFG->dirroot.$handler->handlerfile)) {
-        include_once($CFG->dirroot.$handler->handlerfile);
-
-    } else {
-        $errormessage = "Handler file of component $handler->component: $handler->handlerfile can not be found!";
-        return null;
-    }
-
-    // checks for handler validity
-    if (is_callable($function)) {
-        $result = call_user_func($function, $eventdata);
-        if ($result === false) {
-            $errormessage = "Handler function of component $handler->component: $handler->handlerfunction requested resending of event!";
-            return false;
-        }
-        return true;
-
-    } else {
-        $errormessage = "Handler function of component $handler->component: $handler->handlerfunction not callable function or class method!";
-        return null;
-    }
-}
-
-/**
- * given a queued handler, call the respective event handler to process the event
- *
- * @access protected To be used from eventslib only
- *
- * @param stdClass $qhandler events_queued_handler row from db
- * @return boolean true means event processed, false means retry later, NULL means fatal failure
- */
-function events_process_queued_handler($qhandler) {
-    global $DB;
-
-    // get handler
-    if (!$handler = $DB->get_record('events_handlers', array('id'=>$qhandler->handlerid))) {
-        debugging("Error processing queue handler $qhandler->id, missing handler id: $qhandler->handlerid");
-        //irrecoverable error, remove broken queue handler
-        events_dequeue($qhandler);
-        return NULL;
-    }
-
-    // get event object
-    if (!$event = $DB->get_record('events_queue', array('id'=>$qhandler->queuedeventid))) {
-        // can't proceed with no event object - might happen when two crons running at the same time
-        debugging("Error processing queue handler $qhandler->id, missing event id: $qhandler->queuedeventid");
-        //irrecoverable error, remove broken queue handler
-        events_dequeue($qhandler);
-        return NULL;
-    }
-
-    // call the function specified by the handler
-    try {
-        $errormessage = 'Unknown error';
-        if (events_dispatch($handler, unserialize(base64_decode($event->eventdata)), $errormessage)) {
-            //everything ok
-            events_dequeue($qhandler);
-            return true;
-        }
-    } catch (Exception $e) {
-        // the problem here is that we do not want one broken handler to stop all others,
-        // cron handlers are very tricky because the needed data might have been deleted before the cron execution
-        $errormessage = "Handler function of component $handler->component: $handler->handlerfunction threw exception :" .
-                $e->getMessage() . "\n" . format_backtrace($e->getTrace(), true);
-        if (!empty($e->debuginfo)) {
-            $errormessage .= $e->debuginfo;
-        }
-    }
-
-    //dispatching failed
-    $qh = new stdClass();
-    $qh->id           = $qhandler->id;
-    $qh->errormessage = $errormessage;
-    $qh->timemodified = time();
-    $qh->status       = $qhandler->status + 1;
-    $DB->update_record('events_queue_handlers', $qh);
-
-    debugging($errormessage);
-
-    return false;
-}
-
 /**
  * Removes this queued handler from the events_queued_handler table
  *
@@ -413,205 +139,3 @@ function events_get_handlers($eventname) {
 
     return $handlers[$eventname];
 }
-
-/**
- * Events cron will try to empty the events queue by processing all the queued events handlers
- *
- * @access public Part of the public API
- * @category event
- * @param string $eventname empty means all
- * @return int number of dispatched events
- */
-function events_cron($eventname='') {
-    global $DB;
-
-    $failed = array();
-    $processed = 0;
-
-    if ($eventname) {
-        $sql = "SELECT qh.*
-                  FROM {events_queue_handlers} qh, {events_handlers} h
-                 WHERE qh.handlerid = h.id AND h.eventname=?
-              ORDER BY qh.id";
-        $params = array($eventname);
-    } else {
-        $sql = "SELECT *
-                  FROM {events_queue_handlers}
-              ORDER BY id";
-        $params = array();
-    }
-
-    $rs = $DB->get_recordset_sql($sql, $params);
-    foreach ($rs as $qhandler) {
-        if (isset($failed[$qhandler->handlerid])) {
-            // do not try to dispatch any later events when one already asked for retry or ended with exception
-            continue;
-        }
-        $status = events_process_queued_handler($qhandler);
-        if ($status === false) {
-            // handler is asking for retry, do not send other events to this handler now
-            $failed[$qhandler->handlerid] = $qhandler->handlerid;
-        } else if ($status === NULL) {
-            // means completely broken handler, event data was purged
-            $failed[$qhandler->handlerid] = $qhandler->handlerid;
-        } else {
-            $processed++;
-        }
-    }
-    $rs->close();
-
-    // remove events that do not have any handlers waiting
-    $sql = "SELECT eq.id
-              FROM {events_queue} eq
-              LEFT JOIN {events_queue_handlers} qh ON qh.queuedeventid = eq.id
-             WHERE qh.id IS NULL";
-    $rs = $DB->get_recordset_sql($sql);
-    foreach ($rs as $event) {
-        //debugging('Purging stale event '.$event->id);
-        $DB->delete_records('events_queue', array('id'=>$event->id));
-    }
-    $rs->close();
-
-    return $processed;
-}
-
-/**
- * Do not call directly, this is intended to be used from new event base only.
- *
- * @private
- * @param string $eventname name of the event
- * @param mixed $eventdata event data object
- * @return int number of failed events
- */
-function events_trigger_legacy($eventname, $eventdata) {
-    global $CFG, $USER, $DB;
-
-    $failedcount = 0; // number of failed events.
-
-    // pull out all registered event handlers
-    if ($handlers = events_get_handlers($eventname)) {
-        foreach ($handlers as $handler) {
-            $errormessage = '';
-
-            if ($handler->schedule === 'instant') {
-                if ($handler->status) {
-                    //check if previous pending events processed
-                    if (!$DB->record_exists('events_queue_handlers', array('handlerid'=>$handler->id))) {
-                        // ok, queue is empty, lets reset the status back to 0 == ok
-                        $handler->status = 0;
-                        $DB->set_field('events_handlers', 'status', 0, array('id'=>$handler->id));
-                        // reset static handler cache
-                        events_get_handlers('reset');
-                    }
-                }
-
-                // dispatch the event only if instant schedule and status ok
-                if ($handler->status or (!$handler->internal and $DB->is_transaction_started())) {
-                    // increment the error status counter
-                    $handler->status++;
-                    $DB->set_field('events_handlers', 'status', $handler->status, array('id'=>$handler->id));
-                    // reset static handler cache
-                    events_get_handlers('reset');
-
-                } else {
-                    $errormessage = 'Unknown error';
-                    $result = events_dispatch($handler, $eventdata, $errormessage);
-                    if ($result === true) {
-                        // everything is fine - event dispatched
-                        continue;
-                    } else if ($result === false) {
-                        // retry later - set error count to 1 == send next instant into cron queue
-                        $DB->set_field('events_handlers', 'status', 1, array('id'=>$handler->id));
-                        // reset static handler cache
-                        events_get_handlers('reset');
-                    } else {
-                        // internal problem - ignore the event completely
-                        $failedcount ++;
-                        continue;
-                    }
-                }
-
-                // update the failed counter
-                $failedcount ++;
-
-            } else if ($handler->schedule === 'cron') {
-                //ok - use queueing of events only
-
-            } else {
-                // unknown schedule - ignore event completely
-                debugging("Unknown handler schedule type: $handler->schedule");
-                $failedcount ++;
-                continue;
-            }
-
-            // if even type is not instant, or dispatch asked for retry, queue it
-            $event = new stdClass();
-            $event->userid      = $USER->id;
-            $event->eventdata   = base64_encode(serialize($eventdata));
-            $event->timecreated = time();
-            if (debugging()) {
-                $dump = '';
-                $callers = debug_backtrace();
-                foreach ($callers as $caller) {
-                    if (!isset($caller['line'])) {
-                        $caller['line'] = '?';
-                    }
-                    if (!isset($caller['file'])) {
-                        $caller['file'] = '?';
-                    }
-                    $dump .= 'line ' . $caller['line'] . ' of ' . substr($caller['file'], strlen($CFG->dirroot) + 1);
-                    if (isset($caller['function'])) {
-                        $dump .= ': call to ';
-                        if (isset($caller['class'])) {
-                            $dump .= $caller['class'] . $caller['type'];
-                        }
-                        $dump .= $caller['function'] . '()';
-                    }
-                    $dump .= "\n";
-                }
-                $event->stackdump = $dump;
-            } else {
-                $event->stackdump = '';
-            }
-            $event->id = $DB->insert_record('events_queue', $event);
-            events_queue_handler($handler, $event, $errormessage);
-        }
-    } else {
-        // No handler found for this event name - this is ok!
-    }
-
-    return $failedcount;
-}
-
-/**
- * checks if an event is registered for this component
- *
- * @access public Part of the public API
- *
- * @param string $eventname name of the event
- * @param string $component component name, can be mod/data or moodle
- * @return bool
- */
-function events_is_registered($eventname, $component) {
-    global $DB;
-    return $DB->record_exists('events_handlers', array('component'=>$component, 'eventname'=>$eventname));
-}
-
-/**
- * checks if an event is queued for processing - either cron handlers attached or failed instant handlers
- *
- * @access public Part of the public API
- *
- * @param string $eventname name of the event
- * @return int number of queued events
- */
-function events_pending_count($eventname) {
-    global $DB;
-
-    $sql = "SELECT COUNT('x')
-              FROM {events_queue_handlers} qh
-              JOIN {events_handlers} h ON h.id = qh.handlerid
-             WHERE h.eventname = ?";
-
-    return $DB->count_records_sql($sql, array($eventname));
-}
index 7ee75eb..1c0bd81 100644 (file)
@@ -307,6 +307,44 @@ abstract class advanced_testcase extends base_testcase {
         $this->resetDebugging();
     }
 
+    /**
+     * Asserts how many times debugging has been called.
+     *
+     * @param int $expectedcount The expected number of times
+     * @param array $debugmessages Expected debugging messages, one for each expected message.
+     * @param array $debuglevels Expected debugging levels, one for each expected message.
+     * @param string $message
+     * @return void
+     */
+    public function assertDebuggingCalledCount($expectedcount, $debugmessages = array(), $debuglevels = array(), $message = '') {
+        if (!is_int($expectedcount)) {
+            throw new coding_exception('assertDebuggingCalledCount $expectedcount argument should be an integer.');
+        }
+
+        $debugging = $this->getDebuggingMessages();
+        $this->assertEquals($expectedcount, count($debugging), $message);
+
+        if ($debugmessages) {
+            if (!is_array($debugmessages) || count($debugmessages) != $expectedcount) {
+                throw new coding_exception('assertDebuggingCalledCount $debugmessages should contain ' . $expectedcount . ' messages');
+            }
+            foreach ($debugmessages as $key => $debugmessage) {
+                $this->assertSame($debugmessage, $debugging[$key]->message, $message);
+            }
+        }
+
+        if ($debuglevels) {
+            if (!is_array($debuglevels) || count($debuglevels) != $expectedcount) {
+                throw new coding_exception('assertDebuggingCalledCount $debuglevels should contain ' . $expectedcount . ' messages');
+            }
+            foreach ($debuglevels as $key => $debuglevel) {
+                $this->assertSame($debuglevel, $debugging[$key]->level, $message);
+            }
+        }
+
+        $this->resetDebugging();
+    }
+
     /**
      * Call when no debugging() messages expected.
      * @param string $message
index 55cdbf9..f260cc6 100644 (file)
@@ -29,6 +29,8 @@ require_once(__DIR__.'/fixtures/event_fixtures.php');
 
 class core_event_testcase extends advanced_testcase {
 
+    const DEBUGGING_MSG = 'Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.';
+
     public function test_event_properties() {
         global $USER;
 
@@ -591,6 +593,7 @@ class core_event_testcase extends advanced_testcase {
 
         $DB->delete_records('log', array());
         events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
         $DB->delete_records_select('events_handlers', "component <> 'unittest'");
         events_get_handlers('reset');
         $this->assertEquals(3, $DB->count_records('events_handlers'));
@@ -601,10 +604,12 @@ class core_event_testcase extends advanced_testcase {
 
         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
         $event1->trigger();
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
 
         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>6, 'xx'=>11)));
         $event2->nest = true;
         $event2->trigger();
+        $this->assertDebuggingCalledCount(2, array(self::DEBUGGING_MSG, self::DEBUGGING_MSG), array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
 
         $this->assertSame(
             array('observe_all-5', 'observe_one-5', 'legacy_handler-0', 'observe_all-nesting-6', 'legacy_handler-0', 'observe_one-6', 'observe_all-666', 'observe_one-666', 'legacy_handler-0'),
index 0428744..c62d5cf 100644 (file)
@@ -29,6 +29,8 @@ defined('MOODLE_INTERNAL') || die();
 
 class core_eventslib_testcase extends advanced_testcase {
 
+    const DEBUGGING_MSG = 'Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.';
+
     /**
      * Create temporary entries in the database for these tests.
      * These tests have to work no matter the data currently in the database
@@ -40,7 +42,6 @@ class core_eventslib_testcase extends advanced_testcase {
         // Set global category settings to -1 (not force).
         eventslib_sample_function_handler('reset');
         eventslib_sample_handler_class::static_method('reset');
-        events_update_definition('unittest');
 
         $this->resetAfterTest();
     }
@@ -51,6 +52,9 @@ class core_eventslib_testcase extends advanced_testcase {
     public function test_events_update_definition__install() {
         global $DB;
 
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $dbcount = $DB->count_records('events_handlers', array('component'=>'unittest'));
         $handlers = array();
         require(__DIR__.'/fixtures/events.php');
@@ -63,6 +67,9 @@ class core_eventslib_testcase extends advanced_testcase {
     public function test_events_update_definition__uninstall() {
         global $DB;
 
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         events_uninstall('unittest');
         $this->assertEquals(0, $DB->count_records('events_handlers', array('component'=>'unittest')), 'All handlers should be uninstalled: %s');
     }
@@ -72,6 +79,10 @@ class core_eventslib_testcase extends advanced_testcase {
      */
     public function test_events_update_definition__update() {
         global $DB;
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         // First modify directly existing handler.
         $handler = $DB->get_record('events_handlers', array('component'=>'unittest', 'eventname'=>'test_instant'));
 
@@ -82,6 +93,7 @@ class core_eventslib_testcase extends advanced_testcase {
 
         // Update the definition, it should revert the handler back.
         events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
         $handler = $DB->get_record('events_handlers', array('component'=>'unittest', 'eventname'=>'test_instant'));
         $this->assertSame($handler->handlerfunction, $original, 'update should sync db with file definition: %s');
     }
@@ -90,15 +102,27 @@ class core_eventslib_testcase extends advanced_testcase {
      * Tests events_trigger_is_registered() function.
      */
     public function test_events_is_registered() {
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $this->assertTrue(events_is_registered('test_instant', 'unittest'));
+        $this->assertDebuggingCalled('events_is_registered() has been deprecated along with all Events 1 API in favour of Events 2' .
+            ' API, please use it instead.', DEBUG_DEVELOPER);
     }
 
     /**
      * Tests events_trigger_legacy() function.
      */
     public function test_events_trigger_legacy_instant() {
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'));
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
         $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'));
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
         $this->assertEquals(2, eventslib_sample_function_handler('status'));
     }
 
@@ -106,9 +130,16 @@ class core_eventslib_testcase extends advanced_testcase {
      * Tests events_trigger_legacy() function.
      */
     public function test_events_trigger__cron() {
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $this->assertEquals(0, events_trigger_legacy('test_cron', 'ok'));
         $this->assertEquals(0, eventslib_sample_handler_class::static_method('status'));
         events_cron('test_cron');
+        // The events_cron one + one for each triggered event above (triggered in events_dispatch).
+        $this->assertDebuggingCalledCount(2, array(self::DEBUGGING_MSG, self::DEBUGGING_MSG),
+            array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
         $this->assertEquals(1, eventslib_sample_handler_class::static_method('status'));
     }
 
@@ -116,10 +147,20 @@ class core_eventslib_testcase extends advanced_testcase {
      * Tests events_pending_count() function.
      */
     public function test_events_pending_count() {
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         events_trigger_legacy('test_cron', 'ok');
+        $this->assertDebuggingNotCalled();
         events_trigger_legacy('test_cron', 'ok');
+        $this->assertDebuggingNotCalled();
         events_cron('test_cron');
+        // The events_cron one + one for each triggered event above (triggered in events_dispatch).
+        $this->assertDebuggingCalledCount(3);
         $this->assertEquals(0, events_pending_count('test_cron'), 'all messages should be already dequeued: %s');
+        $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
+            ' API, please use it instead.', DEBUG_DEVELOPER);
     }
 
     /**
@@ -127,34 +168,64 @@ class core_eventslib_testcase extends advanced_testcase {
      */
     public function test_events_trigger__failed_instant() {
         global $CFG;
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $olddebug = $CFG->debug;
 
         $this->assertEquals(1, events_trigger_legacy('test_instant', 'fail'), 'fail first event: %s');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
         $this->assertEquals(1, events_trigger_legacy('test_instant', 'ok'), 'this one should fail too: %s');
+        $this->assertDebuggingNotCalled();
 
         $this->assertEquals(0, events_cron('test_instant'), 'all events should stay in queue: %s');
-        $this->assertDebuggingCalled();
+        // events_cron + one for each dispatched event.
+        $this->assertDebuggingCalledCount(3);
 
         $this->assertEquals(2, events_pending_count('test_instant'), 'two events should in queue: %s');
+        $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
+            ' API, please use it instead.', DEBUG_DEVELOPER);
+
         $this->assertEquals(0, eventslib_sample_function_handler('status'), 'verify no event dispatched yet: %s');
         eventslib_sample_function_handler('ignorefail'); // Ignore "fail" eventdata from now on.
         $this->assertEquals(1, events_trigger_legacy('test_instant', 'ok'), 'this one should go to queue directly: %s');
+        $this->assertDebuggingNotCalled();
+
         $this->assertEquals(3, events_pending_count('test_instant'), 'three events should in queue: %s');
+        $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
+            ' API, please use it instead.', DEBUG_DEVELOPER);
+
         $this->assertEquals(0, eventslib_sample_function_handler('status'), 'verify previous event was not dispatched: %s');
         $this->assertEquals(3, events_cron('test_instant'), 'all events should be dispatched: %s');
+        // events_cron + one for each dispatched event.
+        $this->assertDebuggingCalledCount(4);
+
         $this->assertEquals(3, eventslib_sample_function_handler('status'), 'verify three events were dispatched: %s');
         $this->assertEquals(0, events_pending_count('test_instant'), 'no events should in queue: %s');
+        $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
+            ' API, please use it instead.', DEBUG_DEVELOPER);
+
         $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'), 'this event should be dispatched immediately: %s');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $this->assertEquals(4, eventslib_sample_function_handler('status'), 'verify event was dispatched: %s');
         $this->assertEquals(0, events_pending_count('test_instant'), 'no events should in queue: %s');
+        $this->assertDebuggingCalled('events_pending_count() has been deprecated along with all Events 1 API in favour of Events 2' .
+            ' API, please use it instead.', DEBUG_DEVELOPER);
     }
 
     /**
      * Tests events_trigger() function.
      */
     public function test_events_trigger_debugging() {
+
+        events_update_definition('unittest');
+        $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
+
         $this->assertEquals(0, events_trigger('test_instant', 'ok'));
-        $this->assertDebuggingCalled();
+        $debugmessages = array('events_trigger() is deprecated, please use new events instead', self::DEBUGGING_MSG);
+        $this->assertDebuggingCalledCount(2, $debugmessages, array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
     }
 }
 
index 02437f8..c4e9f6f 100644 (file)
@@ -34,6 +34,9 @@ information provided here is intended especially for developers.
 * groups_delete_group_members() $showfeedback parameter has been removed and is no longer
   respected. Users of this function should output their own feedback if required.
 * Number of changes to Tags API, see tag/upgrade.txt for more details
+* The previous events API handlers are being deprecated in favour of events 2 API, debugging messages are being displayed if
+  there are 3rd party plugins using it. Switch to events 2 API please, see https://docs.moodle.org/dev/Event_2#Event_dispatching_and_observers
+  Note than you will need to bump the plugin version so moodle is aware that you removed the plugin's event handlers.
 
 === 3.0 ===