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

Object To Array Transform Bundle Laravel Package

danilovl/object-to-array-transform-bundle

Symfony bundle that converts objects to arrays using configurable field mappings. Define fields in parameters and provide corresponding getters on your entities. Works with PHP 8.5+ and Symfony 8+.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require danilovl/object-to-array-transform-bundle
    

    Register the bundle in config/bundles.php:

    Danilovl\ObjectToArrayTransformBundle\ObjectToArrayTransformBundle::class => ['all' => true]
    
  2. Basic Configuration: Define field mappings in config/services.yaml:

    parameters:
      api_fields:
        default:
          App\Entity\Shop:
            fields:
              - id
              - name
              - city
    
  3. First Usage: Inject the service in a controller and transform an object:

    use Danilovl\ObjectToArrayTransformBundle\Interfaces\ObjectToArrayTransformServiceInterface;
    
    class ShopController extends AbstractController {
        public function __construct(private ObjectToArrayTransformServiceInterface $transformer) {}
    
        public function index(Shop $shop) {
            $array = $this->transformer->transform('api_fields.default', $shop);
            return new JsonResponse($array);
        }
    }
    

Where to Look First

  • Configuration: config/services.yaml for field mappings.
  • Service Interface: ObjectToArrayTransformServiceInterface for method signatures.
  • Entity Getters: Ensure all referenced fields have getX() methods.

First Use Case

Transform a Doctrine entity into a minimal API response:

# config/services.yaml
parameters:
  api_fields:
    default:
      App\Entity\User:
        fields:
          - id
          - email
          - roles
// Controller
$userArray = $this->transformer->transform('api_fields.default', $user);

Implementation Patterns

Core Workflow

  1. Define Fields: Use YAML to map entities to fields, including nested objects:

    parameters:
      api_fields:
        default:
          App\Entity\Order:
            fields:
              - id
              - customer:
                fields:
                  - id
                  - name
              - items:
                fields:
                  - product
                  - quantity
    
  2. Transform Objects: Inject the service and call transform() with the config key and object:

    $orderArray = $this->transformer->transform('api_fields.default', $order);
    
  3. Handle Custom Logic: Override default behavior with parameters:

    parameters:
      api_fields:
        default:
          App\Entity\Product:
            fields:
              - id
              - name
              - isAvailable:
                  parameters:
                    method: 'getStockStatus'
    

Integration Tips

  • Bulk Transformations: Use in loops or with Doctrine repositories:

    $users = $this->userRepository->findAll();
    $userArrays = array_map(
        fn($user) => $this->transformer->transform('api_fields.default', $user),
        $users
    );
    
  • Dynamic Config Keys: Pass runtime keys for environment-specific transformations:

    # config/services.yaml
    parameters:
      api_fields:
        production:
          App\Entity\Shop: { fields: [id, name] }
        staging:
          App\Entity\Shop: { fields: [id, name, city] }
    
    $configKey = $_ENV['APP_ENV'] === 'production' ? 'production' : 'staging';
    $shopArray = $this->transformer->transform("api_fields.$configKey", $shop);
    
  • DTOs: Transform entities to DTOs before serialization:

    $dto = new ShopDto($shop);
    $array = $this->transformer->transform('api_fields.default', $dto);
    
  • API Platform: Use alongside API Platform for hybrid approaches:

    # config/api_platform/resources.yaml
    resources:
      App\Entity\Shop:
        collectionOperations:
          get:
            normalization_context:
              groups: ['shop:read']
        itemOperations:
          get:
            normalization_context:
              groups: ['shop:read']
    
    # config/services.yaml
    parameters:
      api_fields:
        default:
          App\Entity\Shop:
            fields:
              - id
              - name
              - city
    

