From 9a4c2f50c9e7990f14bfcdc99553c57a5db973bd Mon Sep 17 00:00:00 2001 From: Jerome Mouneyrac Date: Mon, 7 Jan 2013 11:11:14 +0800 Subject: [PATCH] MDL-37355 object are automatically cast into object by the return value --- lib/externallib.php | 10 ++++-- lib/tests/externallib_test.php | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/lib/externallib.php b/lib/externallib.php index 0c6e44dbc04..c70d340e1ce 100644 --- a/lib/externallib.php +++ b/lib/externallib.php @@ -266,10 +266,16 @@ class external_api { } } else if ($description instanceof external_single_structure) { - if (!is_array($response)) { - throw new invalid_response_exception('Only arrays accepted. The bad value is: \'' . + if (!is_array($response) && !is_object($response)) { + throw new invalid_response_exception('Only arrays/objects accepted. The bad value is: \'' . print_r($response, true) . '\''); } + + // Cast objects into arrays. + if (is_object($response)) { + $response = (array) $response; + } + $result = array(); foreach ($description->keys as $key=>$subdesc) { if (!array_key_exists($key, $response)) { diff --git a/lib/tests/externallib_test.php b/lib/tests/externallib_test.php index 5bd6e067364..5349ca42aac 100644 --- a/lib/tests/externallib_test.php +++ b/lib/tests/externallib_test.php @@ -74,4 +74,65 @@ class externallib_testcase extends basic_testcase { $this->assertTrue($result['someid'] === 6); $this->assertTrue($result['text'] === 'aaa'); } + + /** + * Test for clean_returnvalue(). + */ + public function test_clean_returnvalue() { + + // Build some return value decription. + $returndesc = new external_multiple_structure( + new external_single_structure( + array( + 'object' => new external_single_structure( + array('value1' => new external_value(PARAM_INT, 'this is a int'))), + 'value2' => new external_value(PARAM_TEXT, 'some text', VALUE_OPTIONAL)) + )); + + // Clean an object (it should be cast into an array). + $object = new stdClass(); + $object->value1 = 1; + $singlestructure['object'] = $object; + $singlestructure['value2'] = 'Some text'; + $testdata = array($singlestructure); + $cleanedvalue = external_api::clean_returnvalue($returndesc, $testdata); + $cleanedsinglestructure = array_pop($cleanedvalue); + $this->assertEquals($object->value1, $cleanedsinglestructure['object']['value1']); + $this->assertEquals($singlestructure['value2'], $cleanedsinglestructure['value2']); + + // Missing VALUE_OPTIONAL. + $object = new stdClass(); + $object->value1 = 1; + $singlestructure = new stdClass(); + $singlestructure->object = $object; + $testdata = array($singlestructure); + $cleanedvalue = external_api::clean_returnvalue($returndesc, $testdata); + $cleanedsinglestructure = array_pop($cleanedvalue); + $this->assertEquals($object->value1, $cleanedsinglestructure['object']['value1']); + $this->assertEquals(false, array_key_exists('value2', $cleanedsinglestructure)); + + // Unknown attribut (the value should be ignored). + $object = array(); + $object['value1'] = 1; + $singlestructure = array(); + $singlestructure['object'] = $object; + $singlestructure['value2'] = 'Some text'; + $singlestructure['unknownvalue'] = 'Some text to ignore'; + $testdata = array($singlestructure); + $cleanedvalue = external_api::clean_returnvalue($returndesc, $testdata); + $cleanedsinglestructure = array_pop($cleanedvalue); + $this->assertEquals($object['value1'], $cleanedsinglestructure['object']['value1']); + $this->assertEquals($singlestructure['value2'], $cleanedsinglestructure['value2']); + $this->assertEquals(false, array_key_exists('unknownvalue', $cleanedsinglestructure)); + + + // Missing required value (an exception is thrown). + $object = array(); + $singlestructure = array(); + $singlestructure['object'] = $object; + $singlestructure['value2'] = 'Some text'; + $testdata = array($singlestructure); + $this->setExpectedException('invalid_response_exception'); + $cleanedvalue = external_api::clean_returnvalue($returndesc, $testdata); + } }