Skip to content

Commit fa5606e

Browse files
committed
API can get component group by reference
1 parent d8652a3 commit fa5606e

8 files changed

Lines changed: 169 additions & 1 deletion

File tree

features/bootstrap/DoctrineContext.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ final class DoctrineContext implements Context
7373
private UserPasswordHasherInterface $passwordHasher;
7474
private array $classes;
7575
private JWTEncoderInterface $jwtEncoder;
76+
private JsonContext $jsonContext;
7677

7778
/**
7879
* Initializes context.
@@ -110,6 +111,7 @@ public function gatherContexts(BeforeScenarioScope $scope): void
110111
$this->baseRestContext = $scope->getEnvironment()->getContext(BehatchRestContext::class);
111112
$this->minkContext = $scope->getEnvironment()->getContext(MinkContext::class);
112113
$this->restContext = $scope->getEnvironment()->getContext(RestContext::class);
114+
$this->jsonContext = $scope->getEnvironment()->getContext(JsonContext::class);
113115
}
114116

115117
/**
@@ -892,6 +894,16 @@ public function thereShouldBeDummyComponentResources(int $count): void
892894
Assert::assertCount($count, $repo->findAll());
893895
}
894896

897+
/**
898+
* @Then the response resource should be saved as :name
899+
*/
900+
public function theResponseResourceShouldBeSavedAs($name): void
901+
{
902+
$response = $this->jsonContext->getJsonAsArray();
903+
Assert::assertArrayHasKey('@id', $response);
904+
$this->restContext->resources[$name] = $response['@id'];
905+
}
906+
895907
/**
896908
* @Then there should be :count ComponentPosition resources
897909
*/

features/main/component_groups.feature

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ Feature: ComponentGroup resource
3939
And there should be 4 DummyComponent resources
4040
And there should be 0 ComponentPosition resources
4141

42+
@loginUser
43+
Scenario: I can get a component group by reference
44+
Given there is a ComponentGroup with 0 components
45+
When I send a "GET" request to "/_/component_groups/collection"
46+
Then the response status code should be 200
47+
And the JSON node "@id" should be equal to the IRI of the resource "component_group"
48+
4249
Scenario: Components are ordered by the sortValue of the resourcePosition
4350
Given there is a ComponentGroup with 4 components
4451
When I send a "GET" request to the resource "component_group"

features/uploads/uploads.feature

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,27 @@ Feature: API Resources which can have files uploaded
137137
And the JSON should be valid according to the schema "features/assets/schema/uploadable_has_files.schema.json"
138138
And the JSON node "_metadata.publishable.published" should be true
139139

140+
# Replicate a published resource not having an image, creating a draft by uploading and then publishing this draft and the published resource should have the image
141+
@loginAdmin
142+
Scenario: When we create a draft through means of an upload to the published, and then publish the draft, the new published resource should still have a file
143+
Given I add "Content-Type" header equal to "multipart/form-data"
144+
And there is a DummyUploadableAndPublishable
145+
When I send a "POST" request to the resource "dummy_uploadable" and the postfix "/upload" with parameters:
146+
| key | value |
147+
| file | @image.svg |
148+
Then the response status code should be 201
149+
And the response resource should be saved as "dummy_uploadable_draft"
150+
And I send a "PATCH" request to the resource "dummy_uploadable_draft" with body:
151+
"""
152+
{
153+
"publishedAt": "1970-11-11T23:59:59+00:00"
154+
}
155+
"""
156+
Then the response status code should be 200
157+
And the response should be the resource "dummy_uploadable"
158+
And the JSON should be valid according to the schema "features/assets/schema/uploadable_has_files_with_imagine.schema.json"
159+
And the JSON node "_metadata.mediaObjects.file[0].contentUrl" should be a valid download link for the resource "dummy_uploadable"
160+
140161
# DELETE
141162

142163
@loginAdmin
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 Silverback API Components Bundle Project
5+
*
6+
* (c) Daniel West <daniel@silverback.is>
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 Silverback\ApiComponentsBundle\DataProvider\StateProvider;
15+
16+
use ApiPlatform\Doctrine\Orm\State\CollectionProvider;
17+
use ApiPlatform\Doctrine\Orm\State\ItemProvider;
18+
use ApiPlatform\Metadata\CollectionOperationInterface;
19+
use ApiPlatform\Metadata\Operation;
20+
use ApiPlatform\State\ProviderInterface;
21+
use Silverback\ApiComponentsBundle\Repository\Core\ComponentGroupRepository;
22+
use Silverback\ApiComponentsBundle\Repository\Core\RouteRepository;
23+
24+
/**
25+
* @author Daniel West <daniel@silverback.is>
26+
*/
27+
class ComponentGroupStateProvider implements ProviderInterface
28+
{
29+
public function __construct(
30+
private ComponentGroupRepository $componentGroupRepository,
31+
private ProviderInterface $defaultProvider)
32+
{}
33+
34+
public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
35+
{
36+
if ($operation instanceof CollectionOperationInterface) {
37+
return $this->defaultProvider->provide($operation->withProvider(CollectionProvider::class), $uriVariables, $context);
38+
}
39+
40+
$id = $uriVariables['id'];
41+
if (!\is_string($id)) {
42+
return $this->defaultProvider->provide($operation->withProvider(ItemProvider::class), $uriVariables, $context);
43+
}
44+
45+
return $this->componentGroupRepository->findOneByIdOrReference($id);
46+
}
47+
}

