xref: /dokuwiki/inc/Remote/ApiCall.php (revision dd7472d3f89d3f537224163206d7dbf31ffdad22)
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