Installation:
composer require arkounay/image-bundle
(Note: Despite being archived, this package works with Symfony 3.x and Doctrine ORM.)
Register Bundle:
Add to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
Arkounay\ImageBundle\ArkounayImageBundle::class => ['all' => true],
Assets & Routing:
php bin/console assets:install
Add to config/routes.yaml:
arkounay_image:
resource: "@ArkounayImageBundle/Resources/config/routing.yml"
Doctrine Types:
In config/packages/doctrine.yaml:
doctrine:
dbal:
types:
json_image: Arkounay\ImageBundle\Type\JsonImageType
json_images: Arkounay\ImageBundle\Type\JsonImagesType
Entity Setup:
use Arkounay\ImageBundle\Entity\Image;
use Doctrine\Common\Collections\ArrayCollection;
class Product
{
/**
* @ORM\Column(type="json_image")
*/
private $thumbnail;
/**
* @ORM\Column(type="json_images")
*/
private $gallery;
public function __construct()
{
$this->gallery = new ArrayCollection();
}
}
Form Integration:
use Arkounay\ImageBundle\Form\JsonImageType;
use Arkounay\ImageBundle\Form\JsonImagesType;
$builder
->add('thumbnail', JsonImageType::class, [
'allow_alt' => true,
'path_readonly' => false,
])
->add('gallery', JsonImagesType::class, [
'min' => 1,
'max' => 5,
]);
Twig Template:
<link rel="stylesheet" href="{{ asset('bundles/arkounayimage/arkounay_image_bundle.css') }}">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
{% include '@ArkounayImage/assets/include_js.html.twig' %}
Form Submission:
The bundle handles file uploads via AJAX (jQuery-dependent). The JsonImageType/JsonImagesType automatically:
max_size in config).Entity Hydration:
// After form submission, Doctrine persists:
// {
// "path": "/uploads/product_123.jpg",
// "alt": "Product Thumbnail",
// "mime": "image/jpeg"
// }
Displaying Images:
{% for image in product.gallery %}
<img src="{{ asset(image.path) }}" alt="{{ image.alt }}">
{% endfor %}
# config/easy_admin.yaml
properties:
imageCollection:
type: Arkounay\ImageBundle\Form\JsonImagesType
type_options:
allow_add: true
Image entity to add constraints:
use Symfony\Component\Validator\Constraints as Assert;
class Product
{
/**
* @Assert\File(maxSize="2048k")
*/
private $thumbnail;
}
config/packages/arkounay_image.yaml:
arkounay_image:
upload_dir: '%kernel.project_dir%/public/uploads/custom_path'
Leverage ninsuo/symfony-collection options for dynamic collections:
$builder->add('gallery', JsonImagesType::class, [
'init_with_n_elements' => 3, // Pre-populate with 3 empty fields
'add_at_the_end' => false, // Add new items at the top
]);
Deprecated Dependencies:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
JSON Column Quirks:
json type (used internally) may not support all database backends (e.g., SQLite). Test with PostgreSQL/MySQL.json_image fields.File Permissions:
Ensure the upload directory (%kernel.project_dir%/public/uploads) is writable:
chmod -R 775 public/uploads
EasyAdminBundle Conflicts: If using EasyAdmin, ensure the bundle’s JS doesn’t conflict with EasyAdmin’s collection widgets. Disable EasyAdmin’s collection JS for these fields:
{% block easyadmin_collection_widget %}
{% if form.vars.type.class is not same as('Arkounay\ImageBundle\Form\JsonImagesType') %}
{{ parent() }}
{% endif %}
{% endblock %}
AJAX Failures: Check the browser’s Network tab for 403/500 errors. Common causes:
ROLE_ADMIN (default). Override in config/packages/arkounay_image.yaml:
arkounay_image:
roles: ['ROLE_USER'] # Example: Allow all users
{{ form_row(form._token) }}
Doctrine Errors:
If json_image fails to persist, verify:
Image entity is properly mapped (e.g., use Arkounay\ImageBundle\Entity\Image).json_image (not json).Stale Assets: Clear cache after updates:
php bin/console cache:clear
php bin/console assets:clear
Custom Image Entity:
Extend the Image entity to add fields (e.g., width, height):
namespace App\Entity;
use Arkounay\ImageBundle\Entity\Image as BaseImage;
class ExtendedImage extends BaseImage
{
/**
* @ORM\Column(type="integer")
*/
private $width;
}
Update the Doctrine type to handle the extended class.
Override Templates:
Copy Resources/views/forms/fields.html.twig to your theme to customize the upload widget. Example: Add a preview thumbnail:
{% block arkounay_image_widget %}
<div class="image-preview">
{% if form.vars.data.path %}
<img src="{{ asset(form.vars.data.path) }}" width="100">
{% endif %}
</div>
{{ parent() }}
{% endblock %}
Post-Upload Processing:
Hook into the upload process by extending the ImageUploader service:
# config/services.yaml
Arkounay\ImageBundle\Service\ImageUploader:
class: App\Service\CustomImageUploader
decorates: arkounay_image.image_uploader
arguments: ['@arkounay_image.image_uploader']
namespace App\Service;
use Arkounay\ImageBundle\Service\ImageUploader as BaseUploader;
class CustomImageUploader extends BaseUploader
{
public function upload($file, $path)
{
// Add logic (e.g., resize images) before parent upload
$this->resizeImage($file);
return parent::upload($file, $path);
}
}
Configuration Overrides:
Override default settings (e.g., allowed MIME types) in config/packages/arkounay_image.yaml:
arkounay_image:
allowed_mime_types: ['image/jpeg', 'image/png', 'image/gif']
max_size: 5120 # 5MB
How can I help you explore Laravel packages today?