[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/inc/Remote/ -> ApiCall.php (source)

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