### Start Demo Application Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/demo.rst Initiate the demo application stack using the Castor command. This may take a few minutes on the first run as Docker images are built and dependencies are installed. ```bash $ castor demo:start ``` -------------------------------- ### Install oxipng Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/dependencies-and-tooling.rst Manually installs oxipng by downloading a pre-compiled binary and copying it to the bin directory. ```bash cd /tmp \ && wget -O oxipng-9.1.5-x86_64-unknown-linux-musl.tar.gz https://github.com/shssoichiro/oxipng/releases/download/v9.1.5/oxipng-9.1.5-x86_64-unknown-linux-musl.tar.gz \ && tar xzvf oxipng-9.1.5-x86_64-unknown-linux-musl.tar.gz \ && cp oxipng-9.1.5-x86_64-unknown-linux-musl/oxipng /usr/local/bin/oxipng ``` -------------------------------- ### Install mozjpeg Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/dependencies-and-tooling.rst Manually installs mozjpeg by downloading the source, compiling, and installing. ```bash cd /tmp \ && wget -O mozjpeg.tar.gz https://github.com/mozilla/mozjpeg/archive/refs/tags/v4.1.1.tar.gz \ && tar xzvf mozjpeg.tar.gz \ && cd /tmp/mozjpeg-4.1.1 \ && cmake -G"Unix Makefiles" \ && make \ && make install ``` -------------------------------- ### Install cwebp and gif2webp Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/dependencies-and-tooling.rst Manually installs cwebp and gif2webp by downloading and extracting the libwebp binary. ```bash cd /tmp \ && wget -O libwebp-1.6.0-linux-x86-64.tar.gz https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-1.6.0-linux-x86-64.tar.gz \ && tar xzvf libwebp-1.6.0-linux-x86-64.tar.gz \ && cp libwebp-1.6.0-linux-x86-64/bin/cwebp /usr/local/bin/cwebp \ && cp libwebp-1.6.0-linux-x86-64/bin/gif2webp /usr/local/bin/gif2webp ``` -------------------------------- ### Start the Docker Stack Source: https://github.com/jolicode/mediabundle/blob/main/demo/README.md Launches the JoliMediaBundle demo application's Docker environment. The initial start may take a few minutes to complete. ```bash castor start ``` -------------------------------- ### Clone Repository and Navigate Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/demo.rst Clone the MediaBundle repository and navigate into the project directory to begin setup. ```bash git clone https://github.com/JoliCode/MediaBundle.git cd MediaBundle ``` -------------------------------- ### Install JoliMediaBundle Source: https://context7.com/jolicode/mediabundle/llms.txt Install the bundle using Composer. Register the main bundle and any desired bridge bundles in config/bundles.php. ```bash composer require jolicode/media-bundle ``` ```php // config/bundles.php return [ JoliCode\MediaBundle\JoliMediaBundle::class => ['all' => true], // Optional bridges: JoliCode\MediaBundle\Bridge\EasyAdmin\JoliMediaEasyAdminBundle::class => ['all' => true], JoliCode\MediaBundle\Bridge\SonataAdmin\JoliMediaSonataAdminBundle::class => ['all' => true], ]; ``` -------------------------------- ### Full Media Variation Configuration Example Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/variations.rst This example demonstrates a complete variation configuration, including options for auto-webp generation, pixel ratios, post-processors, image processors, transformers, and voters. ```yaml joli_media: libraries: example_library: variations: profile_picture: enable_auto_webp: true pixel_ratios: [1, 2, 3] post_processors: jpegoptim: options: strip_all: false max_quality: 60 processors: imagine: options: jpeg_quality: 99 transformers: thumbnail: width: 100 height: 100 voters: - type: format format: jpg ``` -------------------------------- ### Install JoliMediaBundle Source: https://github.com/jolicode/mediabundle/blob/main/README.md Install the bundle using Composer. Requires Symfony 7+. ```bash composer require jolicode/media-bundle ``` -------------------------------- ### Install Debian Dependencies Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/dependencies-and-tooling.rst Installs common media processing dependencies on Debian-based systems using apt. ```bash sudo apt install \ exiftran \ file \ gifsicle \ imagemagick \ jpegoptim \ libheif1 \ libheif-plugins-all \ libimage-exiftool-perl \ libmagickcore-dev \ pngquant ``` -------------------------------- ### Configure JoliMediaEasyAdminBundle Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/easy-admin.rst Example configuration for the EasyAdmin integration, covering pagination, upload limits, and feature visibility. ```yaml joli_media_easy_admin: pagination: per_page: 20 upload: max_files: 10 max_file_size: 20 accepted_files: - image/* - video/* - application/pdf visibility: show_variations_stored: true show_variations_action_regenerate: true show_html_code: true show_markdown_code: true ``` -------------------------------- ### Watch and Install Demo Application Frontend Assets Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/demo.rst Monitor changes in the admin bridges' asset folders and automatically install the rebuilt assets into the demo application's public folder. This ensures that frontend changes are reflected in the running demo application. ```bash $ castor demo:app:front:watch ``` -------------------------------- ### Insert Fixture Data Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/demo.rst Populate the demo application's database with fixture data after starting the application. ```bash $ castor demo:app:db:fixtures ``` -------------------------------- ### Install JoliMediaBundle with Composer Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/installation.rst Use Composer to add the JoliMediaBundle to your project dependencies. ```bash $ composer require jolicode/media-bundle ``` -------------------------------- ### Configure Flysystem Adapters and Filesystems Source: https://context7.com/jolicode/mediabundle/llms.txt Define Flysystem adapters and filesystems for original and cache storage. This example uses local storage. ```yaml # config/services.yaml services: filesystem.original.adapter: class: League\Flysystem\Local\LocalFilesystemAdapter arguments: '$location': '%kernel.project_dir%/public/media/original' filesystem.original.storage: class: League\Flysystem\Filesystem arguments: '$adapter': '@filesystem.original.adapter' filesystem.cache.adapter: class: League\Flysystem\Local\LocalFilesystemAdapter arguments: '$location': '%kernel.project_dir%/public/media/cache' filesystem.cache.storage: class: League\Flysystem\Filesystem arguments: '$adapter': '@filesystem.cache.adapter' ``` -------------------------------- ### Implement a Custom Pre-processor (PHP) Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/pre-processors.rst Example of a custom pre-processor that resizes an image and adds a yellow background. It must implement the PreProcessorInterface and can leverage services like Imagine. ```php namespace App\Media\PreProcessor; use Imagine\Image\Box; use Imagine\Image\ImagineInterface; use Imagine\Image\Point; use JoliCode\MediaBundle\Binary\Binary; use JoliCode\MediaBundle\PreProcessor\AbstractPreProcessor; use JoliCode\MediaBundle\PreProcessor\PreProcessorInterface; use JoliCode\MediaBundle\Variation\Variation; readonly class OgImagePreProcessor extends AbstractPreProcessor implements PreProcessorInterface { private const WIDTH = 1200; private const HEIGHT = 1000; public function __construct( private ImagineInterface $imagine, ) { } public function process(Binary $binary, Variation $variation): Binary { $image = $this->imagine->load($binary->getContent()); $width = $image->getSize()->getWidth(); $height = $image->getSize()->getHeight(); if (!$width || !$height) { return $binary; } if ($width > self::WIDTH || $height > self::HEIGHT) { $ratio = $width / $height; if ($width > self::WIDTH) { $height = self::WIDTH / $ratio; $width = self::WIDTH; } if ($height > self::HEIGHT) { $width = self::HEIGHT * $ratio; $height = self::HEIGHT; } $image = $image->resize(new Box($width, $height)); } $canvas = $this->imagine->create( new Box(self::WIDTH, self::HEIGHT), $image->palette()->color('#ffff00'), ); $x = (self::WIDTH - $width) / 2; $y = (self::HEIGHT - $height) / 2; $canvas->paste($image, new Point($x, $y)); return new Binary( $binary->getMimeType(), $binary->getFormat(), $canvas->get($binary->getFormat()), ); } } ``` -------------------------------- ### Enable JoliMediaEasyAdminBundle in bundles.php Source: https://github.com/jolicode/mediabundle/blob/main/src/Bridge/EasyAdmin/README.md Add this line to your bundles.php file to enable the JoliMediaEasyAdminBundle. This is typically done during the installation of JoliMediaBundle. ```php return [ // ... JoliCode\MediaBundle\Bridge\EasyAdmin\JoliMediaEasyAdminBundle::class => ['all' => true], ]; ``` -------------------------------- ### Default Post-processor Configuration Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/post-processors.rst Defines the default options for various image optimization post-processors. Ensure required binaries are installed. ```yaml joli_media: post_processors: gifsicle: options: optimize: 3 lossy: 20 colors: 256 jpegoptim: options: strip_all: true progressive: true max_quality: 80 mozjpeg: options: optimize: true progressive: true quality: 80 oxipng: options: optimization: 4 strip: - all zopfli: false pngquant: options: quality: 75-85 speed: 5 ``` -------------------------------- ### Listen to Pre-Delete Media Event Source: https://github.com/jolicode/mediabundle/blob/main/doc/misc-features/events.rst Example of an event listener for the `joli.media.pre_delete_media` event. It logs the path of the media about to be deleted and allows for custom logic. ```php namespace App\EventListener; use JoliCode\MediaBundle\Event\MediaEvents; use JoliCode\MediaBundle\Event\PreDeleteMediaEvent; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; class MediaEventListener { public function __construct(private readonly LoggerInterface $logger) { } #[AsEventListener(event: MediaEvents::PRE_DELETE_MEDIA)] public function onPreDeleteMedia(PreDeleteMediaEvent $event): void { $mediaPath = $event->path; $this->logger->info(sprintf('Media "%s" is about to be deleted.', $mediaPath)); // Add custom logic here } } ``` -------------------------------- ### Access the Docker Builder Container Source: https://github.com/jolicode/mediabundle/blob/main/demo/README.md Starts a container with development tools like Composer and Node.js, allowing modifications to project dependencies or code. ```bash castor docker:builder ``` -------------------------------- ### Implement a Custom Pre-processor for OG Image Generation Source: https://context7.com/jolicode/mediabundle/llms.txt Create a custom pre-processor by extending AbstractPreProcessor and implementing PreProcessorInterface. This example resizes an image to fit specific OG dimensions and pastes it onto a yellow canvas. ```php // src/Media/PreProcessor/OgImagePreProcessor.php namespace App\Media\PreProcessor; use Imagine\Image\Box; use Imagine\Image\ImagineInterface; use Imagine\Image\Point; use JoliCode\MediaBundle\Binary\Binary; use JoliCode\MediaBundle\PreProcessor\AbstractPreProcessor; use JoliCode\MediaBundle\PreProcessor\PreProcessorInterface; use JoliCode\MediaBundle\Variation\Variation; readonly class OgImagePreProcessor extends AbstractPreProcessor implements PreProcessorInterface { private const WIDTH = 1200; private const HEIGHT = 630; public function __construct(private ImagineInterface $imagine) {} public function process(Binary $binary, Variation $variation): Binary { $image = $this->imagine->load($binary->getContent()); $size = $image->getSize(); // Fit image within OG dimensions if ($size->getWidth() > self::WIDTH || $size->getHeight() > self::HEIGHT) { $ratio = $size->getWidth() / $size->getHeight(); $w = self::WIDTH; $h = (int) ($w / $ratio); if ($h > self::HEIGHT) { $h = self::HEIGHT; $w = (int) ($h * $ratio); } $image = $image->resize(new Box($w, $h)); } // Paste onto yellow canvas $canvas = $this->imagine->create( new Box(self::WIDTH, self::HEIGHT), $image->palette()->color('#ffff00'), ); $canvas->paste($image, new Point( (self::WIDTH - $image->getSize()->getWidth()) / 2, (self::HEIGHT - $image->getSize()->getHeight()) / 2, )); return new Binary($binary->getMimeType(), $binary->getFormat(), $canvas->get($binary->getFormat())); } } ``` -------------------------------- ### Sequential Transformer Application Example Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Transformers are applied sequentially as defined in the configuration. The order matters, as swapping transformers can lead to different output dimensions. ```yaml my_variation: transformers: resize: width: 200 height: 150 mode: inside heighten: height: 600 ``` -------------------------------- ### YAML Configuration for MediaBundle Transformers Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Configure a sequence of image transformations using YAML. This example demonstrates chaining crop, expand, heighten, and widen operations with specific parameters. ```yaml transformers: - type: crop width: 60 height: 60 - type: expand width: 80 height: 80 background_color: '#ffcccc' position_x: end position_y: end - type: heighten height: 100 - type: expand width: 120 height: 120 background_color: '#ccffcc' position_x: start position_y: end - type: widen width: 140 - type: expand width: 160 ``` -------------------------------- ### Override Post-processor Options for a Library Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/post-processors.rst Customizes post-processor options, such as max_quality for jpegoptim and quality for mozjpeg, for a specific library named 'example'. ```yaml joli_media: libraries: example: post_processors: jpegoptim: max_quality: 90 mozjpeg: quality: 95 ``` -------------------------------- ### Minimal Media Library Configuration Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/configuration.rst Defines a basic media library with original and cache storage using Flysystem and a simple URL generator. This is a starting point for most applications. ```yaml joli_media: libraries: user_files: original: flysystem: "user_files.storage" url_generator: strategy: "path" path: "/media/user-files/" cache: flysystem: "user_files.cache" url_generator: strategy: "path" path: "/media/cache/user-files/" variations: thumbnail: adaptive_resize: width: 100 height: 100 format: "jpg" ``` -------------------------------- ### Chained Transformers Configuration Source: https://context7.com/jolicode/mediabundle/llms.txt Apply multiple transformers sequentially to an image. This example chains crop, expand, and thumbnail transformations. ```yaml complex: transformers: - type: crop width: 60 height: 60 - type: expand width: 80 height: 80 background_color: '#ffcccc' position_x: end position_y: end - type: thumbnail width: 100 height: 100 ``` -------------------------------- ### Library-Specific imagine Processor Override Source: https://context7.com/jolicode/mediabundle/llms.txt Override global processor settings for a specific library. This example increases JPEG quality for the 'premium' library. ```yaml imagine: jpeg_quality: 95 # override for this library only ``` -------------------------------- ### Prepare for Contribution with Castor Source: https://github.com/jolicode/mediabundle/blob/main/doc/tests-and-qa-tooling.rst Runs essential quality assurance tasks before contributing to the project, including building Docker images, installing tools, and executing all QA checks. ```terminal $ castor docker:build ``` ```terminal $ castor qa:install ``` ```terminal $ castor qa:all ``` -------------------------------- ### Configure Thumbnail Transformer with Vertical Crop Position Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Configure thumbnail generation with specific dimensions and a 'start' crop position for vertical alignment. ```yaml transformers: thumbnail: width: 40 height: 120 crop_position: start ``` -------------------------------- ### Configure AllOf Voter to Combine Voters Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/variation-voters.rst Use the 'allOf' voter to ensure that all specified child voters return true for the variation to be applied. This example requires both folder and filesize conditions to be met. ```yaml joli_media: libraries: example_library: variations: profile_picture: transformers: thumbnail: width: 64 height: 64 voters: - type: allOf voters: - type: folder path: user/profile_pictures - type: filesize min: 1024 ``` -------------------------------- ### Generate Media URLs in PHP Source: https://context7.com/jolicode/mediabundle/llms.txt Use the MediaBundle resolver service to get Media and MediaVariation objects and generate absolute or relative URLs. Ensure the ResolverInterface and UrlGeneratorInterface are available. ```php use JoliCode\MediaBundle\Resolver\ResolverInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class ArticleController { public function __construct(private ResolverInterface $resolver) {} public function show(): void { // Resolve from the default library $media = $this->resolver->resolve('photos/hero.jpg'); // Relative path to original echo $media->getUrl(); // → /media/original/photos/hero.jpg // Absolute URL to original echo $media->getUrl(UrlGeneratorInterface::ABSOLUTE_URL); // → https://example.com/media/original/photos/hero.jpg // Resolve a specific variation (default library) $variation = $this->resolver->resolve('photos/hero.jpg', null, 'thumbnail'); echo $variation->getUrl(); // → /media/cache/thumbnail/photos/hero.jpg // Resolve from a specific library $contrib = $this->resolver->resolve('logo.png', 'contributions', 'product_banner'); echo $contrib->getUrl(UrlGeneratorInterface::ABSOLUTE_URL); // → https://example.com/media/cache/product_banner/logo.png } } ``` -------------------------------- ### List Available MediaBundle Commands Source: https://github.com/jolicode/mediabundle/blob/main/doc/misc-features/commands.rst Execute the main console command to see all available MediaBundle commands and their descriptions. ```bash $ php ./bin/console ``` -------------------------------- ### Install Castor Autocompletion for Bash Source: https://github.com/jolicode/mediabundle/blob/main/demo/README.md Installs Castor shell autocompletion script for Bash. This improves the usability of Castor commands by providing tab completion. ```bash castor completion | sudo tee /etc/bash_completion.d/castor ``` -------------------------------- ### Force Regenerate SSL Certificates Source: https://github.com/jolicode/mediabundle/blob/main/demo/README.md Forces the regeneration of SSL certificates for HTTPS support. This command is useful if existing certificates are outdated or corrupted. A subsequent build and up (`castor build && castor up`) or start (`castor start`) is needed to apply changes. ```bash castor docker:generate-certificates --force ``` -------------------------------- ### Crop Image with Coordinates Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Crops a specific part of an image using start coordinates, width, and height. Coordinates can be absolute pixel values or percentages. If start coordinates are outside the image, it remains unmodified. If width/height are larger than the image, only the fitting part is used. ```yaml crop: start_x: 10% start_y: 20% width: 50% height: 300 ``` -------------------------------- ### Compile Frontend Assets for Production Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/demo.rst Build the frontend assets one last time for production deployment after development is complete. ```bash $ castor frontend:compile ``` -------------------------------- ### Configure ExifRemovalPreProcessor Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/pre-processors.rst Register the ExifRemovalPreProcessor in the MediaBundle configuration to enable EXIF metadata removal. This pre-processor requires exiftool to be installed and configured. ```yaml joli_media: pre_processors: - JoliCode\MediaBundle\PreProcessor\ExifRemovalPreProcessor # - ... ``` -------------------------------- ### Crop Image Transformer with Position Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Configure the crop transformer with starting coordinates. Use percentages for precise positioning of the crop area. ```yaml transformers: crop: width: 50 height: 50 start_x: 50% start_y: 10% ``` -------------------------------- ### Configure /etc/hosts for Demo Domain Source: https://github.com/jolicode/mediabundle/blob/main/demo/README.md Adds an entry to the /etc/hosts file to map the demo domain to the local Docker daemon IP. This is required for the application to be accessible via its configured domain name. ```bash echo '127.0.0.1 jolimediabundle-demo.test' | sudo tee -a /etc/hosts ``` -------------------------------- ### Configure JoliMedia Libraries Source: https://github.com/jolicode/mediabundle/blob/main/doc/storage/storage.rst Define media libraries with original and cache storage configurations, including Flysystem service references and variation settings. ```yaml joli_media: libraries: default: original: flysystem: "filesystem.original.storage" url_generator: strategy: folder path: /media/original/ cache: flysystem: "filesystem.cache.storage" url_generator: strategy: folder path: /media/cache/ enable_auto_webp: false variations: banner: format: webp transformers: thumbnail: width: 1920 height: 512 content: format: webp ``` -------------------------------- ### Configure Global Pre-processors (YAML) Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/pre-processors.rst Define pre-processors to be applied to all media before any variation is computed. They are executed sequentially. ```yaml joli_media: pre_processors: - App\Media\PreProcessor\AutoRotateImagePreProcessor # - ... ``` -------------------------------- ### Define Media Library Routes in routes.yaml Source: https://github.com/jolicode/mediabundle/blob/main/src/Bridge/EasyAdmin/README.md Configure the routes for the media library by specifying the resource and prefix in your routes.yaml file. This makes the media library accessible at the specified URL. ```yaml _joli_media_easy_admin: resource: "@JoliMediaEasyAdminBundle/src/Controller/" prefix: /admin/media ``` -------------------------------- ### Configure MimeType Voter for a Variation Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/variation-voters.rst Use the 'mimeType' voter to restrict a variation to media with a specific MIME type. This example applies the variation only to 'image/png' files. ```yaml joli_media: libraries: example_library: variations: profile_picture: transformers: thumbnail: width: 64 height: 64 voters: - type: mimeType mime_type: image/png ``` -------------------------------- ### Configure Product Image Resource for Media Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sylius.rst Applies the EntityWithMediaImageTrait to the Sylius ProductImage entity to integrate with the MediaBundle. ```diff namespace App\Entity\Product; use Doctrine\ORM\Mapping as ORM; use JoliCode\MediaBundle\Bridge\Sylius\Doctrine\ORM\EntityWithMediaImageTrait; use Sylius\Component\Core\Model\ProductImage as BaseProductImage; #[ORM\Entity] #[ORM\Table(name: 'sylius_product_image')] class ProductImage extends BaseProductImage { use EntityWithMediaImageTrait; } ``` -------------------------------- ### Configuring JoliMedia EasyAdmin Routes Source: https://context7.com/jolicode/mediabundle/llms.txt Configure the routes for the JoliMedia EasyAdmin integration in `config/routes/joli_media.yaml`. This sets up the base path for media-related admin routes. ```yaml # config/routes/joli_media.yaml _joli_media_easy_admin: resource: "@JoliMediaEasyAdminBundle/src/Controller/" prefix: /admin/media ``` -------------------------------- ### Configure Pagination per Page Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sonata-admin.rst Adjust the number of media items displayed per page for performance optimization in large libraries. ```yaml joli_media_sonata_admin: pagination: per_page: 25 ``` -------------------------------- ### Variation-Specific imagine Processor Override Source: https://context7.com/jolicode/mediabundle/llms.txt Override processor settings for a specific variation within a library. This example sets maximum JPEG and PNG quality for the 'print_quality' variation. ```yaml imagine: jpeg_quality: 100 png_quality: 99 quality: 100 ``` -------------------------------- ### Integrate Media Selector Widget in Sylius Form Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sylius.rst Adds the MediaChoiceType to a custom Symfony form type (UserType example) to enable media selection from the media library. ```php namespace App\Form; use App\Entity\User; use JoliCode\MediaBundle\Bridge\Sylius\Admin\Form\Type\MediaChoiceType; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; class UserType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options): void { $builder // ... ->add('profilePicture', MediaChoiceType::class) ; } } ``` -------------------------------- ### Import Sylius Integration Configuration Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sylius.rst Import the bundle configuration in your JolieMediaSylius configuration file. ```yaml imports: - { resource: '@JoliMediaSyliusBundle/config/app.php' } ``` -------------------------------- ### Default Processors Configuration Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/processors.rst Defines the default settings for cwebp, gif2webp, gifsicle, and imagine processors, balancing quality and performance. ```yaml joli_media: processors: cwebp: options: near_lossless: quality: 40 method: 6 metadata: - none near_lossless: 0 lossy: quality: 75 method: 6 af: true pass: 10 metadata: - none gif2webp: options: lossy: true metadata: - none min_size: true gifsicle: options: optimize: 3 lossy: 20 colors: 256 imagine: options: jpeg_quality: 80 png_quality: 80 quality: 80 ``` -------------------------------- ### Configure Format Voter for a Variation Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/variation-voters.rst Use the 'format' voter to restrict a variation to media of a specific file format. This example ensures the variation is only applied to 'jpeg' images. ```yaml joli_media: libraries: example_library: variations: profile_picture: transformers: thumbnail: width: 64 height: 64 voters: - type: format format: jpeg ``` -------------------------------- ### Enable Serving Original Media via PHP Source: https://github.com/jolicode/mediabundle/blob/main/doc/storage/storage.rst Set `enable_serve_using_php` to true in the storage configuration to allow the Symfony application to serve original media files. Be aware of potential performance impacts. ```yaml joli_media: libraries: private: enable_auto_webp: false original: enable_serve_using_php: true flysystem: "filesystem.private.original.storage" url_generator: strategy: folder path: /media/original/ cache: flysystem: "filesystem.private.cache.storage" url_generator: strategy: folder path: /media/cache/ variations: content: format: webp ``` -------------------------------- ### imagine Processor Configuration Source: https://context7.com/jolicode/mediabundle/llms.txt Configure the imagine processor for image manipulation. Specify the driver (gd, imagick, gmagick) and quality settings for JPEG and PNG. ```yaml imagine: # driver: imagick # gd | imagick | gmagick (default: gmagick) options: jpeg_quality: 80 png_quality: 80 quality: 80 ``` -------------------------------- ### Stop Demo Application Source: https://github.com/jolicode/mediabundle/blob/main/doc/getting-started/demo.rst Halt the demo application's Docker containers. ```bash $ castor demo:docker:stop ``` -------------------------------- ### Configure Filesize Voter for a Variation Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/variation-voters.rst Use the 'filesize' voter to restrict a variation to media within a specified byte range. This example sets a minimum and maximum file size for the variation to be applicable. ```yaml joli_media: libraries: example_library: variations: profile_picture: transformers: thumbnail: width: 64 height: 64 voters: - type: filesize min: 1024 max: 4096 ``` -------------------------------- ### Add Media Library to Sylius Admin Menu Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sylius.rst Implement an admin menu listener to add a link to the media library explore route in Sylius. ```php namespace App\Menu\Admin; use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; #[AsEventListener(event: 'sylius.menu.admin.main')] final class AdminMenuListener { public function __invoke(MenuBuilderEvent $event): void { $menu = $event->getMenu(); $this->addContentsSubMenu($menu); } private function addContentsSubMenu(ItemInterface $menu): void { ``` -------------------------------- ### Configure SonataAdmin Routes and Settings Source: https://context7.com/jolicode/mediabundle/llms.txt Define the resource path for SonataAdmin media controllers and configure JoliMediaBundle settings specific to SonataAdmin integration. ```yaml # config/routes/joli_media.yaml _joli_media_sonata_admin: resource: "@JoliMediaSonataAdminBundle/src/Controller/" prefix: /admin/media # config/packages/joli_media_sonata_admin.yaml joli_media_sonata_admin: pagination: per_page: 25 upload: max_files: 10 max_file_size: 20 accepted_files: - image/* visibility: show_variations_stored: true show_variations_action_regenerate: true show_html_code: true show_markdown_code: true ``` -------------------------------- ### Configure Media Variation Voters (YAML) Source: https://context7.com/jolicode/mediabundle/llms.txt Define rules for media eligibility in variations using built-in or composite voters. This example restricts JPEG files to a specific folder and size range, or PNG files. ```yaml joli_media: libraries: default: variations: profile_picture: transformers: thumbnail: width: 64 height: 64 voters: # Only apply to JPEG files in the user profile pictures folder - type: format format: jpg - type: oneOf voters: - type: mimeType mime_type: image/png - type: allOf voters: - type: folder path: uploaded-files/user-profile-pictures - type: filesize min: 5000 # bytes max: 100000 - type: allOf voters: - type: folder path: archive/user-profile - type: filesize min: 100000 max: 2000000 ``` -------------------------------- ### Add Media Library to EasyAdmin Menu Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/easy-admin.rst Include a link to the media library in the EasyAdmin dashboard menu using MenuItem::linkToRoute. ```php use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem; use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController; class DashboardController extends AbstractDashboardController { public function configureMenuItems(): iterable { // ... yield MenuItem::linkToRoute('Media Library', 'fa fa-image', 'joli_media_easy_admin_explore'); } } ``` -------------------------------- ### Configure Media Constraint Options Source: https://github.com/jolicode/mediabundle/blob/main/doc/misc-features/using-in-doctrine-entities.rst Customize the Media constraint with options like allowed extensions, MIME types, path prefixes, and maximum path length for more specific validation. ```php #[MediaConstraint( allowedExtensions: ['jpg', 'jpeg', 'png'], extensionMessage: 'Allowed extensions are: {{ extensions }}.', allowedMimeTypes: ['image/jpeg', 'image/png'], mimeTypeMessage: 'Allowed mime types are: {{ mimeTypes }}.', allowedPaths: ['illustration', 'avatar'], pathMessage: 'The file path "{{ value }}" is not allowed. Allowed paths must start with one of the following: {{ paths }}.', allowedTypes: ['image'], typeMessage: 'Allowed types are: {{ types }}.', maxPathLength: 255, maxPathLengthMessage: 'The file path "{{ value }}" exceeds the maximum length of {{ limit }} characters.', )] public ?Media $image = null; ``` -------------------------------- ### Configure OneOf Voter to Combine Voters Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/variation-voters.rst Use the 'oneOf' voter to allow the variation to be applied if at least one of the specified child voters returns true. This example allows the variation for either JPEG or PNG images. ```yaml joli_media: libraries: example_library: variations: profile_picture: transformers: thumbnail: width: 64 height: 64 voters: - type: oneOf voters: - type: format format: jpeg - type: format format: png ``` -------------------------------- ### Configure Post-processors for Image Optimization Source: https://context7.com/jolicode/mediabundle/llms.txt Define post-processors like jpegoptim, mozjpeg, pngquant, oxipng, and gifsicle to optimize generated image variations. Options can be set globally or overridden at library and variation levels. ```yaml joli_media: post_processors: jpegoptim: # binary: /usr/local/bin/jpegoptim # or env JOLI_MEDIA_JPEGOPTIM_BINARY options: strip_all: true progressive: true max_quality: 80 mozjpeg: options: optimize: true progressive: true quality: 80 pngquant: options: quality: 75-85 speed: 5 oxipng: options: optimization: 4 strip: [all] zopfli: false gifsicle: options: optimize: 3 lossy: 20 colors: 256 libraries: default: post_processors: jpegoptim: max_quality: 90 # library-level override variations: thumbnail: post_processors: jpegoptim: max_quality: 70 # variation-level override lossless_png: post_processors: pngquant: false # disable for this variation oxipng: false ``` -------------------------------- ### Customize Media Deletion Permissions Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/easy-admin.rst Override the canDelete method to define custom logic for when a user can delete a media item. This example shows how to grant John Doe unrestricted deletion, allow admins to delete from 'public-storage', and restrict other users from deleting from 'private/' paths. ```php use JoliCode\MediaBundle\Bridge\Security\Voter\MediaVoter as BaseMediaVoter; use Symfony\Component\DependencyInjection\Attribute\AsAlias; use Symfony\Component\Security\Core\User\UserInterface; #[AsAlias(id: 'joli_media_admin.security.voter')] class MediaVoter extends BaseMediaVoter { protected function canDelete(?UserInterface $user, string $libraryName, string $path): bool { if ('john.doe@example.com' === $user?->getUserIdentifier()) { // John Doe can delete any media return true; } if ('public-storage' === $libraryName) { // only users with the ROLE_ADMIN role can delete media in the public-storage library return \in_array('ROLE_ADMIN', $user?->getRoles() ?? [], true); } // other users cannot delete media in the private folder return !str_starts_with($path, 'private/'); } } ``` -------------------------------- ### Expand Image with Background Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Expands an image to a specified width and height by adding a background color. Useful for adding background to smaller images or achieving specific aspect ratios without distortion. Position can be set using pixels, percentages, or keywords like 'start', 'center', 'end'. ```yaml expand: width: 600 height: 400 background_color: red position_x: 100 position_y: end ``` -------------------------------- ### CLI: Convert and Generate Media Variations Source: https://context7.com/jolicode/mediabundle/llms.txt Generate media variations using the joli:media:convert command for individual files or joli:media:batch-convert for bulk operations. Options include specifying library, variation, and parallelization. ```bash # Generate all variations for a specific file php bin/console joli:media:convert photos/hero.jpg php bin/console joli:media:convert --library=default --variation=thumbnail photos/hero.jpg # Bulk-generate all variations (with parallelism for large libraries) php bin/console joli:media:batch-convert php bin/console joli:media:batch-convert --library=default --variation=thumbnail --force php bin/console joli:media:batch-convert --parallelization=4 --chunk-size=20 ``` -------------------------------- ### Configure Sonata Admin Integration Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sonata-admin.rst Set up the JoliMediaBundle integration for Sonata Admin, including pagination, upload limits, and feature visibility. ```yaml joli_media_sonata_admin: pagination: per_page: 25 upload: max_files: 10 max_file_size: 20 accepted_files: - image/* visibility: show_variations_stored: true show_variations_action_regenerate: true show_html_code: true show_markdown_code: true ``` -------------------------------- ### gif2webp Processor Configuration Source: https://context7.com/jolicode/mediabundle/llms.txt Configure the gif2webp processor for converting GIFs to WebP. Options include enabling lossy compression, metadata handling, and minimum size optimization. ```yaml gif2webp: options: lossy: true metadata: [none] min_size: true ``` -------------------------------- ### Configure Crop and Expand Transformers Source: https://github.com/jolicode/mediabundle/blob/main/doc/variations/transformers.rst Use these transformers to crop an image to a specific size and then expand it to new dimensions, optionally setting a background color. ```yaml transformers: crop: width: 60 height: 60 expand: width: 150 height: 200 background_color: '#ffccff' ``` -------------------------------- ### Generate Media URLs Programmatically Source: https://github.com/jolicode/mediabundle/blob/main/doc/misc-features/url-generation.rst Instantiate Media or MediaVariation objects and call getUrl() to generate relative or absolute paths. Ensure the Library instance is correctly passed. ```php use JoliCode\MediaBundle\Entity\Media; use JoliCode\MediaBundle\Entity\MediaVariation; use JoliCode\MediaBundle\Library\LibraryInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; // $library is an instance of JoliCode\MediaBundle\Library\Library. It can be retrived from the services container $media = new Media('example-image.png', $library); // absolute path echo $media->getUrl(); // absolute URL echo $media->getUrl(UrlGeneratorInterface::ABSOLUTE_URL); // $variation is an instance of JoliCode\MediaBundle\Variation\Variation $mediaVariation = new MediaVariation($media, 'variation_name'); echo $mediaVariation->getUrl(); echo $mediaVariation->getUrl(UrlGeneratorInterface::ABSOLUTE_URL); ``` -------------------------------- ### Default Library Configuration with Variations Source: https://context7.com/jolicode/mediabundle/llms.txt Defines the default media library with a 'profile_picture' variation. This variation enables auto-webp generation, supports multiple pixel ratios, maintains the original format, and applies JPEG optimization post-processing. It also includes a thumbnail transformer and a format voter. ```yaml joli_media: libraries: default: variations: profile_picture: enable_auto_webp: true # also generates profile_picture_webp pixel_ratios: [1, 2, 3] # also generates profile_picture@2x, @3x format: ~ processors: imagine: options: jpeg_quality: 99 post_processors: jpegoptim: options: strip_all: false max_quality: 60 transformers: thumbnail: width: 100 height: 100 voters: - type: format format: jpg ``` -------------------------------- ### Available Image Transformations Source: https://context7.com/jolicode/mediabundle/llms.txt Lists the available sequential image transformations that can be applied. These include crop, expand, heighten, resize, thumbnail, and widen. ```text Apply sequential image transformations: `crop`, `expand`, `heighten`, `resize`, `thumbnail`, `widen`. ``` -------------------------------- ### Media Event Listener for Pre-Delete and Pre-Resolve Operations Source: https://context7.com/jolicode/mediabundle/llms.txt An event listener that hooks into `PRE_DELETE_MEDIA` and `PRE_RESOLVE_MEDIA` events. Use `onPreDeleteMedia` to log or prevent deletion, and `onPreResolve` to rewrite legacy paths before media is resolved. ```php namespace App\EventListener; use JoliCode\MediaBundle\Event\MediaEvents; use JoliCode\MediaBundle\Event\PreDeleteMediaEvent; use JoliCode\MediaBundle\Event\PreResolveMediaEvent; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\Attribute\AsEventListener; class MediaEventListener { public function __construct(private readonly LoggerInterface $logger) {} // Runs before any media is deleted — use to log or prevent deletion #[AsEventListener(event: MediaEvents::PRE_DELETE_MEDIA)] public function onPreDeleteMedia(PreDeleteMediaEvent $event): void { $this->logger->info(sprintf('Media "%s" is about to be deleted.', $event->path)); // Throw an exception here to prevent deletion } // Runs before media is resolved — use to rewrite legacy paths #[AsEventListener(event: MediaEvents::PRE_RESOLVE_MEDIA)] public function onPreResolve(PreResolveMediaEvent $event): void { $legacyPrefix = 'legacy/prefix/'; if (str_starts_with($event->path, $legacyPrefix)) { $event->path = substr($event->path, strlen($legacyPrefix)); } } } // Available event constants in MediaEvents: // PRE_CREATE_MEDIA POST_CREATE_MEDIA // PRE_DELETE_MEDIA POST_DELETE_MEDIA // PRE_MOVE_MEDIA POST_MOVE_MEDIA // PRE_CREATE_FOLDER POST_CREATE_FOLDER // PRE_DELETE_FOLDER POST_DELETE_FOLDER // PRE_MOVE_FOLDER POST_MOVE_FOLDER // PRE_RESOLVE_MEDIA ``` -------------------------------- ### Resolve Media using Resolver Service Source: https://github.com/jolicode/mediabundle/blob/main/doc/misc-features/url-generation.rst Use the media resolver service to obtain Media or MediaVariation objects, which simplifies the process compared to manual instantiation. This is the recommended approach. ```php $resolver = $this->get('joli_media.resolver'); $media = $resolver->resolve('example-image.png', 'library_name'); $mediaVariation = $resolver->resolve('example-image.png', 'library_name', 'variation_name'); echo $media->getUrl(); echo $mediaVariation->getUrl(); ``` -------------------------------- ### Configure JoliMediaBundle Libraries Source: https://context7.com/jolicode/mediabundle/llms.txt Define named libraries, specifying original and cache storage, URL generation strategies, and variation definitions. The 'default' library is configured for local storage with auto WebP generation and pixel ratio support. ```yaml # config/packages/joli_media.yaml joli_media: default_library: default libraries: default: original: flysystem: filesystem.original.storage url_generator: strategy: folder path: /media/original/ enable_serve_using_php: false # set true for access-controlled media trash_path: .trash/ cache: flysystem: filesystem.cache.storage url_generator: strategy: folder path: /media/cache/ must_store_when_generating_url: false enable_auto_webp: true pixel_ratios: [1, 2] variations: thumbnail: transformers: thumbnail: width: 200 height: 200 product_banner: format: webp transformers: resize: width: 1200 height: 400 mode: outside private: original: flysystem: filesystem.original.storage enable_serve_using_php: true # serve via PHP for access control url_generator: path: /media/private/original/ cache: flysystem: filesystem.cache.storage url_generator: path: /media/private/cache/ ``` -------------------------------- ### Configure JoliMedia Sylius Integration Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sylius.rst Customize media upload, pagination, and visibility settings for the Sylius integration. ```yaml imports: - { resource: '@JoliMediaSyliusBundle/config/app.php' } joli_media_easy: pagination: per_page: [10, 25, 50] upload: max_files: 10 max_file_size: 20 accepted_files: - image/* - video/* - application/pdf visibility: show_variations_list: true show_variations_list_admin_variations: true show_variations_stored: true show_variations_action_regenerate: true show_html_code: true show_markdown_code: true ``` -------------------------------- ### Hero Image Transformation Configuration Source: https://context7.com/jolicode/mediabundle/llms.txt Sets up a 'hero' image variation using sequential transformations. It applies a resize transformation with 'outside' mode and then a thumbnail transformation, both to dimensions of 1920x1080. ```yaml hero: transformers: - type: resize width: 1920 height: 1080 mode: outside - type: thumbnail width: 1920 height: 1080 ``` -------------------------------- ### Configure Taxon Image Resource for Media Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sylius.rst Applies the EntityWithMediaImageTrait to the Sylius TaxonImage entity to integrate with the MediaBundle. ```diff namespace App\Entity\Taxonomy; use Doctrine\ORM\Mapping as ORM; use JoliCode\MediaBundle\Bridge\Sylius\Doctrine\ORM\EntityWithMediaImageTrait; use Sylius\Component\Core\Model\TaxonImage as BaseTaxonImage; #[ORM\Entity] #[ORM\Table(name: 'sylius_taxon_image')] class TaxonImage extends BaseTaxonImage { use EntityWithMediaImageTrait; } ``` -------------------------------- ### Define Sonata Admin Media Routes Source: https://github.com/jolicode/mediabundle/blob/main/doc/bridges/sonata-admin.rst Configure the routes for the media library within your Sonata Admin interface. ```yaml _joli_media_sonata_admin: resource: "@JoliMediaSonataAdminBundle/src/Controller/" prefix: /admin/media ``` -------------------------------- ### Configure Pre-processors in MediaBundle Source: https://context7.com/jolicode/mediabundle/llms.txt Register pre-processors, both built-in and custom, in the MediaBundle configuration. Pre-processors can be applied globally or scoped to specific variations. ```yaml # config/packages/joli_media.yaml joli_media: pre_processors: - JoliCode\MediaBundle\PreProcessor\ExifRemovalPreProcessor # built-in: strip EXIF - App\Media\PreProcessor\OgImagePreProcessor # custom libraries: default: variations: og_image: format: webp pre_processors: - App\Media\PreProcessor\ApplyWatermarkPreProcessor # variation-scoped transformers: resize: width: 1200 height: 630 mode: exact ```