parent
e20d695fc3
commit
e4cdba842c
@ -0,0 +1,13 @@ |
||||
<?php |
||||
// SPDX-License-Identifier: EUPL-1.2 |
||||
// Authors: see README.md |
||||
|
||||
namespace SeaCMS\Api; |
||||
|
||||
use Exception; |
||||
|
||||
/** |
||||
* Exception for bad http method |
||||
*/ |
||||
class BadMethodException extends Exception |
||||
{} |
@ -0,0 +1,206 @@ |
||||
<?php |
||||
// SPDX-License-Identifier: EUPL-1.2 |
||||
// Authors: see README.md |
||||
|
||||
namespace SeaCMS\Api; |
||||
|
||||
use JsonSerializable; |
||||
use Throwable; |
||||
|
||||
/** |
||||
* Response for http response |
||||
*/ |
||||
class JsonResponse implements JsonSerializable |
||||
{ |
||||
|
||||
/** |
||||
* HTTP Codes |
||||
* @var array |
||||
*/ |
||||
const HTTP_CODES = [ |
||||
200 => 'OK', |
||||
301 => 'Moved Permanently', |
||||
302 => 'Found', |
||||
304 => 'Not Modified', |
||||
307 => 'Temporary Redirect', |
||||
308 => 'Permanent Redirect', |
||||
400 => 'Bad Request', |
||||
401 => 'Unauthorized', |
||||
403 => 'Forbidden', |
||||
404 => 'Not Found', |
||||
405 => 'Method Not Allowed', |
||||
406 => 'Not Acceptable', |
||||
408 => 'Request Timeout', |
||||
500 => 'Internal Server Error', |
||||
501 => 'Not Implemented', |
||||
503 => 'Service Unavailable', |
||||
]; |
||||
|
||||
/** |
||||
* HTTP CODE |
||||
* @var int |
||||
*/ |
||||
protected $code; |
||||
/** |
||||
* content as array |
||||
* @var array |
||||
*/ |
||||
protected $content; |
||||
/** |
||||
* headers |
||||
* @var array |
||||
*/ |
||||
protected $headers; |
||||
|
||||
|
||||
public function __construct(int $code, array $content, array $headers = []){ |
||||
$this->code = array_key_exists($code, self::HTTP_CODES) ? $code : 501; // default |
||||
$this->content = $content; |
||||
$this->headers = array_merge([ |
||||
'Content-Type' => 'application/json', |
||||
'Access-Control-Allow-Origin' => '*', |
||||
'Access-Control-Allow-Credentials' => 'true', |
||||
'Access-Control-Allow-Headers' => 'X-Requested-With, Location, Slug, Accept, Content-Type', |
||||
'Access-Control-Expose-Headers' => 'Location, Slug, Accept, Content-Type', |
||||
'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, DELETE, PUT, PATCH', |
||||
'Access-Control-Max-Age' => '86400' |
||||
], $headers); |
||||
$this->preparedOutput = ''; |
||||
} |
||||
|
||||
/** |
||||
* merge in content |
||||
* @param array $newContent |
||||
* @return $this |
||||
*/ |
||||
public function mergeInContent(array $newContent){ |
||||
$this->content = array_merge( |
||||
$this->content, |
||||
$newContent |
||||
); |
||||
} |
||||
/** |
||||
* prepend in content |
||||
* @param array $newContent |
||||
* @return $this |
||||
*/ |
||||
protected function prependInContent(array $newContent){ |
||||
$this->content = array_merge( |
||||
$newContent, |
||||
$this->content |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* set code |
||||
* @param int |
||||
*/ |
||||
public function setCode(int $code) |
||||
{ |
||||
$this->code = $code; |
||||
} |
||||
|
||||
/* === Getters === */ |
||||
/** |
||||
* return code |
||||
* @return int |
||||
*/ |
||||
public function getCode(): int |
||||
{ |
||||
return $this->code; |
||||
} |
||||
/** |
||||
* return content |
||||
* @return array |
||||
*/ |
||||
public function getContent(): array |
||||
{ |
||||
return $this->content; |
||||
} |
||||
|
||||
/* === === */ |
||||
|
||||
/** |
||||
* Sends HTTP headers. |
||||
* |
||||
* @return $this |
||||
*/ |
||||
public function sendHeaders(): JsonResponse |
||||
{ |
||||
// headers have already been sent by the developer |
||||
if (!headers_sent()) { |
||||
|
||||
// headers |
||||
foreach ($this->headers as $name => $value) { |
||||
header($name.': '.$value); |
||||
} |
||||
|
||||
// status |
||||
$statusText = self::HTTP_CODES[$this->code]; |
||||
header("HTTP/1.0 {$this->code} $statusText"); |
||||
} |
||||
|
||||
return $this; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* send headers and return output |
||||
* @return string |
||||
*/ |
||||
public function send(): string |
||||
{ |
||||
return $this->preparedOutput()->prepareStatusText()->sendHeaders()->returnContent(); |
||||
} |
||||
|
||||
/** |
||||
* check if output is JSONSerializable |
||||
* @return JsonResponse $this |
||||
*/ |
||||
protected function preparedOutput(): JsonResponse |
||||
{ |
||||
try { |
||||
json_encode($this->content); |
||||
} catch (Throwable $th) { |
||||
$this->code = 500; |
||||
$this->content = ['code' => 500, 'reason' =>"Not possible to JSONSerialize content"]; |
||||
} |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* prepare statusText |
||||
* @return JsonResponse $this |
||||
*/ |
||||
protected function prepareStatusText(): JsonResponse |
||||
{ |
||||
if (!array_key_exists($this->code,self::HTTP_CODES)){ |
||||
$previousCode = intval($this->code); |
||||
$this->code = 501; |
||||
$this->prependInContent(['code' => 501, 'reason' =>"Wanted code ($previousCode) is not implemented !"]); |
||||
} |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* return content as String |
||||
* @return string |
||||
*/ |
||||
protected function returnContent(): string |
||||
{ |
||||
return json_encode($this->getContent()); |
||||
} |
||||
|
||||
/** |
||||
* export class as array |
||||
* @return array |
||||
*/ |
||||
public function jsonSerialize(): mixed |
||||
{ |
||||
return [ |
||||
'code' => $this->getCode(), |
||||
'content' => $this->getContent(), |
||||
'headers' => $this->headers, |
||||
]; |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
<?php |
||||
// SPDX-License-Identifier: EUPL-1.2 |
||||
// Authors: see README.md |
||||
|
||||
namespace SeaCMS\Api; |
||||
|
||||
use Exception; |
||||
|
||||
/** |
||||
* Exception when route not found |
||||
*/ |
||||
class NotFoundRouteException extends Exception |
||||
{} |
Loading…
Reference in new issue