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

Doctrine Orm Bridge Bundle Laravel Package

bengor-file/doctrine-orm-bridge-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Install the Bundle**:
   ```bash
   composer require bengor-file/doctrine-orm-bridge-bundle

Ensure FileBundle and DoctrineORMBridge are also installed (this bundle acts as a bridge between them).

  1. Enable in config/bundles.php:

    return [
        // ...
        BenGor\FileBundle\BenGorFileBundle::class => ['all' => true],
        BenGor\DoctrineORMBridgeBundle\DoctrineORMBridgeBundle::class => ['all' => true],
    ];
    
  2. First Use Case: Persisting a File Entity Define an entity with a File property (e.g., User entity):

    use BenGor\FileBundle\Model\File;
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    class User
    {
        #[ORM\OneToOne(targetEntity: File::class, cascade: ["persist"])]
        private ?File $avatar = null;
    
        // Getters/setters...
    }
    

    Use the File entity from FileBundle directly in Doctrine ORM entities.


Implementation Patterns

Workflow: File Upload and Persistence

  1. Handle Upload in Controller:

    use BenGor\FileBundle\Manager\FileManager;
    use Symfony\Component\HttpFoundation\File\UploadedFile;
    
    public function uploadAvatar(UploadedFile $file, FileManager $fileManager): Response
    {
        $user = $this->getUser();
        $fileEntity = $fileManager->upload($file, 'avatars'); // 'avatars' is a configured storage path
        $user->setAvatar($fileEntity);
        $this->entityManager->persist($user);
        $this->entityManager->flush();
    
        return new Response('Avatar uploaded!');
    }
    
  2. Configure Storage in config/packages/ben_gor_file.yaml:

    ben_gor_file:
        storages:
            avatars:
                type: local
                path: '%kernel.project_dir%/public/uploads/avatars'
                allowed_mime_types: ['image/jpeg', 'image/png']
    
  3. Accessing Files in Templates: Use the file_url Twig filter (if configured):

    <img src="{{ user.avatar|file_url }}" alt="Avatar">
    

Integration Tips

  • Doctrine Lifecycle Callbacks: Use @PrePersist/@PreUpdate to auto-generate filenames or validate files:

    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    class User
    {
        #[ORM\PrePersist]
        public function prePersist(): void
        {
            if ($this->avatar) {
                $this->avatar->setFilename(
                    uniqid() . '.' . $this->avatar->getMimeType()->getExtension()
                );
            }
        }
    }
    
  • Querying Files: Use DQL to filter entities by file properties:

    $usersWithAvatars = $entityManager->createQuery(
        'SELECT u FROM App\Entity\User u WHERE u.avatar IS NOT NULL'
    )->getResult();
    
  • Bulk Operations: Leverage Doctrine’s batch processing for large file uploads:

    $entityManager->getConnection()->beginTransaction();
    try {
        foreach ($uploadedFiles as $file) {
            $fileEntity = $fileManager->upload($file, 'bulk_uploads');
            $entity->setFile($fileEntity);
            $entityManager->persist($entity);
            if ($i % 20 === 0) {
                $entityManager->flush();
                $entityManager->clear();
            }
        }
        $entityManager->flush();
        $entityManager->getConnection()->commit();
    } catch (\Exception $e) {
        $entityManager->getConnection()->rollBack();
        throw $e;
    }
    

Gotchas and Tips

Pitfalls

  1. Outdated Dependencies:

    • The bundle was last updated in 2018 and requires PHP 5.5+ and Symfony 2.8+. Test thoroughly with modern PHP (8.0+) and Symfony (5.x/6.x) as edge cases may arise.
    • Workaround: Use a compatibility layer (e.g., symfony/polyfill) or fork the bundle for updates.
  2. Missing Doctrine Event Listeners:

    • The bridge does not automatically handle file cleanup on entity deletion. Manually implement PostRemove or use a custom event subscriber:
      use Doctrine\Common\EventSubscriber;
      use Doctrine\ORM\Event\OnFlushEventArgs;
      
      class FileCleanupSubscriber implements EventSubscriber
      {
          public function getSubscribedEvents(): array
          {
              return ['onFlush'];
          }
      
          public function onFlush(OnFlushEventArgs $args): void
          {
              $em = $args->getEntityManager();
              $uow = $em->getUnitOfWork();
              foreach ($uow->getScheduledEntityDeletions() as $entity) {
                  if (method_exists($entity, 'getFile') && $entity->getFile()) {
                      $file = $entity->getFile();
                      if ($file->getPath()) {
                          unlink($file->getPath());
                      }
                  }
              }
          }
      }
      
      Register the subscriber in services.yaml:
      services:
          App\EventSubscriber\FileCleanupSubscriber:
              tags: ['doctrine.event_subscriber']
      
  3. File Permissions:

    • Ensure the storage directory (path in config) is writable by the web server user (e.g., www-data or nginx). Use chmod -R 775 cautiously or restrict permissions to the app’s storage directory.
  4. MIME Type Validation:

    • The bundle relies on mime/mime-type-detector for MIME validation. If files are rejected unexpectedly, verify:
      • The allowed_mime_types in config match the actual uploaded files.
      • The mime/mime-type-detector package is installed and up-to-date.

Debugging Tips

  1. Log File Operations: Enable debug logging for ben_gor_file in config/packages/dev/monolog.yaml:

    handlers:
        file_log:
            type: stream
            path: "%kernel.logs_dir%/%kernel.environment%.log"
            level: debug
            channels: ["file"]
    

    Then configure the bundle to log:

    ben_gor_file:
        debug: true
    
  2. Check File Entity State: Use Doctrine’s getEntityManager()->getUnitOfWork()->getOriginalEntityData($entity) to compare pre- and post-persist states:

    $originalData = $em->getUnitOfWork()->getOriginalEntityData($user);
    dump($originalData['avatar']); // Compare with $user->getAvatar()
    
  3. Storage Path Issues: If files aren’t saved, verify:

    • The path in config is absolute and exists.
    • The web server has write permissions (test with touch %path%/test.txt).
    • No typos in the storage name (e.g., avatars vs avatar).

Extension Points

  1. Custom File Metadata: Extend the File entity to add custom fields (e.g., altText, tags):

    #[ORM\Entity]
    class CustomFile extends File
    {
        #[ORM\Column(type: 'string', length: 255, nullable: true)]
        private ?string $altText = null;
    
        // Getters/setters...
    }
    

    Update the bundle’s FileType to support the new fields in forms.

  2. Custom Storage Backends: Implement a new storage adapter by extending BenGor\FileBundle\Storage\StorageInterface:

    class S3Storage implements StorageInterface
    {
        public function save(File $file, string $path): void
        {
            // Custom S3 logic
        }
    
        public function delete(string $path): void
        {
            // Custom S3 deletion
        }
    }
    

    Register it in the bundle’s configuration:

    ben_gor_file:
        storages:
            s3_uploads:
                type: s3
                adapter: App\Storage\S3Storage
                bucket: my-bucket
    
  3. Event Dispatching: Listen for file events (e.g., file.pre_upload, file.post_save) using Symfony’s event dispatcher:

    use BenGor\FileBundle\Event\FileEvents;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class FileEventSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents(): array
        {
            return [
                FileEvents::PRE_UPLOAD => 'onPreUpload',
                FileEvents::POST_SAVE => 'onPostSave',
            ];
        }
    
        public function onPreUpload
    
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.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle