Skip to content

Commit

Permalink
MDL-61307 core: Add component_class_callback functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewnicols committed Mar 9, 2018
1 parent 5a146aa commit 37db3b8
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 0 deletions.
31 changes: 31 additions & 0 deletions lib/moodlelib.php
Original file line number Diff line number Diff line change
Expand Up @@ -7727,6 +7727,37 @@ function component_callback_exists($component, $function) {
return false;
}

/**
* Call the specified callback method on the provided class.
*
* If the callback returns null, then the default value is returned instead.
* If the class does not exist, then the default value is returned.
*
* @param string $classname The name of the class to call upon.
* @param string $methodname The name of the staticically defined method on the class.
* @param array $params The arguments to pass into the method.
* @param mixed $default The default value.
* @return mixed The return value.
*/
function component_class_callback($classname, $methodname, array $params, $default = null) {
if (!class_exists($classname)) {
return $default;
}

if (!method_exists($classname, $methodname)) {
return $default;
}

$fullfunction = $classname . '::' . $methodname;
$result = call_user_func_array($fullfunction, $params);

if (null === $result) {
return $default;
} else {
return $result;
}
}

/**
* Checks whether a plugin supports a specified feature.
*
Expand Down
61 changes: 61 additions & 0 deletions lib/tests/fixtures/component_class_callback_example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Fixtures for component_class_callback tests.
*
* @package core
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();

/**
* Class fixture for component_class_callback.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_component_class_callback_example {
/**
* Function which returns the input value.
*
* @param mixed $output
* @return mixed
*/
public static function method_returns_value($output) {
return $output;
}

/**
* Function which returns all args.
*
* @return mixed
*/
public static function method_returns_all_params() {
return count(func_get_args());
}
}

/**
* Class fixture for component_class_callback which extends another class.
*
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class test_component_class_callback_child_example extends test_component_class_callback_example {
}
126 changes: 126 additions & 0 deletions lib/tests/moodlelib_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -3588,4 +3588,130 @@ public function test_unserialize_array() {
$a = array('aggregatesonly' => [51, 34], 'gradesonly' => [21, 45, 78]);
$this->assertEquals($a, unserialize_array(serialize($a)));
}

/**
* Test that the component_class_callback returns the correct default value when the class was not found.
*
* @dataProvider component_class_callback_default_provider
* @param $default
*/
public function test_component_class_callback_not_found($default) {
$this->assertSame($default, component_class_callback('thisIsNotTheClassYouWereLookingFor', 'anymethod', [], $default));
}

/**
* Test that the component_class_callback returns the correct default value when the class was not found.
*
* @dataProvider component_class_callback_default_provider
* @param $default
*/
public function test_component_class_callback_method_not_found($default) {
require_once(__DIR__ . '/fixtures/component_class_callback_example.php');

$this->assertSame($default, component_class_callback(test_component_class_callback_example::class, 'this_is_not_the_method_you_were_looking_for', ['abc'], $default));
}

/**
* Test that the component_class_callback returns the default when the method returned null.
*
* @dataProvider component_class_callback_default_provider
* @param $default
*/
public function test_component_class_callback_found_returns_null($default) {
require_once(__DIR__ . '/fixtures/component_class_callback_example.php');

$this->assertSame($default, component_class_callback(test_component_class_callback_example::class, 'method_returns_value', [null], $default));
$this->assertSame($default, component_class_callback(test_component_class_callback_child_example::class, 'method_returns_value', [null], $default));
}

/**
* Test that the component_class_callback returns the expected value and not the default when there was a value.
*
* @dataProvider component_class_callback_data_provider
* @param $default
*/
public function test_component_class_callback_found_returns_value($value) {
require_once(__DIR__ . '/fixtures/component_class_callback_example.php');

$this->assertSame($value, component_class_callback(test_component_class_callback_example::class, 'method_returns_value', [$value], 'This is not the value you were looking for'));
$this->assertSame($value, component_class_callback(test_component_class_callback_child_example::class, 'method_returns_value', [$value], 'This is not the value you were looking for'));
}

/**
* Test that the component_class_callback handles multiple params correctly.
*
* @dataProvider component_class_callback_multiple_params_provider
* @param $default
*/
public function test_component_class_callback_found_accepts_multiple($params, $count) {
require_once(__DIR__ . '/fixtures/component_class_callback_example.php');

$this->assertSame($count, component_class_callback(test_component_class_callback_example::class, 'method_returns_all_params', $params, 'This is not the value you were looking for'));
$this->assertSame($count, component_class_callback(test_component_class_callback_child_example::class, 'method_returns_all_params', $params, 'This is not the value you were looking for'));
}

/**
* Data provider with list of default values for user in component_class_callback tests.
*
* @return array
*/
public function component_class_callback_default_provider() {
return [
'null' => [null],
'empty string' => [''],
'string' => ['This is a string'],
'int' => [12345],
'stdClass' => [(object) ['this is my content']],
'array' => [['a' => 'b',]],
];
}

/**
* Data provider with list of default values for user in component_class_callback tests.
*
* @return array
*/
public function component_class_callback_data_provider() {
return [
'empty string' => [''],
'string' => ['This is a string'],
'int' => [12345],
'stdClass' => [(object) ['this is my content']],
'array' => [['a' => 'b',]],
];
}

/**
* Data provider with list of default values for user in component_class_callback tests.
*
* @return array
*/
public function component_class_callback_multiple_params_provider() {
return [
'empty array' => [
[],
0,
],
'string value' => [
['one'],
1,
],
'string values' => [
['one', 'two'],
2,
],
'arrays' => [
[[], []],
2,
],
'nulls' => [
[null, null, null, null],
4,
],
'mixed' => [
['a', 1, null, (object) [], []],
5,
],
];
}
}

0 comments on commit 37db3b8

Please sign in to comment.