Skip to content

Commit

Permalink
code challenge 1 solution
Browse files Browse the repository at this point in the history
  • Loading branch information
jschaedl committed Sep 26, 2023
1 parent 90bcaeb commit efe245d
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 0 deletions.
50 changes: 50 additions & 0 deletions CODING-CHALLENGE-2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# RESTful Webservices in Symfony

## Coding Challenge 2 - Serialization

### Tasks

- use Symfony's Serializer to transform the workshop and attendee entities into a JSON representation
- use `make tests` to check if the api endpoints still work as expected
- make sure that all JSON property names are formatted in _snake_case_
- add an attendee to one of the workshops and use the PostMan collection to test the endpoints

### Solution

- require the Symfony Serializer component: `composer req serializer`
- inject the Serializer into your controllers
- serialize your entities
- create a custom `Normalizer` (implement `ContextAwareNormalizerInterface`) for your Workshop and Attendee entities
- remove the `toArray` method in your entities
- fix the `CircularReferenceException`

#### Problem 1: No snake_case property names anymore

```yaml
# config/packages/framework.yaml

framework:
# ...
serializer:
name_converter: 'serializer.name_converter.camel_case_to_snake_case'
```
#### Problem 2: Fixing the `CircularReferenceException`

Adding an attendee to a workshop and accessing this attendee, or the respective workshop results in a `CircularReferenceException`.

```php
// AttendeeNormalizer
$defaultContext = [
AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => fn ($object, $format, $context) => $object->getFirstname().' '.$object->getLastname(),
];
```

```php
// WorkshopNormalizer
$customContext = [
AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => fn ($object, $format, $context) => $object->getTitle(),
];
```
11 changes: 11 additions & 0 deletions fixtures/attendees.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
App\Entity\Attendee:
attendee_1:
__construct: [ '02d47053-4034-4818-97d1-299c4cd7168d', 'Ferdinand', 'Hale', '[email protected]' ]
attendee_2:
__construct: [ '6047c255-593f-4fa8-888b-f919fafd904f', 'Abraham', 'Noel', '[email protected]' ]
attendee_3:
__construct: [ '92e06a4b-19ac-4e67-b988-00e7250929c6', 'Bertha', 'Tucker', '[email protected]' ]
attendee_4:
__construct: [ 'c153c6c3-c43b-449d-8f5a-2bfb627f9822', 'Melodie', 'Perkins', '[email protected]' ]
attendee_5:
__construct: [ 'f5e2c329-f5b8-4e4b-860d-b5a0189ef35f', 'Keegan', 'Mcpherson', '[email protected]' ]
Empty file removed src/Controller/Attendee/.gitignore
Empty file.
33 changes: 33 additions & 0 deletions src/Controller/Attendee/ListController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace App\Controller\Attendee;

use App\Entity\Attendee;
use App\Repository\AttendeeRepository;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

#[Route('/attendees', name: 'list_attendee', methods: ['GET'])]
final class ListController
{
public function __construct(
private readonly AttendeeRepository $attendeeRepository
) {
}

public function __invoke(): Response
{
$allAttendees = $this->attendeeRepository->findAll();

$allAttendeesAsArray = array_map(
static fn (Attendee $attendee) => $attendee->toArray(),
$allAttendees
);

return new Response(json_encode($allAttendeesAsArray), Response::HTTP_OK, [
'Content-Type' => 'application/json',
]);
}
}
20 changes: 20 additions & 0 deletions src/Controller/Attendee/ReadController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace App\Controller\Attendee;

use App\Entity\Attendee;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

#[Route('/attendees/{identifier}', name: 'read_attendee', methods: ['GET'])]
final class ReadController
{
public function __invoke(Attendee $attendee): Response
{
return new Response(json_encode($attendee->toArray()), Response::HTTP_OK, [
'Content-Type' => 'application/json',
]);
}
}
Empty file.
23 changes: 23 additions & 0 deletions tests/Controller/Attendee/ListControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Tests\Controller\Attendee;

use App\Tests\ApiTestCase;

class ListControllerTest extends ApiTestCase
{
public function test_it_should_list_all_attendees(): void
{
$this->loadFixtures([
__DIR__.'/fixtures/list_attendee.yaml',
]);

$this->browser->request('GET', '/attendees');

static::assertResponseIsSuccessful();

$this->assertMatchesJsonSnapshot($this->browser->getResponse()->getContent());
}
}
23 changes: 23 additions & 0 deletions tests/Controller/Attendee/ReadControllerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace App\Tests\Controller\Attendee;

use App\Tests\ApiTestCase;

class ReadControllerTest extends ApiTestCase
{
public function test_it_should_show_requested_attendee(): void
{
$this->loadFixtures([
__DIR__.'/fixtures/read_attendee.yaml',
]);

$this->browser->request('GET', '/attendees/17058af8-1b0f-4afe-910d-669b4bd0fd26');

static::assertResponseIsSuccessful();

$this->assertMatchesJsonSnapshot($this->browser->getResponse()->getContent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"identifier": "803449f4-9a4c-4ecb-8ce4-cebc804fe70a",
"firstname": "Jan",
"lastname": "Sch\u00e4dlich",
"email": "[email protected]"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"identifier": "17058af8-1b0f-4afe-910d-669b4bd0fd26",
"firstname": "Jan",
"lastname": "Sch\u00e4dlich",
"email": "[email protected]"
}
3 changes: 3 additions & 0 deletions tests/Controller/Attendee/fixtures/list_attendee.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
App\Entity\Attendee:
attendee_1:
__construct: [ '803449f4-9a4c-4ecb-8ce4-cebc804fe70a', 'Jan', 'Schädlich', '[email protected]' ]
3 changes: 3 additions & 0 deletions tests/Controller/Attendee/fixtures/read_attendee.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
App\Entity\Attendee:
attendee_1:
__construct: [ '17058af8-1b0f-4afe-910d-669b4bd0fd26', 'Jan', 'Schädlich', '[email protected]' ]

0 comments on commit efe245d

Please sign in to comment.