llms.abstract.api.handler.php 6.71 KB
Newer Older
cyrille's avatar
cyrille committed
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 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
<?php
/**
 * 3rd Party API request handler abstract
 *
 * @package LifterLMS/Abstracts/Classes
 *
 * @since 3.11.2
 * @version 4.21.3
 */

defined( 'ABSPATH' ) || exit;

/**
 * 3rd Party API request handler abstract class
 *
 * @since 3.11.2
 * @since 3.30.1 self::set_request_body() may respond with `null` in order to send a request with no `body`.
 */
abstract class LLMS_Abstract_API_Handler {

	/**
	 * Determines if an empty response body should be interpreted as an error
	 *
	 * @var bool
	 */
	protected $allow_empty_response = false;

	/**
	 * Default request method
	 *
	 * @var  string
	 */
	protected $default_request_method = 'POST';

	/**
	 * Determine if the request should be made as JSON
	 *
	 * @var bool
	 */
	protected $is_json = true;

	/**
	 * Request timeout in seconds
	 *
	 * @var integer
	 */
	protected $request_timeout = 60;

	private $result        = null;
	private $error_message = null;
	private $error_object  = null;
	private $error_type    = null;

	/**
	 * Construct an API call, parameters are passed to private `call()` function
	 *
	 * @param    stirng $resource  url endpoint or resource to make a request to
	 * @param    array  $data      array of data to pass in the body of the request
	 * @param    string $method    method of request (POST, GET, DELETE, PUT, etc...)
	 * @return   void
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	public function __construct( $resource, $data, $method = null ) {

		$this->call( $resource, $data, $method );

	}

	/**
	 * Execute an API request.
	 *
	 * @since 3.11.2
	 * @since 3.30.1 self::set_request_body() may respond with `null` in order to send a request with no `body`
	 * @since 4.21.3 Use `wp_json_encode()` in favor of `json_encode()`.
	 *                Updated the API connection error message.
	 *
	 * @param    string $resource  url endpoint or resource to make a request to.
	 * @param    array  $data      array of data to pass in the body of the request.
	 * @param    string $method    method of request (POST, GET, DELETE, PUT, etc...).
	 * @return   null
	 */
	private function call( $resource, $data, $method = null ) {

		$method = is_null( $method ) ? $this->default_request_method : $method;

		// setup headers.
		$content_type = $this->is_json ? 'application/json; charset=utf-8' : 'application/x-www-form-urlencoded';
		$headers      = $this->set_request_headers(
			array(
				'content-type' => $content_type,
			),
			$resource,
			$method
		);

		$args = array(
			'headers'    => $headers,
			'method'     => $method,
			'timeout'    => $this->request_timeout,
			'user-agent' => $this->set_user_agent( 'LifterLMS ' . LLMS_VERSION, $resource, $method ),
		);

		// setup body.
		$body = $this->set_request_body( $data, $method, $resource );

		// if "null" if passed to body, don't send a body at all.
		if ( ! is_null( $body ) ) {
			$args['body'] = $this->is_json && $body ? wp_json_encode( $body ) : $body;
		}

		// Attempt to call the API.
		$response = wp_safe_remote_request(
			$this->set_request_url( $resource, $method ),
			$args
		);

		// Connection error.
		if ( is_wp_error( $response ) ) {
			return $this->set_error( __( 'There was a problem connecting to the external API.', 'lifterlms' ), 'api_connection', $response );
		}

		// Empty body.
		if ( ! $this->allow_empty_response && empty( $response['body'] ) ) {

			return $this->set_error( __( 'Empty Response.', 'lifterlms' ), 'empty_response', $response );

		}

		$this->parse_response( $response );

	}

	/**
	 * Retrieve the private "error_message" variable
	 *
	 * @return   string
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	public function get_error_message() {

		return $this->error_message;

	}

	/**
	 * Get the private "error_object" variable
	 *
	 * @return   mixed
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	public function get_error_object() {

		return $this->error_object;

	}

	/**
	 * Retrieve the private "error_type" variable
	 *
	 * @return   string
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	public function get_error_type() {

		return $this->error_type;

	}

	/**
	 * Retrieve the private "result" variable
	 *
	 * @return   mixed
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	public function get_result() {

		return $this->result;

	}

	/**
	 * Determine if the response is an error
	 *
	 * @return   boolean
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	public function is_error() {

		return is_wp_error( $this->get_result() );

	}

	/**
	 * Parse the body of the response and set a success/error
	 *
	 * @param    array $response  response data
	 * @return   array
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	abstract protected function parse_response( $response );

	/**
	 * Set an Error
	 * Sets all error variables and sets the result as a WP_Error so the result can always be tested with `is_wp_error()`
	 *
	 * @param    string $message  error message
	 * @param    string $type     error code or type
	 * @param    object $obj      full error object or api response
	 * @return   void
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	protected function set_error( $message, $type, $obj ) {

		$this->result        = new WP_Error( $type, $message, $obj );
		$this->error_type    = $type;
		$this->error_message = $message;
		$this->error_object  = $obj;

	}

	/**
	 * Set the result
	 *
	 * @param    mixed $result  result data
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	protected function set_result( $result ) {
		$this->result = $result;
	}

	/**
	 * Set request body
	 *
	 * @param    array  $data      request body
	 * @param    string $method    request method
	 * @param    string $resource  requested resource
	 * @return   array
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	abstract protected function set_request_body( $data, $method, $resource );

	/**
	 * Set request headers
	 *
	 * @param    array  $headers   default request headers
	 * @param    string $resource  request resource
	 * @param    string $method    request method
	 * @return   array
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	protected function set_request_headers( $headers, $resource, $method ) {
		return $headers;
	}

	/**
	 * Set the request URL
	 *
	 * @param    string $resource  requested resource
	 * @param    string $method    request method
	 * @return   string
	 * @since    3.11.2
	 * @version  3.11.2
	 */
	abstract protected function set_request_url( $resource, $method );

	/**
	 * Set the request User Agent
	 * Can be overridden by extending classes when necessary
	 *
	 * @param    string $user_agent  default user agent (LifterLMS {$version})
	 * @param    string $resource    requested resource
	 * @param    string $method      request method
	 * @return   string
	 * @since    3.22.0
	 * @version  3.22.0
	 */
	protected function set_user_agent( $user_agent, $resource, $method ) {
		return $user_agent;
	}

}