MDL-68645 output: Make other generators fail if they init the output too
authorDavid Mudrák <david@moodle.com>
Thu, 14 May 2020 05:55:19 +0000 (07:55 +0200)
committerDavid Mudrák <david@moodle.com>
Thu, 14 May 2020 05:55:19 +0000 (07:55 +0200)
Identically to what we've added to the module generators, let's raise a
coding exception if generating a block or a repository triggers the
theme and output initialisation.

lib/testing/generator/block_generator.php
lib/testing/generator/repository_generator.php

index ce5da1f..3c4d9a4 100644 (file)
@@ -114,10 +114,14 @@ abstract class testing_block_generator extends component_generator_base {
      * @return stdClass the block_instance record that has just been created.
      */
     public function create_instance($record = null, $options = array()) {
-        global $DB;
+        global $DB, $PAGE;
 
         $this->instancecount++;
 
+        // Creating a block is a back end operation, which should not cause any output to happen.
+        // This will allow us to check that the theme was not initialised while creating the block instance.
+        $outputstartedbefore = $PAGE->get_where_theme_was_initialised();
+
         $record = (object)(array)$record;
         $this->preprocess_record($record, $options);
         $record = $this->prepare_record($record);
@@ -133,6 +137,19 @@ abstract class testing_block_generator extends component_generator_base {
         context_block::instance($id);
 
         $instance = $DB->get_record('block_instances', array('id' => $id), '*', MUST_EXIST);
+
+        // If the theme was initialised while creating the block instance, something somewhere called an output
+        // function. Rather than leaving this as a hard-to-debug situation, let's make it fail with a clear error.
+        $outputstartedafter = $PAGE->get_where_theme_was_initialised();
+
+        if ($outputstartedbefore === null && $outputstartedafter !== null) {
+            throw new coding_exception('Creating a block_' . $this->get_blockname() . ' initialised the theme and output!',
+                'This should not happen. Creating a block should be a pure back-end operation. Unnecessarily initialising ' .
+                'the output mechanism at the wrong time can cause subtle bugs and is a significant performance hit. There is ' .
+                'likely a call to an output function that caused it:' . PHP_EOL . PHP_EOL .
+                format_backtrace($outputstartedafter, true));
+        }
+
         return $instance;
     }
 
index 3d5f560..21a4066 100644 (file)
@@ -111,12 +111,16 @@ class testing_repository_generator extends component_generator_base {
      * @return stdClass repository instance record
      */
     public function create_instance($record = null, array $options = null) {
-        global $CFG, $DB;
+        global $CFG, $DB, $PAGE;
         require_once($CFG->dirroot . '/repository/lib.php');
 
         $this->instancecount++;
         $record = (array) $record;
 
+        // Creating a repository is a back end operation, which should not cause any output to happen.
+        // This will allow us to check that the theme was not initialised while creating the repository instance.
+        $outputstartedbefore = $PAGE->get_where_theme_was_initialised();
+
         $typeid = $DB->get_field('repository', 'id', array('type' => $this->get_typename()), MUST_EXIST);
         $instanceoptions = repository::static_function($this->get_typename(), 'get_instance_option_names');
 
@@ -146,6 +150,18 @@ class testing_repository_generator extends component_generator_base {
             $id = repository::static_function($this->get_typename(), 'create', $this->get_typename(), 0, $context, $record);
         }
 
+        // If the theme was initialised while creating the repository instance, something somewhere called an output
+        // function. Rather than leaving this as a hard-to-debug situation, let's make it fail with a clear error.
+        $outputstartedafter = $PAGE->get_where_theme_was_initialised();
+
+        if ($outputstartedbefore === null && $outputstartedafter !== null) {
+            throw new coding_exception('Creating a repository_' . $this->get_typename() . ' initialised the theme and output!',
+                'This should not happen. Creating a repository should be a pure back-end operation. Unnecessarily initialising ' .
+                'the output mechanism at the wrong time can cause subtle bugs and is a significant performance hit. There is ' .
+                'likely a call to an output function that caused it:' . PHP_EOL . PHP_EOL .
+                format_backtrace($outputstartedafter, true));
+        }
+
         return $DB->get_record('repository_instances', array('id' => $id), '*', MUST_EXIST);
     }