pentatrion / upload-bundle
Upload Helper and File Manager for your Symfony App
Installs: 3 370
Dependents: 0
Suggesters: 0
Security: 0
Stars: 4
Watchers: 1
Forks: 0
Open Issues: 0
Type:symfony-bundle
Requires
- php: ^7.2.5 || ^8.0
- imagine/imagine: ^1.0
- liip/imagine-bundle: ^2.6
- symfony/config: ^4.4 || ^5.0 || ^6.0
- symfony/dependency-injection: ^4.4 || ^5.0 || ^6.0
- symfony/finder: ^4.4 || ^5.0 || ^6.0
- symfony/form: ^4.4 || ^5.0 || ^6.0
- symfony/framework-bundle: ^4.4 || ^5.0 || ^6.0
- symfony/http-kernel: ^4.4 || ^5.0 || ^6.0
- symfony/mime: ^4.4 || ^5.0 || ^6.0
- symfony/security-bundle: ^4.4 || ^5.0 || ^6.0
- symfony/serializer: ^4.4 || ^5.0 || ^6.0
- symfony/twig-bundle: ^4.4 || ^5.0 || ^6.0
- symfony/validator: ^4.4 || ^5.0 || ^6.0
Requires (Dev)
- phpstan/phpstan: ^1.4
Suggests
- imagine/imagine: required for image modification (resize, crop, rotation)
- liip/imagine-bundle: required to use thumbnails with your file manager
- symfony/security-bundle: required with Form
- symfony/validator: required for upload file validation
This package is auto-updated.
Last update: 2024-10-24 20:03:57 UTC
README
UploadBundle for your Symfony application.
This Symfony bundle provides :
- Upload Helpers
- Endpoints for a Mini File Manager in your Symfony Application.
- Twig functions for your uploaded files
- FilePickerType for your forms
Installation
composer require pentatrion/upload-bundle
Recommended optional dependencies
- symfony/validator : required for upload file validation
- liip/imagine-bundle : required to use thumbnails with your file manager.
- imagine/imagine : required for image modification (resize, crop, rotation)
composer require symfony/validator liip/imagine-bundle imagine/imagine
Other dependencies
- symfony/security-bundle : only required with FilePickerType
If you have installed liip/imagine-bundle
, configure at least the small
filter for your thumbnails.
# config/packages/pentatrion_upload.yaml # default configuration pentatrion_upload: liip_filters: ["small"]
# config/packages/liip_imagine.yaml liip_imagine: driver: "gd" # define filters defined in pentatrion_upload.liip_filters filter_sets: small: filters: thumbnail: { size: [250, 250], mode: inset, allow_upscale: true }
Create directories with Apache user access in upload path and liipImagineBundle cache path (public/uploads
, public/media
)
mkdir public/{uploads,media} chmod 777 public/{uploads,media}
Utilisation
FileHelper
in your FormType create a non mapped FileType
use App\Entity\Post; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\FormBuilderInterface; class PostType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder // ... ->add('image', FileType::class, [ 'mapped' => false, 'required' => false ]) ; } // ... }
in your Controller
class PostController extends AbstractController { /** * @Route("/{id}/edit", name="post_edit", methods={"GET","POST"}) */ public function edit(Request $request, Post $post, FileHelper $fileHelper): Response { $form = $this->createForm(PostType::class, $post); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $image = $form['image']->getData(); if ($image) { /** @var UploadedFile $uploadedFile */ $uploadedFile = $fileHelper->uploadFile($image, 'posts'); // posts/my-image.jpg $post->setImagePath($fileInfos->getUploadRelativePath()); } $this->getDoctrine()->getManager()->flush(); // ... } // ... } }
$file // file from $_FILES $directory = 'relative/path'; // path to add into public_uploads. // configured in config/packages/pentatrion_upload.yaml // pentatrion_upload.origins.<origin> // default value public_uplads -> "%kernel.project_dir%/public/uploads" $originName = 'public_uploads'; $options = [ 'forceFilename' => 'beach.jpg', 'prefix' => null, // prefix your file name 'img-' 'guessExtension' => false, // guess Extension from content //(if you don't trust the uploader) 'urlize' => true, // my File Name.jPg -> my-file-name.jpg 'unique' => true, // suffixe your file with hash // beach-[hash].jpg ]; $fileInfos = $fileHelper->uploadFile($file, $directory, $originName, $options); print_r($fileInfos);
{ "id": null, "liipId": "@public_uploads:beach.jpg", "mimeGroup": "image", "mimeType": "image/jpeg", "filename": "beach.jpg", "directory": "", "origin": "public_uploads", "imageWidth": 1200, "imageHeight": 1200, "type": "file", "size": 134558, "updatedAt": "2021-08-07T23:12:09+02:00", "icon": "image-jpg.svg", "public": false, "absolutePath": null, "uploadRelativePath": "beach.jpg" }
Twig functions
The bundle provide 2 twig functions :
- uploaded_file_web_path('path/to/file', '')
- uploaded_image_filtered('path/to/file', 'filter', '')
class PageController extends AbstractController { #[Route('/page/{slug}', name: 'page_show')] public function show(Page $page): Response { return $this->render('page/show.html.twig', [ 'page' => $page ]); }
in your page/show.html.twig
template
<!-- folder/my-uploaded-file.pdf --> {{ page.imagePath }} <!-- /uploads/folder/my-uploaded-file.pdf --> {{ uploaded_file_web_path(page.imagePath) }} <!-- /media-manager/get/show/private_uploads/folder/my-uploaded-file.pdf --> {{ uploaded_file_web_path(page.imagePath, "private_uploads") }} <!-- for your original --> <!-- <img src="/uploads/folder/logo.jpg"/> --> <img src="{{ uploaded_file_web_path(page.imagePath) }}"/> <!-- for your cropped image (250x250px) --> <!-- <img src="http://localhost/media/cache/resolve/small/posts/logo.jpg"/> --> <img src="{{ uploaded_image_filtered(page.imagePath, 'small') }}"/> <!-- <img src="http://localhost/media/cache/resolve/small/posts/logo.jpg"/> --> <img src="{{ uploaded_image_filtered(page.imagePath, 'small', 'private_uploads') }}"/>
with Mini File Manager JS library.
this bundle has been designed to integrate perfectly with Mini File Manager.
He offers /media-manager
endpoint for the backend integration.
npm i mini-file-manager
without helpers
<head> <link rel="stylesheet" href="/dist/style.css" /> </head> <body> <div id="file-manager"></div> <script type="module"> import { fileManager } from "mini-file-manager"; let config = { "endPoint": "/media-manager", "entryPoints": [ { "directory": "", "origin": "public_uploads", "readOnly": false, "icon": "fa-lock", "label": "Uploads", "webPrefix": "/uploads" } ] }; fileManager("#file-manager", config); </script> </body>
with helpers
use Pentatrion\UploadBundle\Service\FileManagerHelper; class ManagerController extends AbstractController { #[Route('/manager', name: 'manager')] public function index(FileManagerHelperInterface $fileManagerHelper): Response { $config = $fileManagerHelper->completeConfig([ 'entryPoints' => [ [ 'label' => 'Uploads', 'directory' => '', 'origin' => 'public_uploads', 'readOnly' => false, 'icon' => 'fa-lock' ] ], 'fileUpload' => [ 'maxFileSize' => 10 * 1024 * 1024, ], ]); return $this->render('manager/index.html.twig', [ 'fileManagerConfig' => $config, ]); } }
Twig template for the file manager. the mini-file-manager config is placed in data-props attribute.
<head> <link rel="stylesheet" href="/dist/style.css" /> </head> <body> <div id="file-manager" data-minifilemanager="{{ fileManagerConfig | json_encode | e('html_attr') }}"></div> <script type="module"> import { fileManager } from "mini-file-manager"; fileManager("#file-manager"); </script> </body>
Twig template for the file picker.
<head> <link rel="stylesheet" href="/dist/style.css" /> </head> <body> <button id="find-file" data-minifilemanager="{{ fileManagerConfig | json_encode | e('html_attr') }}">Find</button> <script type="module"> import { fileManagerModal } from "mini-file-manager"; let pickerElt = document.querySelector("#file-picker"); let options = JSON.parse(pickerElt.dataset.minifilemanager); pickerElt.addEventListener("click", () => { fileManagerModal(options, (selectedFiles) => { console.log(selectedFiles); }); }) </script> </body>
If you want more details about configuration, check Mini File Manager.
If you want exemple, check Mini File Manager Template
FilePickerType with mini-file-manager for your form
use Pentatrion\UploadBundle\Form\TextFilePickerType; class AdminUserFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('poster', TextFilePickerType::class, [ 'required' => false, 'fileManagerConfig' => [ 'entryPoints' => [ [ 'label' => 'Uploads', 'directory' => 'form', 'origin' => 'public_uploads', ], ], 'fileUpload' => [ 'maxFileSize' => 512 * 1024 * 1024, ], 'fileValidation' => [ 'imageOptions' => [ 'ratio' => 1, ], ], 'multiple' => false ], ]) ; } }
for full-list of imageOptions, have a look into mini-file-manager#Configuration repository.
add custom form theme for your form builder :
# config/packages/twig.yaml twig: default_path: "%kernel.project_dir%/templates" form_themes: ["_form_theme.html.twig"]
look at _form_theme.html.twig
{# templates/_form_theme.html.twig #} {%- block file_picker_widget -%} {%- set attr = attr|merge({ class: (attr.class|default('') ~ ' file-picker')|trim, 'data-files': files, 'data-minifilemanager': filemanager_config, 'data-formpreview': formpreview_config }) -%} {{- block('form_widget_simple') -}} {%- endblock -%}
Advanced Bundle Configuration
configure your upload directories
package configuration
# config/packages/pentatrion_upload.yaml pentatrion_upload: # Advanced config # must implement UploadedFileHelperInterface uploaded_file_helper: 'App\Service\AppUploadedFileHelper' origins: # choose the name of your choice public_uploads: # if directory is inside %kernel.project_dir%/public, files # will be directly accessible. path: "%kernel.project_dir%/public/uploads" # prefix to add in order to be found by a liip_imagine loader liip_path: "/uploads" private_uploads: path: "%kernel.project_dir%/var/uploads" liip_path: "" # if multiple origins default_origin: "public_uploads" # when you get infos from uploaded file put filters (liip_imagine.filter_sets) # you want the url used with mini-file-manager, put "small" to get thumbnails liip_filters: ["small", "large"]
if you set your class who implement UploadedFileHelperInterface (file_infos_helper
option), you can extends UploadedFileHelper base class.
<?php namespace App\Service; use Pentatrion\UploadBundle\Service\UploadedFileHelper; class AppUploadedFileHelper extends UploadedFileHelper { }
You have to add 3 binding for your constructor
#config/services.yaml services: # default configuration for services in *this* file _defaults: autowire: true # Automatically injects dependencies in your services. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. bind: $liipFilters: "%pentatrion_upload.liip_filters%" $defaultOriginName: "%pentatrion_upload.default_origin%" $uploadOrigins: "%pentatrion_upload.origins%"
Manual installation
composer require pentatrion/vite-bundle
if you do not want to use the recipe or want to see in depth what is modified by it.
add upload routes to your Symfony app.
# config/routes/pentatrion_upload.yaml # routes starting with /media-manager _pentatrion_upload: prefix: /media-manager resource: "@PentatrionUploadBundle/Resources/config/routing.yaml"
add a config file for your bundle
# config/packages/pentatrion_upload.yaml # default configuration pentatrion_upload: uploaded_file_helper: 'Pentatrion\UploadBundle\Service\UploadedFileHelper' origins: public_uploads: path: "%kernel.project_dir%/public/uploads" liip_path: "/uploads" # update to ["small"] if you have installed liip/imagine-bundle liip_filters: []
if you have installed liip/imagine-bundle add the small filter.
# config/packages/liip_imagine.yaml liip_imagine: driver: "gd" # define filters defined in pentatrion_upload.liip_filters # (at least small filter) filter_sets: small: filters: thumbnail: { size: [250, 250], mode: inset, allow_upscale: true } loaders: default: filesystem: data_root: # must be linked with pentatrion_upload -> origin.[origin-name].liip_path - "%kernel.project_dir%/public"