Advanced Patterns

  • Conditional Fields: Use custom methods to include/exclude fields dynamically:

    parameters:
      api_fields:
        default:
          App\Entity\Order:
            fields:
              - id
              - customer
              - shippingAddress:
                  parameters:
                    method: 'getShippingAddressIfReady'
    
  • Date Formatting: Standardize datetime outputs:

    parameters:
      api_fields:
        default:
          parameters:
            date_format: 'Y-m-d\TH:i:sP'
          App\Entity\Event:
            fields:
              - id
              - name
              - startsAt
              - endsAt
    
  • Circular References: Handle self-referential entities with ignore_circular:

    parameters:
      api_fields:
        default:
          App\Entity\User:
            fields:
              - id
              - name
              - friends:
                  parameters:
                    ignore_circular: true
    

Gotchas and Tips

Pitfalls

  1. Missing Getters:

    • Error: Undefined method 'getNonExistentField'.
    • Fix: Ensure all fields in YAML have corresponding getX() methods. Use IDE autocompletion to verify.
  2. Circular References:

    • Error: Infinite recursion for entities with bidirectional relationships (e.g., User → Orders → User).
    • Fix: Explicitly ignore circular paths in config or use ignore_circular: true.
  3. Nested Field Typos:

    • Error: Silent failure if a nested field path is incorrect (e.g., city.address when address doesn’t exist).
    • Fix: Test with var_dump($transformer->transform(...)) to debug paths.
  4. Configuration Overrides:

    • Error: Later config keys override earlier ones if not namespaced.
    • Fix: Use unique keys (e.g., api_fields.production, api_fields.staging).
  5. Performance with Deep Nesting:

    • Issue: Recursive transformations can slow down bulk operations.
    • Fix: Cache transformed objects or limit depth in config.

Debugging Tips

  • Enable Debug Mode: Symfony’s debug toolbar shows the transformed array structure.

  • Log Config: Dump the config to verify mappings:

    $config = $this->container->getParameter('api_fields');
    file_put_contents('debug/config_dump.json', json_encode($config, JSON_PRETTY_PRINT));
    
  • Test Edge Cases:

    • Null fields: Ensure getters return null or defaults.
    • Empty collections: Test with new ArrayCollection().
    • Custom objects: Verify non-Doctrine entities work (they do, as long as getters exist).

Configuration Quirks

  1. Field Order: YAML lists preserve order, but nested fields may not. Use explicit keys for consistency:

    fields:
      id: ~
      name: ~
      city: { fields: [id, name] }
    
  2. Boolean Fields: Methods returning bool may serialize as 1/0. Use custom methods to return strings:

    fields:
      isActive:
        parameters:
          method: 'getActiveStatus' # Returns "active"/"inactive"
    
  3. Parameters Merge: Nested parameters override parent config:

    parameters:
      date_format: 'Y-m-d'
    App\Entity\Event:
      fields:
        createdAt:
          parameters:
            format: 'Y-m-d H:i:s' # Overrides parent
    

Extension Points

  1. Custom Transformers: Implement Danilovl\ObjectToArrayTransformBundle\Interfaces\ObjectToArrayTransformerInterface for non-standard objects (e.g., arrays, non-getter-accessible classes).

  2. Pre/Post Processing: Use Symfony’s event system to modify arrays before/after transformation:

    // src/EventListener/TransformListener.php
    use Danilovl\ObjectToArrayTransformBundle\Event\TransformEvent;
    
    class TransformListener {
        public function onTransform(TransformEvent $event) {
            $event->setArray(array_merge($event->getArray(), ['custom_field' => 'value']));
        }
    }
    
  3. Dynamic Field Resolution: Override Danilovl\ObjectToArrayTransformBundle\Service\ObjectToArrayTransformService to resolve fields at runtime (e.g., based on user roles).

  4. Alternative Config Sources: Load fields from databases or APIs by extending the service to accept dynamic config providers.

Laravel-Specific Adaptations

If porting to Laravel:

  1. Service Container: Replace ParameterBag with Laravel’s config:

    // config/api_fields.php
    return [
        'default' => [
            'App\Models\Shop' => ['fields' => ['id', 'name']],
        ],
    ];
    
  2. Service Binding: Bind the transformer in `AppServiceProvider

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.
monarobase/country-list
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