setModel(new None()) ->setModel(new Any()) ->setModel(new Error()) ->setModel(new ErrorDev()) // Lists ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT)) ->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION)) ->setModel(new BaseList('Databases List', self::MODEL_DATABASE_LIST, 'databases', self::MODEL_DATABASE)) ->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX)) ->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER)) ->setModel(new BaseList('Sessions List', self::MODEL_SESSION_LIST, 'sessions', self::MODEL_SESSION)) ->setModel(new BaseList('Identities List', self::MODEL_IDENTITY_LIST, 'identities', self::MODEL_IDENTITY)) ->setModel(new BaseList('Logs List', self::MODEL_LOG_LIST, 'logs', self::MODEL_LOG)) ->setModel(new BaseList('Files List', self::MODEL_FILE_LIST, 'files', self::MODEL_FILE)) ->setModel(new BaseList('Buckets List', self::MODEL_BUCKET_LIST, 'buckets', self::MODEL_BUCKET)) ->setModel(new BaseList('Teams List', self::MODEL_TEAM_LIST, 'teams', self::MODEL_TEAM)) ->setModel(new BaseList('Memberships List', self::MODEL_MEMBERSHIP_LIST, 'memberships', self::MODEL_MEMBERSHIP)) ->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION)) ->setModel(new BaseList('Installations List', self::MODEL_INSTALLATION_LIST, 'installations', self::MODEL_INSTALLATION)) ->setModel(new BaseList('Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_LIST, 'providerRepositories', self::MODEL_PROVIDER_REPOSITORY)) ->setModel(new BaseList('Branches List', self::MODEL_BRANCH_LIST, 'branches', self::MODEL_BRANCH)) ->setModel(new BaseList('Runtimes List', self::MODEL_RUNTIME_LIST, 'runtimes', self::MODEL_RUNTIME)) ->setModel(new BaseList('Deployments List', self::MODEL_DEPLOYMENT_LIST, 'deployments', self::MODEL_DEPLOYMENT)) ->setModel(new BaseList('Executions List', self::MODEL_EXECUTION_LIST, 'executions', self::MODEL_EXECUTION)) ->setModel(new BaseList('Builds List', self::MODEL_BUILD_LIST, 'builds', self::MODEL_BUILD)) // Not used anywhere yet ->setModel(new BaseList('Projects List', self::MODEL_PROJECT_LIST, 'projects', self::MODEL_PROJECT, true, false)) ->setModel(new BaseList('Webhooks List', self::MODEL_WEBHOOK_LIST, 'webhooks', self::MODEL_WEBHOOK, true, false)) ->setModel(new BaseList('API Keys List', self::MODEL_KEY_LIST, 'keys', self::MODEL_KEY, true, false)) ->setModel(new BaseList('Auth Providers List', self::MODEL_AUTH_PROVIDER_LIST, 'platforms', self::MODEL_AUTH_PROVIDER, true, false)) ->setModel(new BaseList('Platforms List', self::MODEL_PLATFORM_LIST, 'platforms', self::MODEL_PLATFORM, true, false)) ->setModel(new BaseList('Countries List', self::MODEL_COUNTRY_LIST, 'countries', self::MODEL_COUNTRY)) ->setModel(new BaseList('Continents List', self::MODEL_CONTINENT_LIST, 'continents', self::MODEL_CONTINENT)) ->setModel(new BaseList('Languages List', self::MODEL_LANGUAGE_LIST, 'languages', self::MODEL_LANGUAGE)) ->setModel(new BaseList('Currencies List', self::MODEL_CURRENCY_LIST, 'currencies', self::MODEL_CURRENCY)) ->setModel(new BaseList('Phones List', self::MODEL_PHONE_LIST, 'phones', self::MODEL_PHONE)) ->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false)) ->setModel(new BaseList('Variables List', self::MODEL_VARIABLE_LIST, 'variables', self::MODEL_VARIABLE)) ->setModel(new BaseList('Status List', self::MODEL_HEALTH_STATUS_LIST, 'statuses', self::MODEL_HEALTH_STATUS)) ->setModel(new BaseList('Rule List', self::MODEL_PROXY_RULE_LIST, 'rules', self::MODEL_PROXY_RULE)) ->setModel(new BaseList('Locale codes list', self::MODEL_LOCALE_CODE_LIST, 'localeCodes', self::MODEL_LOCALE_CODE)) ->setModel(new BaseList('Provider list', self::MODEL_PROVIDER_LIST, 'providers', self::MODEL_PROVIDER)) ->setModel(new BaseList('Message list', self::MODEL_MESSAGE_LIST, 'messages', self::MODEL_MESSAGE)) ->setModel(new BaseList('Topic list', self::MODEL_TOPIC_LIST, 'topics', self::MODEL_TOPIC)) ->setModel(new BaseList('Subscriber list', self::MODEL_SUBSCRIBER_LIST, 'subscribers', self::MODEL_SUBSCRIBER)) ->setModel(new BaseList('Target list', self::MODEL_TARGET_LIST, 'targets', self::MODEL_TARGET)) ->setModel(new BaseList('Migrations List', self::MODEL_MIGRATION_LIST, 'migrations', self::MODEL_MIGRATION)) ->setModel(new BaseList('Migrations Firebase Projects List', self::MODEL_MIGRATION_FIREBASE_PROJECT_LIST, 'projects', self::MODEL_MIGRATION_FIREBASE_PROJECT)) // Entities ->setModel(new Database()) ->setModel(new Collection()) ->setModel(new Attribute()) ->setModel(new AttributeList()) ->setModel(new AttributeString()) ->setModel(new AttributeInteger()) ->setModel(new AttributeFloat()) ->setModel(new AttributeBoolean()) ->setModel(new AttributeEmail()) ->setModel(new AttributeEnum()) ->setModel(new AttributeIP()) ->setModel(new AttributeURL()) ->setModel(new AttributeDatetime()) ->setModel(new AttributeRelationship()) ->setModel(new Index()) ->setModel(new ModelDocument()) ->setModel(new Log()) ->setModel(new User()) ->setModel(new AlgoMd5()) ->setModel(new AlgoSha()) ->setModel(new AlgoPhpass()) ->setModel(new AlgoBcrypt()) ->setModel(new AlgoScrypt()) ->setModel(new AlgoScryptModified()) ->setModel(new AlgoArgon2()) ->setModel(new Account()) ->setModel(new Preferences()) ->setModel(new Session()) ->setModel(new Identity()) ->setModel(new Token()) ->setModel(new JWT()) ->setModel(new Locale()) ->setModel(new LocaleCode()) ->setModel(new File()) ->setModel(new Bucket()) ->setModel(new Team()) ->setModel(new Membership()) ->setModel(new Func()) ->setModel(new Installation()) ->setModel(new ProviderRepository()) ->setModel(new Detection()) ->setModel(new Branch()) ->setModel(new Runtime()) ->setModel(new Deployment()) ->setModel(new Execution()) ->setModel(new Build()) ->setModel(new Project()) ->setModel(new Webhook()) ->setModel(new Key()) ->setModel(new AuthProvider()) ->setModel(new Platform()) ->setModel(new Variable()) ->setModel(new Country()) ->setModel(new Continent()) ->setModel(new Language()) ->setModel(new Currency()) ->setModel(new Phone()) ->setModel(new HealthAntivirus()) ->setModel(new HealthQueue()) ->setModel(new HealthStatus()) ->setModel(new HealthCertificate()) ->setModel(new HealthTime()) ->setModel(new HealthVersion()) ->setModel(new Metric()) ->setModel(new MetricBreakdown()) ->setModel(new UsageDatabases()) ->setModel(new UsageDatabase()) ->setModel(new UsageCollection()) ->setModel(new UsageUsers()) ->setModel(new UsageStorage()) ->setModel(new UsageBuckets()) ->setModel(new UsageFunctions()) ->setModel(new UsageFunction()) ->setModel(new UsageProject()) ->setModel(new Headers()) ->setModel(new Rule()) ->setModel(new TemplateSMS()) ->setModel(new TemplateEmail()) ->setModel(new ConsoleVariables()) ->setModel(new MFAChallenge()) ->setModel(new MFAType()) ->setModel(new MFAFactors()) ->setModel(new Provider()) ->setModel(new Message()) ->setModel(new Topic()) ->setModel(new Subscriber()) ->setModel(new Target()) ->setModel(new Migration()) ->setModel(new MigrationReport()) ->setModel(new MigrationFirebaseProject()) // Tests (keep last) ->setModel(new Mock()); parent::__construct($response); } /** * HTTP content types */ public const CONTENT_TYPE_YAML = 'application/x-yaml'; public const CONTENT_TYPE_NULL = 'null'; /** * List of defined output objects */ protected $models = []; /** * Set Model Object * * @return self */ public function setModel(Model $instance) { $this->models[$instance->getType()] = $instance; return $this; } /** * Get Model Object * * @param string $key * @return Model * @throws Exception */ public function getModel(string $key): Model { if (!isset($this->models[$key])) { throw new Exception('Undefined model: ' . $key); } return $this->models[$key]; } /** * Get Models List * * @return Model[] */ public function getModels(): array { return $this->models; } /** * Validate response objects and outputs * the response according to given format type * * @param Document $document * @param string $model * * return void * @throws Exception */ public function dynamic(Document $document, string $model): void { $output = $this->output(clone $document, $model); // If filter is set, parse the output if (self::hasFilter()) { $output = self::getFilter()->parse($output, $model); } switch ($this->getContentType()) { case self::CONTENT_TYPE_JSON: $this->json(!empty($output) ? $output : new \stdClass()); break; case self::CONTENT_TYPE_YAML: $this->yaml(!empty($output) ? $output : new \stdClass()); break; case self::CONTENT_TYPE_NULL: break; default: if ($model === self::MODEL_NONE) { $this->noContent(); } else { $this->json(!empty($output) ? $output : new \stdClass()); } break; } } /** * Generate valid response object from document data * * @param Document $document * @param string $model * * return array * @return array * @throws Exception */ public function output(Document $document, string $model): array { $data = clone $document; $model = $this->getModel($model); $output = []; $data = $model->filter($data); if ($model->isAny()) { $this->payload = $data->getArrayCopy(); return $this->payload; } foreach ($model->getRules() as $key => $rule) { if (!$data->isSet($key) && $rule['required']) { // do not set attribute in response if not required if (\array_key_exists('default', $rule)) { $data->setAttribute($key, $rule['default']); } else { throw new Exception('Model ' . $model->getName() . ' is missing response key: ' . $key); } } if ($rule['array']) { if (!is_array($data[$key])) { throw new Exception($key . ' must be an array of type ' . $rule['type']); } foreach ($data[$key] as $index => $item) { if ($item instanceof Document) { if (\is_array($rule['type'])) { foreach ($rule['type'] as $type) { $condition = false; foreach ($this->getModel($type)->conditions as $attribute => $val) { $condition = $item->getAttribute($attribute) === $val; if (!$condition) { break; } } if ($condition) { $ruleType = $type; break; } } } else { $ruleType = $rule['type']; } if (!array_key_exists($ruleType, $this->models)) { throw new Exception('Missing model for rule: ' . $ruleType); } $data[$key][$index] = $this->output($item, $ruleType); } } } else { if ($data[$key] instanceof Document) { $data[$key] = $this->output($data[$key], $rule['type']); } } $output[$key] = $data[$key]; } $this->payload = $output; return $this->payload; } /** * Output response * * Generate HTTP response output including the response header (+cookies) and body and prints them. * * @param string $body * * @return void */ public function file(string $body = ''): void { $this->payload = [ 'payload' => $body ]; $this->send($body); } /** * 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 * * @return void * @throws Exception */ public function yaml(array $data): void { 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)); } /** * @return array */ public function getPayload(): array { return $this->payload; } /** * Function to set a response filter * * @param $filter the response filter to set * * @return void */ public static function setFilter(?Filter $filter) { self::$filter = $filter; } /** * Return the currently set filter * * @return Filter */ public static function getFilter(): ?Filter { return self::$filter; } /** * Check if a filter has been set * * @return bool */ public static function hasFilter(): bool { return self::$filter != null; } /** * Set Header * * @param string $key * @param string $value * @return void */ public function setHeader(string $key, string $value): void { $this->sendHeader($key, $value); } }