Weave 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

Aviary Bundle Laravel Package

appventus/aviary-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require appventus/aviary-bundle:dev-master
    

    Add to AppKernel.php:

    new AppVentus\AviaryBundle\AviaryBundle(),
    
  2. Configure Upload Path: In config.yml:

    parameters:
        aviary.uploadpath: "%kernel.root_dir%/../web/uploads"
    
  3. Twig Configuration: In config.yml:

    twig:
        form:
            resources:
                - 'AviaryBundle:Form:fields.html.twig'
    
  4. First Use Case: Create an entity with a OneToOne relation to Gallery (e.g., Product):

    /**
     * @ORM\OneToOne(targetEntity="Appventus\AviaryBundle\Entity\Gallery", cascade={"persist"})
     */
    private $gallery;
    

    Add GalleryType to your form type:

    use Appventus\AviaryBundle\Form\GalleryType;
    $builder->add('gallery', new GalleryType());
    
  5. Render the Form:

    {{ form_start(form, {'method': 'POST', 'attr': {'id': 'fileupload'}}) }}
    {{ form_widget(form.gallery) }}
    {{ form_end(form) }}
    
  6. Initialize Aviary: Include the Aviary JS library and initialize it in your frontend:

    var featherEditor = new Aviary.Feather({
        apiKey: 'YOUR_AVIARY_API_KEY',
        appendTo: '#fileupload',
        onSave: function(imageID, newURL) { /* Handle save */ }
    });
    

Implementation Patterns

Workflow: Image Upload and Editing

  1. Form Submission: The GalleryType handles multiple file uploads via BlueImp jQuery File Uploader. Files are stored in the configured aviary.uploadpath.

  2. Entity Integration: Attach the Gallery entity to your main entity (e.g., Product) via the OneToOne relation. The bundle persists the Gallery automatically when saving the parent entity.

  3. Frontend Integration:

    • Use AsseticInjectorBundle to inject Aviary scripts/styles:
      {% javascripts injector='aviary_scripts' %}
          // Aviary JS library
      {% endjavascripts %}
      
    • Initialize Aviary on the file upload container (e.g., #fileupload).
  4. Image Editing: After upload, trigger Aviary’s editor via JavaScript:

    featherEditor.launch({
        image: uploadedImageURL,
        onSave: function(imageID, newURL) {
            // Update the entity with the edited image URL
            $.post('/update-image', { id: imageID, url: newURL });
        }
    });
    
  5. Backend Handling:

    • Override the Gallery entity’s setter to handle edited image URLs:
      public function setImages(array $images) {
          foreach ($images as $image) {
              if (isset($image['edited'])) {
                  $image['path'] = $image['edited']; // Update path to edited image
              }
          }
          $this->images = $images;
      }
      
    • Use a controller to update the edited image path in the database.

Integration Tips

  1. Custom Validation: Extend the GalleryType to add validation rules for file types/sizes:

    $builder->add('images', CollectionType::class, [
        'entry_type' => FileType::class,
        'allow_add' => true,
        'allow_delete' => true,
        'constraints' => [
            new File([
                'maxSize' => '1024k',
                'mimeTypes' => ['image/jpeg', 'image/png'],
            ]),
        ],
    ]);
    
  2. Dynamic Upload Paths: Use a service to dynamically set the upload path based on the entity type:

    services:
        aviary.upload_path_resolver:
            class: App\Service\AviaryUploadPathResolver
            arguments: ['@request_stack']
    

    Then inject it into the GalleryType to override the default path.

  3. Batch Processing: For large uploads, use a queue system (e.g., Symfony Messenger) to process images asynchronously:

    $gallery->setImages($request->files->get('gallery')['images']);
    $this->messageBus->dispatch(new ProcessGalleryImagesMessage($gallery));
    
  4. Twig Extensions: Create a custom Twig extension to generate Aviary initialization scripts dynamically:

    $twig->addExtension(new class extends \Twig\Extension\AbstractExtension {
        public function getFunctions() {
            return [
                new \Twig\TwigFunction('aviary_init_script', [$this, 'getAviaryScript']),
            ];
        }
        public function getAviaryScript() {
            return 'var featherEditor = new Aviary.Feather({...});';
        }
    });
    

    Usage in Twig:

    {{ aviary_init_script() }}
    

Gotchas and Tips

Pitfalls

  1. API Key Management:

    • The Aviary API key is hardcoded in JavaScript, which is a security risk. Use environment variables or a backend proxy to avoid exposing it:
      // Bad: Hardcoded
      apiKey: 'YOUR_API_KEY'
      // Good: Fetch from backend
      fetch('/api/aviary-config')
          .then(response => response.json())
          .then(config => {
              var featherEditor = new Aviary.Feather({ apiKey: config.apiKey });
          });
      
  2. File Permissions: Ensure the aviary.uploadpath directory is writable by the web server:

    chmod -R 775 %kernel.root_dir%/../web/uploads
    
  3. CSRF Token Mismatch: The bundle’s file upload may fail if the CSRF token is not included. Ensure your form includes:

    {{ form_start(form, {'attr': {'id': 'fileupload', 'data-csrf-token': app.request.csrfToken}}) }}
    
  4. BlueImp Dependency: The bundle relies on BlueImp jQuery File Uploader, which may conflict with other upload libraries. Exclude its assets if needed:

    // Disable BlueImp's default behavior if using another uploader
    $('#fileupload').fileupload('option', 'autoUpload', false);
    
  5. Entity Cascade Issues: If the parent entity (e.g., Product) is deleted without cascading, the Gallery entity may become orphaned. Explicitly handle this in your repository:

    public function deleteProduct(Product $product) {
        $gallery = $product->getGallery();
        if ($gallery) {
            $this->getEntityManager()->remove($gallery);
        }
        $this->getEntityManager()->remove($product);
    }
    

Debugging Tips

  1. Check Upload Path: Verify the aviary.uploadpath parameter is correctly set and the directory exists. Log it in a controller:

    $this->container->getParameter('aviary.uploadpath');
    
  2. Aviary Console Errors: Inspect the browser’s console for Aviary-specific errors (e.g., apiKey missing or invalid). Example error:

    Aviary error: Invalid API key
    
  3. File Upload Failures:

    • Check the server logs for PHP errors (e.g., move_uploaded_file failures).
    • Ensure the enctype="multipart/form-data" is set in the form:
      {{ form_start(form, {'attr': {'enctype': 'multipart/form-data'}}) }}
      
  4. JavaScript Initialization: Wrap Aviary initialization in a DOMContentLoaded event to avoid race conditions:

    document.addEventListener('DOMContentLoaded', function() {
        var featherEditor = new Aviary.Feather({...});
    });
    

Extension Points

  1. Custom Gallery Entity: Extend the Gallery entity to add metadata (e.g., altText, caption):

    /**
     * @ORM\Column(type="string", nullable=true)
     */
    private $caption;
    

    Update the GalleryType to include these fields.

  2. Plugin-Specific Config: Aviary supports plugins (e.g., filters, effects). Pass custom config via the featherEditor options:

    var featherEditor = new Aviary.Feather({
        tools: ['crop', 'enhance', 'draw'],
        // Plugin-specific config
        crop: {
            preset: 'square',
        },
    });
    
  3. Event Listeners: Listen for Gallery events to trigger actions (e.g., image optimization):

    $gallery->addEventListener('postPersist', function(Gallery $gallery) {
        $this->optimize
    
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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style