262 lines
7 KiB
PHP
262 lines
7 KiB
PHP
<?php
|
|
|
|
namespace Appwrite\Utopia;
|
|
|
|
use Exception;
|
|
use Appwrite\Database\Document;
|
|
use Appwrite\Utopia\Response\Model;
|
|
use Appwrite\Utopia\Response\Model\Error;
|
|
use Appwrite\Utopia\Response\Model\ErrorDev;
|
|
use Appwrite\Utopia\Response\Model\User;
|
|
use Appwrite\Utopia\Response\Model\Session;
|
|
use Appwrite\Utopia\Response\Model\Team;
|
|
use Appwrite\Utopia\Response\Model\TeamList;
|
|
use Appwrite\Utopia\Response\Model\Locale;
|
|
use Appwrite\Utopia\Response\Model\Membership;
|
|
use Appwrite\Utopia\Response\Model\MembershipList;
|
|
use Utopia\Response as UtopiaResponse;
|
|
use Swoole\Http\Response as SwooleResponse;
|
|
|
|
class Response extends UtopiaResponse
|
|
{
|
|
// General
|
|
const MODEL_LOG = 'log'; // - Missing
|
|
const MODEL_ERROR = 'error';
|
|
const MODEL_ERROR_DEV = 'errorDev';
|
|
const MODEL_BASE_LIST = 'baseList';
|
|
|
|
// Users
|
|
const MODEL_USER = 'user';
|
|
const MODEL_SESSION = 'session';
|
|
const MODEL_TOKEN = 'token'; // - Missing
|
|
|
|
// Database
|
|
const MODEL_COLLECTION = 'collection'; // - Missing
|
|
|
|
// Locale
|
|
const MODEL_LOCALE = 'locale';
|
|
const MODEL_COUNTRY = 'country'; // - Missing
|
|
const MODEL_CONTINENT = 'continent'; // - Missing
|
|
const MODEL_CURRENCY = 'currency'; // - Missing
|
|
const MODEL_LANGUAGE = 'langauge'; // - Missing
|
|
const MODEL_PHONE = 'phone'; // - Missing
|
|
|
|
// Storage
|
|
const MODEL_FILE = 'file'; // - Missing
|
|
const MODEL_BUCKET = 'bucket'; // - Missing
|
|
|
|
// Teams
|
|
const MODEL_TEAM = 'team';
|
|
const MODEL_TEAM_LIST = 'teamList';
|
|
const MODEL_MEMBERSHIP = 'membership';
|
|
const MODEL_MEMBERSHIP_LIST = 'membershipList';
|
|
|
|
/**
|
|
* Swoole Response Object
|
|
*
|
|
* @var SwooleResponse
|
|
*/
|
|
protected $swoole = null;
|
|
|
|
/**
|
|
* Response constructor.
|
|
*/
|
|
public function __construct(SwooleResponse $response)
|
|
{
|
|
$this->swoole = $response;
|
|
$this
|
|
->setModel(new Error())
|
|
->setModel(new ErrorDev())
|
|
->setModel(new User())
|
|
->setModel(new Session())
|
|
->setModel(new Locale())
|
|
->setModel(new Team())
|
|
->setModel(new TeamList())
|
|
->setModel(new Membership())
|
|
->setModel(new MembershipList())
|
|
;
|
|
}
|
|
|
|
/**
|
|
* HTTP content types
|
|
*/
|
|
const CONTENT_TYPE_YAML = 'application/x-yaml';
|
|
|
|
/**
|
|
* List of defined output objects
|
|
*/
|
|
protected $models = [];
|
|
|
|
/**
|
|
* Set Model Object
|
|
*
|
|
* @return self
|
|
*/
|
|
public function setModel(Model $instance): self
|
|
{
|
|
$this->models[$instance->getType()] = $instance;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get Model Object
|
|
*
|
|
* @return Model
|
|
*/
|
|
public function getModel(string $key): Model
|
|
{
|
|
if(!isset($this->models[$key])) {
|
|
throw new Exception('Undefined model: '.$key);
|
|
}
|
|
|
|
return $this->models[$key];
|
|
}
|
|
|
|
/**
|
|
* Validate response objects and outputs
|
|
* the response according to given format type
|
|
*/
|
|
public function dynamic(Document $document, string $model)
|
|
{
|
|
return $this->json($this->output($document, $model));
|
|
}
|
|
|
|
/**
|
|
* Generate valid response object from document data
|
|
*/
|
|
protected function output(Document $document, string $model): array
|
|
{
|
|
$data = $document;
|
|
$model = $this->getModel($model);
|
|
$output = [];
|
|
|
|
foreach($model->getRules() as $key => $rule) {
|
|
if(!$document->isSet($key)) {
|
|
if(!is_null($rule['default'])) {
|
|
$document->setAttribute($key, $rule['default']);
|
|
}
|
|
else {
|
|
throw new Exception('Missing response key: '.$key);
|
|
}
|
|
}
|
|
|
|
if($rule['array']) {
|
|
if(!is_array($data[$key])) {
|
|
throw new Exception($key.' must be an array of '.$rule['type'].' types');
|
|
}
|
|
|
|
foreach ($data[$key] as &$item) {
|
|
if(array_key_exists($rule['type'], $this->models) && $item instanceof Document) {
|
|
$item = $this->output($item, $rule['type']);
|
|
}
|
|
}
|
|
}
|
|
|
|
$output[$key] = $data[$key];
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* YAML
|
|
*
|
|
* This helper is for sending YAML HTTP response.
|
|
* It sets relevant content type header ('application/x-yaml') and convert a PHP array ($data) to valid YAML using native yaml_parse
|
|
*
|
|
* @see https://en.wikipedia.org/wiki/YAML
|
|
*
|
|
* @param array $data
|
|
*/
|
|
public function yaml(array $data)
|
|
{
|
|
if(!extension_loaded('yaml')) {
|
|
throw new Exception('Missing yaml extension. Learn more at: https://www.php.net/manual/en/book.yaml.php');
|
|
}
|
|
|
|
$this
|
|
->setContentType(Response::CONTENT_TYPE_YAML)
|
|
->send(yaml_emit($data, YAML_UTF8_ENCODING))
|
|
;
|
|
}
|
|
|
|
/**
|
|
* Output response
|
|
*
|
|
* Generate HTTP response output including the response header (+cookies) and body and prints them.
|
|
*
|
|
* @param string $body
|
|
* @param int $exit exit code or don't exit if code is null
|
|
*
|
|
* @return self
|
|
*/
|
|
public function send(string $body = '', int $exit = null): void
|
|
{
|
|
if(!$this->disablePayload) {
|
|
$this->addHeader('X-Debug-Speed', microtime(true) - $this->startTime);
|
|
|
|
$this
|
|
->appendCookies()
|
|
->appendHeaders()
|
|
;
|
|
|
|
$this->size = $this->size + mb_strlen(implode("\n", $this->headers)) + mb_strlen($body, '8bit');
|
|
|
|
$this->swoole->end($body);
|
|
|
|
$this->disablePayload();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Append headers
|
|
*
|
|
* Iterating over response headers to generate them using native PHP header function.
|
|
* This method is also responsible for generating the response and content type headers.
|
|
*
|
|
* @return self
|
|
*/
|
|
protected function appendHeaders(): self
|
|
{
|
|
// Send status code header
|
|
$this->swoole->status($this->statusCode);
|
|
|
|
// Send content type header
|
|
$this
|
|
->addHeader('Content-Type', $this->contentType . '; charset=UTF-8')
|
|
;
|
|
|
|
// Set application headers
|
|
foreach ($this->headers as $key => $value) {
|
|
$this->swoole->header($key, $value);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Append cookies
|
|
*
|
|
* Iterating over response cookies to generate them using native PHP cookie function.
|
|
*
|
|
* @return self
|
|
*/
|
|
protected function appendCookies(): self
|
|
{
|
|
foreach ($this->cookies as $cookie) {
|
|
$this->swoole->cookie(
|
|
$cookie['name'],
|
|
$cookie['value'],
|
|
$cookie['expire'],
|
|
$cookie['path'],
|
|
$cookie['domain'],
|
|
$cookie['secure'],
|
|
$cookie['httponly'],
|
|
$cookie['samesite'],
|
|
);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
}
|