diff --git a/composer.json b/composer.json index ab8fc18..7a1cf70 100644 --- a/composer.json +++ b/composer.json @@ -10,10 +10,14 @@ } ], "require": { - "php": ">=7.0", + "php": ">=7.1", "guzzlehttp/guzzle": "^5.3.3|^6.2.1|^7.0", "guzzlehttp/psr7": "^1.4.1", - "guzzlehttp/promises": "^1.0" + "guzzlehttp/promises": "^1.0", + "ext-json": "*" + }, + "require-dev": { + "symfony/var-dumper": "^5.1" }, "autoload": { "psr-4": { diff --git a/src/App/App.php b/src/App/App.php new file mode 100644 index 0000000..8900d4b --- /dev/null +++ b/src/App/App.php @@ -0,0 +1,19 @@ +domain = $this->addScheme($domain, $scheme); - $this->credentials = $credentials; - $this->httpClient = new \GuzzleHttp\Client([ - 'base_uri' => rtrim($this->domain, '/'), - 'timeout' => $timeout - ]); - } - - function addScheme($domain, $scheme) - { - return parse_url($domain, PHP_URL_SCHEME) === null ? - $scheme . $domain : $domain; - } - - /** - * @param $data - * @return array - * @throws EntityCreationException - */ - public function create($data) - { - try { - $response = $this->httpClient->post($this->getPath(), [ - 'body' => json_encode($data), - 'headers' => $this->getHeaders(), - ]); - } catch (BadResponseException $e) { - throw new EntityCreationException($e->getMessage(), $e->getCode(), $e); - } - - return json_decode($response->getBody() - ->getContents(), true); - } - - /** - * @param $id - * @param $data - * @return array - * @throws EntityCreationException - */ - public function update($id, $data) - { - try { - $response = $this->httpClient->patch($this->getPathWithId($id), [ - 'body' => json_encode($data), - 'headers' => $this->getHeaders(true), - ]); - } catch (BadResponseException $e) { - throw new EntityCreationException($e->getMessage(), $e->getCode(), $e); - } - - return json_decode($response->getBody() - ->getContents(), true); - } - - /** - * @param $id - * @param array $filters - * @return mixed - * @throws EntityFetchException - */ - public function find($id, $filters = []) - { - try { - $response = $this->httpClient->get($this->getPathWithId($id), [ - 'headers' => $this->getHeaders(), - 'query' => $filters - ]); - } catch (BadResponseException $e) { - throw new EntityFetchException($e->getMessage(), $e->getCode(), $e); - } - - return json_decode($response->getBody() - ->getContents(), true); - } - - /** - * @param array $filters - * @param int $pageSize - * @param int $page - * @return array - * @throws EntityFetchException - */ - public function findAll($filters = [], $pageSize = 10, $page = 1) - { - try { - $response = $this->httpClient->get($this->getPath(), [ - 'headers' => $this->getHeaders(), - 'query' => array_merge(compact('pageSize', 'page'), $filters) - ]); - } catch (BadResponseException $e) { - throw new EntityFetchException($e->getMessage(), $e->getCode(), $e); - } - - return json_decode($response->getBody() - ->getContents(), true); - } - - /** - * @param bool $patch - * @return array - */ - protected function getHeaders($patch = false): array - { - $headers = [ - 'x-api-key' => $this->credentials['api_key'], - 'content-type' => 'application/json' - ]; - - if ($patch) { - $headers['content-type'] = 'application/merge-patch+json'; - } - - return $headers; - } - - /** - * @param $id - * @return string - */ - protected function getPathWithId($id): string - { - return $this->getPath() . '/' . $id; - } - - abstract protected function getPath(); -} diff --git a/src/Cohort/Cohort.php b/src/Cohort/Cohort.php new file mode 100644 index 0000000..849bfcb --- /dev/null +++ b/src/Cohort/Cohort.php @@ -0,0 +1,20 @@ +getBody() ->getContents()); } -} \ No newline at end of file + + public static function getModel() + { + return new LoyaltyGroup(); + } +} diff --git a/src/MagicFields/MagicField.php b/src/MagicFields/MagicField.php new file mode 100644 index 0000000..ba6f124 --- /dev/null +++ b/src/MagicFields/MagicField.php @@ -0,0 +1,25 @@ +data = $data; + $this->total = $total; + } + + public function getIterator() + { + return new \ArrayIterator($this->data); + } + + public function getGenerator() + { + foreach ($this->data as $item) { + yield $item; + } + } + + public function __toString() + { + return json_encode($this->data, JSON_PRETTY_PRINT); + } +} diff --git a/src/RealifeServiceResolver.php b/src/RealifeServiceResolver.php new file mode 100644 index 0000000..63ff67d --- /dev/null +++ b/src/RealifeServiceResolver.php @@ -0,0 +1,165 @@ +validateConfig($config); + $this->setRegion($config[self::CONFIG_REGION]); + $this->setEnvironment($config[self::CONFIG_ENVIRONMENT]); + $this->setVpc($config[self::CONFIG_VPC]); + $this->setAuthType($config[self::CONFIG_AUTH_TYPE]); + $this->credentials = $config[self::CONFIG_CREDENTIALS]; + $this->endpoint = $config[self::CONFIG_ENDPOINT]; + } + + /** + * @param string $serviceIdentifier + * @return ServiceClient + * @throws Exception\ServiceNotFoundException + */ + public function getService(string $serviceIdentifier): ServiceClient + { + $service = (new ServiceMap())->resolve($serviceIdentifier); + + return new $service($this->endpoint, [$this->authType => $this->credentials]); + } + + /** + * @param $config + * @return bool + * @throws UnsupportedConfigParameterException + * @throws ConfigParameterRequiredException + */ + private function validateConfig($config) + { + $configKeys = array_keys($config); + $schemaKeys = self::CONFIG_SCHEMA; + $res = array_merge(array_diff($configKeys, $schemaKeys), array_diff($schemaKeys, $configKeys)); + + if (empty($res)) { + return true; + } + + $field = $res[0]; + + if (in_array($field, self::CONFIG_SCHEMA)) { + throw new ConfigParameterRequiredException($field); + } else { + throw new UnsupportedConfigParameterException($field); + } + } + + /** + * @param $environment + * @throws InvalidConfigValueException + */ + private function setEnvironment($environment) + { + $this->validateSupported($environment, self::CONFIG_ENVIRONMENT, self::SUPPORTED_ENVIRONMENTS); + + $this->environment = $environment; + } + + /** + * @param $region + * @throws InvalidConfigValueException + */ + private function setRegion($region) + { + $this->validateSupported($region, self::CONFIG_REGION, self::SUPPORTED_REGIONS); + + $this->region = $region; + } + + /** + * @param $value + * @param $configKey + * @param $configArray + * @throws InvalidConfigValueException + */ + private function validateSupported($value, $configKey, $configArray) + { + if (!in_array($value, $configArray)) { + throw new InvalidConfigValueException([$value, $configKey]); + } + } + + /** + * @param $vpc + * @throws InvalidConfigValueException + */ + private function setVpc($vpc) + { + if (!is_bool($vpc)) { + throw new InvalidConfigValueException([$vpc, self::CONFIG_VPC]); + } + + $this->vpc = $vpc; + } + + /** + * @param $authType + * @throws InvalidConfigValueException + */ + private function setAuthType($authType) + { + $this->validateSupported($authType, self::CONFIG_AUTH_TYPE, self::SUPPORTED_AUTH_TYPES); + + $this->authType = $authType; + } +} diff --git a/src/Season/Season.php b/src/Season/Season.php new file mode 100644 index 0000000..8d01183 --- /dev/null +++ b/src/Season/Season.php @@ -0,0 +1,24 @@ +domain = $this->addScheme($domain, $scheme); + $this->credentials = $credentials; + $this->httpClient = new \GuzzleHttp\Client([ + 'base_uri' => rtrim($this->domain, '/'), + 'timeout' => $timeout + ]); + } + + abstract protected function getPath(); + + abstract public static function getModel(); + + function addScheme($domain, $scheme) + { + return parse_url($domain, PHP_URL_SCHEME) === null ? + $scheme . $domain : $domain; + } + + /** + * @param $data + * @return array + * @throws EntityCreationException + */ + public function create($data) + { + try { + $response = $this->httpClient->post($this->getPath(), [ + 'body' => json_encode($data), + 'headers' => $this->getHeaders(), + ]); + } catch (BadResponseException $e) { + throw new EntityCreationException($e->getMessage(), $e->getCode(), $e); + } + + return json_decode($response->getBody() + ->getContents(), true); + } + + /** + * @param $id + * @param $data + * @return array + * @throws EntityCreationException + */ + public function update($id, $data) + { + try { + $response = $this->httpClient->patch($this->getPathWithId($id), [ + 'body' => json_encode($data), + 'headers' => $this->getHeaders(true), + ]); + } catch (BadResponseException $e) { + throw new EntityCreationException($e->getMessage(), $e->getCode(), $e); + } + + return json_decode($response->getBody() + ->getContents(), true); + } + + /** + * @param $id + * @param array $filters + * @return mixed + * @throws EntityFetchException + */ + public function find($id, $filters = []) + { + try { + $response = $this->get($this->getPathWithId($id), $filters); + } catch (BadResponseException $e) { + throw new EntityFetchException($e->getMessage(), $e->getCode(), $e); + } + + return json_decode($response->getBody() + ->getContents(), true); + } + + /** + * @param array $filters + * @param int $pageSize + * @param int $page + * @return array + * @throws EntityFetchException + */ + public function findAll($filters = [], $pageSize = 10, $page = 1) + { + try { + $response = $this->get($this->getPath(), array_merge(compact('pageSize', 'page'), $filters)); + } catch (BadResponseException $e) { + throw new EntityFetchException($e->getMessage(), $e->getCode(), $e); + } + + return json_decode($response->getBody() + ->getContents(), true); + } + + /** + * @param bool $patch + * @return array + */ + protected function getHeaders($patch = false): array + { + $headers = [ + 'x-api-key' => $this->credentials['api_key'], + 'content-type' => 'application/json' + ]; + + if ($patch) { + $headers['content-type'] = 'application/merge-patch+json'; + } + + return $headers; + } + + /** + * @param $id + * @return string + */ + protected function getPathWithId($id): string + { + return $this->getPath() . '/' . $id; + } + + /** + * @param array $filters + * @param int $pageSize + * @param int $page + * @return RealifeResult + * @throws EntityFetchException + */ + public function getCollection($filters = [], $pageSize = 2, $page = 1): RealifeResult + { + try { + $response = $this->get($this->getPath(), array_merge(compact('pageSize', 'page'), $filters)); + } catch (BadResponseException $e) { + throw new EntityFetchException($e->getMessage(), $e->getCode(), $e); + } + + return $this->getRealifeResult($response); + } + + public function getUniqueItem($resource, $params) + { + //todo need to implement + } + + /** + * @param $id + * @param array $filters + * @return Item + * @throws EntityFetchException + */ + public function getItem($id, $filters = []) + { + try { + $response = $this->get($this->getPathWithId($id), $filters); + } catch (BadResponseException $e) { + throw new EntityFetchException($e->getMessage(), $e->getCode(), $e); + } + + return $this->getItemResponse($response); + } + + public function postCollection($resource, $data) + { + //todo need to implement + } + + public function putItem($resource, $id) + { + //todo need to implement + } + + public function patchItem($resource, $id) + { + //todo need to implement + } + + public function deleteItem($resource, $id) + { + //todo need to implement + } + + public function collectionOperation($resource, $method, $data) + { + //todo need to implement + } + + public function itemOperation($resource, $action, $id) + { + //todo need to implement + } + + /** + * @param \Psr\Http\Message\ResponseInterface $response + * @return RealifeResult + */ + private function getRealifeResult(\Psr\Http\Message\ResponseInterface $response): RealifeResult + { + $response = $this->decodeResponse($response); + $data = $response['hydra:member'] ?? []; + $total = $response['hydra:totalItems'] ?? 0; + + $data = array_map(function ($item) { + if (!$this->isResource($item)) { + return null; + } + + return $this->hydrateItem($item['@id'], $item['@type'], $item); + }, $data); + + return new RealifeResult($data, $total); + } + + private function hydrateItem(string $iri, string $type, array $responseItem): ?Item + { + $object = $this->resolveModel($type); + $object->iri = $iri; + $object->_type = $type; + + foreach ($responseItem as $property => $value) { + if (is_array($value)) { + $object->$property = $this->hydrateSubProperty($value); + } else { + $object->$property = $value; + } + } + + return $object; + } + + /** + * @param array $subProperty + * @return Item + */ + private function hydrateSubProperty(array $subProperty) + { + if (isset($subProperty[0])) { + $property = $this->processArrayProperty($subProperty); + } else { + $property = $this->processProperty($subProperty); + } + + return $property; + } + + private function convertToSnakeCase(string $type) + { + return strtolower(preg_replace('/(?convertToSnakeCase($type); + + if (isset(ServiceMap::SERVICE_MAP[$type])) { + /** + * @var $clientMapping self + */ + $clientMapping = ServiceMap::SERVICE_MAP[$type]; + + return $clientMapping::getModel(); + } else { + return new Item(); + } + } + + /** + * @param \Psr\Http\Message\ResponseInterface $response + * @return Item + */ + private function getItemResponse(\Psr\Http\Message\ResponseInterface $response): Item + { + $response = $this->decodeResponse($response); + + return $this->hydrateItem($response['@id'], $response['@type'], $response); + } + + /** + * @param \Psr\Http\Message\ResponseInterface $response + * @return mixed + */ + private function decodeResponse(\Psr\Http\Message\ResponseInterface $response) + { + return json_decode($response->getBody()->getContents(), true); + } + + /** + * @param $path + * @param array $filters + * @param array $headers + * @return \Psr\Http\Message\ResponseInterface + */ + private function get($path, array $filters, $headers = []): \Psr\Http\Message\ResponseInterface + { + return $this->httpClient->get($path, [ + 'headers' => array_merge($this->getHeaders(), $headers), + 'query' => $filters + ]); + } + + private function isResource($item): bool + { + return isset($item['@id']); + } + + /** + * @param array $arrayProperty + * @return array + */ + private function processArrayProperty(array $arrayProperty): array + { + $property = []; + + foreach ($arrayProperty as $item) { + if (!$this->isResource($item)) { + $property[] = $item; + } else { + $property[] = $this->hydrateItem($item['@id'], $item['@type'], $item); + } + } + + return $property; + } + + /** + * @param array $subProperty + * @return Item|null + */ + private function processProperty(array $subProperty) + { + if (!$this->isResource($subProperty)) { + return null; + } + + return $this->hydrateItem($subProperty['@id'], $subProperty['@type'], $subProperty); + } +} diff --git a/src/ServiceMap.php b/src/ServiceMap.php new file mode 100644 index 0000000..149d3c6 --- /dev/null +++ b/src/ServiceMap.php @@ -0,0 +1,196 @@ + AppService::class, + self::BOOKING => BookingService::class, + self::COHORT => CohortService::class, + self::COMPETITION => CompetitionService::class, + self::CURRENCY => CurrencyService::class, + self::DEVICE => DeviceService::class, + self::DEVICE_PREFERENCE => DevicePreferenceService::class, + self::DEVICE_TOKEN => DeviceTokenService::class, + self::EVENT => EventService::class, + self::EVENT_ACTIVITY => EventActivityService::class, + self::EVENT_CATEGORY => EventCategoryService::class, + self::EVENT_DATE => EventDateService::class, + self::EVENT_INTEGRATION => EventIntegrationService::class, + self::EVENT_STAGE => EventStageService::class, + self::EVENT_TRANSLATION => EventTranslationService::class, + self::EVENT_USER_ACTION => EventUserActionService::class, + self::FIXTURE => FixtureService::class, + self::FORM => FormService::class, + self::FORM_FIELD => FormFieldService::class, + self::FULFILMENT_POINT => FulfilmentPointService::class, + self::FULFILMENT_POINT_CATEGORY => FulfilmentPointCategoryService::class, + self::INTEGRATION => IntegrationService::class, + self::LEAGUE_TABLE => LeagueTableService::class, + self::LEAGUE_TABLE_GROUP => LeagueTableGroupService::class, + self::LOYALTY_GROUP => LoyaltyGroupsService::class, + self::MAGIC_FIELD => MagicFieldsService::class, + self::MERCHANT_CUSTOMER => MerchantCustomerService::class, + self::NEWS => NewsService::class, + self::ORDER => OrderService::class, + self::PRODUCT => ProductService::class, + self::PRODUCT_CATEGORY => ProductCategoryService::class, + self::PRODUCT_MODIFIER_ITEM => ProductModifierItemService::class, + self::PRODUCT_MODIFIER_LIST => ProductModifierListService::class, + self::PRODUCT_MODIFIER_LIST_TRANSLATION => ProductModifierListTranslationService::class, + self::PRODUCT_VARIANT => ProductVariantService::class, + self::PRODUCT_VARIANT_STOCK => ProductVariantStockService::class, + self::PUSH_APP => PushAppService::class, + self::PUSH_BROADCAST => PushBroadcastService::class, + self::PUSH_CONSENT => PushConsentService::class, + self::SEASON => SeasonService::class, + self::SOCIAL_MEDIA => SocialMediaService::class, + self::SOCIAL_MEDIA_TRANSLATION => SocialMediaTranslationService::class, + self::SPORT_VENUE => SportVenueService::class, + self::TEAM => TeamService::class, + self::TICKET => TicketService::class, + self::TICKET_AUTH => TicketAuthService::class, + self::TICKET_INTEGRATION => TicketIntegrationService::class, + self::USEFUL_INFO => UsefulInfoService::class, + self::USEFUL_INFO_TRANSLATION => UsefulInfoTranslationService::class, + self::USER => UsersService::class, + self::USER_EMAIL => UserEmailService::class, + self::USER_INFO => UserInfoService::class, + self::VENUE => VenueService::class, + self::WORKFLOW => WorkflowService::class, + self::WORKFLOW_ACTION => WorkflowActionService::class, + self::WORKFLOW_TRIGGER => WorkflowTriggerService::class, + ]; + + /** + * @param string $service + * @return string + * @throws ServiceNotFoundException + */ + public function resolve(string $service): string + { + if (!array_key_exists($service, self::SERVICE_MAP)) { + throw new ServiceNotFoundException("No such service {$service}"); + } + + return self::SERVICE_MAP[$service]; + } +} diff --git a/src/SocialMedia/SocialMedia.php b/src/SocialMedia/SocialMedia.php new file mode 100644 index 0000000..4d5ec75 --- /dev/null +++ b/src/SocialMedia/SocialMedia.php @@ -0,0 +1,26 @@ +getBody() ->getContents(), true); } + + public static function getModel() + { + return new User(); + } } diff --git a/src/UserEmail/UserEmail.php b/src/UserEmail/UserEmail.php new file mode 100644 index 0000000..612bc04 --- /dev/null +++ b/src/UserEmail/UserEmail.php @@ -0,0 +1,18 @@ +