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

Media Bundle Laravel Package

braunstetter/media-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require braunstetter/media-bundle
    

    Register the bundle in config/bundles.php:

    return [
        // ...
        Braunstetter\MediaBundle\MediaBundle::class => ['all' => true],
    ];
    
  2. Create a Media Entity: Extend BaseFile for your media type (e.g., Image, Document):

    // src/Entity/Image.php
    namespace App\Entity;
    use Braunstetter\MediaBundle\Entity\BaseFile;
    
    class Image extends BaseFile {}
    

    Run migrations:

    php bin/console make:migration
    php bin/console doctrine:migrations:migrate
    
  3. First Use Case: Upload a file via a form (see FormTypes for details). Example controller:

    use Braunstetter\MediaBundle\Form\Type\FileType;
    use Symfony\Component\HttpFoundation\Request;
    
    public function upload(Request $request): Response
    {
        $image = new Image();
        $form = $this->createForm(FileType::class, $image);
        $form->handleRequest($request);
    
        if ($form->isSubmitted() && $form->isValid()) {
            $image->upload(); // Persist and upload
            $this->getDoctrine()->getManager()->flush();
        }
        return $this->render('upload.html.twig', ['form' => $form->createView()]);
    }
    

Implementation Patterns

Core Workflows

  1. Entity Design:

    • Extend BaseFile for all media types (e.g., Image, Video, Document).
    • Override getMimeType() or getAllowedMimeTypes() to enforce constraints:
      public function getAllowedMimeTypes(): array
      {
          return ['image/jpeg', 'image/png'];
      }
      
  2. Form Integration:

    • Use FileType for file uploads in forms. Customize with options:
      {{ form_start(form) }}
          {{ form_widget(form.file) }} {# Renders file input #}
          {{ form_errors(form) }}
      {{ form_end(form) }}
      
    • Configure allowed extensions/mime types in the form type:
      $builder->add('file', FileType::class, [
          'allowed_mime_types' => ['image/jpeg', 'image/png'],
          'allowed_extensions' => ['jpg', 'png'],
      ]);
      
  3. Upload Handling:

    • Use the FilesystemUploader (default) or implement UploaderInterface for custom storage (e.g., S3):
      $uploader = new FilesystemUploader($this->getParameter('kernel.project_dir').'/public/uploads');
      $image->upload($uploader); // Persists and uploads
      
    • Chain uploaders for multi-storage (e.g., local + cloud):
      $image->upload($localUploader);
      $image->upload($cloudUploader, 'cloud_path');
      
  4. File Processing:

    • Leverage BaseFile methods for metadata:
      $image->getOriginalName(); // Original filename
      $image->getWebPath();      // Public URL (e.g., `/uploads/filename.jpg`)
      $image->getSize();         // Filesize in bytes
      
    • Add custom logic via entity methods (e.g., resize() for images).
  5. Validation:

    • Validate files pre-upload via FileType constraints or entity logic:
      public function validate(): void
      {
          if ($this->getSize() > 5 * 1024 * 1024) {
              throw new \RuntimeException('File too large');
          }
      }
      

Gotchas and Tips

Pitfalls

  1. Mime Type Validation:

    • The bundle validates mime types after upload. For pre-upload validation, use Symfony’s File constraint in forms:
      $builder->add('file', FileType::class, [
          'mime_types' => ['image/jpeg'],
          'mime_types_message' => 'Only JPEG images allowed',
      ]);
      
  2. Filesystem Permissions:

    • Ensure the upload directory is writable by the web server user. Default: public/uploads.
    • Custom paths? Set permissions explicitly:
      chmod -R 775 /path/to/uploads
      
  3. Entity Lifecycle:

    • Always call $entity->upload() after setting the file field. This:
      • Validates the file.
      • Persists the entity.
      • Triggers the uploader.
    • Never manually save the file path—let BaseFile handle it.
  4. Deletion Quirks:

    • Files are not auto-deleted when entities are removed. Implement a pre-remove event:
      // src/EventSubscriber/MediaSubscriber.php
      use Doctrine\Common\EventSubscriber;
      use Doctrine\ORM\Event\PreRemoveEventArgs;
      
      class MediaSubscriber implements EventSubscriber
      {
          public function getSubscribedEvents(): array
          {
              return ['preRemove'];
          }
      
          public function preRemove(PreRemoveEventArgs $args): void
          {
              $entity = $args->getObject();
              if ($entity instanceof BaseFile && $entity->getFile()) {
                  $entity->deleteFile(); // Custom method to delete file
              }
          }
      }
      
  5. Large Files:

    • For files >2MB, configure Symfony’s max_file_size in php.ini and adjust post_max_size.
    • Stream uploads for very large files (not supported out-of-the-box; consider symfony/ux-upload).

Tips

  1. Custom Uploaders:

    • Implement UploaderInterface for cloud storage (e.g., AWS S3):
      class S3Uploader implements UploaderInterface
      {
          public function upload(BaseFile $file, string $path = null): void
          {
              $s3->putObject([
                  'Bucket' => 'your-bucket',
                  'Key'    => $path ?? $file->getFile()->getClientOriginalName(),
                  'Body'   => fopen($file->getFile()->getPathname(), 'r'),
              ]);
              $file->setPath($path ?? $file->getFile()->getClientOriginalName());
          }
      }
      
  2. Dynamic Paths:

    • Use getUploadRoot() to customize upload directories per entity:
      public function getUploadRoot(): string
      {
          return $this->getUser()->getId() . '/uploads';
      }
      
  3. Soft Deletes:

    • Extend BaseFile to support soft deletes:
      use Doctrine\ORM\Mapping as ORM;
      use Gedmo\Timestampable\Traits\TimestampableEntity;
      
      #[ORM\Table(name: 'images')]
      class Image extends BaseFile
      {
          #[ORM\Column(options: ['default' => false])]
          private bool $isDeleted = false;
      
          public function delete(): void
          {
              $this->isDeleted = true;
              $this->setUpdatedAt(new \DateTime());
          }
      }
      
  4. Testing:

    • Mock uploaders in tests:
      $uploader = $this->createMock(UploaderInterface::class);
      $uploader->expects($this->once())
               ->method('upload')
               ->with($this->isInstanceOf(Image::class));
      $image->upload($uploader);
      
  5. Performance:

    • Batch uploads for bulk operations (e.g., admin imports):
      $uploader = new FilesystemUploader($uploadDir);
      foreach ($images as $image) {
          $image->upload($uploader); // Reuse uploader instance
      }
      
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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware