diff --git a/lib/classes/output/external.php b/lib/classes/output/external.php index 509ec4403c0..cdca30c03bf 100644 --- a/lib/classes/output/external.php +++ b/lib/classes/output/external.php @@ -58,15 +58,6 @@ class external extends external_api { ); } - /** - * Remove comments from mustache template. - * @param string $templatestr - * @return mixed - */ - protected static function strip_template_comments($templatestr) { - return preg_replace('/(?={{!)(.*)(}})/sU', '', $templatestr); - } - /** * Return a mustache template, and all the strings it requires. * @@ -84,23 +75,14 @@ class external extends external_api { 'themename' => $themename, 'includecomments' => $includecomments)); - $component = $params['component']; - $template = $params['template']; - $themename = $params['themename']; - $includecomments = $params['includecomments']; - - $templatename = $component . '/' . $template; - + $loader = new mustache_template_source_loader(); // Will throw exceptions if the template does not exist. - $filename = mustache_template_finder::get_template_filepath($templatename, $themename); - $templatestr = file_get_contents($filename); - - // Remove comments from template. - if (!$includecomments) { - $templatestr = self::strip_template_comments($templatestr); - } - - return $templatestr; + return $loader->load( + $params['component'], + $params['template'], + $params['themename'], + $params['includecomments'] + ); } /** @@ -112,6 +94,95 @@ class external extends external_api { return new external_value(PARAM_RAW, 'template'); } + /** + * Returns description of load_template_with_dependencies() parameters. + * + * @return external_function_parameters + */ + public static function load_template_with_dependencies_parameters() { + return new external_function_parameters([ + 'component' => new external_value(PARAM_COMPONENT, 'component containing the template'), + 'template' => new external_value(PARAM_ALPHANUMEXT, 'name of the template'), + 'themename' => new external_value(PARAM_ALPHANUMEXT, 'The current theme.'), + 'includecomments' => new external_value(PARAM_BOOL, 'Include comments or not', VALUE_DEFAULT, false) + ]); + } + + /** + * Return a mustache template, and all the child templates and strings it requires. + * + * @param string $component The component that holds the template. + * @param string $template The name of the template. + * @param string $themename The name of the current theme. + * @param bool $includecomments Whether to strip comments from the template source. + * @return string the template + */ + public static function load_template_with_dependencies( + string $component, + string $template, + string $themename, + bool $includecomments = false + ) { + global $DB, $CFG, $PAGE; + + $params = self::validate_parameters( + self::load_template_with_dependencies_parameters(), + [ + 'component' => $component, + 'template' => $template, + 'themename' => $themename, + 'includecomments' => $includecomments + ] + ); + + $loader = new mustache_template_source_loader(); + // Will throw exceptions if the template does not exist. + $dependencies = $loader->load_with_dependencies( + $params['component'], + $params['template'], + $params['themename'], + $params['includecomments'] + ); + $formatdependencies = function($dependency) { + $results = []; + foreach ($dependency as $dependencycomponent => $dependencyvalues) { + foreach ($dependencyvalues as $dependencyname => $dependencyvalue) { + array_push($results, [ + 'component' => $dependencycomponent, + 'name' => $dependencyname, + 'value' => $dependencyvalue + ]); + } + } + return $results; + }; + + // Now we have to unpack the dependencies into a format that can be returned + // by external functions (because they don't support dynamic keys). + return [ + 'templates' => $formatdependencies($dependencies['templates']), + 'strings' => $formatdependencies($dependencies['strings']) + ]; + } + + /** + * Returns description of load_template_with_dependencies() result value. + * + * @return external_description + */ + public static function load_template_with_dependencies_returns() { + $resourcestructure = new external_single_structure([ + 'component' => new external_value(PARAM_COMPONENT, 'component containing the resource'), + 'name' => new external_value(PARAM_TEXT, 'name of the resource'), + 'value' => new external_value(PARAM_RAW, 'resource value') + ]); + + return new external_single_structure([ + 'templates' => new external_multiple_structure($resourcestructure), + 'strings' => new external_multiple_structure($resourcestructure) + ]); + } + /** * Returns description of load_icon_map() parameters. * diff --git a/lib/db/services.php b/lib/db/services.php index 6d930b87a40..066f226f035 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1396,6 +1396,14 @@ $functions = array( 'loginrequired' => false, 'ajax' => true, ), + 'core_output_load_template_with_dependencies' => array( + 'classname' => 'core\output\external', + 'methodname' => 'load_template_with_dependencies', + 'description' => 'Load a template and its dependencies for a renderable', + 'type' => 'read', + 'loginrequired' => false, + 'ajax' => true, + ), 'core_output_load_fontawesome_icon_map' => array( 'classname' => 'core\output\external', 'methodname' => 'load_fontawesome_icon_map', diff --git a/lib/tests/output_external_test.php b/lib/tests/output_external_test.php deleted file mode 100644 index 35acb97cff1..00000000000 --- a/lib/tests/output_external_test.php +++ /dev/null @@ -1,147 +0,0 @@ -. - -/** - * Unit tests for lib/classes/output/external.php - * @author Guy Thomas - * @copyright Copyright (c) 2017 Blackboard Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -use core\output\external; - -require_once(__DIR__.'/../../lib/externallib.php'); -require_once(__DIR__.'/../../lib/mustache/src/Mustache/Tokenizer.php'); -require_once(__DIR__.'/../../lib/mustache/src/Mustache/Parser.php'); - -/** - * Class core_output_external_testcase - test \core\output\external class. - * @package core - * @author Guy Thomas - * @copyright Copyright (c) 2017 Blackboard Inc. - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class core_output_external_testcase extends base_testcase { - - /** - * Ensure that stripping comments from templates does not mutilate the template body. - */ - public function test_strip_template_comments() { - - $templatebody = <<<'TBD' -

{{# str }} pluginname, mod_lemmings {{/ str }}

-
{{test}}
-
{{{unescapedtest}}}
- {{#lemmings}} -
-

{{name}}

- {{> mod_lemmings/lemmingprofile }} - {{# pix }} t/edit, core, Edit Lemming {{/ pix }} -
- {{/lemmings}} - {{^lemmings}}Sorry, no lemmings today{{/lemmings}} -
- {{# tabheader }} - - {{/ tabheader }} - {{# tabbody }} -
- {{# tabcontent }} - {{# tabs }} - {{> core/notification_info}} - {{/ tabs }} - {{/ tabcontent }} -
- {{/ tabbody }} -
- {{#js}} - require(['jquery','core/tabs'], function($, tabs) { - - var container = $("#{{ uniqid }}-tab-container"); - tabs.create(container); - }); - {{/js}} -TBD; - $templatewithcomment = <<. - }} - {{! - @template mod_lemmings/lemmings - - Lemmings template. - - The purpose of this template is to render a lot of lemmings. - - Classes required for JS: - * none - - Data attributes required for JS: - * none - - Context variables required for this template: - * attributes Array of name / value pairs. - - Example context (json): - { - "lemmings": [ - { "name": "Lemmy Winks", "age" : 1, "size" : "big" }, - { "name": "Rocky", "age" : 2, "size" : "small" } - ] - } - - }} - $templatebody - {{! - Here's some more comment text - Note, there is no need to test bracketed variables inside comments as gherkin does not support that! - See this issue: https://github.com/mustache/spec/issues/8 - }} -TBC; - - // Ensure that the template when stripped of comments just includes the body. - $stripped = phpunit_util::call_internal_method(null, 'strip_template_comments', - [$templatewithcomment], 'core\output\external'); - $this->assertEquals(trim($templatebody), trim($stripped)); - - $tokenizer = new Mustache_Tokenizer(); - $tokens = $tokenizer->scan($templatebody); - $parser = new Mustache_Parser(); - $tree = $parser->parse($tokens); - $this->assertNotEmpty($tree); - } -} diff --git a/version.php b/version.php index 98db871a797..498a8ccfdc2 100644 --- a/version.php +++ b/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2018122000.00; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2018122000.01; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes.