Skip to content

Commit 4482c01

Browse files
committed
Update from internal 0.9 release
1 parent c4570fb commit 4482c01

27 files changed

+355
-67
lines changed

composer.json

+16-6
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,32 @@
44
"type": "symfony-bundle",
55
"require": {
66
"php": ">=7.0.0",
7-
"symfony/symfony": "^3.1",
7+
"symfony/framework-bundle": "^3.1",
88
"neomerx/json-api": "^1.0",
99
"doctrine/orm": "~2.4,<2.5|^2.5",
1010
"doctrine/doctrine-bundle": "~1.6",
11-
"sensio/framework-extra-bundle": "^3.0"
11+
"sensio/framework-extra-bundle": "^3.0",
12+
"symfony/form": "^3.1",
13+
"symfony/translation": "^3.3",
14+
"symfony/validator": "^3.3",
15+
"symfony/monolog-bundle": "^3.1"
1216
},
1317
"require-dev": {
1418
"sensio/generator-bundle": "^3.0",
15-
"phpunit/phpunit": "^5.2",
16-
"phpunit/php-code-coverage": "^3.3",
19+
"phpunit/phpunit": "^5.7",
20+
"phpunit/php-code-coverage": "^4.0",
1721
"symfony/phpunit-bridge": "^3.0",
1822
"justinrainbow/json-schema": "^1.6",
1923
"doctrine/doctrine-fixtures-bundle": "^2.3",
2024
"fzaninotto/faker": "^1.5",
21-
"symfony/monolog-bundle": "^2.8",
22-
"sensiolabs/security-checker": "^4.1"
25+
"sensiolabs/security-checker": "^4.1",
26+
"symfony/security-bundle": "^3.1",
27+
"symfony/twig-bundle": "^3.3",
28+
"doctrine/cache": "^1.6",
29+
"symfony/debug-bundle": "^3.3",
30+
"symfony/web-profiler-bundle": "^3.3",
31+
"symfony/web-server-bundle": "^3.3",
32+
"symfony/browser-kit": "^3.3"
2333
},
2434
"autoload": {
2535
"psr-4": {

src/Controller/Traits/Actions/CreateTrait.php

+40-15
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,15 @@
2222
*/
2323
trait CreateTrait
2424
{
25-
2625
/**
26+
* @param ConfigInterface $config
27+
* @param object $emptyModel
2728
* @param Request $request
2829
* @return object
2930
* @throws ModelValidationException
3031
*/
31-
protected function createModelFromRequest(Request $request)
32+
protected function handleCreateModelInputFromRequest(ConfigInterface $config, $emptyModel, Request $request)
3233
{
33-
/** @var ConfigInterface $config */
34-
$config = $this->getJsonApiConfig();
35-
36-
//TODO make sure request has data in array
37-
38-
// create empty object, config executes and closures
39-
$emptyModelFactory = $config->getCreate()->getCreateFactory();
40-
$emptyModel = $emptyModelFactory->create($config->getApi()->getModelClass());
41-
4234
// merge it with request data
4335
if (true === method_exists($this, 'getCreateInputHandler')) {
4436
// TODO - add check if callable, and give info it should be protected
@@ -53,23 +45,35 @@ protected function createModelFromRequest(Request $request)
5345

5446
// update model input with files from request
5547
$modelInput = $request->request->all();
56-
if($request->files->count() > 0) {
48+
if ($request->files->count() > 0) {
5749
foreach ($request->files->all() as $filesKey => $filesValue) {
58-
if(array_key_exists($filesKey, $modelInput)) {
59-
throw new RuntimeException(sprintf('Conflict with request files, duplicate param found in request and files %s', $filesKey));
50+
if (array_key_exists($filesKey, $modelInput)) {
51+
throw new RuntimeException(sprintf('Conflict with request files, duplicate param found in request and files %s',
52+
$filesKey));
6053
}
6154
$modelInput[$filesKey] = $filesValue;
6255
}
6356
}
6457
$model = $handler->forModel($emptyModel)->handle($modelInput)->getResult();
6558

6659
// validate result
67-
if($handler instanceof ModelValidatorInterface) {
60+
if ($handler instanceof ModelValidatorInterface) {
6861
$validated = $handler->validate();
6962
if (true !== $validated) {
7063
throw new ModelValidationException($validated);
7164
}
7265
}
66+
67+
return $model;
68+
}
69+
70+
/**
71+
* @param ConfigInterface $config
72+
* @param object $model
73+
* @throws ModelValidationException
74+
*/
75+
protected function validateCreatedModel(ConfigInterface $config, $model)
76+
{
7377
if (true === method_exists($this, 'getCreateValidator')) {
7478
// TODO - add check if callable, and give info it should be protected
7579
/** @var ModelValidatorInterface $validator */
@@ -87,6 +91,27 @@ protected function createModelFromRequest(Request $request)
8791
// TODO get errors and send them as response
8892
throw new ModelValidationException($validated);
8993
}
94+
}
95+
96+
/**
97+
* @param Request $request
98+
* @return object
99+
* @throws ModelValidationException
100+
*/
101+
protected function createModelFromRequest(Request $request)
102+
{
103+
/** @var ConfigInterface $config */
104+
$config = $this->getJsonApiConfig();
105+
106+
//TODO make sure request has data in array
107+
108+
// create empty object, config executes and closures
109+
$emptyModelFactory = $config->getCreate()->getCreateFactory();
110+
$emptyModel = $emptyModelFactory->create($config->getApi()->getModelClass());
111+
112+
$model = $this->handleCreateModelInputFromRequest($config, $emptyModel, $request);
113+
114+
$this->validateCreatedModel($config, $model);
90115

91116
// save it
92117
$config->getApi()->getRepository()->save($model);

src/Controller/Traits/Actions/IndexTrait.php

+12
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ private function generateSelfUrlFromRequest(RouterInterface $router, Request $re
7878

7979
$routeParams = array_merge($routeParams, $overrideParams);
8080

81+
foreach ($routeParams as $paramName => &$paramValues) {
82+
if (in_array($paramName, ['fields', 'filter']) && is_array($paramValues)) {
83+
foreach ($paramValues as $fieldName => $fieldProperties) {
84+
if (is_array($fieldProperties)) {
85+
$paramValues[$fieldName] = implode(',', $fieldProperties);
86+
}
87+
}
88+
} elseif ($paramName === 'include' && is_array($paramValues)) {
89+
$routeParams[$paramName] = implode(',', $paramValues);
90+
}
91+
}
92+
8193
return $router->generate(
8294
$routeName,
8395
$routeParams,

src/Controller/Traits/Actions/UpdateTrait.php

+44-17
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ protected function updateModelFromRequestUsingId(Request $request, $id)
5252
$model = $repository->getOne($id, $config->getApi()->getFixedFiltering());
5353

5454
// check if model is loaded
55-
if(null === $model) {
55+
if (null === $model) {
5656
throw new NotFoundHttpException();
5757
}
5858

@@ -63,22 +63,14 @@ protected function updateModelFromRequestUsingId(Request $request, $id)
6363
}
6464

6565
/**
66-
* @param Request $request
66+
* @param ConfigInterface $config
6767
* @param $model
68+
* @param Request $request
6869
* @return object
6970
* @throws ModelValidationException
7071
*/
71-
protected function updateModelFromRequestUsingModel(Request $request, $model) {
72-
/** @var ConfigInterface $config */
73-
$config = $this->getJsonApiConfig();
74-
75-
//TODO make sure request has data in array
76-
77-
/** @var RepositoryInterface $repository */
78-
$repository = $config->getApi()->getRepository();
79-
80-
// TODO - check if model correct class?
81-
72+
protected function handleUpdateModelInputFromRequest(ConfigInterface $config, $model, Request $request)
73+
{
8274
// merge it with request data
8375
if (true === method_exists($this, 'getUpdateInputHandler')) {
8476
// TODO - add check if callable, and give info it should be protected
@@ -93,10 +85,11 @@ protected function updateModelFromRequestUsingModel(Request $request, $model) {
9385

9486
// update model input with files from request
9587
$modelInput = $request->request->all();
96-
if($request->files->count() > 0) {
88+
if ($request->files->count() > 0) {
9789
foreach ($request->files->all() as $filesKey => $filesValue) {
98-
if(array_key_exists($filesKey, $modelInput)) {
99-
throw new RuntimeException(sprintf('Conflict with request files, duplicate param found in request and files %s', $filesKey));
90+
if (array_key_exists($filesKey, $modelInput)) {
91+
throw new RuntimeException(sprintf('Conflict with request files, duplicate param found in request and files %s',
92+
$filesKey));
10093
}
10194
$modelInput[$filesKey] = $filesValue;
10295
}
@@ -105,12 +98,23 @@ protected function updateModelFromRequestUsingModel(Request $request, $model) {
10598
$model = $handler->forModel($model)->handle($modelInput)->getResult();
10699

107100
// validate result
108-
if($handler instanceof ModelValidatorInterface) {
101+
if ($handler instanceof ModelValidatorInterface) {
109102
$validated = $handler->validate();
110103
if (true !== $validated) {
111104
throw new ModelValidationException($validated);
112105
}
113106
}
107+
108+
return $model;
109+
}
110+
111+
/**
112+
* @param ConfigInterface $config
113+
* @param $model
114+
* @throws ModelValidationException
115+
*/
116+
protected function validateUpdatedModel(ConfigInterface $config, $model)
117+
{
114118
if (true === method_exists($this, 'getUpdateValidator')) {
115119
// TODO - add check if callable, and give info it should be protected
116120
/** @var ModelValidatorInterface $validator */
@@ -126,6 +130,29 @@ protected function updateModelFromRequestUsingModel(Request $request, $model) {
126130
if (true !== $validated) {
127131
throw new ModelValidationException($validated);
128132
}
133+
}
134+
135+
/**
136+
* @param Request $request
137+
* @param $model
138+
* @return object
139+
* @throws ModelValidationException
140+
*/
141+
protected function updateModelFromRequestUsingModel(Request $request, $model)
142+
{
143+
/** @var ConfigInterface $config */
144+
$config = $this->getJsonApiConfig();
145+
146+
//TODO make sure request has data in array
147+
148+
// TODO - check if model correct class?
149+
150+
$model = $this->handleUpdateModelInputFromRequest($config, $model, $request);
151+
152+
$this->validateUpdatedModel($config, $model);
153+
154+
/** @var RepositoryInterface $repository */
155+
$repository = $config->getApi()->getRepository();
129156

130157
// save it
131158
$repository->save($model);

src/Listener/KernelListener.php

+4
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ private function getResponseFromControllerResult($controllerResult, array $resul
239239
*/
240240
protected function encode($data = '', array $meta = null, array $links = [])
241241
{
242+
// if meta is empty, ommit it
243+
if (true === empty($meta)) {
244+
$meta = null;
245+
}
242246
return $this->encoderService->encode($this->schemaClassMapProvider, $data,
243247
$this->requestDecoder->getParsedRequestParameters(), $meta, $links);
244248
}

src/Services/ModelInput/Traits/ConstraintViolationToErrorTransformer.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ protected function convertViolationsToErrors(ConstraintViolationListInterface $v
3636
protected function convertViolationToError(ConstraintViolationInterface $violation)
3737
{
3838
$code = $violation->getCode();
39-
$title = 'Constraint violation';
40-
$detail = $violation->getMessage();
39+
$title = $violation->getMessage();
40+
$detail = sprintf('Constraint violation "%s"', $title);
4141
$source = [];
4242
if ($violation->getPropertyPath()) {
4343
// TODO - make diff between attributes and relationships

src/Services/ModelInput/Traits/FormErrorToErrorTransformer.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ protected function convertFormErrorsToErrors(FormErrorIterator $formErrors)
3737
*/
3838
protected function convertFormErrorToError(FormError $violation)
3939
{
40-
$title = 'Form Constraint violation';
41-
$detail = $violation->getMessage();
40+
$title = $violation->getMessage();
41+
$detail = sprintf('Form error "%s"', $violation->getMessage());
4242
$source = [];
4343
if ($violation->getOrigin()) {
4444
// TODO - make diff between attributes and relationships

src/Services/Neomerx/ErrorFactory.php

+10-2
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,21 @@ public function fromString(string $error): ErrorInterface
2525
*/
2626
public function fromException(Exception $exception): ErrorInterface
2727
{
28+
$errorDescription = sprintf("Exception of type: %s", get_class($exception));
29+
if (false === empty($exception->getMessage())) {
30+
$errorTitle = $exception->getMessage();
31+
} else {
32+
$errorTitle = $errorDescription;
33+
$errorDescription = '';
34+
}
35+
2836
return new Error(
2937
null,
3038
null,
3139
$exception instanceof HttpExceptionInterface ? $exception->getStatusCode() : Response::HTTP_INTERNAL_SERVER_ERROR,
3240
$exception->getCode(),
33-
get_class($exception),
34-
$exception->getMessage()
41+
$errorTitle,
42+
$errorDescription
3543
);
3644
}
3745
}

src/Services/Neomerx/FactoryService.php

+15-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
namespace Trikoder\JsonApiBundle\Services\Neomerx;
44

5+
use Neomerx\JsonApi\Contracts\Schema\SchemaProviderInterface;
56
use Neomerx\JsonApi\Encoder\Encoder;
67
use Neomerx\JsonApi\Encoder\EncoderOptions;
78
use Neomerx\JsonApi\Factories\Factory;
8-
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
9-
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
109
use Symfony\Component\DependencyInjection\ContainerInterface;
10+
use Trikoder\JsonApiBundle\Services\Neomerx\ResourceObject;
1111

1212
/**
1313
* Class FactoryService
@@ -63,4 +63,16 @@ public function createContainer(array $providers = [])
6363
return $container;
6464
}
6565

66-
}
66+
/**
67+
* @inheritdoc
68+
*/
69+
public function createResourceObject(
70+
SchemaProviderInterface $schema,
71+
$resource,
72+
$isInArray,
73+
$attributeKeysFilter = null
74+
) {
75+
return new ResourceObject($schema, $resource, $isInArray, $attributeKeysFilter);
76+
}
77+
78+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Trikoder\JsonApiBundle\Services\Neomerx;
4+
5+
use Closure;
6+
use Neomerx\JsonApi\Schema\ResourceObject as BaseResourceObject;
7+
8+
class ResourceObject extends BaseResourceObject
9+
{
10+
public function getAttributes()
11+
{
12+
$attributes = parent::getAttributes();
13+
14+
array_walk($attributes, function (&$value, $key) {
15+
if ($value instanceof Closure) {
16+
$value = $value();
17+
}
18+
});
19+
20+
return $attributes;
21+
}
22+
}

src/Services/RequestDecoder.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ function () use ($currentRequest, $config) {
128128
*/
129129

130130
// create new reqest that will replace original one
131-
$transformedRequest = new Request(
131+
// empty duplicated to get copy of current request with allowed preserved properties
132+
$transformedRequest = $currentRequest->duplicate();
133+
// we favour initialize for setup because we can give content of request here, what we cannot do in duplicate
134+
$transformedRequest->initialize(
132135
$queryParams,
133136
// TODO - should we merge original request with decoded content? see comment block above
134137
(null === $decodedContent ? [] : $decodedContent),

0 commit comments

Comments
 (0)