Installation Add the bundle to your Symfony project via Composer:
composer require c975l/gallery-bundle
Enable it in config/bundles.php:
return [
// ...
C975L\GalleryBundle\C975LGalleryBundle::class => ['all' => true],
];
Database Migration Run migrations to create the required tables:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
EasyAdmin Integration
Ensure EasyAdminBundle is installed and configured. The bundle provides CRUD for galleries, categories, and images out-of-the-box.
First Upload
Configure config/packages/c975l_gallery.yaml with your storage paths (e.g., uploads/gallery/). Use the EasyAdmin dashboard to:
Displaying Images Use the provided Twig helpers in your templates:
{{ gallery_image(image, 'medium') }} {# Renders resized image #}
{{ gallery_thumbnail(image) }} {# Renders thumbnail #}
Pre-upload Validation
Override the C975L\GalleryBundle\Form\ImageType to add custom validation (e.g., file size, MIME types):
// src/Form/ExtendedImageType.php
use C975L\GalleryBundle\Form\ImageType as BaseImageType;
class ExtendedImageType extends BaseImageType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('file', FileType::class, [
'constraints' => [
new File([
'maxSize' => '10M',
'mimeTypes' => ['image/jpeg', 'image/png'],
]),
],
]);
}
}
Update config/packages/c975l_gallery.yaml to use your extended form:
gallery:
form_type: App\Form\ExtendedImageType
Batch Processing
Use the GalleryManager service to handle bulk operations:
use C975L\GalleryBundle\Manager\GalleryManager;
class MyController {
public function __construct(private GalleryManager $galleryManager) {}
public function uploadBatch(Request $request) {
$files = $request->files->get('images');
foreach ($files as $file) {
$this->galleryManager->upload($file, $categoryId);
}
return new Response('Uploaded!');
}
}
Customize CRUD Extend the EasyAdmin configuration to add fields or filters:
# config/easyadmin.yaml
easy_admin:
entities:
C975L\GalleryBundle\Entity\Gallery:
list:
fields: ['title', 'category', 'createdAt', 'updatedAt']
form:
fields: ['title', 'category', 'images']
Add Custom Actions Create a custom action to delete multiple images at once:
// src/Action/GalleryBulkDeleteAction.php
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use Symfony\Component\HttpFoundation\Response;
class GalleryBulkDeleteAction extends AbstractAction {
public function __invoke(EntityManagerInterface $em, $entity, AdminUrlGenerator $adminUrlGenerator) {
foreach ($entity->getImages() as $image) {
$em->remove($image);
}
$em->flush();
return new Response('Deleted!');
}
}
Register it in your EasyAdmin config:
entities:
C975L\GalleryBundle\Entity\Gallery:
actions:
- { name: 'delete_bulk', icon: 'delete', type: 'C975L\GalleryBundle\Action\GalleryBulkDeleteAction' }
Custom Resolutions
Extend the ImageDerivative service to add new resolutions:
// src/Service/CustomDerivativeService.php
use C975L\GalleryBundle\Service\ImageDerivative;
class CustomDerivativeService extends ImageDerivative {
protected function getResolutions(): array {
return array_merge(parent::getResolutions(), [
'large' => ['width' => 1920, 'height' => 1080],
]);
}
}
Override the service in config/services.yaml:
services:
C975L\GalleryBundle\Service\ImageDerivative: '@App\Service\CustomDerivativeService'
Lazy Loading
Use the gallery_image Twig helper with lazy loading for performance:
{% set imageUrl = gallery_image(image, 'medium', { lazy: true }) %}
<img src="{{ asset(imageUrl) }}" loading="lazy" alt="{{ image.title }}">
Storage Permissions
Ensure the upload directory (uploads/gallery/) is writable by the web server:
chmod -R 775 var/uploads/gallery/
Symptom: Uploads fail silently or images appear broken.
Derivative Generation
The bundle uses liip-imagine under the hood. If derivatives fail:
liip-imagine is installed (composer require liip/imagine-bundle).config/packages/liip_imagine.yaml for filter configurations.EasyAdmin Cache After extending the CRUD, clear the EasyAdmin cache:
php bin/console cache:clear
Symptom: Changes to fields/actions don’t appear.
File Overwrites The bundle does not handle duplicate filenames by default. Use a unique slug:
$image->setFilename(uniqid() . '_' . $file->getClientOriginalName());
Log Upload Errors
Enable debug mode and check var/log/dev.log for file upload issues:
# config/packages/dev/monolog.yaml
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
Verify Entity States Use Doctrine debug tools to inspect entity states:
php bin/console doctrine:query:sql "SELECT * FROM gallery_image WHERE id = ?" 1
Check Derivative Paths
Temporarily enable debug:twig to inspect generated image paths:
php bin/console debug:twig
Custom Entity Repositories
Extend C975L\GalleryBundle\Repository\GalleryRepository to add custom queries:
// src/Repository/CustomGalleryRepository.php
class CustomGalleryRepository extends GalleryRepository {
public function findByCategoryWithImages($categoryId) {
return $this->createQueryBuilder('g')
->where('g.category = :category')
->leftJoin('g.images', 'i')
->addSelect('i')
->setParameter('category', $categoryId)
->getQuery()
->getResult();
}
}
Update the service in config/services.yaml:
services:
C975L\GalleryBundle\Repository\GalleryRepository: '@App\Repository\CustomGalleryRepository'
Event Listeners Hook into lifecycle events (e.g., post-upload):
// src/EventListener/GalleryUploadListener.php
use C975L\GalleryBundle\Entity\Image;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
class GalleryUploadListener implements EventSubscriber {
public function getSubscribedEvents() {
return ['postPersist'];
}
public function postPersist(LifecycleEventArgs $args) {
$entity = $args->getObject();
if ($entity instanceof Image) {
// Send notification, log, etc.
}
}
}
API Integration Expose gallery data via API Platform or custom API:
# config/packages/api_platform.yaml
api_platform:
formats:
jsonld:
mime_types: ['application/ld+json']
resources:
C975L\GalleryBundle\Entity\Gallery:
collectionOperations:
get:
normalization_context:
groups: ['gallery:read']
itemOperations:
get:
normalization_context:
groups: ['gallery:read']
How can I help you explore Laravel packages today?