diff --git a/_test/tests/inc/remote.test.php b/_test/tests/inc/remote.test.php index 407992ae7e7128e2729ad2542656f4a16525804f..3cbc14f6bc368bd2008814a5ae57b3182ddf39bf 100644 --- a/_test/tests/inc/remote.test.php +++ b/_test/tests/inc/remote.test.php @@ -106,14 +106,32 @@ class remote_plugin_testplugin extends DokuWiki_Remote_Plugin { function methodString() { return 'success'; } function method2($str, $int, $bool = false) { return array($str, $int, $bool); } function publicCall() {return true;} +} + +class remote_plugin_testplugin2 extends DokuWiki_Remote_Plugin { + /** + * This is a dummy method + * + * @param string $str some more parameter description + * @param int $int + * @param bool $bool + * @param Object $unknown + * @return array + */ + public function commented($str, $int, $bool, $unknown) { return array($str, $int, $bool); } + private function privateMethod() {return true;} + protected function protectedMethod() {return true;} + public function _underscore() {return true;} } + class remote_test extends DokuWikiTest { var $userinfo; + /** @var RemoteAPI */ var $remote; function setUp() { @@ -125,10 +143,18 @@ class remote_test extends DokuWikiTest { parent::setUp(); + // mock plugin controller to return our test plugins $pluginManager = $this->getMock('Doku_Plugin_Controller'); - $pluginManager->expects($this->any())->method('getList')->will($this->returnValue(array('testplugin'))); - $pluginManager->expects($this->any())->method('load')->will($this->returnValue(new remote_plugin_testplugin())); - + $pluginManager->method('getList')->willReturn(array('testplugin', 'testplugin2')); + $pluginManager->method('load')->willReturnCallback( + function($type, $plugin) { + if($plugin == 'testplugin2') { + return new remote_plugin_testplugin2(); + } else { + return new remote_plugin_testplugin(); + } + } + ); $plugin_controller = $pluginManager; $conf['remote'] = 1; @@ -151,11 +177,28 @@ class remote_test extends DokuWikiTest { $methods = $this->remote->getPluginMethods(); $actual = array_keys($methods); sort($actual); - $expect = array('plugin.testplugin.method1', 'plugin.testplugin.method2', 'plugin.testplugin.methodString', 'plugin.testplugin.method2ext', 'plugin.testplugin.publicCall'); + $expect = array( + 'plugin.testplugin.method1', + 'plugin.testplugin.method2', + 'plugin.testplugin.methodString', + 'plugin.testplugin.method2ext', + 'plugin.testplugin.publicCall', + + 'plugin.testplugin2.commented' + ); sort($expect); $this->assertEquals($expect,$actual); } + function test_pluginDescriptors() { + $methods = $this->remote->getPluginMethods(); + $this->assertEquals(array('string','int','bool','string'), $methods['plugin.testplugin2.commented']['args']); + $this->assertEquals('array', $methods['plugin.testplugin2.commented']['return']); + $this->assertEquals(0, $methods['plugin.testplugin2.commented']['public']); + $this->assertContains('This is a dummy method', $methods['plugin.testplugin2.commented']['doc']); + $this->assertContains('string $str some more parameter description', $methods['plugin.testplugin2.commented']['doc']); + } + function test_hasAccessSuccess() { global $conf; $conf['remoteuser'] = ''; diff --git a/lib/plugins/remote.php b/lib/plugins/remote.php index 47f954ee6034aa05d4b726a184ee9f9642e135e9..c2253dbd5dad4e146563ee0e96f62adc740f2ae3 100644 --- a/lib/plugins/remote.php +++ b/lib/plugins/remote.php @@ -17,10 +17,82 @@ abstract class DokuWiki_Remote_Plugin extends DokuWiki_Plugin { /** * Get all available methods with remote access. * - * @abstract + * By default it exports all public methods of a remote plugin. Methods beginning + * with an underscore are skipped. + * * @return array Information about all provided methods. {@see RemoteAPI}. */ - public abstract function _getMethods(); + public function _getMethods() { + $result = array(); + + $reflection = new \ReflectionClass($this); + foreach($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + // skip parent methods, only methods further down are exported + $declaredin = $method->getDeclaringClass()->name; + if($declaredin == 'DokuWiki_Plugin' || $declaredin == 'DokuWiki_Remote_Plugin') continue; + $method_name = $method->name; + if(substr($method_name, 0, 1) == '_') continue; + + // strip asterisks + $doc = $method->getDocComment(); + $doc = preg_replace( + array('/^[ \t]*\/\*+[ \t]*/m', '/[ \t]*\*+[ \t]*/m', '/\*+\/\s*$/m','/\s*\/\s*$/m'), + array('', '', '', ''), + $doc + ); + + // prepare data + $data = array(); + $data['name'] = $method_name; + $data['public'] = 0; + $data['doc'] = $doc; + $data['args'] = array(); + + // get parameter type from doc block type hint + foreach($method->getParameters() as $parameter) { + $name = $parameter->name; + $type = 'string'; // we default to string + if(preg_match('/^@param[ \t]+([\w|\[\]]+)[ \t]\$'.$name.'/m', $doc, $m)){ + $type = $this->cleanTypeHint($m[1]); + } + $data['args'][] = $type; + } + + // get return type from doc block type hint + if(preg_match('/^@return[ \t]+([\w|\[\]]+)/m', $doc, $m)){ + $data['return'] = $this->cleanTypeHint($m[1]); + } else { + $data['return'] = 'string'; + } + + // add to result + $result[$method_name] = $data; + } + + return $result; + } + + /** + * Matches the given type hint against the valid options for the remote API + * + * @param string $hint + * @return string + */ + protected function cleanTypeHint($hint) { + $types = explode('|', $hint); + foreach($types as $t) { + if(substr($t, -2) == '[]') { + return 'array'; + } + if($t == 'boolean') { + return 'bool'; + } + if(in_array($t, array('array', 'string', 'int', 'double', 'bool', 'null', 'date', 'file'))) { + return $t; + } + } + return 'string'; + } /** * @return RemoteAPI