Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Serializer Laravel Package

jms/serializer

Serialize and deserialize complex PHP object graphs to JSON or XML with flexible metadata (annotations, YAML, XML). Handles circular references, exclusion strategies, versioning, dates/intervals, and integrates with Doctrine ORM—ideal for APIs and data interchange.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Installation:

    composer require jms/serializer-bundle
    

    For Laravel, manually register the bundle in config/app.php under extra.bundles:

    JMS\SerializerBundle\JMSSerializerBundle::class
    
  2. Basic Usage:

    use JMS\Serializer\SerializerBuilder;
    use JMS\Serializer\SerializerInterface;
    
    $builder = SerializerBuilder::create();
    $serializer = $builder->build();
    $data = ['name' => 'John', 'age' => 30];
    
    // Serialize to JSON
    $json = $serializer->serialize($data, 'json');
    echo $json; // '{"name":"John","age":30}'
    
    // Deserialize from JSON
    $decoded = $serializer->deserialize($json, 'stdClass', 'json');
    
  3. First Use Case: Convert a Laravel Eloquent model to JSON with custom formatting:

    use App\Models\User;
    use JMS\Serializer\SerializationContext;
    
    $user = User::find(1);
    $context = SerializationContext::create()
        ->setGroups(['default', 'public'])
        ->setSerializeNull(true);
    
    $json = $serializer->serialize($user, 'json', $context);
    

Implementation Patterns

Common Workflows

  1. Model Serialization with Groups: Use annotations or YAML/XML configs to define serialization groups:

    // In User.php
    use JMS\Serializer\Annotation as Serializer;
    
    class User
    {
        /**
         * @Serializer\ExclusionPolicy("all")
         * @Serializer\Groups({"default"})
         */
        public $name;
    
        /**
         * @Serializer\Groups({"admin"})
         */
        public $email;
    }
    

    Serialize with:

    $serializer->serialize($user, 'json', SerializationContext::create()->setGroups(['default']));
    
  2. Custom Handlers for Complex Types: Handle custom objects like Carbon or Uuid:

    use JMS\Serializer\Handler\SubscribingHandlerInterface;
    
    class CarbonHandler implements SubscribingHandlerInterface
    {
        public static function getSubscribingMethods()
        {
            return [
                [
                    'direction' => SerializerBuilder::DIRECTION_SERIALIZATION,
                    'format' => 'json',
                    'type' => 'Carbon\Carbon',
                    'method' => 'serializeToJson',
                ],
            ];
        }
    
        public function serializeToJson(Carbon $date, ExchangeInterface $exchange, array $context)
        {
            return $date->toIso8601String();
        }
    }
    

    Register in SerializerBuilder:

    $builder->configureHandlers(function (HandlerRegistry $registry) {
        $registry->registerSubscribingHandler(new CarbonHandler());
    });
    
  3. API Versioning: Use metadata factories to version responses:

    $metadataFactory = MetadataFactory::create();
    $metadataFactory->setMetadataCache(new FileLocatorMetadataFactory([
        __DIR__.'/metadata',
    ]));
    
    $builder->setMetadataFactory($metadataFactory);
    

    Create versioned configs in metadata/v1/, metadata/v2/, etc.

  4. Deserialization with Validation: Validate incoming JSON before deserialization:

    use Symfony\Component\Validator\Validator\ValidatorInterface;
    
    $validator = app(ValidatorInterface::class);
    $data = json_decode($json, true);
    
    $errors = $validator->validate($data, new UserConstraints());
    if (count($errors) > 0) {
        throw new \InvalidArgumentException('Validation failed');
    }
    
    $user = $serializer->deserialize($json, User::class, 'json');
    

