Skip to content

Commit

Permalink
Merge 3.2
Browse files Browse the repository at this point in the history
  • Loading branch information
soyuka committed Apr 29, 2024
2 parents 5448f9c + 2a7ba96 commit 3811502
Show file tree
Hide file tree
Showing 25 changed files with 486 additions and 219 deletions.
2 changes: 1 addition & 1 deletion admin/schema.org.md
Expand Up @@ -18,7 +18,7 @@ To configure which property should be shown to represent your entity, map the pr
// api/src/Entity/Person.php
...

#[ApiProperty(types: ["https://schema.org/name"])]
#[ApiProperty(iris: ["https://schema.org/name"])]
private $name;

...
Expand Down
25 changes: 22 additions & 3 deletions core/dto.md
Expand Up @@ -11,6 +11,7 @@ Using an input, the request body will be denormalized to the input instead of yo
```php
<?php
// api/src/Dto/UserResetPasswordDto.php

namespace App\Dto;

use Symfony\Component\Validator\Constraints as Assert;
Expand All @@ -25,6 +26,7 @@ final class UserResetPasswordDto
```php
<?php
// api/src/Model/User.php

namespace App\Model;

use ApiPlatform\Metadata\Post;
Expand All @@ -39,6 +41,7 @@ And the processor:

```php
<?php
// api/src/State/UserResetPasswordProcessor.php

namespace App\State;

Expand All @@ -47,12 +50,17 @@ use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
* @implements ProcessorInterface<UserResetPasswordDto, User>
*/
final class UserResetPasswordProcessor implements ProcessorInterface
{
/**
* @param UserResetPasswordDto $data
*
* @throws NotFoundHttpException
*/
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): User
{
if ('user@example.com' === $data->email) {
return new User(email: $data->email, id: 1);
Expand All @@ -71,6 +79,7 @@ Let's use a message that will be processed by [Symfony Messenger](https://symfon

```php
<?php
// api/src/Model/SendMessage.php

namespace App\Model;

