2020-05-16 11:28:26 +00:00
|
|
|
<?php
|
|
|
|
|
|
2020-06-22 12:17:14 +00:00
|
|
|
namespace Appwrite\Utopia;
|
2020-05-16 11:28:26 +00:00
|
|
|
|
2024-08-07 13:15:53 +00:00
|
|
|
use Appwrite\Utopia\Fetch\BodyMultipart;
|
2020-12-22 15:24:30 +00:00
|
|
|
use Appwrite\Utopia\Response\Filter;
|
2024-10-01 14:30:47 +00:00
|
|
|
use Appwrite\Utopia\Response\Models;
|
2024-03-06 17:34:21 +00:00
|
|
|
use Exception;
|
2024-08-07 13:15:53 +00:00
|
|
|
use JsonException;
|
2023-08-04 08:56:46 +00:00
|
|
|
// Keep last
|
2024-03-06 17:34:21 +00:00
|
|
|
use Utopia\Database\Document;
|
2024-10-01 14:30:47 +00:00
|
|
|
use Utopia\Http\Adapter\Swoole\Response as HttpResponse;
|
|
|
|
|
|
|
|
|
|
// Keep last
|
2020-05-16 11:28:26 +00:00
|
|
|
|
2020-10-31 11:06:09 +00:00
|
|
|
/**
|
2022-05-04 09:17:19 +00:00
|
|
|
* @method int getStatusCode()
|
2021-07-14 08:52:26 +00:00
|
|
|
* @method Response setStatusCode(int $code = 200)
|
2020-10-31 11:06:09 +00:00
|
|
|
*/
|
2024-10-01 14:30:47 +00:00
|
|
|
class Response extends HttpResponse
|
2020-05-16 11:28:26 +00:00
|
|
|
{
|
2020-06-23 18:53:24 +00:00
|
|
|
// General
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_NONE = 'none';
|
|
|
|
|
public const MODEL_ANY = 'any';
|
|
|
|
|
public const MODEL_LOG = 'log';
|
|
|
|
|
public const MODEL_LOG_LIST = 'logList';
|
|
|
|
|
public const MODEL_ERROR = 'error';
|
|
|
|
|
public const MODEL_METRIC = 'metric';
|
|
|
|
|
public const MODEL_METRIC_LIST = 'metricList';
|
2023-12-11 15:19:08 +00:00
|
|
|
public const MODEL_METRIC_BREAKDOWN = 'metricBreakdown';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_ERROR_DEV = 'errorDev';
|
|
|
|
|
public const MODEL_BASE_LIST = 'baseList';
|
2022-06-22 10:51:49 +00:00
|
|
|
public const MODEL_USAGE_DATABASES = 'usageDatabases';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_USAGE_DATABASE = 'usageDatabase';
|
|
|
|
|
public const MODEL_USAGE_COLLECTION = 'usageCollection';
|
|
|
|
|
public const MODEL_USAGE_USERS = 'usageUsers';
|
|
|
|
|
public const MODEL_USAGE_BUCKETS = 'usageBuckets';
|
|
|
|
|
public const MODEL_USAGE_STORAGE = 'usageStorage';
|
|
|
|
|
public const MODEL_USAGE_FUNCTIONS = 'usageFunctions';
|
2022-07-17 10:30:58 +00:00
|
|
|
public const MODEL_USAGE_FUNCTION = 'usageFunction';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_USAGE_PROJECT = 'usageProject';
|
2022-05-23 14:54:50 +00:00
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
// Database
|
2022-06-22 10:51:49 +00:00
|
|
|
public const MODEL_DATABASE = 'database';
|
|
|
|
|
public const MODEL_DATABASE_LIST = 'databaseList';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_COLLECTION = 'collection';
|
|
|
|
|
public const MODEL_COLLECTION_LIST = 'collectionList';
|
|
|
|
|
public const MODEL_INDEX = 'index';
|
|
|
|
|
public const MODEL_INDEX_LIST = 'indexList';
|
|
|
|
|
public const MODEL_DOCUMENT = 'document';
|
|
|
|
|
public const MODEL_DOCUMENT_LIST = 'documentList';
|
2020-10-29 13:07:56 +00:00
|
|
|
|
2021-08-13 20:58:54 +00:00
|
|
|
// Database Attributes
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_ATTRIBUTE = 'attribute';
|
|
|
|
|
public const MODEL_ATTRIBUTE_LIST = 'attributeList';
|
|
|
|
|
public const MODEL_ATTRIBUTE_STRING = 'attributeString';
|
|
|
|
|
public const MODEL_ATTRIBUTE_INTEGER = 'attributeInteger';
|
|
|
|
|
public const MODEL_ATTRIBUTE_FLOAT = 'attributeFloat';
|
|
|
|
|
public const MODEL_ATTRIBUTE_BOOLEAN = 'attributeBoolean';
|
|
|
|
|
public const MODEL_ATTRIBUTE_EMAIL = 'attributeEmail';
|
|
|
|
|
public const MODEL_ATTRIBUTE_ENUM = 'attributeEnum';
|
|
|
|
|
public const MODEL_ATTRIBUTE_IP = 'attributeIp';
|
|
|
|
|
public const MODEL_ATTRIBUTE_URL = 'attributeUrl';
|
2022-07-25 08:53:41 +00:00
|
|
|
public const MODEL_ATTRIBUTE_DATETIME = 'attributeDatetime';
|
2023-03-14 08:24:53 +00:00
|
|
|
public const MODEL_ATTRIBUTE_RELATIONSHIP = 'attributeRelationship';
|
2021-08-13 20:58:54 +00:00
|
|
|
|
2020-06-23 18:53:24 +00:00
|
|
|
// Users
|
2022-06-10 08:03:09 +00:00
|
|
|
public const MODEL_ACCOUNT = 'account';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_USER = 'user';
|
|
|
|
|
public const MODEL_USER_LIST = 'userList';
|
|
|
|
|
public const MODEL_SESSION = 'session';
|
|
|
|
|
public const MODEL_SESSION_LIST = 'sessionList';
|
2023-05-18 01:11:45 +00:00
|
|
|
public const MODEL_IDENTITY = 'identity';
|
|
|
|
|
public const MODEL_IDENTITY_LIST = 'identityList';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_TOKEN = 'token';
|
|
|
|
|
public const MODEL_JWT = 'jwt';
|
|
|
|
|
public const MODEL_PREFERENCES = 'preferences';
|
2022-05-23 14:54:50 +00:00
|
|
|
|
2023-06-22 13:35:49 +00:00
|
|
|
// MFA
|
2024-02-15 11:26:34 +00:00
|
|
|
public const MODEL_MFA_TYPE = 'mfaType';
|
|
|
|
|
public const MODEL_MFA_FACTORS = 'mfaFactors';
|
2023-06-22 13:35:49 +00:00
|
|
|
public const MODEL_MFA_OTP = 'mfaTotp';
|
|
|
|
|
public const MODEL_MFA_CHALLENGE = 'mfaChallenge';
|
2024-03-01 16:22:51 +00:00
|
|
|
public const MODEL_MFA_RECOVERY_CODES = 'mfaRecoveryCodes';
|
2023-06-22 13:35:49 +00:00
|
|
|
|
2022-06-15 08:11:48 +00:00
|
|
|
// Users password algos
|
|
|
|
|
public const MODEL_ALGO_MD5 = 'algoMd5';
|
|
|
|
|
public const MODEL_ALGO_SHA = 'algoSha';
|
|
|
|
|
public const MODEL_ALGO_SCRYPT = 'algoScrypt';
|
|
|
|
|
public const MODEL_ALGO_SCRYPT_MODIFIED = 'algoScryptModified';
|
|
|
|
|
public const MODEL_ALGO_BCRYPT = 'algoBcrypt';
|
|
|
|
|
public const MODEL_ALGO_ARGON2 = 'algoArgon2';
|
|
|
|
|
public const MODEL_ALGO_PHPASS = 'algoPhpass';
|
|
|
|
|
|
2020-06-23 18:53:24 +00:00
|
|
|
// Storage
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_FILE = 'file';
|
|
|
|
|
public const MODEL_FILE_LIST = 'fileList';
|
|
|
|
|
public const MODEL_BUCKET = 'bucket';
|
|
|
|
|
public const MODEL_BUCKET_LIST = 'bucketList';
|
2020-06-23 18:53:24 +00:00
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
// Locale
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_LOCALE = 'locale';
|
2023-04-17 02:10:17 +00:00
|
|
|
public const MODEL_LOCALE_CODE = 'localeCode';
|
|
|
|
|
public const MODEL_LOCALE_CODE_LIST = 'localeCodeList';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_COUNTRY = 'country';
|
|
|
|
|
public const MODEL_COUNTRY_LIST = 'countryList';
|
|
|
|
|
public const MODEL_CONTINENT = 'continent';
|
|
|
|
|
public const MODEL_CONTINENT_LIST = 'continentList';
|
|
|
|
|
public const MODEL_CURRENCY = 'currency';
|
|
|
|
|
public const MODEL_CURRENCY_LIST = 'currencyList';
|
|
|
|
|
public const MODEL_LANGUAGE = 'language';
|
|
|
|
|
public const MODEL_LANGUAGE_LIST = 'languageList';
|
|
|
|
|
public const MODEL_PHONE = 'phone';
|
|
|
|
|
public const MODEL_PHONE_LIST = 'phoneList';
|
2020-10-29 13:07:56 +00:00
|
|
|
|
2023-08-07 15:26:03 +00:00
|
|
|
// Messaging
|
|
|
|
|
public const MODEL_PROVIDER = 'provider';
|
|
|
|
|
public const MODEL_PROVIDER_LIST = 'providerList';
|
|
|
|
|
public const MODEL_MESSAGE = 'message';
|
|
|
|
|
public const MODEL_MESSAGE_LIST = 'messageList';
|
|
|
|
|
public const MODEL_TOPIC = 'topic';
|
|
|
|
|
public const MODEL_TOPIC_LIST = 'topicList';
|
|
|
|
|
public const MODEL_SUBSCRIBER = 'subscriber';
|
|
|
|
|
public const MODEL_SUBSCRIBER_LIST = 'subscriberList';
|
|
|
|
|
public const MODEL_TARGET = 'target';
|
|
|
|
|
public const MODEL_TARGET_LIST = 'targetList';
|
|
|
|
|
|
2020-06-23 18:53:24 +00:00
|
|
|
// Teams
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_TEAM = 'team';
|
|
|
|
|
public const MODEL_TEAM_LIST = 'teamList';
|
|
|
|
|
public const MODEL_MEMBERSHIP = 'membership';
|
|
|
|
|
public const MODEL_MEMBERSHIP_LIST = 'membershipList';
|
2020-06-05 09:53:06 +00:00
|
|
|
|
2023-05-22 10:58:13 +00:00
|
|
|
// VCS
|
|
|
|
|
public const MODEL_INSTALLATION = 'installation';
|
|
|
|
|
public const MODEL_INSTALLATION_LIST = 'installationList';
|
2023-07-31 06:47:47 +00:00
|
|
|
public const MODEL_PROVIDER_REPOSITORY = 'providerRepository';
|
|
|
|
|
public const MODEL_PROVIDER_REPOSITORY_LIST = 'providerRepositoryList';
|
2023-05-25 22:29:08 +00:00
|
|
|
public const MODEL_BRANCH = 'branch';
|
|
|
|
|
public const MODEL_BRANCH_LIST = 'branchList';
|
2023-06-13 18:44:44 +00:00
|
|
|
public const MODEL_DETECTION = 'detection';
|
2024-06-26 10:03:27 +00:00
|
|
|
public const MODEL_VCS_CONTENT = 'vcsContent';
|
|
|
|
|
public const MODEL_VCS_CONTENT_LIST = 'vcsContentList';
|
2023-05-22 10:58:13 +00:00
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
// Functions
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_FUNCTION = 'function';
|
|
|
|
|
public const MODEL_FUNCTION_LIST = 'functionList';
|
|
|
|
|
public const MODEL_RUNTIME = 'runtime';
|
|
|
|
|
public const MODEL_RUNTIME_LIST = 'runtimeList';
|
|
|
|
|
public const MODEL_DEPLOYMENT = 'deployment';
|
|
|
|
|
public const MODEL_DEPLOYMENT_LIST = 'deploymentList';
|
|
|
|
|
public const MODEL_EXECUTION = 'execution';
|
|
|
|
|
public const MODEL_EXECUTION_LIST = 'executionList';
|
|
|
|
|
public const MODEL_BUILD = 'build';
|
|
|
|
|
public const MODEL_BUILD_LIST = 'buildList'; // Not used anywhere yet
|
|
|
|
|
public const MODEL_FUNC_PERMISSIONS = 'funcPermissions';
|
2023-02-14 11:01:38 +00:00
|
|
|
public const MODEL_HEADERS = 'headers';
|
2024-07-31 11:27:32 +00:00
|
|
|
public const MODEL_SPECIFICATION = 'specification';
|
|
|
|
|
public const MODEL_SPECIFICATION_LIST = 'specificationList';
|
2024-07-26 12:17:03 +00:00
|
|
|
public const MODEL_TEMPLATE_FUNCTION = 'templateFunction';
|
|
|
|
|
public const MODEL_TEMPLATE_FUNCTION_LIST = 'templateFunctionList';
|
|
|
|
|
public const MODEL_TEMPLATE_RUNTIME = 'templateRuntime';
|
|
|
|
|
public const MODEL_TEMPLATE_VARIABLE = 'templateVariable';
|
2022-05-23 14:54:50 +00:00
|
|
|
|
2023-03-08 18:30:01 +00:00
|
|
|
// Proxy
|
|
|
|
|
public const MODEL_PROXY_RULE = 'proxyRule';
|
|
|
|
|
public const MODEL_PROXY_RULE_LIST = 'proxyRuleList';
|
|
|
|
|
|
2023-08-04 16:21:41 +00:00
|
|
|
// Migrations
|
|
|
|
|
public const MODEL_MIGRATION = 'migration';
|
|
|
|
|
public const MODEL_MIGRATION_LIST = 'migrationList';
|
|
|
|
|
public const MODEL_MIGRATION_REPORT = 'migrationReport';
|
|
|
|
|
public const MODEL_MIGRATION_FIREBASE_PROJECT = 'firebaseProject';
|
|
|
|
|
public const MODEL_MIGRATION_FIREBASE_PROJECT_LIST = 'firebaseProjectList';
|
2022-05-23 14:54:50 +00:00
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
// Project
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_PROJECT = 'project';
|
|
|
|
|
public const MODEL_PROJECT_LIST = 'projectList';
|
|
|
|
|
public const MODEL_WEBHOOK = 'webhook';
|
|
|
|
|
public const MODEL_WEBHOOK_LIST = 'webhookList';
|
|
|
|
|
public const MODEL_KEY = 'key';
|
|
|
|
|
public const MODEL_KEY_LIST = 'keyList';
|
2024-02-11 14:51:19 +00:00
|
|
|
public const MODEL_MOCK_NUMBER = 'mockNumber';
|
2023-08-07 10:49:55 +00:00
|
|
|
public const MODEL_AUTH_PROVIDER = 'authProvider';
|
|
|
|
|
public const MODEL_AUTH_PROVIDER_LIST = 'authProviderList';
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_PLATFORM = 'platform';
|
|
|
|
|
public const MODEL_PLATFORM_LIST = 'platformList';
|
2022-07-20 07:18:49 +00:00
|
|
|
public const MODEL_VARIABLE = 'variable';
|
|
|
|
|
public const MODEL_VARIABLE_LIST = 'variableList';
|
2023-05-22 10:58:13 +00:00
|
|
|
public const MODEL_VCS = 'vcs';
|
2023-03-13 09:33:11 +00:00
|
|
|
public const MODEL_SMS_TEMPLATE = 'smsTemplate';
|
2023-03-10 11:04:11 +00:00
|
|
|
public const MODEL_EMAIL_TEMPLATE = 'emailTemplate';
|
2021-12-14 14:17:55 +00:00
|
|
|
|
|
|
|
|
// Health
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_HEALTH_STATUS = 'healthStatus';
|
|
|
|
|
public const MODEL_HEALTH_VERSION = 'healthVersion';
|
|
|
|
|
public const MODEL_HEALTH_QUEUE = 'healthQueue';
|
|
|
|
|
public const MODEL_HEALTH_TIME = 'healthTime';
|
|
|
|
|
public const MODEL_HEALTH_ANTIVIRUS = 'healthAntivirus';
|
2024-02-12 01:18:19 +00:00
|
|
|
public const MODEL_HEALTH_CERTIFICATE = 'healthCertificate';
|
2022-10-17 11:43:57 +00:00
|
|
|
public const MODEL_HEALTH_STATUS_LIST = 'healthStatusList';
|
2022-05-23 14:54:50 +00:00
|
|
|
|
2023-03-31 15:14:59 +00:00
|
|
|
// Console
|
|
|
|
|
public const MODEL_CONSOLE_VARIABLES = 'consoleVariables';
|
|
|
|
|
|
2021-08-03 13:34:29 +00:00
|
|
|
// Deprecated
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_PERMISSIONS = 'permissions';
|
|
|
|
|
public const MODEL_RULE = 'rule';
|
|
|
|
|
public const MODEL_TASK = 'task';
|
2023-08-19 18:26:47 +00:00
|
|
|
public const MODEL_DOMAIN = 'domain';
|
|
|
|
|
public const MODEL_DOMAIN_LIST = 'domainList';
|
2021-08-03 13:34:29 +00:00
|
|
|
|
2021-03-05 06:40:29 +00:00
|
|
|
// Tests (keep last)
|
2022-06-02 13:03:37 +00:00
|
|
|
public const MODEL_MOCK = 'mock';
|
2020-10-29 13:07:56 +00:00
|
|
|
|
2020-12-22 15:24:30 +00:00
|
|
|
/**
|
2024-03-07 13:48:36 +00:00
|
|
|
* @var array<Filter>
|
2020-12-22 15:24:30 +00:00
|
|
|
*/
|
2024-03-07 14:41:20 +00:00
|
|
|
protected array $filters = [];
|
2020-12-22 15:24:30 +00:00
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
/**
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
2022-08-01 10:22:04 +00:00
|
|
|
protected array $payload = [];
|
2020-10-29 13:07:56 +00:00
|
|
|
|
2020-06-26 12:27:58 +00:00
|
|
|
/**
|
|
|
|
|
* Response constructor.
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-10-27 00:08:29 +00:00
|
|
|
* @param float $time
|
2020-06-26 12:27:58 +00:00
|
|
|
*/
|
2024-10-01 14:30:47 +00:00
|
|
|
public function __construct(HttpResponse $response)
|
2020-06-05 09:53:06 +00:00
|
|
|
{
|
2024-10-01 14:30:47 +00:00
|
|
|
parent::__construct($response->swoole);
|
2020-06-05 09:53:06 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-16 11:28:26 +00:00
|
|
|
/**
|
|
|
|
|
* HTTP content types
|
|
|
|
|
*/
|
2022-06-02 13:03:37 +00:00
|
|
|
public const CONTENT_TYPE_YAML = 'application/x-yaml';
|
2022-07-11 21:52:00 +00:00
|
|
|
public const CONTENT_TYPE_NULL = 'null';
|
2024-08-07 13:15:53 +00:00
|
|
|
public const CONTENT_TYPE_MULTIPART = 'multipart/form-data';
|
2020-05-16 11:28:26 +00:00
|
|
|
|
2024-03-07 15:20:34 +00:00
|
|
|
public function applyFilters(array $data, string $model): array
|
|
|
|
|
{
|
|
|
|
|
foreach ($this->filters as $filter) {
|
|
|
|
|
$data = $filter->parse($data, $model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-05 09:53:06 +00:00
|
|
|
/**
|
|
|
|
|
* Validate response objects and outputs
|
|
|
|
|
* the response according to given format type
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-10-31 08:42:41 +00:00
|
|
|
* @param Document $document
|
|
|
|
|
* @param string $model
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-10-31 08:42:41 +00:00
|
|
|
* return void
|
2022-10-19 23:12:09 +00:00
|
|
|
* @throws Exception
|
2020-06-05 09:53:06 +00:00
|
|
|
*/
|
2020-10-31 11:06:09 +00:00
|
|
|
public function dynamic(Document $document, string $model): void
|
2020-06-05 09:53:06 +00:00
|
|
|
{
|
2023-08-25 15:13:25 +00:00
|
|
|
$output = $this->output(clone $document, $model);
|
2024-03-07 15:20:34 +00:00
|
|
|
$output = $this->applyFilters($output, $model);
|
2021-01-03 18:12:11 +00:00
|
|
|
|
2022-07-11 21:52:00 +00:00
|
|
|
switch ($this->getContentType()) {
|
2021-02-26 19:25:52 +00:00
|
|
|
case self::CONTENT_TYPE_JSON:
|
2024-08-07 13:15:53 +00:00
|
|
|
try {
|
|
|
|
|
$this->json(!empty($output) ? $output : new \stdClass());
|
|
|
|
|
} catch (JsonException $e) {
|
2024-08-08 08:19:33 +00:00
|
|
|
throw new Exception('Failed to parse response: ' . $e->getMessage(), 400);
|
2024-08-07 13:15:53 +00:00
|
|
|
}
|
2021-02-26 19:25:52 +00:00
|
|
|
break;
|
2022-07-11 21:52:00 +00:00
|
|
|
|
2021-02-26 19:25:52 +00:00
|
|
|
case self::CONTENT_TYPE_YAML:
|
2022-10-19 23:12:09 +00:00
|
|
|
$this->yaml(!empty($output) ? $output : new \stdClass());
|
2021-02-26 19:25:52 +00:00
|
|
|
break;
|
2022-07-11 21:52:00 +00:00
|
|
|
|
2021-03-18 18:55:43 +00:00
|
|
|
case self::CONTENT_TYPE_NULL:
|
|
|
|
|
break;
|
|
|
|
|
|
2024-08-07 13:15:53 +00:00
|
|
|
case self::CONTENT_TYPE_MULTIPART:
|
|
|
|
|
$this->multipart(!empty($output) ? $output : new \stdClass());
|
|
|
|
|
break;
|
|
|
|
|
|
2022-07-11 21:52:00 +00:00
|
|
|
default:
|
2021-03-18 18:55:43 +00:00
|
|
|
if ($model === self::MODEL_NONE) {
|
|
|
|
|
$this->noContent();
|
|
|
|
|
} else {
|
2022-10-19 23:12:09 +00:00
|
|
|
$this->json(!empty($output) ? $output : new \stdClass());
|
2021-03-18 18:55:43 +00:00
|
|
|
}
|
2021-02-26 19:25:52 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2020-10-31 08:42:41 +00:00
|
|
|
}
|
|
|
|
|
|
2020-06-24 06:05:43 +00:00
|
|
|
/**
|
|
|
|
|
* Generate valid response object from document data
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-10-31 08:42:41 +00:00
|
|
|
* @param Document $document
|
|
|
|
|
* @param string $model
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-10-31 08:42:41 +00:00
|
|
|
* return array
|
2022-10-19 23:12:09 +00:00
|
|
|
* @return array
|
|
|
|
|
* @throws Exception
|
2020-06-24 06:05:43 +00:00
|
|
|
*/
|
2020-10-29 13:07:56 +00:00
|
|
|
public function output(Document $document, string $model): array
|
2020-06-24 06:05:43 +00:00
|
|
|
{
|
2023-08-25 15:13:25 +00:00
|
|
|
$data = clone $document;
|
2024-10-01 14:30:47 +00:00
|
|
|
$model = Models::getModel($model);
|
2020-06-05 09:53:06 +00:00
|
|
|
$output = [];
|
|
|
|
|
|
2023-08-25 15:13:25 +00:00
|
|
|
$data = $model->filter($data);
|
2021-03-17 20:45:47 +00:00
|
|
|
|
2020-10-29 22:44:01 +00:00
|
|
|
if ($model->isAny()) {
|
2023-07-19 23:12:44 +00:00
|
|
|
$this->payload = $data->getArrayCopy();
|
2022-08-01 10:22:04 +00:00
|
|
|
|
2020-11-30 21:41:58 +00:00
|
|
|
return $this->payload;
|
2020-10-29 13:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
2020-10-29 22:44:01 +00:00
|
|
|
foreach ($model->getRules() as $key => $rule) {
|
2023-08-25 15:13:25 +00:00
|
|
|
if (!$data->isSet($key) && $rule['required']) { // do not set attribute in response if not required
|
2022-08-08 10:35:28 +00:00
|
|
|
if (\array_key_exists('default', $rule)) {
|
2023-07-19 23:12:44 +00:00
|
|
|
$data->setAttribute($key, $rule['default']);
|
2020-10-29 22:44:01 +00:00
|
|
|
} else {
|
2022-05-23 14:54:50 +00:00
|
|
|
throw new Exception('Model ' . $model->getName() . ' is missing response key: ' . $key);
|
2020-06-22 14:33:37 +00:00
|
|
|
}
|
2020-06-05 09:53:06 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-22 02:43:29 +00:00
|
|
|
if (!$data->isSet($key) && !$rule['required']) { // set output key null if data key is not set and required is false
|
2024-07-15 05:35:04 +00:00
|
|
|
$output[$key] = null;
|
2024-07-14 05:46:02 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2024-07-14 06:05:51 +00:00
|
|
|
|
2020-10-29 22:44:01 +00:00
|
|
|
if ($rule['array']) {
|
|
|
|
|
if (!is_array($data[$key])) {
|
2022-05-23 14:54:50 +00:00
|
|
|
throw new Exception($key . ' must be an array of type ' . $rule['type']);
|
2020-06-24 06:05:43 +00:00
|
|
|
}
|
|
|
|
|
|
2022-08-01 10:22:04 +00:00
|
|
|
foreach ($data[$key] as $index => $item) {
|
2020-10-29 22:44:01 +00:00
|
|
|
if ($item instanceof Document) {
|
2021-09-14 08:26:16 +00:00
|
|
|
if (\is_array($rule['type'])) {
|
|
|
|
|
foreach ($rule['type'] as $type) {
|
|
|
|
|
$condition = false;
|
2024-10-01 14:30:47 +00:00
|
|
|
foreach (Models::getModel($type)->conditions as $attribute => $val) {
|
2021-09-14 08:26:16 +00:00
|
|
|
$condition = $item->getAttribute($attribute) === $val;
|
2022-05-23 14:54:50 +00:00
|
|
|
if (!$condition) {
|
2021-09-14 08:26:16 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($condition) {
|
|
|
|
|
$ruleType = $type;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$ruleType = $rule['type'];
|
2020-10-29 13:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
2024-10-01 14:30:47 +00:00
|
|
|
if (!array_key_exists($ruleType, Models::getModels())) {
|
2022-05-23 14:54:50 +00:00
|
|
|
throw new Exception('Missing model for rule: ' . $ruleType);
|
2020-10-29 13:07:56 +00:00
|
|
|
}
|
|
|
|
|
|
2022-08-01 10:22:04 +00:00
|
|
|
$data[$key][$index] = $this->output($item, $ruleType);
|
2020-06-24 06:05:43 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-08-01 10:22:04 +00:00
|
|
|
} else {
|
|
|
|
|
if ($data[$key] instanceof Document) {
|
|
|
|
|
$data[$key] = $this->output($data[$key], $rule['type']);
|
|
|
|
|
}
|
2020-06-23 15:01:20 +00:00
|
|
|
}
|
2021-09-14 08:26:16 +00:00
|
|
|
|
2020-06-05 09:53:06 +00:00
|
|
|
$output[$key] = $data[$key];
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
$this->payload = $output;
|
|
|
|
|
|
2020-11-30 21:41:58 +00:00
|
|
|
return $this->payload;
|
2020-05-16 11:28:26 +00:00
|
|
|
}
|
|
|
|
|
|
2022-07-24 09:49:51 +00:00
|
|
|
/**
|
2022-07-30 19:10:30 +00:00
|
|
|
* Output response
|
2022-07-24 09:49:51 +00:00
|
|
|
*
|
2022-07-30 19:10:30 +00:00
|
|
|
* Generate HTTP response output including the response header (+cookies) and body and prints them.
|
|
|
|
|
*
|
|
|
|
|
* @param string $body
|
2022-07-24 09:49:51 +00:00
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2022-08-14 15:01:34 +00:00
|
|
|
public function file(string $body = ''): void
|
2022-07-23 17:42:42 +00:00
|
|
|
{
|
|
|
|
|
$this->payload = [
|
2022-08-14 15:01:34 +00:00
|
|
|
'payload' => $body
|
2022-07-26 12:50:33 +00:00
|
|
|
];
|
2022-07-28 15:24:18 +00:00
|
|
|
|
2022-08-14 15:01:34 +00:00
|
|
|
$this->send($body);
|
2022-07-23 17:42:42 +00:00
|
|
|
}
|
|
|
|
|
|
2020-05-16 11:28:26 +00:00
|
|
|
/**
|
|
|
|
|
* 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
|
2020-10-27 00:08:29 +00:00
|
|
|
*
|
|
|
|
|
* @return void
|
2022-10-19 23:12:09 +00:00
|
|
|
* @throws Exception
|
2020-05-16 11:28:26 +00:00
|
|
|
*/
|
2020-10-27 00:08:29 +00:00
|
|
|
public function yaml(array $data): void
|
2020-05-16 11:28:26 +00:00
|
|
|
{
|
2020-10-27 19:44:15 +00:00
|
|
|
if (!extension_loaded('yaml')) {
|
2020-05-16 11:28:26 +00:00
|
|
|
throw new Exception('Missing yaml extension. Learn more at: https://www.php.net/manual/en/book.yaml.php');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this
|
|
|
|
|
->setContentType(Response::CONTENT_TYPE_YAML)
|
2023-06-22 13:35:49 +00:00
|
|
|
->send(\yaml_emit($data, YAML_UTF8_ENCODING));
|
2020-05-16 11:28:26 +00:00
|
|
|
}
|
2020-10-29 13:07:56 +00:00
|
|
|
|
2024-08-07 13:15:53 +00:00
|
|
|
/**
|
|
|
|
|
* Multipart
|
|
|
|
|
*
|
|
|
|
|
* This helper is for sending multipart/form-data HTTP response.
|
|
|
|
|
* It sets relevant content type header ('multipart/form-data') and convert a PHP array ($data) to valid Multipart using BodyMultipart
|
|
|
|
|
*
|
|
|
|
|
* @param array $data
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function multipart(array $data): void
|
|
|
|
|
{
|
|
|
|
|
$multipart = new BodyMultipart();
|
|
|
|
|
foreach ($data as $key => $value) {
|
|
|
|
|
$multipart->setPart($key, $value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this
|
2024-08-14 09:39:55 +00:00
|
|
|
->setContentType($multipart->exportHeader())
|
2024-08-07 13:15:53 +00:00
|
|
|
->send($multipart->exportBody());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* JSON
|
|
|
|
|
*
|
|
|
|
|
* This helper is for sending JSON HTTP response.
|
|
|
|
|
* It sets relevant content type header ('application/json') and convert a PHP array ($data) to valid JSON using native json_encode
|
|
|
|
|
*
|
|
|
|
|
* @see http://en.wikipedia.org/wiki/JSON
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $data
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function json($data): void
|
|
|
|
|
{
|
|
|
|
|
if (!is_array($data) && !$data instanceof \stdClass) {
|
2024-08-10 20:55:03 +00:00
|
|
|
throw new \Exception('Response body is not a valid JSON object.');
|
2024-08-07 13:15:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this
|
|
|
|
|
->setContentType(Response::CONTENT_TYPE_JSON, self::CHARSET_UTF8)
|
|
|
|
|
->send(\json_encode($data, JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR));
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-29 13:07:56 +00:00
|
|
|
/**
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2022-05-23 14:54:50 +00:00
|
|
|
public function getPayload(): array
|
2020-10-29 13:07:56 +00:00
|
|
|
{
|
|
|
|
|
return $this->payload;
|
|
|
|
|
}
|
2020-12-22 15:24:30 +00:00
|
|
|
|
|
|
|
|
/**
|
2024-03-07 13:48:36 +00:00
|
|
|
* Function to add a response filter, the order of filters are first in - first out.
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-12-22 15:24:30 +00:00
|
|
|
* @param $filter the response filter to set
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-12-22 15:24:30 +00:00
|
|
|
* @return void
|
|
|
|
|
*/
|
2024-03-07 14:41:20 +00:00
|
|
|
public function addFilter(Filter $filter): void
|
2020-12-22 15:24:30 +00:00
|
|
|
{
|
2024-03-07 14:41:20 +00:00
|
|
|
$this->filters[] = $filter;
|
2020-12-22 15:24:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the currently set filter
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-12-22 15:24:30 +00:00
|
|
|
* @return Filter
|
|
|
|
|
*/
|
2024-03-07 14:41:20 +00:00
|
|
|
public function getFilters(): array
|
2020-12-22 15:24:30 +00:00
|
|
|
{
|
2024-03-07 14:41:20 +00:00
|
|
|
return $this->filters;
|
2024-03-07 13:48:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Reset filters
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
2024-03-07 14:41:20 +00:00
|
|
|
public function resetFilters(): void
|
2024-03-07 13:48:36 +00:00
|
|
|
{
|
2024-03-07 14:41:20 +00:00
|
|
|
$this->filters = [];
|
2020-12-22 15:24:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if a filter has been set
|
2021-10-06 14:22:38 +00:00
|
|
|
*
|
2020-12-22 15:24:30 +00:00
|
|
|
* @return bool
|
|
|
|
|
*/
|
2024-03-07 14:41:20 +00:00
|
|
|
public function hasFilters(): bool
|
2020-12-22 15:24:30 +00:00
|
|
|
{
|
2024-03-07 14:41:20 +00:00
|
|
|
return !empty($this->filters);
|
2020-12-22 15:24:30 +00:00
|
|
|
}
|
2023-02-14 13:58:13 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set Header
|
|
|
|
|
*
|
|
|
|
|
* @param string $key
|
|
|
|
|
* @param string $value
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function setHeader(string $key, string $value): void
|
|
|
|
|
{
|
|
|
|
|
$this->sendHeader($key, $value);
|
|
|
|
|
}
|
2020-05-16 11:28:26 +00:00
|
|
|
}
|