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

Disable Orm Bundle Laravel Package

dualmedia/disable-orm-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Bundle:
    composer require dualmedia/disable-orm-bundle
    
  2. Register the Bundle: Add to config/bundles.php:
    DualMedia\DisableORMBundle\DisableORMBundle::class => ['all' => true],
    
  3. Configure Entity Manager: Update config/packages/doctrine.yaml:
    doctrine:
        orm:
            entity_managers:
                default:
                    class_metadata_factory_name: DualMedia\DisableORMBundle\Metadata\Factory\DisableORMMetadataFactory
    
  4. Mark a Field for Disabling: Add the #[DisableORM] attribute to the field in your entity:
    #[ORM\Entity]
    class User
    {
        #[DisableORM]
        #[ORM\Column]
        private ?string $legacyField = null;
    }
    

First Use Case

Scenario: You need to remove a field (legacyField) from your User entity but cannot do so immediately due to legacy systems still using it. Use this bundle to:

  1. Mark the field with #[DisableORM].
  2. Deploy the new version of the app (the field is now ignored by Doctrine).
  3. Run a migration to drop the column after confirming legacy systems no longer access it.

Implementation Patterns

Usage Patterns

  1. Gradual Field Removal:

    • Step 1: Add #[DisableORM] to the field in the new codebase.
    • Step 2: Deploy the new version (Doctrine ignores the field).
    • Step 3: Verify legacy systems can still access the field via raw SQL.
    • Step 4: Drop the column in a migration after confirming no active usage.
  2. Conditional Disabling:

    • Use the disable_on_commands config to exclude specific Doctrine commands (e.g., doctrine:schema:validate) from the bundle’s logic:
      dm_disable_orm:
          disable_on_commands:
              - 'doctrine:schema:validate'
              - 'doctrine:migrations:diff'
      
  3. PHPStan Integration:

    • Enable the bundled PHPStan rule to catch potential issues with disabled fields:
      includes:
          - vendor/dualmedia/disable-orm-bundle/extension.neon
      
    • This helps enforce that disabled fields are not accidentally used in new code.
  4. CI/CD Validation:

    • Use the provided GitLab CI script (/scripts/gitlab-ci.job.yml) to detect incorrect field removals (e.g., removing a field without first marking it with #[DisableORM]).

Workflows

  1. Feature Deprecation Workflow:

    • Phase 1: Mark the field with #[DisableORM] and deploy.
    • Phase 2: Update legacy systems to use raw SQL or remove their dependency on the field.
    • Phase 3: Drop the column in a migration and remove the #[DisableORM] attribute.
  2. Multi-Version Deployment:

    • Deploy the new version with disabled fields to a subset of users (e.g., canary release).
    • Monitor for errors or unexpected behavior.
    • Gradually roll out to all users once confirmed stable.
  3. Legacy System Migration:

    • Use raw SQL queries in legacy systems to access disabled fields until they are fully migrated.
    • Example:
      $legacyData = $entityManager->getConnection()->fetchAssociative(
          'SELECT legacy_field FROM users WHERE id = ?',
          [$userId]
      );
      

Integration Tips

  1. Avoid in Critical Queries:

    • Do not disable fields used in WHERE, JOIN, or ORDER BY clauses in Doctrine queries. These will break silently or throw errors.
  2. Default Values:

    • Always set a default value for disabled fields to avoid issues with new entity creation:
      #[DisableORM]
      #[ORM\Column(options: ['default' => null])]
      private ?string $legacyField = null;
      
  3. Testing:

    • Write integration tests to verify that:
      • Disabled fields are not included in find() or findBy() results.
      • Raw SQL queries can still access the field.
      • Legacy code using the field via raw SQL works as expected.
  4. Documentation:

    • Document disabled fields in your entity classes to inform other developers:
      /**
       * @DisableORM This field will be removed in a future migration.
       */
      private ?string $legacyField = null;
      

Gotchas and Tips

Pitfalls

  1. Silent Failures:

    • Disabled fields are completely removed from the ORM metadata, so accessing them via Doctrine methods (e.g., getLegacyField()) will throw PropertyAccessException. Always use raw SQL for legacy access.
  2. Query Builder Issues:

    • Using disabled fields in QueryBuilder methods like where(), join(), or select() will result in errors or unexpected behavior. Example:
      // This will fail if $legacyField is disabled
      $qb->where('u.legacyField = :value');
      
  3. Schema Validation:

    • The bundle disables its logic for commands like doctrine:schema:validate by default. If you need to validate the schema with disabled fields, remove the command from the disable_on_commands config.
  4. Performance Overhead:

    • The metadata factory adds a small overhead to entity hydration. Benchmark if you have performance-critical applications with thousands of entities.
  5. No Re-enabling:

    • Once a field is disabled, there is no built-in way to re-enable it. Plan carefully before disabling fields.

Debugging

  1. Check Metadata:

    • Verify that the field is correctly excluded from the ORM metadata:
      $metadata = $entityManager->getClassMetadata(User::class);
      var_dump($metadata->getFieldNames()); // Should not include 'legacyField'
      
  2. Raw SQL Access:

    • If legacy systems fail to access disabled fields, ensure they are using raw SQL:
      $result = $entityManager->getConnection()->executeQuery(
          'SELECT legacy_field FROM users WHERE id = ?',
          [$userId]
      );
      
  3. PHPStan Errors:

    • If you see PHPStan errors about undefined properties, ensure the extension.neon file is included in your PHPStan config and that the bundle is installed.
  4. Doctrine Events:

    • If you encounter issues with lifecycle callbacks (e.g., prePersist, preUpdate), ensure they are not relying on disabled fields.

Config Quirks

  1. Metadata Factory Name:

    • The config key class_metadata_factory_name is case-sensitive and must match exactly:
      class_metadata_factory_name: DualMedia\DisableORMBundle\Metadata\Factory\DisableORMMetadataFactory
      
  2. Bundle Order:

    • Ensure the DisableORMBundle is loaded after the DoctrineBundle in config/bundles.php to avoid initialization issues.
  3. Doctrine Extensions:

    • If you use Doctrine extensions (e.g., Gedmo), test thoroughly as they may rely on ORM metadata. Some extensions might not work correctly with disabled fields.

Extension Points

  1. Custom Metadata Factory:

    • Extend the DisableORMMetadataFactory to add custom logic for disabling fields based on environment variables or other conditions:
      class CustomDisableORMMetadataFactory extends DisableORMMetadataFactory
      {
          public function getMetadataFor($className, Doctrine\Common\Persistence\Mapping\ClassMetadataFactory $factory)
          {
              $metadata = parent::getMetadataFor($className, $factory);
              // Add custom logic here
              return $metadata;
          }
      }
      
    • Update the config to use your custom factory:
      doctrine:
          orm:
              entity_managers:
                  default:
                      class_metadata_factory_name: App\Metadata\CustomDisableORMMetadataFactory
      
  2. Dynamic Field Disabling:

    • While the bundle does not support dynamic disabling at runtime, you can achieve similar behavior by:
      • Using a feature flag to conditionally apply the #[DisableORM] attribute.
      • Dynamically generating proxy entities that exclude certain fields.
  3. Event Listeners:

    • Add event listeners to log warnings when disabled fields are accessed:
      $eventManager->addEventListener(
          KernelEvents::CONTROLLER,
          function (ControllerEvent $event) {
              $request = $event->getRequest();
              if ($request->attributes->has('legacy_field_accessed')) {
                  Logger::warning('Access to disabled field detected!');
              }
          }
      );
      
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle