Skip to content

Commit bb32ee8

Browse files
authored
Merge branch 'master' into exception_response_http_status_code
2 parents 61762a7 + 0d73b8c commit bb32ee8

23 files changed

+179
-77
lines changed

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,20 @@ api_response:
4141
serializer: json_encode
4242
serialize_groups: []
4343
cors_allow_origin_regex: https://.*\.mydomain\.com
44-
cors_allow_headers: Authorization, Content-Type
44+
cors_allow_headers: [Authorization, Content-Type]
4545
cors_max_age: 86400
4646
paths:
4747
somename:
48-
pattern: ^/api/v1/
48+
prefix: /api/v1/
4949
serializer: jms_serializer
5050
othername:
51-
pattern: ^/api/v2/
52-
cors_allow_origin_regex: https://.*\.(mydomain|theirdomain)\.com
51+
pattern: ^/api/v[2-4]/
52+
cors_allow_origin_regex: .*
5353
```
5454
55+
The serializer can be empty, 'array', 'json_encode', 'json_group_encode', 'jms_serializer',
56+
or the name of a service which must implement the SerializerAdapterInterface. It defaults to 'json_encode'.
57+
5558
## Usage
5659
5760
In your API controllers, just return whatever you want serialized in the response. The ApiResponseBundle takes care of

src/Compiler/ApiConfigCompiler.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,13 @@ public function compileApiConfig(Request $request)
7777
$originPath = $request->getPathInfo();
7878
foreach ($this->pathConfigs as $pathConfig) {
7979
$pathRegex = $pathConfig->getPattern();
80-
if (!preg_match('#' . str_replace('#', '\#', $pathRegex) . '#', $originPath)) {
80+
if ($pathRegex !== null && !preg_match('#' . str_replace('#', '\#', $pathRegex) . '#', $originPath)) {
81+
// No path match.
82+
continue;
83+
}
84+
85+
$pathPrefix = $pathConfig->getPrefix();
86+
if ($pathPrefix !== null && strpos($originPath, $pathPrefix) !== 0) {
8187
// No path match.
8288
continue;
8389
}
@@ -161,6 +167,7 @@ private function generateApiPathConfig(array $configArray)
161167

162168
// @TODO Use PHP 7 null coalescing operator.
163169
$apiPathConfig->setPattern(isset($configArray['pattern']) ? $configArray['pattern'] : null);
170+
$apiPathConfig->setPrefix(isset($configArray['prefix']) ? $configArray['prefix'] : null);
164171

165172
return $apiPathConfig;
166173
}
@@ -174,7 +181,7 @@ private function applyApiConfig(array $configArray, ApiConfig $apiConfig)
174181
// @TODO Use PHP 7 null coalescing operator.
175182
$apiConfig
176183
->setSerializer(isset($configArray['serializer']) ? $configArray['serializer'] : null)
177-
->setGroups(isset($configArray['serialize_groups']) ? $configArray['serialize_groups'] : null)
184+
->setGroups(isset($configArray['serialize_groups']) && is_array($configArray['serialize_groups']) ? $configArray['serialize_groups'] : null)
178185
->setCorsAllowHeaders(isset($configArray['cors_allow_headers']) ? $configArray['cors_allow_headers'] : null)
179186
->setCorsAllowOriginRegex(isset($configArray['cors_allow_origin_regex']) ? $configArray['cors_allow_origin_regex'] : null)
180187
->setCorsMaxAge(isset($configArray['cors_max_age']) ? $configArray['cors_max_age'] : null)

src/DependencyInjection/Configuration.php

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ public function getConfigTreeBuilder()
3131
$rootNode->children()
3232
->arrayNode('defaults')
3333
->children()
34-
->arrayNode('pattern')
35-
->prototype('scalar')->isRequired()->end()
36-
->end()
3734
);
3835

3936
$this->buildConfigNode(
@@ -42,7 +39,8 @@ public function getConfigTreeBuilder()
4239
->useAttributeAsKey('name')
4340
->prototype('array')
4441
->children()
45-
->scalarNode('pattern')->end()
42+
->scalarNode('pattern')->end()
43+
->scalarNode('prefix')->end()
4644
);
4745

4846
return $treeBuilder;
@@ -56,17 +54,8 @@ public function getConfigTreeBuilder()
5654
private function buildConfigNode(NodeBuilder $nodeBuilder)
5755
{
5856
return $nodeBuilder
59-
->enumNode('serializer')
60-
->values([
61-
self::SERIALIZER_ARRAY,
62-
self::SERIALIZER_JSON_ENCODE,
63-
self::SERIALIZER_JSON_GROUP_ENCODE,
64-
self::SERIALIZER_JMS_SERIALIZER,
65-
])
66-
->end()
67-
->arrayNode('serialize_groups')
68-
->prototype('scalar')->end()
69-
->end()
57+
->scalarNode('serializer')->end()
58+
->variableNode('serialize_groups')->end()
7059
->scalarNode('cors_allow_origin_regex')->end()
7160
->arrayNode('cors_allow_headers')
7261
->prototype('scalar')->end()

src/Factory/SerializerAdapterFactory.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
namespace MattJanssen\ApiResponseBundle\Factory;
44

55
use MattJanssen\ApiResponseBundle\DependencyInjection\Configuration;
6-
use MattJanssen\ApiResponseBundle\Serializer\Adapter as Adapter;
6+
use MattJanssen\ApiResponseBundle\Serializer\Adapter;
77
use Symfony\Component\DependencyInjection\ContainerInterface;
88

99
/**
@@ -66,7 +66,17 @@ public function createSerializerAdapter($serializerName)
6666
break;
6767

6868
default:
69-
throw new \RuntimeException('Unrecognized serializer configured.');
69+
if ($this->container->has($serializerName)) {
70+
$serializerAdapter = $this->container->get($serializerName);
71+
if (!$serializerAdapter instanceof Adapter\SerializerAdapterInterface) {
72+
throw new \RuntimeException(sprintf(
73+
'Serializer adapter "%s" does not implement SerializerAdapterInterface.',
74+
$serializerName
75+
));
76+
}
77+
} else {
78+
throw new \RuntimeException(sprintf('Unrecognized serializer "%s".', $serializerName));
79+
}
7080
}
7181

7282
return $serializerAdapter;

src/Generator/ApiResponseGenerator.php

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
namespace MattJanssen\ApiResponseBundle\Generator;
44

5+
use MattJanssen\ApiResponseBundle\Compiler\ApiConfigCompiler;
56
use MattJanssen\ApiResponseBundle\DependencyInjection\Configuration;
67
use MattJanssen\ApiResponseBundle\Factory\SerializerAdapterFactory;
78
use MattJanssen\ApiResponseBundle\Model\ApiResponseErrorModel;
89
use MattJanssen\ApiResponseBundle\Model\ApiResponseResponseModel;
10+
use Symfony\Component\HttpFoundation\RequestStack;
911
use Symfony\Component\HttpFoundation\Response;
1012

1113
/**
@@ -15,6 +17,16 @@
1517
*/
1618
class ApiResponseGenerator
1719
{
20+
/**
21+
* @var RequestStack
22+
*/
23+
private $requestStack;
24+
25+
/**
26+
* @var ApiConfigCompiler
27+
*/
28+
private $configCompiler;
29+
1830
/**
1931
* Serializer Adapter Factory
2032
*
@@ -25,11 +37,17 @@ class ApiResponseGenerator
2537
/**
2638
* Constructor
2739
*
40+
* @param RequestStack $requestStack
41+
* @param ApiConfigCompiler $configCompiler
2842
* @param SerializerAdapterFactory $serializerAdapterFactory
2943
*/
3044
public function __construct(
45+
RequestStack $requestStack,
46+
ApiConfigCompiler $configCompiler,
3147
SerializerAdapterFactory $serializerAdapterFactory
3248
) {
49+
$this->requestStack = $requestStack;
50+
$this->configCompiler = $configCompiler;
3351
$this->serializerAdapterFactory = $serializerAdapterFactory;
3452
}
3553

@@ -39,8 +57,8 @@ public function __construct(
3957
* Defaults to json_encode serializer.
4058
*
4159
* @param mixed $data
42-
* @param int $httpCode
43-
* @param array $serializeGroups
60+
* @param int|null $httpCode
61+
* @param string[]|null $serializeGroups
4462
* @param string|null $serializerName Name of serializer to use instead of the default.
4563
*
4664
* @return Response
@@ -52,17 +70,23 @@ public function generateSuccessResponse(
5270
array $serializeGroups = null,
5371
$serializerName = null
5472
) {
55-
// Set defaults.
56-
if (null === $httpCode) {
73+
if ($httpCode === null) {
5774
$httpCode = Response::HTTP_OK;
5875
}
5976

60-
if (null === $serializeGroups) {
61-
$serializeGroups = [];
77+
$request = $this->requestStack->getMasterRequest();
78+
$pathConfig = $request ? $this->configCompiler->compileApiConfig($request) : null;
79+
80+
if ($serializeGroups === null && $pathConfig !== null) {
81+
$serializeGroups = $pathConfig->getGroups();
6282
}
6383

64-
if (null === $serializerName) {
65-
$serializerName = Configuration::SERIALIZER_JSON_ENCODE;
84+
if ($serializerName === null) {
85+
if ($pathConfig !== null) {
86+
$serializerName = $pathConfig->getSerializer();
87+
} else {
88+
$serializerName = Configuration::SERIALIZER_JSON_ENCODE;
89+
}
6690
}
6791

6892
$serializerAdapter = $this->serializerAdapterFactory->createSerializerAdapter($serializerName);
@@ -83,7 +107,7 @@ public function generateSuccessResponse(
83107
* This assumes the json_encode serializer.
84108
*
85109
* @param int $httpCode
86-
* @param int $errorCode
110+
* @param string $errorCode
87111
* @param string|null $errorTitle
88112
* @param mixed|null $errorData
89113
*

src/Model/ApiConfigTrait.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ trait ApiConfigTrait
1414
/**
1515
* Serializer Adapter to Use
1616
*
17-
* One of the Configuration::SERIALIZER_* constants.
17+
* One of the Configuration::SERIALIZER_* constants or a service name.
1818
* @see MattJanssen\ApiResponseBundle\DependencyInjection\Configuration::SERIALIZER_JSON_ENCODE
1919
*
2020
* @var string
2121
*/
2222
private $serializer;
2323

2424
/**
25-
* Optional Groups Names for JMS Serializer
25+
* Optional Groups Names for Serializer
2626
*
27-
* @var string[]
27+
* @var string[]|null
2828
*/
2929
private $groups;
3030

@@ -72,7 +72,7 @@ public function getGroups()
7272
}
7373

7474
/**
75-
* @param string[] $groups
75+
* @param string[]|null $groups
7676
*
7777
* @return $this
7878
*/

src/Model/ApiPathConfig.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ class ApiPathConfig extends ApiConfig
1212
*/
1313
private $pattern;
1414

15+
/**
16+
* @var string
17+
*/
18+
private $prefix;
19+
1520
/**
1621
* @return string
1722
*/
@@ -31,4 +36,24 @@ public function setPattern($pattern)
3136

3237
return $this;
3338
}
39+
40+
/**
41+
* @return string
42+
*/
43+
public function getPrefix()
44+
{
45+
return $this->prefix;
46+
}
47+
48+
/**
49+
* @param string $prefix
50+
*
51+
* @return $this
52+
*/
53+
public function setPrefix($prefix)
54+
{
55+
$this->prefix = $prefix;
56+
57+
return $this;
58+
}
3459
}

src/Model/ApiResponseErrorModel.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class ApiResponseErrorModel implements \JsonSerializable
1212
/**
1313
* Application-specific API Error Code
1414
*
15-
* @var int
15+
* @var string
1616
*/
1717
private $code;
1818

@@ -33,7 +33,7 @@ class ApiResponseErrorModel implements \JsonSerializable
3333
/**
3434
* {@inheritdoc}
3535
*/
36-
function jsonSerialize()
36+
public function jsonSerialize()
3737
{
3838
return [
3939
'code' => $this->code,
@@ -45,7 +45,7 @@ function jsonSerialize()
4545
/**
4646
* Set the API Error Code
4747
*
48-
* @return int
48+
* @return string
4949
*/
5050
public function getCode()
5151
{
@@ -55,7 +55,7 @@ public function getCode()
5555
/**
5656
* Get the API Error Code
5757
*
58-
* @param int $code
58+
* @param string $code
5959
*
6060
* @return $this
6161
*/

src/Model/ApiResponseResponseModel.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ApiResponseResponseModel implements \JsonSerializable, ArraySerializable
3131
/**
3232
* {@inheritdoc}
3333
*/
34-
public function jsonSerialize(): array
34+
public function jsonSerialize()
3535
{
3636
return [
3737
'data' => $this->data,

src/Resources/config/services.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
services:
2-
# Seralizer Adapter
3-
api_response.serializer_adapter:
4-
class: MattJanssen\ApiResponseBundle\Serializer\Adapter\SerializerAdapterInterface
5-
synthetic: true
6-
72
# Compiler
83
api_response.compiler.api_config: # Generated in ApiResponseExtension compile pass.
94
class: MattJanssen\ApiResponseBundle\Compiler\ApiConfigCompiler
5+
public: false
106
arguments:
117
- %api_response.defaults%
128
- %api_response.paths%
@@ -18,16 +14,20 @@ services:
1814
arguments:
1915
- "@api_response.generator.api_response"
2016
- "@api_response.compiler.api_config"
17+
- "@logger"
2118
- %kernel.debug%
2219

2320
# Factory
2421
api_response.factory.serializer_adapter:
2522
class: MattJanssen\ApiResponseBundle\Factory\SerializerAdapterFactory
23+
public: false
2624
arguments:
2725
- "@service_container"
2826

2927
# Generator
3028
api_response.generator.api_response:
3129
class: MattJanssen\ApiResponseBundle\Generator\ApiResponseGenerator
3230
arguments:
31+
- "@request_stack"
32+
- "@api_response.compiler.api_config"
3333
- "@api_response.factory.serializer_adapter"

0 commit comments

Comments
 (0)