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

Image Bundle Laravel Package

comur/image-bundle

Symfony bundle for image upload and cropping in forms. Built on jQuery File Upload and JCrop with Bootstrap-friendly widgets (single image or gallery), library selection, ordering, and optional Imagick support for animated GIF cropping.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require comur/image-bundle
    

    Enable in config/bundles.php:

    Comur\ImageBundle\ComurImageBundle::class => ['all' => true],
    
  2. Routing: Create config/routes/comur_image.yaml:

    comur_image:
        resource: "@ComurImageBundle/Resources/config/routing.yml"
        prefix: /
    
  3. Modal Template: Include in your base layout (e.g., base.html.twig):

    <body>
        {% include "ComurImage/Form/croppable_image_modal.html.twig" %}
    </body>
    
  4. FOSJsRouting: Add to <head>:

    <script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
    <script src="{{ path('fos_js_routing_js', {'callback': 'fos.Router.setData'}) }}"></script>
    

First Use Case: Single Image Upload

  1. Entity Setup:

    // src/Entity/YourEntity.php
    use Doctrine\ORM\Mapping as ORM;
    
    class YourEntity {
        /**
         * @ORM\Column(type="string", length=255, nullable=true)
         */
        protected $image;
    
        public function getUploadDir() {
            return 'uploads/your_entity';
        }
    
        public function getWebPath() {
            return $this->image ? '/'.$this->getUploadDir().'/'.$this->image : null;
        }
    }
    
  2. Form Type:

    // src/Form/YourEntityType.php
    use Comur\ImageBundle\Form\Type\CroppableImageType;
    
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('image', CroppableImageType::class, [
            'uploadConfig' => [
                'uploadDir' => 'uploads/your_entity',
                'webDir' => 'uploads/your_entity',
                'fileExt' => '*.jpg;*.png;*.gif',
                'maxFileSize' => 5, // MB
            ],
            'cropConfig' => [
                'minWidth' => 500,
                'minHeight' => 300,
                'aspectRatio' => true,
                'thumbs' => [
                    ['maxWidth' => 200, 'maxHeight' => 200, 'useAsFieldImage' => true],
                ],
            ],
        ]);
    }
    
  3. Template:

    {{ form_row(form.image) }}
    

Implementation Patterns

Common Workflows

  1. Dynamic Upload Directories: Use entity methods for dynamic paths:

    // Entity
    public function getUploadDir() {
        return 'uploads/'.$this->getSlug();
    }
    
  2. Reusing Configs: Extract uploadConfig/cropConfig to a service or trait for consistency:

    // src/Service/ImageConfig.php
    class ImageConfig {
        public static function getDefaultConfig() {
            return [
                'uploadConfig' => [...],
                'cropConfig' => [...],
            ];
        }
    }
    
  3. Gallery Integration: For galleries, use CroppableGalleryType with an array field:

    // Entity
    /**
     * @ORM\Column(type="array", nullable=true)
     */
    protected $galleryImages;
    
    // Form
    $builder->add('gallery', CroppableGalleryType::class, [
        'uploadConfig' => [
            'uploadDir' => 'uploads/your_entity/gallery',
            'webDir' => 'uploads/your_entity/gallery',
        ],
        'galleryDir' => 'gallery',
    ]);
    

Integration Tips

  1. Symfony UX: Combine with Symfony UX Turbo for seamless updates:

    {{ form_theme(form.image, ['ComurImage/Form/croppable_image_widget.html.twig']) }}
    
  2. Validation: Add custom validation for file types/sizes:

    use Symfony\Component\Validator\Constraints as Assert;
    
    /**
     * @Assert\File(
     *     maxSize="5M",
     *     mimeTypes={"image/jpeg", "image/png"},
     *     mimeTypesMessage="Please upload a valid image (JPEG/PNG)"
     * )
     */
    protected $image;
    
  3. API Endpoints: For API projects, override routes to use JsonResponse:

    # config/routes/comur_image.yaml
    comur_api_upload:
        path: /api/upload
        defaults: { _controller: 'comur_image.controller:uploadAction' }
        methods: POST
    
  4. Asset Management: Use webpack-encore to bundle assets if not using Bower:

    // webpack.config.js
    Encore
        .addEntry('comur-image', './vendor/comur/image-bundle/public/js/comur-image.js')
        .splitEntry('comur-image')
        .enableSingleRuntimeChunk();
    

Gotchas and Tips

Pitfalls

  1. Deprecated uploadUrl:

    • Issue: Using uploadUrl (absolute path) triggers security warnings.
    • Fix: Replace with uploadDir (relative to public_dir config).
    • Example:
      # config/packages/comur_image.yaml
      comur_image:
          config:
              public_dir: '%kernel.project_dir%/public'
      
  2. Imagick Requirement:

    • Issue: Animated GIF cropping fails without Imagick.
    • Fix: Install PHP Imagick extension or disable GIF support:
      // CropConfig
      'disableGifCrop' => true,
      
  3. Bootstrap Version Conflicts:

    • Issue: Bundle assumes Bootstrap 4 by default.
    • Fix: Explicitly set version in modal inclusion:
      {% include "ComurImage/Form/croppable_image_modal.html.twig" with {
          'bootstrap_version': 3
      } %}
      
  4. File Permissions:

    • Issue: Uploads fail with "Permission denied" errors.
    • Fix: Ensure public/uploads/ is writable:
      chmod -R 775 public/uploads/
      
  5. Route Overrides:

    • Issue: Custom routes break bundle functionality.
    • Fix: Avoid overriding comur_api_upload, comur_api_crop, or comur_api_image_library.

Debugging Tips

  1. Check Upload Paths:

    • Verify uploadDir and webDir match your filesystem structure.
    • Log paths in your entity:
      public function getUploadDir() {
          error_log('Upload dir: ' . 'uploads/'.$this->getSlug());
          return 'uploads/'.$this->getSlug();
      }
      
  2. JavaScript Errors:

    • Clear cache and check browser console for:
      • Missing fos.Router (ensure FOSJsRouting is loaded).
      • 404 errors on /js/router.js (verify asset paths).
  3. Crop Configuration:

    • Test minWidth/minHeight values with actual image dimensions.
    • Disable aspectRatio temporarily to isolate issues:
      'cropConfig' => ['aspectRatio' => false],
      
  4. Gallery Sorting:

    • Ensure the array field is serialized correctly:
      // Entity
      public function __serialize() {
          return [$this->galleryImages];
      }
      

Extension Points

  1. Custom Templates: Override Twig templates in templates/ComurImage/:

    # templates/ComurImage/Form/croppable_image_widget.html.twig
    {% extends 'ComurImage/Form/croppable_image_widget.html.twig' %}
    {% block image_preview %}
        {{ parent() }} <!-- Customize preview logic -->
    {% endblock %}
    
  2. Event Listeners: Hook into upload/crop events via Symfony events:

    // src/EventListener/ImageUploadListener.php
    use Comur\ImageBundle\Event\ImageUploadEvent;
    
    class ImageUploadListener {
        public function onUpload(ImageUploadEvent $event) {
            $file = $event->getFile();
            // Add custom logic (e.g., rename files)
        }
    }
    

    Register in services.yaml:

    services:
        App\EventListener\ImageUploadListener:
            tags:
                - { name: kernel.event_listener, event: comur.image.upload, method: onUpload }
    
  3. Dynamic Configs: Use form events to modify configs dynamically:

    $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
        $form = $event->getForm();
        $data = $event->getData();
        $form
    
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