Class-based Group Attributes

Adrian Brajkovic
Contributed by Adrian Brajkovic in #49594

Serialization groups allow to serialize different sets of attributes from your entities according to your needs. A group name is an arbitrary string that associates a property to one or more of those serialization sets.

In Symfony 6.4 we're improving serialization groups so you can also define them at class level. This will associate all properties to that group, in addition to the groups that each property optionally associates to:

1
2
3
4
5
6
7
8
9
10
11
12
13
#[ORM\Entity]
#[Groups(['show_product'])]
class Product
{
    // ...

    #[ORM\Column(type: 'string', length: 255)]
    #[Groups(['list_product'])]
    private string $name;

    #[ORM\Column(type: 'text')]
    private string $description;
}

In this example, the name property belongs to show_product and list_product groups, but the description property only belongs to the show_product group.

Translatable Objects Normalizer

Hubert Lenoir
Contributed by Hubert Lenoir in #50212

In Symfony 5.2 we introduced translatable objects, which are objects that contain all the information needed to translate its own contents, such as the translation parameters and the translation domain.

In Symfony 6.4, we're introducing a TranslatableObject normalizer, which translates the contents of these objects to the locale defined in the NORMALIZATION_LOCALE_KEY option when serializing objects. There's nothing to do to use this new normalizer. Upgrade your application to Symfony 6.4 or higher and this will work out-of-the-box.

Validation Groups Provider Outside DTOs

Yonel Ceruto
Contributed by Yonel Ceruto in #51348

Currently, you can determine the sequence of groups to apply dynamically based on the state of your DTO by implementing the GroupSequenceProviderInterface in your DTO class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\Validator\GroupSequenceProviderInterface;

#[Assert\GroupSequenceProvider]
class UserDto implements GroupSequenceProviderInterface
{
    // ...

    public function getGroupSequence(): array|GroupSequence
    {
        if ($this->isCompanyType()) {
            return ['User', 'Company'];
        }

        return ['User'];
    }
}

However, in more advanced cases you might need to use a service to define that group sequence. A possible solution would be to inject the service in the DTO constructor, but that's usually out of the scope of the DTO responsibility (and, strictly speaking, could not fit the SOLID principles).

In Symfony 6.4 we're improving this by allowing you to create a class that implements the GroupProviderInterface and then use it in your DTO via the GroupSequenceProvider attribute:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
use Symfony\Component\Validator\Constraints as Assert;

#[Assert\GroupSequenceProvider(provider: UserGroupProvider::class)]
class UserDto
{
    // ...
}

use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\GroupProviderInterface;

class UserGroupProvider implements GroupProviderInterface
{
    public __constructor(private readonly ConfigService $config)
    {
    }

    public function getGroups(object $object): array|GroupSequence
    {
        if ($this->config->isEnabled()) {
            return ['User', $this->config->getGroup()];
        }

        return ['User'];
    }
}

Detailed JSON Decoding Errors

Gabriel Ostrolucký
Contributed by Gabriel Ostrolucký in #51215 and #51172

Consider the following JSON snippet which contains a certain syntax error:

1
$jsonContent = "{'foo': 'bar'}";

In current Symfony versions, when trying to deserialize that content, you'll see this error:

1
2
3
4
{
    "title": "Deserialization Failed",
    "detail": "Syntax error"
}

Not very useful, right? In Symfony 6.4 we're improving this significantly. First, install the seld/jsonlint dependency in your project. Then, upgrade to Symfony 6.4 or higher and, when the application runs in the debug mode, you'll see detailed errors like the following:

1
2
3
4
{
    "title": "Deserialization Failed",
    "detail": "Parse error on line 1: {'foo': 'bar'} Invalid string, it appears you used single quotes instead of double quotes"
}
Published in #Living on the edge