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

Association Hydrator Laravel Package

sylius-labs/association-hydrator

Doctrine ORM association hydrator for Sylius apps, inspired by Ocramius’ hydration optimization technique. Helps efficiently load and hydrate entity associations to reduce queries and improve performance in read-heavy workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require sylius-labs/association-hydrator
    

    Add to your config/packages/doctrine.yaml:

    doctrine:
        orm:
            dbal:
                types:
                    association_hydrator: SyliusLabs\AssociationHydrator\DBAL\Types\AssociationHydratorType
    
  2. First Use Case: Apply the hydrator to a one-to-many or many-to-many association in your entity:

    use SyliusLabs\AssociationHydrator\Annotation as Hydrator;
    
    #[Hydrator\HydrateAssociations]
    #[ORM\OneToMany(targetEntity: Product::class, mappedBy: "category")]
    private Collection $products;
    
    • Trigger hydration via:
      $entityManager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('association_hydrator', 'json');
      $entityManager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('association_hydrator', 'array');
      

Implementation Patterns

Workflows

  1. Lazy vs. Eager Hydration:

    • Use annotations (@HydrateAssociations) for automatic hydration on find()/findAll().
    • Manually hydrate with:
      $hydrator = new AssociationHydrator($entityManager);
      $hydrator->hydrate($entity, ['products']);
      
  2. Partial Hydration:

    // Hydrate only specific associations
    $hydrator->hydrate($entity, ['products', 'tags']);
    
  3. Custom Serialization: Override default JSON/array serialization via a custom type:

    #[Hydrator\HydrateAssociations(type: "custom_type")]
    #[ORM\ManyToMany(targetEntity: Tag::class)]
    private Collection $tags;
    

    Register the type in doctrine.yaml:

    types:
        custom_type: App\Doctrine\DBAL\Types\CustomHydratorType
    
  4. QueryBuilder Integration:

    $qb->select('e', 'HYDRATE(e.products) AS products_hydrated');
    

Integration Tips

  • Symfony Forms: Use HydrateAssociations with DataTransformer to avoid N+1 queries in form submissions.
  • API Platform: Combine with @ApiResource to hydrate associations in serializers:
    #[ApiResource(collectionOperations: ["get"], itemOperations: ["get"])]
    class CategoryEntity { ... }
    
  • Doctrine Extensions: Works seamlessly with StoDoctrineExtensionsBundle (e.g., SoftDeleteable).

Gotchas and Tips

Pitfalls

  1. Circular References:

    • Hydrating bidirectional associations (e.g., Category ↔ Product) may cause infinite loops.
    • Fix: Exclude one side or use maxDepth:
      $hydrator->hydrate($entity, ['products'], 1); // Depth limit
      
  2. Database Schema Mismatch:

    • Ensure the association column is JSON/array-compatible (e.g., JSON in PostgreSQL, JSON in MySQL 5.7+).
    • Error: InvalidArgumentException if the column type is unsupported.
  3. Caching Conflicts:

    • Hydrated data may bypass Doctrine’s cache. Use entityManager->clear() cautiously after bulk hydration.
  4. Transaction Boundaries:

    • Hydration outside a transaction may fail if the connection is closed.
    • Fix: Wrap in a transaction or ensure the connection persists.

Debugging

  • Enable SQL Logging:

    # config/packages/dev/doctrine.yaml
    doctrine:
        dbal:
            logging: true
            profiling: true
    

    Look for HYDRATE() in generated SQL.

  • Check Hydration Status:

    if (!$entity->products->isInitialized()) {
        $hydrator->hydrate($entity, ['products']);
    }
    

Extension Points

  1. Custom Hydrator: Implement HydratorInterface for non-standard logic:

    class CustomHydrator implements HydratorInterface {
        public function hydrate(EntityManagerInterface $em, object $entity, string $association, array $options): void {
            // Custom logic (e.g., API-specific filtering)
        }
    }
    
  2. Event Subscribers: Listen to preHydrate/postHydrate events:

    $eventDispatcher->addListener(
        AssociationHydratorEvents::PRE_HYDRATE,
        fn(PreHydrateEvent $event) => $event->setOptions(['filter' => 'active'])
    );
    
  3. Batch Hydration: For large datasets, use batch processing:

    $hydrator->hydrateBatch($entities, ['products'], 100);
    

Performance Tips

  • Selective Hydration: Only hydrate associations needed for the current request.
  • Denormalization: Store hydrated data in a separate column (e.g., products_json) to avoid repeated hydration.
  • Caching: Cache hydrated results with Redis or APCu:
    $cache = new RedisCache();
    $hydrator->setCache($cache);
    
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.
nasirkhan/laravel-sharekit
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony