diff --git a/lib/externallib.php b/lib/externallib.php index 8f20b35456b..7fd7e52abe8 100644 --- a/lib/externallib.php +++ b/lib/externallib.php @@ -48,7 +48,7 @@ function external_function_info($function, $strictness=MUST_EXIST) { // Fallback to explicit include of externallib.php. $function->classpath = empty($function->classpath) ? core_component::get_component_directory($function->component).'/externallib.php' : $CFG->dirroot.'/'.$function->classpath; if (!file_exists($function->classpath)) { - throw new coding_exception('Cannot find file with external function implementation'); + throw new coding_exception('Cannot find file with external function implementation: ' . $function->classname); } require_once($function->classpath); if (!class_exists($function->classname)) { @@ -551,6 +551,30 @@ class external_multiple_structure extends external_description { * @since Moodle 2.0 */ class external_function_parameters extends external_single_structure { + + /** + * Constructor - does extra checking to prevent top level optional parameters. + * + * @param array $keys + * @param string $desc + * @param bool $required + * @param array $default + */ + public function __construct(array $keys, $desc='', $required=VALUE_REQUIRED, $default=null) { + global $CFG; + + if ($CFG->debugdeveloper) { + foreach ($keys as $key => $value) { + if ($value instanceof external_value) { + if ($value->required == VALUE_OPTIONAL) { + debugging('External function parameters: invalid OPTIONAL value specified.', DEBUG_DEVELOPER); + break; + } + } + } + } + parent::__construct($keys, $desc, $required, $default); + } } /** diff --git a/lib/tests/externallib_test.php b/lib/tests/externallib_test.php index 0caa69eb8bf..63d7b519165 100644 --- a/lib/tests/externallib_test.php +++ b/lib/tests/externallib_test.php @@ -264,6 +264,26 @@ class core_externallib_testcase extends advanced_testcase { $this->setExpectedException('invalid_parameter_exception'); test_exernal_api::get_context_wrapper(array('roleid' => 3, 'userid' => $USER->id, 'instanceid' => $course->id)); } + + public function test_all_external_info() { + global $DB; + + $functions = $DB->get_records('external_functions', array(), 'name'); + // We are testing here that all the external function descriptions can be generated without + // producing warnings. E.g. misusing optional params will generate a debugging message which + // will fail this test. + foreach ($functions as $f) { + $desc = external_function_info($f); + $this->assertNotEmpty($desc->name); + $this->assertNotEmpty($desc->classname); + $this->assertNotEmpty($desc->methodname); + $this->assertEquals($desc->component, clean_param($desc->component, PARAM_COMPONENT)); + $this->assertInstanceOf('external_function_parameters', $desc->parameters_desc); + if ($desc->returns_desc != null) { + $this->assertInstanceOf('external_description', $desc->returns_desc); + } + } + } } /*