src/Entity/Core/ComponentGroup.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Doctrine\Common\Collections\ArrayCollection;
1818
use Doctrine\Common\Collections\Collection;
1919
use Silverback\ApiComponentsBundle\Annotation as Silverback;
20+
use Silverback\ApiComponentsBundle\DataProvider\StateProvider\ComponentGroupStateProvider;
2021
use Silverback\ApiComponentsBundle\Entity\Utility\IdTrait;
2122
use Silverback\ApiComponentsBundle\Entity\Utility\TimestampedTrait;
2223
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
@@ -30,7 +31,8 @@
3031
#[ApiResource(
3132
normalizationContext: ['groups' => ['ComponentGroup:read']],
3233
denormalizationContext: ['groups' => ['ComponentGroup:write']],
33-
mercure: true
34+
mercure: true,
35+
provider: ComponentGroupStateProvider::class
3436
)]
3537
#[UniqueEntity(fields: ['reference'], message: 'There is already a ComponentGroup resource with that reference.')]
3638
class ComponentGroup

src/EventListener/Api/PublishableEventListener.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public function onPostRead(RequestEvent $event): void
8383
return;
8484
}
8585

86+
// this will merge the draft into published on a GET request if the publish date is reached.
8687
$this->checkMergeDraftIntoPublished($request, $attributes['data'], true);
8788
}
8889

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Silverback API Components Bundle Project
5+
*
6+
* (c) Daniel West <daniel@silverback.is>
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 Silverback\ApiComponentsBundle\Repository\Core;
15+
16+
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
17+
use Doctrine\Persistence\ManagerRegistry;
18+
use Ramsey\Uuid\Exception\InvalidUuidStringException;
19+
use Ramsey\Uuid\Uuid;
20+
use Silverback\ApiComponentsBundle\Entity\Core\ComponentGroup;
21+
22+
/**
23+
* @author Daniel West <daniel@silverback.is>
24+
*
25+
* @method ComponentGroup|null find($id, $lockMode = null, $lockVersion = null)
26+
* @method ComponentGroup|null findOneBy(array $criteria, array $orderBy = null)
27+
* @method ComponentGroup[] findAll()
28+
* @method ComponentGroup[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
29+
*/
30+
class ComponentGroupRepository extends ServiceEntityRepository
31+
{
32+
public function __construct(ManagerRegistry $registry)
33+
{
34+
parent::__construct($registry, ComponentGroup::class);
35+
}
36+
37+
public function findOneByIdOrReference(string $idOrRef): ?ComponentGroup
38+
{
39+
$byRef = $this->findOneBy([
40+
'reference' => $idOrRef,
41+
]);
42+
if ($byRef) {
43+
return $byRef;
44+
}
45+
46+
try {
47+
$uuid = Uuid::fromString($idOrRef);
48+
49+
return $this->find($uuid);
50+
} catch (InvalidUuidStringException $e) {
51+
}
52+
53+
return null;
54+
}
55+
}

src/Resources/config/services.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use Silverback\ApiComponentsBundle\Command\RefreshTokensExpireCommand;
4848
use Silverback\ApiComponentsBundle\Command\UserCreateCommand;
4949
use Silverback\ApiComponentsBundle\DataProvider\PageDataProvider;
50+
use Silverback\ApiComponentsBundle\DataProvider\StateProvider\ComponentGroupStateProvider;
5051
use Silverback\ApiComponentsBundle\DataProvider\StateProvider\FormStateProvider;
5152
use Silverback\ApiComponentsBundle\DataProvider\StateProvider\PageDataMetadataStateProvider;
5253
use Silverback\ApiComponentsBundle\DataProvider\StateProvider\RouteStateProvider;
@@ -131,6 +132,7 @@
131132
use Silverback\ApiComponentsBundle\RamseyUuid\UuidUriVariableTransformer\UuidUriVariableTransformer;
132133
use Silverback\ApiComponentsBundle\RefreshToken\Storage\DoctrineRefreshTokenStorage;
133134
use Silverback\ApiComponentsBundle\Repository\Core\AbstractPageDataRepository;
135+
use Silverback\ApiComponentsBundle\Repository\Core\ComponentGroupRepository;
134136
use Silverback\ApiComponentsBundle\Repository\Core\ComponentPositionRepository;
135137
use Silverback\ApiComponentsBundle\Repository\Core\FileInfoRepository;
136138
use Silverback\ApiComponentsBundle\Repository\Core\LayoutRepository;
@@ -828,6 +830,17 @@
828830
->autoconfigure(false)
829831
->tag('api_platform.state_provider');
830832

833+
$services
834+
->set(ComponentGroupStateProvider::class)
835+
->args(
836+
[
837+
new Reference('silverback.doctrine.repository.component_group'),
838+
new Reference('api_platform.state_provider'),
839+
]
840+
)
841+
->autoconfigure(false)
842+
->tag('api_platform.state_provider');
843+
831844
$services
832845
->set(FormStateProvider::class)
833846
->args(
@@ -1366,6 +1379,16 @@
13661379
)
13671380
->tag('doctrine.repository_service');
13681381

1382+
$services
1383+
->set('silverback.doctrine.repository.component_group')
1384+
->class(ComponentGroupRepository::class)
1385+
->args(
1386+
[
1387+
new Reference(ManagerRegistry::class),
1388+
]
1389+
)
1390+
->tag('doctrine.repository_service');
1391+
13691392
$services
13701393
->set('silverback.event_listener.api.orphaned_component')
13711394
->class(OrphanedComponentEventListener::class)

0 commit comments

Comments
 (0)