diff --git a/Data/JsonToArrayTransformer.php b/Data/JsonToArrayTransformer.php deleted file mode 100644 index b359bb6..0000000 --- a/Data/JsonToArrayTransformer.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ -class JsonToArrayTransformer -{ - protected $originalData; - protected $data; - - /** - * @return mixed - */ - public function getOriginalData() - { - return $this->originalData; - } - - /** - * @param mixed $originalData - * @return ArrayTransformer - */ - public function setOriginalData($originalData) - { - $this->originalData = $originalData; - return $this; - } - - /** - * @return mixed - */ - public function getData() - { - return $this->data; - } - - /** - * @param mixed $data - * @return ArrayTransformer - */ - public function setData($data) - { - $this->originalData = $data; - $this->data = json_decode($data, true); - - return $this; - } -} diff --git a/DependencyInjection/AlpixelJiraExtension.php b/DependencyInjection/AlpixelJiraExtension.php index 5d4130d..455a547 100644 --- a/DependencyInjection/AlpixelJiraExtension.php +++ b/DependencyInjection/AlpixelJiraExtension.php @@ -22,8 +22,11 @@ public function load(array $configs, ContainerBuilder $container) $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); - $container->setParameter('alpixel_jira.auth', $config['auth']); + $container->setParameter('alpixel_jira.auth.method', $config['auth']['method']); + $container->setParameter('alpixel_jira.auth.parameters', $config['auth']['parameters']); + $container->setParameter('alpixel_jira.auth.authentication_class', $config['auth']['authentication_class']); $container->setParameter('alpixel_jira.base_url', $config['base_url']); + $container->setParameter('alpixel_jira.base_api', $config['base_api']); $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index fd5b249..a9a6c47 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -2,6 +2,7 @@ namespace Alpixel\Bundle\JiraBundle\DependencyInjection; +use Alpixel\Bundle\JiraBundle\Request\BasicAuthentication; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; @@ -23,40 +24,42 @@ public function getConfigTreeBuilder() $rootNode ->children() ->scalarNode('base_url')->isRequired()->cannotBeEmpty()->end() - ->append($this->addAuthParameters()) + ->scalarNode('base_api')->isRequired()->cannotBeEmpty()->end() + ->append($this->addAuthConfiguration()) ->end(); return $treeBuilder; } - public function addAuthParameters() + public function addAuthConfiguration() { $treeBuilder = new TreeBuilder(); $node = $treeBuilder->root('auth'); $node->isRequired() ->children() - ->arrayNode('method') - ->children() - ->arrayNode('basic') - ->children() - ->scalarNode('username')->end() - ->scalarNode('password')->end() - ->end() - ->end() - ->arrayNode('oauth') - ->children() - ->scalarNode('id')->end() - ->scalarNode('key')->end() - ->end() - ->end() - ->end() + ->scalarNode('method')->defaultValue('basic')->end() + ->arrayNode('parameters') + ->prototype('scalar')->end() + ->end() + ->scalarNode('authentication_class') + ->defaultValue(BasicAuthentication::class) ->beforeNormalization() - ->ifTrue(function ($v) { return (count($v) === 1) ? false : true ; }) - ->thenInvalid('You must set only one authentification method.') + ->always() + ->then(function ($fqcn) { + $isValidClass = false; + if (class_exists($fqcn)) { + $interfaces = class_implements($fqcn); + $isValidClass = isset($interfaces['\Alpixel\Bundle\JiraBundle\Request\AuthenticationInterface']); + } + + if (!$isValidClass) { + throw new \InvalidArgumentException('The class has been not found or not implement "\Alpixel\Bundle\JiraBundle\Request\AuthenticationInterface"'); + } + }) + ->end() ->end() ->end(); - return $node; } } diff --git a/Request/AbstractRequest.php b/Request/AbstractRequest.php new file mode 100644 index 0000000..ad50c0d --- /dev/null +++ b/Request/AbstractRequest.php @@ -0,0 +1,204 @@ + + */ +abstract class AbstractRequest +{ + const METHOD_GET = 'GET'; + const METHOD_POST = 'POST'; + + /** + * @var string + */ + protected $baseUrlAPI; + /** + * @var SecurityContext + */ + private $securityContext; + /** + * @var array curl options + */ + private $curlOptions; + /** + * @var LoggerInterface + */ + private $monolog; + + public function __construct(string $baseUrlAPI, SecurityContext $securityContext, LoggerInterface $monolog) + { + $this->setBaseUrlAPI($baseUrlAPI); + $this->setSecurityContext($securityContext); + $this->setMonolog($monolog); + } + + /** + * @return string + */ + public function getBaseUrlAPI(): string + { + return $this->baseUrlAPI; + } + + /** + * @param string $baseUrlAPI + * @return $this + */ + protected function setBaseUrlAPI(string $baseUrlAPI) + { + if (substr($baseUrlAPI, -1) !== '/') { + $baseUrlAPI .= '/'; + } + + $this->baseUrlAPI = $baseUrlAPI; + + return $this; + } + + /** + * @return SecurityContext + */ + public function getSecurityContext(): SecurityContext + { + return $this->securityContext; + } + + /** + * @param SecurityContext $securityContext + * @return $this + */ + public function setSecurityContext(SecurityContext $securityContext) + { + $this->securityContext = $securityContext; + + return $this; + } + + /** + * @return LoggerInterface + */ + private function getMonolog() + { + return $this->monolog; + } + + /** + * @param LoggerInterface $monolog + * @return LoggerInterface + */ + protected function setMonolog(LoggerInterface $monolog) + { + $this->monolog = $monolog; + + return $this->monolog; + } + + /** + * @return array + */ + public function getCurlOptions(): array + { + return $this->curlOptions; + } + + /** + * @param array $curlOptions + * @return $this + */ + public function setCurlOptions(array $curlOptions) + { + $this->curlOptions = $curlOptions; + + return $this; + } + + public function get(string $url, array $urlParameters = [], array $curlOptions = []) + { + return $this->buildRequest(self::METHOD_GET, $url, $urlParameters, $curlOptions); + } + + public function buildRequest(string $method, string $url, $urlParameters = [], array $curlOptions = []) + { + switch ($method) { + case self::METHOD_GET: + $curlOptions[CURLOPT_HTTPGET] = true; + if (!empty($urlParameters)) { + $url .= '?' . http_build_query($urlParameters); + } + break; + case self::METHOD_POST: + $curlOptions[CURLOPT_POST] = true; + break; + default: + throw new \InvalidArgumentException(sprintf('Unknown HTTP method "%s"'), $method); + } + + return $this->executeRequest($url, $curlOptions); + } + + /** + * Create final url to API + * + * @param $urlAPIEndpoint + * @return string + */ + public function createUrl($urlAPIEndpoint) + { + if (substr($urlAPIEndpoint, 0, 1) === '/') { + $urlAPIEndpoint = substr($urlAPIEndpoint, 1); + } + + return $this->getBaseUrlAPI() . $urlAPIEndpoint; + } + + /** + * @param array $curlOptions + * @return array + */ + protected function resolveCurlOptions(array $curlOptions = []) + { + return array_replace([ + CURLOPT_TIMEOUT => 300, + CURLOPT_FORBID_REUSE => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + ], + ], $curlOptions); + } + + /** + * @param string $urlAPIEndpoint + * @param array $curlOptions + * @return Response + */ + public function executeRequest(string $urlAPIEndpoint, array $curlOptions = []) + { + $url = $this->createUrl($urlAPIEndpoint); + + $this->getMonolog()->info('Alpixel JIRA API [Request] : ' . $urlAPIEndpoint); + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + $curlOptions = $this->resolveCurlOptions($curlOptions); + curl_setopt_array($ch, $curlOptions); + + $this->getSecurityContext()->applyAuthentication($ch); + + $data = curl_exec($ch); + $error = curl_error($ch); + + $response = new Response(); + $response->setResponse($ch, $error, $data); + + return $response; + } +} diff --git a/Request/AuthenticationInterface.php b/Request/AuthenticationInterface.php new file mode 100644 index 0000000..6796681 --- /dev/null +++ b/Request/AuthenticationInterface.php @@ -0,0 +1,15 @@ + + */ +interface AuthenticationInterface +{ + /** + * @param resource (curl) $curlRessource + * @return mixed + */ + public function applyAuthentication($curlRessource); +} diff --git a/Request/AuthenticationProvider.php b/Request/AuthenticationProvider.php new file mode 100644 index 0000000..169cb66 --- /dev/null +++ b/Request/AuthenticationProvider.php @@ -0,0 +1,64 @@ + + */ +class AuthenticationProvider +{ + + /** + * @var string + */ + protected $authMethod; + + /** + * @var array + */ + protected $authParameters; + + public function __construct(string $authMethod, array $authParameters) + { + $this->setAuthMethod($authMethod); + $this->setAuthParameters($authParameters); + } + + private function setAuthMethod(string $authMethod) + { + $this->authMethod = $authMethod; + + return $this; + } + + /** + * @return string + */ + public function getAuthMethod(): string + { + return $this->authMethod; + } + + /** + * @return mixed + */ + public function getAuthParameters(): array + { + return $this->authParameters; + } + + /** + * @param array $authParameters + * @return $this + */ + private function setAuthParameters(array $authParameters) + { + $this->authParameters = $authParameters; + + return $this; + } +} diff --git a/Request/BasicAuthentication.php b/Request/BasicAuthentication.php new file mode 100644 index 0000000..f6910eb --- /dev/null +++ b/Request/BasicAuthentication.php @@ -0,0 +1,58 @@ + + */ +class BasicAuthentication implements AuthenticationInterface +{ + /** + * @var AuthenticationProvider + */ + private $authenticationProvider; + + /** + * @var string + */ + private $credentials; + + public function __construct(AuthenticationProvider $authenticationProvider) + { + $this->authenticationProvider = $authenticationProvider; + $this->setCredentials($authenticationProvider->getAuthParameters()); + } + + public function getAuthenticationProvider(): AuthenticationProvider + { + return $this->authenticationProvider; + } + + public function setCredentials(array $authParameters) + { + if (!isset($authParameters['username']) || !isset($authParameters['password'])) { + throw new \InvalidArgumentException(sprintf('You must set "username", "password" under "auth.parameters" configuration for "alpixel_jira" in your config.yml to use the authentication class "%s"', self::class)); + } + + $credentials = [ + $authParameters['username'], + $authParameters['password'], + ]; + + $this->credentials = implode(':', $credentials); + + return $this; + } + + + protected function getCredentials() + { + return $this->credentials; + } + + public function applyAuthentication($curlResource) + { + curl_setopt($curlResource, CURLOPT_USERPWD, $this->getCredentials()); + } +} diff --git a/Request/Request.php b/Request/Request.php index e2d1102..0c4d440 100644 --- a/Request/Request.php +++ b/Request/Request.php @@ -2,7 +2,6 @@ namespace Alpixel\Bundle\JiraBundle\Request; -use Alpixel\Bundle\JiraBundle\Data\JsonToArrayTransformer; use Alpixel\Bundle\JiraBundle\Response\Response; use Psr\Log\LoggerInterface; @@ -12,105 +11,161 @@ */ class Request { - const METHOD_GET = 'GET'; const METHOD_POST = 'POST'; - const TIMEOUT = 300; - /** * @var SecurityContext */ - private $security; + private $securityContext; /** * @var array curl options */ - private $options; + private $curlOptions; /** * @var LoggerInterface */ private $monolog; - protected $baseUrl; + /** + * @var string + */ + protected $baseUrlAPI; - public function __construct(SecurityContext $security, string $baseUrl, LoggerInterface $monolog) + public function __construct(string $baseUrlAPI, SecurityContext $securityContext, LoggerInterface $monolog) { - $this->security = $security; + $this->setBaseUrlAPI($baseUrlAPI); + $this->setSecurityContext($securityContext); + $this->setMonolog($monolog); + } - if (substr($baseUrl, (strlen($baseUrl) -1 )) !== '/') { - $baseUrl .= '/'; - } + /** + * @return SecurityContext + */ + public function getSecurityContext(): SecurityContext + { + return $this->securityContext; + } - $this->baseUrl = $baseUrl; - $this->monolog = $monolog; + /** + * @param SecurityContext $securityContext + * @return Request + */ + public function setSecurityContext(SecurityContext $securityContext): Request + { + $this->securityContext = $securityContext; + + return $this; } - protected function getMonolog() + /** + * @return array + */ + public function getCurlOptions(): array { - return $this->monolog; + return $this->curlOptions; } - protected function getSecurity() : SecurityContext + /** + * @param array $curlOptions + * @return Request + */ + public function setCurlOptions(array $curlOptions): Request { - return $this->security; + $this->curlOptions = $curlOptions; + + return $this; } - protected function applyAuthentication() + /** + * @return string + */ + public function getBaseUrlAPI(): string { - $security = $this->getSecurity(); - if ($security->getAuthMethod() === SecurityContext::METHOD_BASIC) { - $parameters = $security->getCredentials(); - $credentials = implode(':', $parameters); - $this->options[CURLOPT_USERPWD] = $credentials; - } else { - $this->getMonolog()->error('Alpixel JIRA API [Authentication] invalid format of credentials : '.$error, [ - 'file' => __FILE__, - 'line' => __LINE__, - ]); - throw new \Exception('Invalid authentification.'); + return $this->baseUrlAPI; + } + + /** + * @param string $baseUrl + * @return Request + */ + protected function setBaseUrlAPI(string $baseUrl): Request + { + if (substr($baseUrl, (strlen($baseUrl) -1 )) !== '/') { + $baseUrl .= '/'; } + + $this->baseUrlAPI = $baseUrl; + + return $this; } - public function exec(string $url, array $opt = []) + /** + * @param LoggerInterface $monolog + * @return LoggerInterface + */ + protected function setMonolog(LoggerInterface $monolog) { - $this->applyAuthentication(); + $this->monolog = $monolog; - $urlRequest = $this->baseUrl.$url; + return $this->monolog; + } - $monolog = $this->getMonolog(); - $monolog->info('Alpixel JIRA API [Request] : '.$urlRequest, [ - 'file' => __FILE__, - 'line' => __LINE__, - ]); + /** + * @return LoggerInterface + */ + private function getMonolog() + { + return $this->monolog; + } + + protected function applyAuthentication($ch) + { + $this->getSecurityContext()->applyAuthentication($ch); + } - $options = array_replace([ - CURLOPT_URL => $urlRequest, - CURLOPT_TIMEOUT => self::TIMEOUT, + protected function resolveCurlContext(array $context = []) + { + return array_replace([ + CURLOPT_TIMEOUT => 300, CURLOPT_FORBID_REUSE => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', ], - ], $this->options, $opt); + ], $context); + } + + public function createUrl($urlAPIEndpoint) + { + if (substr($urlAPIEndpoint, 0, 1) === '/') { + $urlAPIEndpoint = substr($urlAPIEndpoint, 1); + } + + return $this->getBaseUrlAPI().$urlAPIEndpoint; + } + + public function executeRequest(string $urlAPIEndpoint, array $curlOptions = []) + { + $url = $this->createUrl($urlAPIEndpoint); + + $this->getMonolog()->info('Alpixel JIRA API [Request] : '.$urlAPIEndpoint); $ch = curl_init(); - curl_setopt_array($ch, $options); + curl_setopt($ch, CURLOPT_URL, $url); + + $curlContext = $this->resolveCurlContext($curlOptions); + curl_setopt_array($ch, $curlContext); + + $this->applyAuthentication($ch); $data = curl_exec($ch); $error = curl_error($ch); - if (!empty($error)) { - $monolog->error('Alpixel JIRA API [Response] curl error : '.$error, [ - 'file' => __FILE__, - 'line' => __LINE__, - ]); - throw new \RuntimeException(sprintf('curl reports the following errors : "%s"', $error)); - } - - $response = new Response(new JsonToArrayTransformer()); - $response->setResponse($data, $error); + $response = new Response(); + $response->setResponse($ch, $error, $data); return $response; } @@ -119,20 +174,20 @@ public function buildRequest(string $method, string $url, $parameters = [], arra { switch ($method) { case self::METHOD_GET: - $this->options[CURLOPT_HTTPGET] = true; + $this->curlOptions[CURLOPT_HTTPGET] = true; if (!empty($parameters)) { $queryParams = http_build_query($parameters); $url .= '?'.$queryParams; } break; case self::METHOD_POST: - $this->options[CURLOPT_POST] = true; + $this->curlOptions[CURLOPT_POST] = true; break; default: throw new \InvalidArgumentException(sprintf('Unknown HTTP method "%s"'), $method); } - return $this->exec($url, $opt); + return $this->executeRequest($url, $opt); } public function get(string $url, array $parameters = [], array $opt = []) diff --git a/Request/SecurityContext.php b/Request/SecurityContext.php index 41c29cb..8684f4f 100644 --- a/Request/SecurityContext.php +++ b/Request/SecurityContext.php @@ -2,83 +2,59 @@ namespace Alpixel\Bundle\JiraBundle\Request; -use Alpixel\Bundle\JiraBundle\Exception\SecurityContext\AuthMethodException; -use Symfony\Component\OptionsResolver\OptionsResolver; - /** * @author Alexis BUSSIERES */ class SecurityContext { - const METHOD_BASIC = 'basic'; - const METHOD_OAUTH = 'oauth'; + /** + * @var string + */ + private $authClassName; - private $authMethod; - private $credentials; + /** + * @var AuthenticationInterface + */ + private $authObject; - public function __construct(array $auth) + public function __construct(string $authClassName, AuthenticationProvider $authProvider) { - $resolver = new OptionsResolver(); - $this->configureAuthMethod($resolver); - $resolver->resolve($auth); - $this->authMethod = strtolower(key($auth['method'])); - - $resolver = new OptionsResolver(); - $this->configureCredentials($resolver, $this->getAuthMethod()); - $this->credentials = $resolver->resolve($auth['method'][$this->getAuthMethod()]); + $this->authClassName = $authClassName; + $this->authObject = $this->createAuthObject($authClassName, $authProvider); } - public static function getAvailablesAuthMethods() + /** + * @return string + */ + public function getAuthClassName(): string { - return [ - self::METHOD_BASIC, - self::METHOD_OAUTH, - ]; + return $this->authClassName; } - protected function configureAuthMethod(OptionsResolver $resolver) + /** + * @return AuthenticationInterface + */ + public function getAuthObject(): AuthenticationInterface { - $resolver - ->setRequired('method') - ->setAllowedTypes('method', 'array') - ->setAllowedValues('method', function ($value) { - $method = strtolower(key($value)); - - if (!in_array($method, self::getAvailablesAuthMethods())) { - throw new AuthMethodException(); - } - - return $method; - }); + return $this->authObject; } - protected function configureCredentials(OptionsResolver $resolver, string $authMethod) + /** + * @param string $authClassName + * @param AuthenticationProvider $authProvider + * @return object + */ + private function createAuthObject(string $authClassName, AuthenticationProvider $authProvider) { - if ($authMethod === self::METHOD_BASIC) { - $resolver - ->setRequired('username') - ->setAllowedTypes('username', 'string') - ->setRequired('password') - ->setAllowedTypes('password', 'string'); - } else if ($authMethod === self::METHOD_OAUTH) { - $resolver - ->setRequired('id') - ->setAllowedTypes('id', 'string') - ->setRequired('key') - ->setAllowedTypes('key', 'string'); - } else { - throw new AuthMethodException(); - } + return new $authClassName($authProvider); } - public function getAuthMethod() - { - return $this->authMethod; - } - public function getCredentials() + public function applyAuthentication($curlResource) { - return $this->credentials; + $this->getAuthObject()->applyAuthentication($curlResource); + + return $this; } } diff --git a/Resources/config/services.yml b/Resources/config/services.yml index 8ed08d0..764583e 100644 --- a/Resources/config/services.yml +++ b/Resources/config/services.yml @@ -1,14 +1,19 @@ services: + alpixel_jira.authentication_provider: + class: Alpixel\Bundle\JiraBundle\Request\AuthenticationProvider + arguments: ["%alpixel_jira.auth.method%", "%alpixel_jira.auth.parameters%"] + alpixel_jira.security_context: class: Alpixel\Bundle\JiraBundle\Request\SecurityContext arguments: - - "%alpixel_jira.auth%" + - "%alpixel_jira.auth.authentication_class%" + - "@alpixel_jira.authentication_provider" alpixel_jira.request: class: Alpixel\Bundle\JiraBundle\Request\Request arguments: + - "%alpixel_jira.base_api%" - "@alpixel_jira.security_context" - - "%alpixel_jira.base_url%" - "@monolog.logger" alpixel_jira.api: diff --git a/Response/AbstractResponse.php b/Response/AbstractResponse.php new file mode 100644 index 0000000..7de01e5 --- /dev/null +++ b/Response/AbstractResponse.php @@ -0,0 +1,210 @@ + + */ +abstract class AbstractResponse +{ + /** + * @var string + */ + protected $curlStringError; + + /** + * @var bool + */ + protected $isCurlError = false; + + /** + * @var TransformerInterface + */ + protected $transformer; + + /** + * @var resource (curl) + */ + protected $curlResource; + + /** + * @var int + */ + protected $httpStatusCode; + + /** + * @var bool + */ + protected $isSuccessHttpStatusCode; + + /** + * @var mixed + */ + protected $data; + + /** + * @var mixed + */ + protected $originalData; + + /** + * @return mixed + */ + public function getOriginalData() + { + return $this->originalData; + } + + /** + * @param mixed $originalData + * @return AbstractResponse + */ + public function setOriginalData($originalData) + { + $this->originalData = $originalData; + + return $this; + } + + /** + * @return TransformerInterface + */ + public function getTransformer() + { + return $this->transformer; + } + + /** + * @param TransformerInterface $transformer + * @return $this + */ + public function setTransformer(TransformerInterface $transformer) + { + $this->data = null; + $this->transformer = $transformer; + + return $this; + } + + /** + * @param resource (curl) $curlResource + * @param string $curlStringError + * @param mixed $data + */ + public function setResponse($curlResource, string $curlStringError = '', $data) + { + $this->setCurlResource($curlResource); + $this->transformCurlResource($curlResource); + $this->setOriginalData($data); + + if (!empty($curlStringError)) { + $this->setCurlStringError($curlStringError); + $this->isCurlError = true; + } + } + + /** + * @param string $error + * @return $this + */ + protected function setCurlStringError(string $error) + { + $this->curlStringError = $error; + + return $this; + } + + /** + * @return boolean + */ + protected function isCurlError(): bool + { + return $this->isCurlError; + } + + /** + * @return bool + */ + public function isSuccess() + { + return (!$this->isCurlError() && $this->isSuccessHttpStatusCode()); + } + + /** + * @param int $httpStatusCode + * @return $this + */ + protected function setHttpStatusCode(int $httpStatusCode) + { + $this->httpStatusCode = (int) $httpStatusCode; + + $isSuccess = ($httpStatusCode >= 200 && $httpStatusCode < 300 || $httpStatusCode === 304); + $this->isSuccessHttpStatusCode = $isSuccess; + + return $this; + } + + /** + * @return bool + */ + public function isSuccessHttpStatusCode() + { + return $this->isSuccessHttpStatusCode; + } + + /** + * @return int + */ + public function getHttpStatusCode() + { + return $this->httpStatusCode; + } + + /** + * @param resource $curlResource A curl resource + * @return $this + */ + protected function setCurlResource($curlResource) + { + if (!is_resource($curlResource) || get_resource_type($curlResource) !== 'curl') { + throw new \InvalidArgumentException('The parameter "$curlResource" must be a ressource of curl.'); + } + + $this->curlResource = $curlResource; + + return $this; + } + + /** + * @param $curlRessource + * @return $this + */ + public function transformCurlResource($curlRessource) + { + $this->setHttpStatusCode(curl_getinfo($curlRessource, CURLINFO_HTTP_CODE)); + + return $this; + } + + /** + * @return mixed + */ + public function getData() + { + if ($this->data === null) { + if ($this->getTransformer() === null) { + $this->setTransformer(new JsonToArrayTransformer()); + } + + $originalData = $this->getOriginalData(); + $this->data = $this->getTransformer()->transformData($originalData); + } + + return $this->data; + } + +} diff --git a/Response/Response.php b/Response/Response.php index b56fac2..2436190 100644 --- a/Response/Response.php +++ b/Response/Response.php @@ -5,43 +5,7 @@ /** * @author Alexis BUSSIERES */ -class Response +class Response extends AbstractResponse { - private $error; - private $transformer; - public function __construct($transformer) - { - $this->transformer = $transformer; - } - - public function setResponse($data, $error) - { - $this->getTransformer()->setData($data); - $this->error = $error; - } - - /** - * @return mixed - */ - public function getData() - { - return $this->getTransformer()->getData(); - } - - /** - * @return mixed - */ - public function getError() - { - return $this->error; - } - - /** - * @return mixed - */ - public function getTransformer() - { - return $this->transformer; - } } diff --git a/Transformer/JsonToArrayTransformer.php b/Transformer/JsonToArrayTransformer.php new file mode 100644 index 0000000..b28b1b2 --- /dev/null +++ b/Transformer/JsonToArrayTransformer.php @@ -0,0 +1,78 @@ + + */ +class JsonToArrayTransformer implements TransformerInterface +{ + /** + * @var array + */ + protected $context; + + /** + * @var bool + */ + protected $jsonHasError; + + public function __construct(array $context = []) + { + $this->setContext($context); + } + + /** + * @return array + */ + public function getContext(): array + { + return $this->context; + } + + /** + * @param array $context + * @return JsonToArrayTransformer + */ + public function setContext(array $context): JsonToArrayTransformer + { + $this->context = $context; + + return $this; + } + + /** + * @return bool + */ + public function jsonHasError() + { + return $this->jsonHasError; + } + + /** + * @return array + */ + protected function resolveContext() + { + return array_merge([ + 'json_decode_associative_array' => true, + 'json_decode_depth' => 512, + 'json_decode_option' => 0, + ], $this->context); + } + + public function transformData($dataToTransform) + { + $context = $this->resolveContext(); + $transformedData = json_decode( + $dataToTransform, + $context['json_decode_associative_array'], + $context['json_decode_depth'], + $context['json_decode_option'] + ); + + $this->jsonHasError = !(json_last_error() === JSON_ERROR_NONE); + + return $transformedData; + } +} diff --git a/Transformer/TransformerInterface.php b/Transformer/TransformerInterface.php new file mode 100644 index 0000000..1078544 --- /dev/null +++ b/Transformer/TransformerInterface.php @@ -0,0 +1,15 @@ + + */ +interface TransformerInterface +{ + /** + * @param $dataToTransform + * @return mixed + */ + public function transformData($dataToTransform); +}