Installation:
composer require jms/serializer-bundle
Add the bundle to config/bundles.php:
return [
// ...
JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true],
];
First Use Case: Serialize an object to JSON in a controller:
use JMS\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
public function show(SerializerInterface $serializer, $id)
{
$entity = $this->entityManager->find(Entity::class, $id);
$json = $serializer->serialize($entity, 'json');
return new JsonResponse($json, 200, [], true);
}
Where to Look First:
config/packages/jms_serializer.yaml (auto-generated; customize as needed).src/Serializer/ directory (for custom serializers/normalizers).Serialization/Deserialization:
// Serialize
$serializer->serialize($data, 'json'); // 'xml', 'yaml', etc.
// Deserialize
$deserialized = $serializer->deserialize($json, Entity::class, 'json');
Type-Specific Handling:
@Serializer\Type, @Serializer\ExclusionPolicy) for fine-grained control:
use JMS\Serializer\Annotation as Serializer;
class User
{
/** @Serializer\Type("string") */
public $uuid;
/** @Serializer\ExclusionPolicy("all") */
public $password;
}
API Responses:
public, admin):
# config/packages/jms_serializer.yaml
jms_serializer:
metadata:
directories:
FOSUserBundle
App
// In a normalizer
$context['groups'] = ['public'];
Event Listeners:
serializer.pre_serialize/serializer.post_deserialize:
public function onPreSerialize(PreSerializeEvent $event)
{
$data = $event->getData();
$data->setSerializedAt(new \DateTime()); // Add dynamic fields
}
Custom Normalizers:
JMS\Serializer\Normalizer\AbstractNormalizer for complex types:
class DateTimeNormalizer extends AbstractNormalizer
{
public function normalize($object, $format, array $context = [])
{
return $object->format(\DateTime::ATOM);
}
}
services.yaml:
services:
App\Serializer\Normalizer\DateTimeNormalizer:
tags: [jms_serializer.normalizer]
Symfony Forms:
JMS\Serializer\Handler\HandlerRegistry to transform form data:
$handler = $serializer->getHandlerRegistry();
$handler->registerSubscribingHandler(new MyCustomHandler());
Doctrine Integration:
$serializer->serialize($entity, 'json', [
'groups' => ['default', 'associations'],
]);
API Platform:
Messaging (e.g., Symfony Messenger):
$serialized = $serializer->serialize($message, 'json');
Caching:
$cacheKey = md5($serializedData);
$cached = $cache->get($cacheKey, function() use ($serializer, $data) {
return $serializer->serialize($data, 'json');
});
Circular References:
CircularReferenceException. Use max_depth or custom handlers:
$serializer->serialize($data, 'json', ['max_depth' => 2]);
JMS\Serializer\ContextBuilderInterface to handle cycles.Metadata Conflicts:
# config/packages/jms_serializer.yaml
jms_serializer:
metadata:
directories:
App
FOSUserBundle # Lower priority
Performance:
max_depth.JMS\Serializer\SerializationContext to limit fields dynamically:
$context = new SerializationContext();
$context->setGroups(['light']);
Deserialization Security:
$deserialized = $serializer->deserialize($json, Entity::class, 'json', [
'object_to_populate' => new Entity(), // Safe default
]);
Doctrine Proxy Issues:
LazyLoadingException handling:
try {
$serializer->serialize($proxy, 'json');
} catch (\Doctrine\ORM\PersistentCollection::class $e) {
// Initialize collections first
}
Enable Debug Mode:
JMS_SERIALIZER_DEBUG env var to log metadata and serialization steps.Check Metadata:
$metadataFactory = $serializer->getMetadataFactory();
$metadata = $metadataFactory->getMetadataFor(get_class($object));
var_dump($metadata);
Common Errors:
@Serializer\Type annotations or YAML config.ExclusionPolicy or groups filters.Custom Serialization Formats:
JMS\Serializer\SerializerBuilderInterface for new formats (e.g., MessagePack).Dynamic Metadata:
JMS\Serializer\Metadata\StaticPropertyMetadataFactory to generate metadata at runtime.Event Dispatching:
JMS\Serializer\EventDispatcher\EventDispatcher to add custom events.Performance Optimization:
JMS\Serializer\Metadata\MetadataFactoryInterface:
jms_serializer:
metadata:
cache: apcu
Testing:
SerializerInterface in tests:
$serializer = $this->createMock(SerializerInterface::class);
$serializer->method('serialize')->willReturn('{"test":true}');
How can I help you explore Laravel packages today?