Integration Tips

  1. Laravel Service Provider: Bind the serializer to the container in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(SerializerInterface::class, function () {
            return SerializerBuilder::create()
                ->configureHandlers(function (HandlerRegistry $registry) {
                    $registry->registerSubscribingHandler(new CarbonHandler());
                })
                ->build();
        });
    }
    
  2. Middleware for API Responses: Automatically serialize API responses:

    namespace App\Http\Middleware;
    
    use Closure;
    use JMS\Serializer\SerializerInterface;
    
    class SerializeResponseMiddleware
    {
        public function __construct(protected SerializerInterface $serializer) {}
    
        public function handle($request, Closure $next)
        {
            $response = $next($request);
            if ($response->getContent() !== '') {
                $data = json_decode($response->getContent(), true);
                $response->setContent($this->serializer->serialize($data, 'json'));
            }
            return $response;
        }
    }
    
  3. Form Request Validation: Use the serializer to validate and deserialize form data:

    use JMS\Serializer\Exception\RuntimeException;
    
    public function rules()
    {
        return [
            'data' => 'required|string',
        ];
    }
    
    public function validated()
    {
        $data = $this->serializer->deserialize(
            $this->input('data'),
            User::class,
            'json'
        );
        return $data;
    }
    
  4. Caching Metadata: Improve performance with cached metadata:

    $builder->setMetadataCache(new FileLocatorMetadataFactory([
        __DIR__.'/var/cache/serializer',
    ]));
    

Gotchas and Tips

Pitfalls

  1. Circular References:

    • Default behavior throws an exception. Use MaxDepthHandler to limit recursion:
      $builder->configureHandlers(function (HandlerRegistry $registry) {
          $registry->registerSubscribingHandler(new MaxDepthHandler(5));
      });
      
    • Or enable circular reference handling:
      $context = SerializationContext::create()->setEnableMaxDepthChecks(false);
      
  2. Doctrine Integration:

    • Ensure Doctrine proxies are initialized before serialization:
      $entityManager->getRepository(User::class)->find($id); // Initialize proxy
      
    • Avoid serializing excluded fields in Doctrine:
      // In User.php
      /**
       * @Serializer\ExclusionPolicy("all")
       * @Serializer\Expose
       */
      public $name;
      
  3. Type Mismatches:

    • Deserializing to wrong types silently fails. Use strict mode:
      $context = SerializationContext::create()->setStrictMode(true);
      
    • Custom DateTimeInterface implementations may fail. Use handlers:
      $builder->configureHandlers(function (HandlerRegistry $registry) {
          $registry->registerSubscribingHandler(new CustomDateTimeHandler());
      });
      
  4. Annotation Caching:

    • Clear cache after adding new annotations:
      php artisan cache:clear
      
    • Or manually delete cached files in var/cache/serializer.
  5. XML Namespaces:

    • XML serialization may require namespace handling:
      $context = SerializationContext::create()
          ->setXmlRootName('user')
          ->setXmlNamespace('http://example.com/ns');
      

Debugging Tips

  1. Enable Debug Mode:

    $builder->setDebug(true);
    

    Logs metadata loading and serialization steps.

  2. Inspect Metadata:

    $metadata = $serializer->getMetadataFactory()->getMetadataFor(User::class);
    dump($metadata->propertyMetadata);
    
  3. Handle Exceptions: Catch RuntimeException for deserialization errors:

    try {
        $user = $serializer->deserialize($json, User::class, 'json');
    } catch (RuntimeException $e) {
        Log::error('Deserialization failed: ' . $e->getMessage());
        throw new \InvalidArgumentException('Invalid data format');
    }
    
  4. PHP Attributes vs Annotations:

    • PHP 8+ uses attributes by default. Ensure compatibility:
      // For PHP 8 attributes
      #[Serializer\Expose]
      public string $name;
      
    • Fallback to annotations if needed:
      $builder->setMetadataDir(__DIR__.'/metadata');
      

Extension Points

  1. Custom Metadata: Dynamically add metadata at runtime:

    $metadataFactory = MetadataFactory::create();
    $metadataFactory->setMetadataCache(new ArrayCollectionMetadataFactory());
    
    $classMetadata = new ClassMetadata(User::class);
    $classMetadata->propertyMetadata['email'] = new PropertyMetadata(
        'email',
        'string',
        ['groups' => ['admin']]
    );
    $metadataFactory->setMetadataFor(User::class, $classMetadata);
    
  2. Event Listeners: Hook into serialization events:

    $builder->setEventDispatcher(new EventDispatcher());
    $eventDispatcher->
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views