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

File Bundle Laravel Package

chamber-orchestra/file-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require chamber-orchestra/file-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        ChamberOrchestra\FileBundle\ChamberOrchestraFileBundle::class => ['all' => true],
    ];
    
  2. Configure Storage Define storage backends in config/packages/chamber_orchestra_file.yaml:

    chamber_orchestra_file:
        storages:
            default:
                type: 'local' # or 's3'
                options:
                    directory: '%kernel.project_dir%/public/uploads'
            s3_backup:
                type: 's3'
                options:
                    bucket: 'my-bucket'
                    region: 'us-east-1'
                    key: 'AKIAXXXXX'
                    secret: 'XXXXXXXXXXXXXXXXXXXX'
    
  3. Annotate an Entity Use the #[File] attribute on a property:

    use ChamberOrchestra\FileBundle\Attribute\File;
    
    #[ORM\Entity]
    class Product {
        #[File(storage: 'default')]
        private ?FileInfo $image;
    }
    
  4. First Upload Use a form with enctype="multipart/form-data" and submit to a controller. The bundle handles the rest via Doctrine lifecycle events.


First Use Case: Basic File Upload

// src/Controller/ProductController.php
#[Route('/product/{id}/upload', name: 'upload_product_image')]
public function uploadImage(Product $product, Request $request): Response
{
    $form = $this->createFormBuilder($product)
        ->add('image', FileType::class)
        ->getForm();

    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        $this->entityManager->flush(); // Bundle handles upload automatically
        $this->addFlash('success', 'Image uploaded!');
    }

    return $this->redirectToRoute('product_show', ['id' => $product->getId()]);
}

Implementation Patterns

Workflow: File Handling in Entities

  1. Define the Entity Use #[File] with optional parameters:

    #[File(
        storage: 's3_backup',
        cdn: 'https://cdn.example.com',
        namingStrategy: 'uuid',
        allowedTypes: ['image/jpeg', 'image/png'],
        maxSize: 5 * 1024 * 1024 // 5MB
    )]
    private ?FileInfo $thumbnail;
    
  2. Form Integration Use Symfony’s FileType in forms:

    $builder->add('document', FileType::class, [
        'label' => 'PDF Document',
        'mapped' => false, // If not directly mapped to entity
    ]);
    
  3. Lifecycle Events The bundle hooks into prePersist, preUpdate, and preRemove to:

    • Upload files on persist/update.
    • Delete files on remove.
  4. Accessing File Info Retrieve metadata via FileInfo:

    $product->getImage()->getPath(); // e.g., 'uploads/products/123.jpg'
    $product->getImage()->getUrl();  // e.g., 'https://cdn.example.com/uploads/123.jpg'
    

Integration Tips

  1. Multiple Storage Backends Route files dynamically based on logic:

    #[File(storage: $product->isPremium() ? 's3_backup' : 'default')]
    private ?FileInfo $media;
    
  2. CDN and URL Generation Generate public URLs with CDN support:

    $this->twig->render('product/show.html.twig', [
        'imageUrl' => $product->getImage()->getUrl(), // Uses CDN if configured
    ]);
    
  3. Validation Leverage Symfony’s constraints:

    #[File(
        allowedTypes: ['image/jpeg', 'image/png'],
        maxSize: 2097152, // 2MB
    )]
    #[Assert\File(maxSize: "2M")]
    private ?FileInfo $avatar;
    
  4. Embeddables Use with Doctrine embeddables for reusable file logic:

    #[ORM\Embeddable]
    class MediaAsset {
        #[File(storage: 'default')]
        private ?FileInfo $file;
    }
    
  5. Custom Naming Strategies Extend NamingStrategyInterface:

    class CustomNamingStrategy implements NamingStrategyInterface {
        public function generateName(FileInfo $file): string {
            return 'custom_' . uniqid() . '.' . $file->getExtension();
        }
    }
    

    Register in config:

    chamber_orchestra_file:
        naming_strategies:
            custom: App\Strategy\CustomNamingStrategy
    

    Use in entity:

    #[File(namingStrategy: 'custom')]
    

Gotchas and Tips

Pitfalls

  1. Doctrine Events Override Avoid manually handling prePersist/preUpdate for file fields—let the bundle manage it. Overriding these may break uploads.

  2. File Deletion on Entity Remove The bundle deletes files when the entity is removed. To bypass this, use:

    $entityManager->remove($entity);
    $entityManager->flush(); // File is deleted
    $entityManager->clear(); // Prevents accidental deletion
    
  3. S3 Permissions Ensure your S3 IAM user has:

    • s3:PutObject
    • s3:GetObject
    • s3:DeleteObject Permissions for the specified bucket.
  4. File Overwrites By default, files are overwritten if the filename collides. To prevent this, use a unique namingStrategy (e.g., uuid).

  5. Symfony Cache Clear the cache after changing bundle configurations:

    php bin/console cache:clear
    

Debugging

  1. Enable Debug Mode Set debug: true in config to log uploads/deletions:

    chamber_orchestra_file:
        debug: true
    
  2. Check Events Verify Doctrine events are firing:

    // In a subscriber or listener
    public function onPrePersist(LifecycleEventArgs $args) {
        $entity = $args->getObject();
        if ($entity instanceof Product) {
            dump($entity->getImage()); // Debug file info
        }
    }
    
  3. Storage Issues

    • For local storage, check directory permissions (chmod -R 775 public/uploads).
    • For S3, verify credentials and bucket policies. Test with:
      php bin/console debug:container chamber_orchestra_file.storage.s3_backup
      

Extension Points

  1. Custom Storage Backends Implement StorageInterface:

    class CustomStorage implements StorageInterface {
        public function upload(FileInfo $file, string $path): void { /* ... */ }
        public function delete(string $path): void { /* ... */ }
        public function getUrl(string $path): string { /* ... */ }
    }
    

    Register in config:

    chamber_orchestra_file:
        storages:
            custom:
                type: 'custom'
                class: App\Storage\CustomStorage
    
  2. Event Subscribers Listen to FileUploadEvent or FileDeleteEvent:

    #[AsEventListener(event: FileUploadEvent::class)]
    public function onFileUpload(FileUploadEvent $event) {
        if ($event->getFile()->getMimeType() === 'image/jpeg') {
            // Resize image, etc.
        }
    }
    
  3. File Archiving Use the archive option to move old files to a separate directory:

    chamber_orchestra_file:
        archive:
            enabled: true
            directory: '%kernel.project_dir%/public/uploads/archive'
    
  4. Doctrine Types Extend the FileType for custom behavior:

    #[Type]
    class CustomFileType extends FileType {
        public function convertToPHPValue($value, AbstractPlatform $platform) {
            // Custom logic
            return parent::convertToPHPValue($value, $platform);
        }
    }
    

    Register in doctrine.yaml:

    dbal:
        types:
            custom_file: App\Doctrine\DBAL\Types\CustomFileType
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
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
christhompsontldr/laravel-inky