Skip to content

Commit 6a75de1

Browse files
committed
json/jsonld
1 parent b2f2ea3 commit 6a75de1

File tree

8 files changed

+308
-44
lines changed

8 files changed

+308
-44
lines changed

src/Hydra/State/JsonStreamerProcessor.php

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
namespace ApiPlatform\Hydra\State;
1515

1616
use ApiPlatform\Hydra\Collection;
17-
use ApiPlatform\Hydra\PartialCollectionView;
1817
use ApiPlatform\Hydra\State\Util\PaginationHelperTrait;
1918
use ApiPlatform\Hydra\State\Util\SearchHelperTrait;
2019
use ApiPlatform\Metadata\CollectionOperationInterface;
@@ -66,24 +65,22 @@ public function __construct(
6665

6766
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
6867
{
69-
if (!$operation->getJsonStream() || !($request = $context['request'] ?? null)) {
70-
return $this->processor->process($data, $operation, $uriVariables, $context);
71-
}
72-
73-
// TODO: remove this before merging
74-
if ($request->query->has('skip_json_stream')) {
75-
return $this->processor->process($data, $operation, $uriVariables, $context);
76-
}
77-
78-
if ($operation instanceof Error || $data instanceof Response || !$operation instanceof HttpOperation) {
68+
if (
69+
$operation instanceof Error
70+
|| $data instanceof Response
71+
|| !$operation instanceof HttpOperation
72+
|| !($request = $context['request'] ?? null)
73+
|| !$operation->getJsonStream()
74+
|| 'jsonld' !== $request->getRequestFormat()
75+
) {
7976
return $this->processor->process($data, $operation, $uriVariables, $context);
8077
}
8178

8279
if ($operation instanceof CollectionOperationInterface) {
8380
$requestUri = $request->getRequestUri() ?? '';
8481
$collection = new Collection();
8582
$collection->member = $data;
86-
$collection->view = $this->getView($data, $requestUri, $operation);
83+
$collection->view = $this->getPartialCollectionView($data, $requestUri, $this->pageParameterName, $this->enabledParameterName, $operation->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
8784

8885
if ($operation->getParameters()) {
8986
$parts = parse_url($requestUri);
@@ -104,10 +101,11 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
104101
['data' => $data, 'operation' => $operation],
105102
);
106103
} else {
107-
$data = $this->jsonStreamer->write($data, Type::object($operation->getClass()), [
108-
'data' => $data,
109-
'operation' => $operation,
110-
]);
104+
$data = $this->jsonStreamer->write(
105+
$data,
106+
Type::object($operation->getClass()),
107+
['data' => $data, 'operation' => $operation],
108+
);
111109
}
112110

113111
/** @var iterable<string> $data */
@@ -119,9 +117,4 @@ public function process(mixed $data, Operation $operation, array $uriVariables =
119117

120118
return $this->processor->process($response, $operation, $uriVariables, $context);
121119
}
122-
123-
private function getView(mixed $object, string $requestUri, Operation $operation): PartialCollectionView
124-
{
125-
return $this->getPartialCollectionView($object, $requestUri, $this->pageParameterName, $this->enabledParameterName, $operation->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
126-
}
127120
}

src/Hydra/State/JsonStreamerProvider.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,13 @@ public function provide(Operation $operation, array $uriVariables = [], array $c
3535

3636
$data = $this->decorated ? $this->decorated->provide($operation, $uriVariables, $context) : $request->attributes->get('data');
3737

38-
if (!$operation->canDeserialize()) {
38+
if (!$operation->canDeserialize() || 'jsonld' !== $request->attributes->get('input_format')) {
3939
return $data;
4040
}
4141

42+
$data = $this->jsonStreamReader->read($request->getContent(true), Type::object($operation->getClass()));
4243
$context['request']->attributes->set('deserialized', true);
4344

44-
return $this->jsonStreamReader->read($request->getContent(true), Type::object($operation->getClass()));
45+
return $data;
4546
}
4647
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Serializer\State;
15+
16+
use ApiPlatform\Metadata\CollectionOperationInterface;
17+
use ApiPlatform\Metadata\Error;
18+
use ApiPlatform\Metadata\HttpOperation;
19+
use ApiPlatform\Metadata\IriConverterInterface;
20+
use ApiPlatform\Metadata\Operation;
21+
use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactoryInterface;
22+
use ApiPlatform\Metadata\ResourceClassResolverInterface;
23+
use ApiPlatform\State\ProcessorInterface;
24+
use ApiPlatform\State\Util\HttpResponseHeadersTrait;
25+
use ApiPlatform\State\Util\HttpResponseStatusTrait;
26+
use Symfony\Component\HttpFoundation\Response;
27+
use Symfony\Component\HttpFoundation\StreamedResponse;
28+
use Symfony\Component\JsonStreamer\StreamWriterInterface;
29+
use Symfony\Component\TypeInfo\Type;
30+
31+
/**
32+
* @implements ProcessorInterface<mixed,mixed>
33+
*/
34+
final class JsonStreamerProcessor implements ProcessorInterface
35+
{
36+
use HttpResponseHeadersTrait;
37+
use HttpResponseStatusTrait;
38+
39+
/**
40+
* @param ProcessorInterface<mixed,mixed> $processor
41+
* @param StreamWriterInterface<array<string,mixed>> $jsonStreamer
42+
*/
43+
public function __construct(
44+
private readonly ProcessorInterface $processor,
45+
private readonly StreamWriterInterface $jsonStreamer,
46+
?IriConverterInterface $iriConverter = null,
47+
?ResourceClassResolverInterface $resourceClassResolver = null,
48+
?OperationMetadataFactoryInterface $operationMetadataFactory = null,
49+
) {
50+
$this->resourceClassResolver = $resourceClassResolver;
51+
$this->iriConverter = $iriConverter;
52+
$this->operationMetadataFactory = $operationMetadataFactory;
53+
}
54+
55+
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
56+
{
57+
if (
58+
$operation instanceof Error
59+
|| $data instanceof Response
60+
|| !$operation instanceof HttpOperation
61+
|| !($request = $context['request'] ?? null)
62+
|| !$operation->getJsonStream()
63+
|| 'json' !== $request->getRequestFormat()
64+
) {
65+
return $this->processor->process($data, $operation, $uriVariables, $context);
66+
}
67+
68+
if ($operation instanceof CollectionOperationInterface) {
69+
$data = $this->jsonStreamer->write(
70+
$data,
71+
Type::list(Type::object($operation->getClass())),
72+
['data' => $data, 'operation' => $operation],
73+
);
74+
} else {
75+
$data = $this->jsonStreamer->write(
76+
$data,
77+
Type::object($operation->getClass()),
78+
['data' => $data, 'operation' => $operation],
79+
);
80+
}
81+
82+
/** @var iterable<string> $data */
83+
$response = new StreamedResponse(
84+
$data,
85+
$this->getStatus($request, $operation, $context),
86+
$this->getHeaders($request, $operation, $context)
87+
);
88+
89+
return $this->processor->process($response, $operation, $uriVariables, $context);
90+
}
91+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Serializer\State;
15+
16+
use ApiPlatform\Metadata\HttpOperation;
17+
use ApiPlatform\Metadata\Operation;
18+
use ApiPlatform\State\ProviderInterface;
19+
use Symfony\Component\JsonStreamer\StreamReaderInterface;
20+
use Symfony\Component\TypeInfo\Type;
21+
22+
final class JsonStreamerProvider implements ProviderInterface
23+
{
24+
public function __construct(
25+
private readonly ?ProviderInterface $decorated,
26+
private readonly StreamReaderInterface $jsonStreamReader,
27+
) {
28+
}
29+
30+
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
31+
{
32+
if (!$operation instanceof HttpOperation || !$operation->getJsonStream() || !($request = $context['request'] ?? null)) {
33+
return $this->decorated?->provide($operation, $uriVariables, $context);
34+
}
35+
36+
$data = $this->decorated ? $this->decorated->provide($operation, $uriVariables, $context) : $request->attributes->get('data');
37+
38+
if (!$operation->canDeserialize() || 'json' !== $request->attributes->get('input_format')) {
39+
return $data;
40+
}
41+
42+
$data = $this->jsonStreamReader->read($request->getContent(true), Type::object($operation->getClass()));
43+
$context['request']->attributes->set('deserialized', true);
44+
45+
return $data;
46+
}
47+
}

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public function load(array $configs, ContainerBuilder $container): void
172172
$this->registerMakerConfiguration($container, $config, $loader);
173173
$this->registerArgumentResolverConfiguration($loader);
174174
$this->registerLinkSecurityConfiguration($loader, $config);
175-
$this->registerJsonStreamerConfiguration($loader, $config);
175+
$this->registerJsonStreamerConfiguration($container, $loader, $formats, $config);
176176

177177
if (class_exists(ObjectMapper::class)) {
178178
$loader->load('state/object_mapper.xml');
@@ -192,7 +192,8 @@ public function load(array $configs, ContainerBuilder $container): void
192192
->addTag('api_platform.resource')
193193
->addTag('container.excluded', ['source' => 'by #[ApiResource] attribute']);
194194
});
195-
$container->registerAttributeForAutoconfiguration(AsResourceMutator::class,
195+
$container->registerAttributeForAutoconfiguration(
196+
AsResourceMutator::class,
196197
static function (ChildDefinition $definition, AsResourceMutator $attribute, \Reflector $reflector): void {
197198
if (!$reflector instanceof \ReflectionClass) {
198199
return;
@@ -208,7 +209,8 @@ static function (ChildDefinition $definition, AsResourceMutator $attribute, \Ref
208209
},
209210
);
210211

211-
$container->registerAttributeForAutoconfiguration(AsOperationMutator::class,
212+
$container->registerAttributeForAutoconfiguration(
213+
AsOperationMutator::class,
212214
static function (ChildDefinition $definition, AsOperationMutator $attribute, \Reflector $reflector): void {
213215
if (!$reflector instanceof \ReflectionClass) {
214216
return;
@@ -981,10 +983,21 @@ private function registerLinkSecurityConfiguration(XmlFileLoader $loader, array
981983
}
982984
}
983985

984-
private function registerJsonStreamerConfiguration(XmlFileLoader $loader, array $config): void
986+
private function registerJsonStreamerConfiguration(ContainerBuilder $container, XmlFileLoader $loader, array $formats, array $config): void
985987
{
986-
if ($config['enable_json_streamer']) {
987-
$loader->load('json_streamer.xml');
988+
if (!$config['enable_json_streamer']) {
989+
return;
990+
}
991+
992+
if (isset($formats['jsonld'])) {
993+
$container->setParameter('.json_streamer.stream_writers_dir.jsonld', '%kernel.cache_dir%/json_streamer/stream_writer/jsonld');
994+
$container->setParameter('.json_streamer.stream_readers_dir.jsonld', '%kernel.cache_dir%/json_streamer/stream_reader/jsonld');
995+
$container->setParameter('.json_streamer.lazy_ghosts_dir.jsonld', '%kernel.cache_dir%/json_streamer/lazy_ghost/jsonld');
996+
$loader->load('json_streamer/hydra.xml');
997+
}
998+
999+
if (isset($formats['json'])) {
1000+
$loader->load('json_streamer/json.xml');
9881001
}
9891002
}
9901003
}

src/Symfony/Bundle/Resources/config/json_streamer.xml renamed to src/Symfony/Bundle/Resources/config/json_streamer/hydra.xml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
44
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
55
<services>
6-
<service id="api_platform.json_streamer.stream_writer" class="Symfony\Component\JsonStreamer\JsonStreamWriter">
6+
<service id="api_platform.jsonld.json_streamer.stream_writer" class="Symfony\Component\JsonStreamer\JsonStreamWriter">
77
<argument type="tagged_locator" tag="json_streamer.value_transformer" />
88
<argument type="service" id="api_platform.jsonld.json_streamer.write.property_metadata_loader" />
9-
<argument>%.json_streamer.stream_writers_dir%</argument>
9+
<argument>%.json_streamer.stream_writers_dir.jsonld%</argument>
1010
</service>
1111

12-
<service id="api_platform.json_streamer.stream_reader" class="Symfony\Component\JsonStreamer\JsonStreamReader">
12+
<service id="api_platform.jsonld.json_streamer.stream_reader" class="Symfony\Component\JsonStreamer\JsonStreamReader">
1313
<argument type="tagged_locator" tag="json_streamer.value_transformer" />
1414
<argument type="service" id="json_streamer.read.property_metadata_loader" />
15-
<argument>%.json_streamer.stream_readers_dir%</argument>
16-
<argument>%.json_streamer.lazy_ghosts_dir%</argument>
15+
<argument>%.json_streamer.stream_readers_dir.jsonld%</argument>
16+
<argument>%.json_streamer.lazy_ghosts_dir.jsonld%</argument>
1717
</service>
1818

1919
<service id="api_platform.jsonld.json_streamer.write.property_metadata_loader" class="ApiPlatform\JsonLd\JsonStreamer\WritePropertyMetadataLoader">
@@ -35,9 +35,9 @@
3535
<tag name="json_streamer.value_transformer"/>
3636
</service>
3737

38-
<service id="api_platform.state_processor.json_streamer" class="ApiPlatform\Hydra\State\JsonStreamerProcessor" decorates="api_platform.state_processor.main" decoration-priority="190">
39-
<argument type="service" id="api_platform.state_processor.json_streamer.inner" />
40-
<argument type="service" id="api_platform.json_streamer.stream_writer" />
38+
<service id="api_platform.jsonld.state_processor.json_streamer" class="ApiPlatform\Hydra\State\JsonStreamerProcessor" decorates="api_platform.state_processor.main" decoration-priority="190">
39+
<argument type="service" id="api_platform.jsonld.state_processor.json_streamer.inner" />
40+
<argument type="service" id="api_platform.jsonld.json_streamer.stream_writer" />
4141
<argument type="service" id="api_platform.iri_converter" />
4242
<argument type="service" id="api_platform.resource_class_resolver" />
4343
<argument type="service" id="api_platform.metadata.operation.metadata_factory" />
@@ -46,10 +46,9 @@
4646
<argument>%api_platform.url_generation_strategy%</argument>
4747
</service>
4848

49-
<service id="api_platform.state_provider.json_streamer" class="ApiPlatform\Hydra\State\JsonStreamerProvider" decorates="api_platform.state_provider.main" decoration-priority="310">
50-
<argument type="service" id="api_platform.state_provider.json_streamer.inner" />
51-
<argument type="service" id="api_platform.json_streamer.stream_reader" />
49+
<service id="api_platform.jsonld.state_provider.json_streamer" class="ApiPlatform\Hydra\State\JsonStreamerProvider" decorates="api_platform.state_provider.main" decoration-priority="310">
50+
<argument type="service" id="api_platform.jsonld.state_provider.json_streamer.inner" />
51+
<argument type="service" id="api_platform.jsonld.json_streamer.stream_reader" />
5252
</service>
5353
</services>
5454
</container>
55-
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" ?>
2+
<container xmlns="http://symfony.com/schema/dic/services"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
5+
<services>
6+
<service id="api_platform.state_processor.json_streamer" class="ApiPlatform\Serializer\State\JsonStreamerProcessor" decorates="api_platform.state_processor.main" decoration-priority="190">
7+
<argument type="service" id="api_platform.state_processor.json_streamer.inner" />
8+
<argument type="service" id="json_streamer.stream_writer" />
9+
<argument type="service" id="api_platform.iri_converter" />
10+
<argument type="service" id="api_platform.resource_class_resolver" />
11+
<argument type="service" id="api_platform.metadata.operation.metadata_factory" />
12+
</service>
13+
14+
<service id="api_platform.state_provider.json_streamer" class="ApiPlatform\Serializer\State\JsonStreamerProvider" decorates="api_platform.state_provider.main" decoration-priority="310">
15+
<argument type="service" id="api_platform.state_provider.json_streamer.inner" />
16+
<argument type="service" id="json_streamer.stream_reader" />
17+
</service>
18+
</services>
19+
</container>

0 commit comments

Comments
 (0)