142e66c7aSAndreas Gohr<?php 242e66c7aSAndreas Gohr 342e66c7aSAndreas Gohrnamespace dokuwiki\Remote; 442e66c7aSAndreas Gohr 542e66c7aSAndreas Gohr 6*dd7472d3SAndreas Gohruse dokuwiki\Remote\OpenApiDoc\DocBlockMethod; 7*dd7472d3SAndreas Gohr 842e66c7aSAndreas Gohrclass ApiCall 942e66c7aSAndreas Gohr{ 1042e66c7aSAndreas Gohr /** @var callable The method to be called for this endpoint */ 1142e66c7aSAndreas Gohr protected $method; 1242e66c7aSAndreas Gohr 1342e66c7aSAndreas Gohr /** @var bool Whether this call can be called without authentication */ 1442e66c7aSAndreas Gohr protected bool $isPublic = false; 1542e66c7aSAndreas Gohr 16*dd7472d3SAndreas Gohr /** @var DocBlockMethod The meta data of this call as parsed from its doc block */ 17*dd7472d3SAndreas Gohr protected $docs; 1866f07661SAndreas Gohr 1942e66c7aSAndreas Gohr /** 2042e66c7aSAndreas Gohr * Make the given method available as an API call 2142e66c7aSAndreas Gohr * 2242e66c7aSAndreas Gohr * @param string|array $method Either [object,'method'] or 'function' 2342e66c7aSAndreas Gohr */ 2442e66c7aSAndreas Gohr public function __construct($method) 2542e66c7aSAndreas Gohr { 2642e66c7aSAndreas Gohr if (!is_callable($method)) { 2742e66c7aSAndreas Gohr throw new \InvalidArgumentException('Method is not callable'); 2842e66c7aSAndreas Gohr } 2942e66c7aSAndreas Gohr 3042e66c7aSAndreas Gohr $this->method = $method; 3142e66c7aSAndreas Gohr } 3242e66c7aSAndreas Gohr 3342e66c7aSAndreas Gohr /** 3442e66c7aSAndreas Gohr * Call the method 3542e66c7aSAndreas Gohr * 3642e66c7aSAndreas Gohr * Important: access/authentication checks need to be done before calling this! 3742e66c7aSAndreas Gohr * 3842e66c7aSAndreas Gohr * @param array $args 3942e66c7aSAndreas Gohr * @return mixed 4042e66c7aSAndreas Gohr */ 4142e66c7aSAndreas Gohr public function __invoke($args) 4242e66c7aSAndreas Gohr { 4342e66c7aSAndreas Gohr if (!array_is_list($args)) { 4442e66c7aSAndreas Gohr $args = $this->namedArgsToPositional($args); 4542e66c7aSAndreas Gohr } 4642e66c7aSAndreas Gohr return call_user_func_array($this->method, $args); 4742e66c7aSAndreas Gohr } 4842e66c7aSAndreas Gohr 4942e66c7aSAndreas Gohr /** 50*dd7472d3SAndreas Gohr * Access the method documentation 51*dd7472d3SAndreas Gohr * 52*dd7472d3SAndreas Gohr * This lazy loads the docs only when needed 53*dd7472d3SAndreas Gohr * 54*dd7472d3SAndreas Gohr * @return DocBlockMethod 55*dd7472d3SAndreas Gohr */ 56*dd7472d3SAndreas Gohr public function getDocs() 57*dd7472d3SAndreas Gohr { 58*dd7472d3SAndreas Gohr if ($this->docs === null) { 59*dd7472d3SAndreas Gohr try { 60*dd7472d3SAndreas Gohr if (is_array($this->method)) { 61*dd7472d3SAndreas Gohr $reflect = new \ReflectionMethod($this->method[0], $this->method[1]); 62*dd7472d3SAndreas Gohr } else { 63*dd7472d3SAndreas Gohr $reflect = new \ReflectionFunction($this->method); 64*dd7472d3SAndreas Gohr } 65*dd7472d3SAndreas Gohr $this->docs = new DocBlockMethod($reflect); 66*dd7472d3SAndreas Gohr } catch (\ReflectionException $e) { 67*dd7472d3SAndreas Gohr throw new \RuntimeException('Failed to parse API method documentation', 0, $e); 68*dd7472d3SAndreas Gohr } 69*dd7472d3SAndreas Gohr 70*dd7472d3SAndreas Gohr } 71*dd7472d3SAndreas Gohr return $this->docs; 72*dd7472d3SAndreas Gohr } 73*dd7472d3SAndreas Gohr 74*dd7472d3SAndreas Gohr 75*dd7472d3SAndreas Gohr /** 7642e66c7aSAndreas Gohr * @return bool 7742e66c7aSAndreas Gohr */ 7842e66c7aSAndreas Gohr public function isPublic(): bool 7942e66c7aSAndreas Gohr { 8042e66c7aSAndreas Gohr return $this->isPublic; 8142e66c7aSAndreas Gohr } 8242e66c7aSAndreas Gohr 8342e66c7aSAndreas Gohr /** 8442e66c7aSAndreas Gohr * @param bool $isPublic 8542e66c7aSAndreas Gohr * @return $this 8642e66c7aSAndreas Gohr */ 8742e66c7aSAndreas Gohr public function setPublic(bool $isPublic = true): self 8842e66c7aSAndreas Gohr { 8942e66c7aSAndreas Gohr $this->isPublic = $isPublic; 9042e66c7aSAndreas Gohr return $this; 9142e66c7aSAndreas Gohr } 9242e66c7aSAndreas Gohr 9342e66c7aSAndreas Gohr 9442e66c7aSAndreas Gohr /** 9542e66c7aSAndreas Gohr * @return array 9642e66c7aSAndreas Gohr */ 9742e66c7aSAndreas Gohr public function getArgs(): array 9842e66c7aSAndreas Gohr { 99*dd7472d3SAndreas Gohr return $this->getDocs()->getParameters(); 10042e66c7aSAndreas Gohr } 10142e66c7aSAndreas Gohr 10242e66c7aSAndreas Gohr /** 10342e66c7aSAndreas Gohr * @return array 10442e66c7aSAndreas Gohr */ 10542e66c7aSAndreas Gohr public function getReturn(): array 10642e66c7aSAndreas Gohr { 107*dd7472d3SAndreas Gohr return $this->getDocs()->getReturn(); 10842e66c7aSAndreas Gohr } 10942e66c7aSAndreas Gohr 11042e66c7aSAndreas Gohr /** 11142e66c7aSAndreas Gohr * @return string 11242e66c7aSAndreas Gohr */ 11342e66c7aSAndreas Gohr public function getSummary(): string 11442e66c7aSAndreas Gohr { 115*dd7472d3SAndreas Gohr return $this->getDocs()->getSummary(); 11642e66c7aSAndreas Gohr } 11742e66c7aSAndreas Gohr 11842e66c7aSAndreas Gohr /** 11942e66c7aSAndreas Gohr * @return string 12042e66c7aSAndreas Gohr */ 12142e66c7aSAndreas Gohr public function getDescription(): string 12242e66c7aSAndreas Gohr { 123*dd7472d3SAndreas Gohr return $this->getDocs()->getDescription(); 12442e66c7aSAndreas Gohr } 12542e66c7aSAndreas Gohr 12642e66c7aSAndreas Gohr /** 12742e66c7aSAndreas Gohr * Converts named arguments to positional arguments 12842e66c7aSAndreas Gohr * 12942e66c7aSAndreas Gohr * @fixme with PHP 8 we can use named arguments directly using the spread operator 13042e66c7aSAndreas Gohr * @param array $params 13142e66c7aSAndreas Gohr * @return array 13242e66c7aSAndreas Gohr */ 13342e66c7aSAndreas Gohr protected function namedArgsToPositional($params) 13442e66c7aSAndreas Gohr { 13542e66c7aSAndreas Gohr $args = []; 13642e66c7aSAndreas Gohr 137*dd7472d3SAndreas Gohr foreach (array_keys($this->docs->getParameters()) as $arg) { 13842e66c7aSAndreas Gohr if (isset($params[$arg])) { 13942e66c7aSAndreas Gohr $args[] = $params[$arg]; 14042e66c7aSAndreas Gohr } else { 14142e66c7aSAndreas Gohr $args[] = null; 14242e66c7aSAndreas Gohr } 14342e66c7aSAndreas Gohr } 14442e66c7aSAndreas Gohr 14542e66c7aSAndreas Gohr return $args; 14642e66c7aSAndreas Gohr } 14742e66c7aSAndreas Gohr 14842e66c7aSAndreas Gohr} 149