Expand All @@ -90,6 +99,7 @@ To return another representation of your data in a [State Provider](./state-prov

```php
<?php
// api/src/Entity/Book.php

namespace App\Entity;

Expand All @@ -103,6 +113,7 @@ class Book {}

```php
<?php
// api/src/State/BookRepresentationProvider.php

namespace App\State;

Expand All @@ -111,9 +122,12 @@ use App\Model\Book;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;

/**
* @implements ProviderInterface<AnotherRepresentation>
*/
final class BookRepresentationProvider implements ProviderInterface
{
public function provide(Operation $operation, array $uriVariables = [], array $context = [])
public function provide(Operation $operation, array $uriVariables = [], array $context = []): AnotherRepresentation
{
return new AnotherRepresentation();
}
Expand All @@ -128,6 +142,7 @@ For returning another representation of your data in a [State Processor](./state

```php
<?php
// api/src/Entity/Book.php

namespace App\Entity;

Expand Down Expand Up @@ -171,6 +186,7 @@ Here the `$data` attribute represents an instance of your resource.

```php
<?php
// api/src/State/BookRepresentationProcessor.php

namespace App\State;

Expand All @@ -179,12 +195,15 @@ use ApiPlatform\State\ProcessorInterface;
use App\Dto\AnotherRepresentation;
use App\Model\Book;

/**
* @implements ProcessorInterface<Book, AnotherRepresentation>
*/
final class BookRepresentationProcessor implements ProcessorInterface
{
/**
* @param Book $data
*/
public function process($data, Operation $operation, array $uriVariables = [], array $context = [])
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): AnotherRepresentation
{
return new AnotherRepresentation(
$data->getId(),
Expand Down
2 changes: 1 addition & 1 deletion core/errors.md
Expand Up @@ -25,7 +25,7 @@ This can also be configured on an `ApiResource` or in an `HttpOperation`, for ex

## Exception status code decision

There are many ways of configuring the exception status code we recommend reading the guides on how to use an [Error Provider](/docs/guides/error-provider) or create an [Error Resource](/docs/guides/error-resource).
There are many ways of configuring the exception status code we recommend reading the guides on how to use an [Error Provider](https://api-platform.com/docs/guides/error-provider/) or create an [Error Resource](https://api-platform.com/docs/guides/error-resource/).

1. we look at `exception_to_status` and take one if there's a match
2. If your exception is a `Symfony\Component\HttpKernel\Exception\HttpExceptionInterface` we get its status.
Expand Down
6 changes: 4 additions & 2 deletions core/extensions.md
Expand Up @@ -65,10 +65,12 @@ use App\Entity\Offer;
use Doctrine\ORM\QueryBuilder;
use Symfony\Bundle\SecurityBundle\Security;

final class CurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
final readonly class CurrentUserExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{

public function __construct(private readonly Security $security)
public function __construct(
private Security $security,
)
{
}

Expand Down
100 changes: 60 additions & 40 deletions core/file-upload.md
Expand Up @@ -169,43 +169,53 @@ A [normalizer](serialization.md#normalization) could be used to set the `content

```php
<?php
// api/src/Serializer/MediaObjectNormalizer.php

namespace App\Serializer;

use App\Entity\MediaObject;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Vich\UploaderBundle\Storage\StorageInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

final class MediaObjectNormalizer implements NormalizerAwareInterface
class MediaObjectNormalizer implements NormalizerInterface
{
use NormalizerAwareTrait;

private const ALREADY_CALLED = 'MEDIA_OBJECT_NORMALIZER_ALREADY_CALLED';
private const ALREADY_CALLED = 'MEDIA_OBJECT_NORMALIZER_ALREADY_CALLED';

public function __construct(private StorageInterface $storage)
{
}
public function __construct(
#[Autowire(service: 'serializer.normalizer.object')]
private readonly NormalizerInterface $normalizer,
private readonly StorageInterface $storage
) {
}

public function normalize($object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
{
$context[self::ALREADY_CALLED] = true;
public function normalize($object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
{
$context[self::ALREADY_CALLED] = true;

$object->contentUrl = $this->storage->resolveUri($object, 'file');
$object->contentUrl = $this->storage->resolveUri($object, 'file');

return $this->normalizer->normalize($object, $format, $context);
}
return $this->normalizer->normalize($object, $format, $context);
}

public function supportsNormalization($data, ?string $format = null, array $context = []): bool
{
if (isset($context[self::ALREADY_CALLED])) {
return false;
}
public function supportsNormalization($data, ?string $format = null, array $context = []): bool
{

return $data instanceof MediaObject;
if (isset($context[self::ALREADY_CALLED])) {
return false;
}

return $data instanceof MediaObject;
}

public function getSupportedTypes(?string $format): array
{
return [
MediaObject::class => true,
];
}
}

```

### Making a Request to the `/media_objects` Endpoint
Expand Down Expand Up @@ -234,8 +244,8 @@ You will need to modify your `Caddyfile` to allow the above `contentUrl` to be a
@pwa expression `(
header({'Accept': '*text/html*'})
&& !path(
- '/docs*', '/graphql*', '/bundles*', '/media*', '/contexts*', '/_profiler*', '/_wdt*',
+ '/media*', '/docs*', '/graphql*', '/bundles*', '/media*', '/contexts*', '/_profiler*', '/_wdt*',
- '/docs*', '/graphql*', '/bundles*', '/contexts*', '/_profiler*', '/_wdt*',
+ '/media*', '/docs*', '/graphql*', '/bundles*', '/contexts*', '/_profiler*', '/_wdt*',
'*.json*', '*.html', '*.csv', '*.yml', '*.yaml', '*.xml'
)
)
Expand Down Expand Up @@ -313,25 +323,26 @@ class MediaObjectTest extends ApiTestCase

public function testCreateAMediaObject(): void
{
$file = new UploadedFile('fixtures/files/image.png', 'image.png');
// The file "image.jpg" is the folder fixtures which is in the project dir
$file = new UploadedFile(__DIR__ . '/../fixtures/image.jpg', 'image.jpg');
$client = self::createClient();

$client->request('POST', '/media_objects', [
'headers' => ['Content-Type' => 'multipart/form-data'],
'extra' => [
// If you have additional fields in your MediaObject entity, use the parameters.
'parameters' => [
'title' => 'My file uploaded',
],
'files' => [
'file' => $file,
],
]
$client->request('POST', 'http://localhost:8888/api/media_objects', [
'headers' => ['Content-Type' => 'multipart/form-data'],
'extra' => [
// If you have additional fields in your MediaObject entity, use the parameters.
'parameters' => [
// 'title' => 'title'
],
'files' => [
'file' => $file,
],
]
]);
$this->assertResponseIsSuccessful();
$this->assertMatchesResourceItemJsonSchema(MediaObject::class);
$this->assertJsonContains([
'title' => 'My file uploaded',
// 'title' => 'My file uploaded',
]);
}
}
Expand Down Expand Up @@ -451,19 +462,28 @@ We also need to make sure the field containing the uploaded file is not denormal

namespace App\Serializer;

use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

final class UploadedFileDenormalizer implements DenormalizerInterface
{
public function denormalize($data, string $type, string $format = null, array $context = []): UploadedFile
public function denormalize($data, string $type, string $format = null, array $context = []): File
{
return $data;
}

public function supportsDenormalization($data, $type, $format = null): bool
public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
{
return $data instanceof File;
}

public function getSupportedTypes(?string $format): array
{
return $data instanceof UploadedFile;
return [
'object' => null,
'*' => false,
File::class => true,
];
}
}
```
Expand Down

0 comments on commit 3811502

Please sign in to comment.