123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- <?php
- namespace Gogs\API\Request {
- /**
- * Base class for request types.
- *
- * Each request shall inherit this class to ensure
- * it will have the correct methods required by interface,
- * and get the cURL functionality.
- *
- * @author Joachim M. Giaever (joachim[]giaever.org)
- * @abstact
- */
- abstract class Base implements RequestInterface {
- private $tag;
- protected $loaded = false;
- protected $scope;
- use \Gogs\Lib\Curl\Client {
- get as private mget;
- post as private mpost;
- delete as private mdelete;
- }
- /**
- * @param string $api_url The URL to the API.
- * @param string $api_token A token for an authorized user
- */
- public function __construct(string $api_url, string $api_token) {
- $this->url = $api_url;
- $this->token = $api_token;
- $this->tag = strtolower(basename(str_replace("\\", "/", get_class($this))));
- }
- /**
- * Load an object.
- *
- * If `$force = true` the object will be fetched
- * from the Gogs API again.
- *
- * @throws Exception\NotImplementedException when method doesnt support load
- * @return object
- */
- final public function load(bool $force = false) {
- if (!$this->set_scope("load"))
- throw new Exception\NotImplementedException("::load:: Not implemented for class '" . get_class($this) . "'");
- if ($this->loaded && !$force)
- return $this;
- $jenc = $this->mget($this->scope);
- $this->json_set_property($this->json_decode($jenc));
- /*
- * JSON set property should also do this, but
- * to ensure its done, we'll also do it here
- */
- $this->loaded = true;
- return $this;
- }
- /**
- * Perform a GET-request against the Gogs API.
- *
- * Ensure the correct scope i set first, with
- * ```php
- * $this->set_scope("*valid scope*"); // e.g create
- * ```
- *
- * @param array $params The parameters
- * @return string
- */
- final protected function method_get(array $params = array()) {
- return $this->mget($this->scope, $params);
- }
- /**
- * Perform a POST-request against the Gogs API.
- *
- * Ensure the correct scope i set first, with
- * ```php
- * $this->set_scope("*valid scope*"); // e.g create
- * ```
- *
- * @param array $params The parameters
- * @return string
- */
- final protected function method_post(array $params = array()) {
- return $this->mpost($this->scope, $params);
- }
- /**
- * Perform a DELETE-request against the Gogs API.
- *
- * Ensure the correct scope i set first, with
- * ```php
- * $this->set_scope("*valid scope*"); // e.g delete
- * ```
- *
- * @return string
- */
- final protected function method_delete() {
- return $this->mdelete($this->scope);
- }
- /**
- * Get object references by identifier.
- *
- * @param string $s Identifier to look up.
- * @return null
- */
- public function get(string $s) {
- //if (!$this->set_scope("get"))
- throw new Exception\NotImplementedException("::get:: Not implemented for class '" . get_class($this) . "'");
- return null;
- }
- /**
- * Create object inherited by class.
- *
- * Child class must add a scope for 'create' and ensure child is not *loaded*,
- * otherwise will `create` throw an exception.
- *
- * @param string $args yeah, well
- * @return true
- * @throws Exception\InvalidMethodRequestException
- * @throws Exception\NotImplementedException
- */
- public function create(...$args) {
- if ($this->loaded)
- throw new Exception\InvalidMethodRequestException("::create:: Cant create on an git-initialized object. Create new object.");
- if (!$this->set_scope("create"))
- throw new Exception\NotImplementedException("::create:: Not implemented for class '" . get_class($this) . "'");
- $ret = $this->method_post(...$args);
- $this->json_set_property($this->json_decode($ret));
- return true;
- }
- /**
- * Patch (update) object
- *
- * @throws Exception\InvalidMethodRequestException
- * @throws Exception\NotImplementedException
- */
- public function patch() {
- if (!$this->loaded)
- throw new Exception\InvalidMethodRequestException("::patch:: Cant patch an git-uninitialized object. Load it first.");
- if (!$this->set_scope("patch"))
- throw new Exception\NotImplementedException("::patch:: Not implemented for class '" . get_class($this) . "'");
- }
- /**
- * Delete object.
- *
- * @throws Exception\NotImplementedException
- */
- public function delete() {
- if (!$this->set_scope("delete"))
- throw new Exception\NotImplementedException("::delete:: Not implemented for class '" . get_class($this) . "'");
- return $this->method_delete();
- }
- /**
- * Decode JSON-string.
- *
- * Will ensure that there weren't any errors by calling `$this->json_error`.
- *
- * @param string $jenc Encoded JSON string
- * @return object
- */
- final protected function json_decode(string $jenc) {
- $obj = json_decode($jenc);
- $this->json_error();
- return $obj;
- }
- /**
- * Encode JSON-object/array.
- *
- * Will ensure that there weren't any errors by calling `$this->json_error`.
- *
- * @param iterable $jdec JSON-data
- * @return string
- */
- final protected function json_encode(iterable $jdec) {
- $jenc = json_encode($jdec);
- $this->json_error();
- return $jenc;
- }
- /**
- * Check for errors on encoding/decoding.
- *
- * @throws Exception\RequestErrorException
- */
- final protected function json_error() {
- if (($err = json_last_error()) != JSON_ERROR_NONE)
- throw new Exception\RequestErrorException(json_last_error_msg(), $err);
- }
- /**
- * Get basename of a class (remove namespace).
- *
- * @param string $class The FQN
- * @return string
- */
- private function basename_class(string $class) {
- return strtolower(basename(str_replace("\\", "/", $class)));
- }
- /**
- * Return basename of parent class.
- *
- * @return string
- */
- private function get_parent() {
- $parent = get_parent_class($this);
- if ($parent != __CLASS__)
- return $this->basename_class($parent);
- return null;
- }
- /**
- * Get property key by name.
- *
- * Classes sets property from json directly, but they are
- * named within the class by `classname_propertyname`. This
- * method returns the key name.
- *
- * @param string $name Name of the key
- * @param bool $parent Get key in parent
- * @return string
- */
- final private function key(string $name, bool $parent = false) {
- $tag = sprintf("%s_", $this->tag);
- if (strpos($name, $tag) === 0) {
- if ($parent && !empty($ptag = $this->get_parent()))
- return sprintf("%s_%s", $ptag, substr($name, strlen($tag)));
- return $name . "?";
- }
- if ($parent && !empty($ptag = $this->get_parent()))
- return sprintf("%s_%s", $ptag, $name);
- return $tag . $name;
- }
- /**
- * Checks if the property (key) exists within self
- * or parent class.
- *
- * Returns the actual key if it does. A class key (aka property)
- * start with the tag `classname_` followed by property name,
- * reflecting the JSON-object, and can be reached by
- *
- * * `$class->parameter`,
- * * `$class->classname_parameter` or alternatively (for classes that inherits another class).
- * * `$class->parentclassname_parameter`.
- *
- * If a class override a parent class with the same parameter,
- * the class's own parameter will be favoured.
- *
- * As this is public properties this wont be an security issue;
- *
- * @param $name Name of the key.
- * @return string|false False on failure
- */
- final protected function property_exists($name) {
- if (property_exists($this, $key = $this->key($name)))
- return $key;
- if (property_exists($this, $key = $this->key($name, true)))
- return $key;
- return false;
- }
- /**
- * Get property by name.
- *
- * Checks both self and parent for the property.
- *
- * Returns the value if property exists, otherwise an `E_USER_NOTICE`
- * is triggered.
- *
- * @param string $name
- * @return mixed|null Null when unknown
- */
- final public function __get(string $name) {
- $key = $this->property_exists($name);
- if ($key)
- return $this->{$key};
- $trace = debug_backtrace();
- trigger_error(
- sprintf(
- "Undefined property '%s' {%s} in '%s' on line %s. Neither does its parent '%s'",
- $name,
- $this->key($name),
- $trace[0]["file"],
- $trace[0]["line"],
- $this->basename_class(get_parent_class($this))
- ),
- E_USER_NOTICE
- );
- return null;
- }
- /**
- * Set property by name.
- *
- * Checks both self and parent for the property.
- *
- * Returns the value if property exists, otherwise an `E_USER_NOTICE`
- * is triggered.
- *
- * @param string $name Property name
- * @param mixed $value Property value
- * @return mixed|null Null when unknown
- */
- final public function __set(string $name, $value) {
- $key = $this->property_exists($name);
- if ($key)
- return $this->{$key} = $value;
- $trace = debug_backtrace();
- trigger_error(
- sprintf(
- "Undefined property '%s' {%s} in '%s' on line %s. Neither does its parent '%s'",
- $name,
- $this->key($name),
- $trace[0]["file"],
- $trace[0]["line"],
- $this->basename_class(get_parent_class($this))
- ),
- E_USER_NOTICE
- );
- return null;
- }
- /**
- * Checks if property is set.
- *
- * Checks both self and parent for property.
- *
- * Triggers E_USER_NOTICE if property is unknown.
- *
- * @param string $name Property name
- * @return bool
- */
- final public function __isset(string $name) {
- $key = $this->property_exists($name);
- if ($key)
- return isset($this->{$key});
- $trace = debug_backtrace();
- trigger_error(
- sprintf(
- "Undefined property '%s' {%s} in '%s' on line %s. Neither does its parent '%s'",
- $name,
- $this->key($name),
- $trace[0]["file"],
- $trace[0]["line"],
- $this->basename_class(get_parent_class($this))
- ),
- E_USER_NOTICE
- );
- return false;
- }
- /**
- * Set properties for the current object.
- *
- * Each child class must implement this to set its data. Will
- * be called by methods such as `load` and from collection
- * classes.
- *
- * Will return true/false for singel objects but an array on collections.
- * The array will contain the newly inserted elements. This to prevent
- * additional iterations.
- *
- * This method should also set loaded to true or false, depending
- * on success or failure.
- *
- * @see Collection
- * @param mixed $obj
- * @return true|array
- */
- abstract protected function json_set_property($obj);
- /**
- * Set the scope for the request methods accepted by the child.
- *
- * This can be
- * * `get`,
- * * `search`,
- * * `delete` etc.
- *
- * Must return true if scope exists of false otherwise. Methods
- * the calls this will throw an exception if not true is returned.
- *
- * @param string $method Method type, e.g "get"
- * @return bool
- */
- abstract protected function set_scope(string $method);
- }
- }
- ?>
|