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

Jms Serializer Bidirectional Relation Laravel Package

coosos/jms-serializer-bidirectional-relation

Adds JMS Serializer subscribers that embed a _mapping_bidirectional_relation in serialized data so bidirectional associations can be restored on deserialize. Supports Symfony or standalone setup via event subscribers, with annotations to enable mapping on root models and exclude fields.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require coosos/jms-serializer-bidirectional-relation
    

    For Symfony, add the subscribers to services.yaml as shown in the README.

  2. First Use Case:

    • Add @SerializerBidirectionalRelation to your root entity class (e.g., User).
    • Serialize an object with bidirectional relations (e.g., User with posts and author).
    • The package will automatically inject a _mapping_bidirectional_relation key into the serialized output.
    use Coosos\BidirectionalRelation\Annotations\SerializerBidirectionalRelation;
    
    

/**

  • @SerializerBidirectionalRelation */ class User { ... }
    
    
  1. Deserialize: The package ensures bidirectional relations (e.g., User->posts and Post->author) are restored correctly during deserialization.

Implementation Patterns

Workflow for Bidirectional Relations

  1. Annotate Root Entities: Apply @SerializerBidirectionalRelation to entities that act as root objects in serialization (e.g., DTOs or API responses). Example:

    /**
     * @SerializerBidirectionalRelation
     */
    class UserResponse {
        /** @var Post[] */
        public $posts;
        public $author;
    }
    
  2. Exclude Fields (Optional): Use @ExcludeFromMapping on fields that shouldn’t participate in bidirectional mapping (e.g., non-relational fields).

    use Coosos\BidirectionalRelation\Annotations\ExcludeFromMapping;
    
    class Post {
        /** @ExcludeFromMapping */
        public $publishedAt;
    }
    
  3. Serialization: Serialize objects as usual. The package injects metadata for bidirectional relations:

    $serializer->serialize($userResponse, 'json');
    // Output includes `_mapping_bidirectional_relation` for relation tracking.
    
  4. Deserialization: The package automatically restores relations during deserialization:

    $deserialized = $serializer->deserialize($json, UserResponse::class, 'json');
    // Relations like $deserialized->posts[0]->author are now correctly set.
    

Integration Tips

  • Symfony Forms: Use this package with Symfony’s AbstractType to ensure form submissions restore bidirectional relations. Example:

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('posts', CollectionType::class, [
            'entry_type' => PostType::class,
            'allow_add' => true,
            'by_reference' => false, // Critical for bidirectional mapping
        ]);
    }
    
  • API Platform: Combine with @ApiResource to handle nested relations in GraphQL or REST APIs. Ensure the root entity has @SerializerBidirectionalRelation.

  • Custom Metadata: Extend the _mapping_bidirectional_relation structure by overriding the subscribers (see Gotchas).


Gotchas and Tips

Pitfalls

  1. Root Annotation Requirement:

    • Issue: Forgetting @SerializerBidirectionalRelation on the root entity causes the package to silently skip bidirectional mapping.
    • Fix: Always annotate the outermost serialized object (e.g., DTOs, API responses).
  2. Circular References:

    • Issue: Deeply nested bidirectional relations (e.g., User->posts->comments->author->posts) may cause infinite loops during deserialization.
    • Fix: Use @ExcludeFromMapping on problematic fields or limit relation depth in serialization groups.
  3. Symfony Dependency Injection:

    • Issue: If using Symfony, ensure the subscribers are properly tagged in services.yaml. Missing tags = no bidirectional mapping.
    • Fix: Verify the jms_serializer.event_subscriber tag is present for both subscribers.
  4. Overwriting Metadata:

    • Issue: Custom serializers or handlers might overwrite the _mapping_bidirectional_relation key, breaking the package.
    • Fix: Avoid modifying the serialized output directly. Use postSerialize/postDeserialize events to extend functionality instead.

Debugging

  1. Check Serialized Output: Inspect the JSON/XML output for the _mapping_bidirectional_relation key. If missing, the root entity lacks the annotation or subscribers aren’t loaded.

    php bin/console debug:container | grep BidirectionalRelation
    
  2. Event Dispatcher Logs: Enable JMS Serializer’s event dispatcher logs to trace subscriber execution:

    # config/packages/jms_serializer.yaml
    jms_serializer:
        handlers:
            event_dispatcher:
                logging: true
    
  3. Deserialization Validation: If relations aren’t restored, compare the serialized _mapping_bidirectional_relation with the deserialized object’s state. Mismatches indicate subscriber failures.


Extension Points

  1. Custom Mapping Logic: Extend MapSerializerSubscriber or MapDeserializerSubscriber to add custom relation logic. Override methods like:

    public function onPostSerialize(PostSerializeEvent $event) { ... }
    
  2. Dynamic Relation Handling: Use the onPostDeserialize event to dynamically resolve relations based on external data (e.g., caching layers):

    $event->getObject()->setAuthor($this->resolveAuthorFromCache($event->getData()));
    
  3. Performance Optimization: For large datasets, batch relation restoration by overriding MapDeserializerSubscriber::onPostDeserialize to process relations in chunks.


  1. Testing: Mock the subscribers in PHPUnit to isolate bidirectional logic:
    $this->getMockBuilder(MapDeserializerSubscriber::class)
         ->disableOriginalConstructor()
         ->onlyMethods(['onPostDeserialize'])
         ->getMock();
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
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