1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
<?php
namespace dokuwiki\Remote;
use dokuwiki\Remote\OpenApiDoc\DocBlockMethod;
use InvalidArgumentException;
use ReflectionException;
use ReflectionFunction;
use ReflectionMethod;
use RuntimeException;
class ApiCall
{
/** @var callable The method to be called for this endpoint */
protected $method;
/** @var bool Whether this call can be called without authentication */
protected bool $isPublic = false;
/** @var string The category this call belongs to */
protected string $category;
/** @var DocBlockMethod The meta data of this call as parsed from its doc block */
protected $docs;
/**
* Make the given method available as an API call
*
* @param string|array $method Either [object,'method'] or 'function'
* @param string $category The category this call belongs to
*/
public function __construct($method, $category = '')
{
if (!is_callable($method)) {
throw new InvalidArgumentException('Method is not callable');
}
$this->method = $method;
$this->category = $category;
}
/**
* Call the method
*
* Important: access/authentication checks need to be done before calling this!
*
* @param array $args
* @return mixed
*/
public function __invoke($args)
{
if (!array_is_list($args)) {
$args = $this->namedArgsToPositional($args);
}
return call_user_func_array($this->method, $args);
}
/**
* Access the method documentation
*
* This lazy loads the docs only when needed
*
* @return DocBlockMethod
*/
public function getDocs()
{
if ($this->docs === null) {
try {
if (is_array($this->method)) {
$reflect = new ReflectionMethod($this->method[0], $this->method[1]);
} else {
$reflect = new ReflectionFunction($this->method);
}
$this->docs = new DocBlockMethod($reflect);
} catch (ReflectionException $e) {
throw new RuntimeException('Failed to parse API method documentation', 0, $e);
}
}
return $this->docs;
}
/**
* Is this a public method?
*
* Public methods can be called without authentication
*
* @return bool
*/
public function isPublic()
{
return $this->isPublic;
}
/**
* Set the public flag
*
* @param bool $isPublic
* @return $this
*/
public function setPublic(bool $isPublic = true)
{
$this->isPublic = $isPublic;
return $this;
}
/**
* Get information about the argument of this call
*
* @return array
*/
public function getArgs()
{
return $this->getDocs()->getParameters();
}
/**
* Get information about the return value of this call
*
* @return array
*/
public function getReturn()
{
return $this->getDocs()->getReturn();
}
/**
* Get the summary of this call
*
* @return string
*/
public function getSummary()
{
return $this->getDocs()->getSummary();
}
/**
* Get the description of this call
*
* @return string
*/
public function getDescription()
{
return $this->getDocs()->getDescription();
}
/**
* Get the category of this call
*
* @return string
*/
public function getCategory()
{
return $this->category;
}
/**
* Converts named arguments to positional arguments
*
* @fixme with PHP 8 we can use named arguments directly using the spread operator
* @param array $params
* @return array
*/
protected function namedArgsToPositional($params)
{
$args = [];
foreach ($this->getDocs()->getParameters() as $arg => $arginfo) {
if (isset($params[$arg])) {
$args[] = $params[$arg];
} elseif ($arginfo['optional'] && array_key_exists('default', $arginfo)) {
$args[] = $arginfo['default'];
} else {
throw new InvalidArgumentException("Missing argument $arg");
}
}
return $args;
}
}
|