Media bundle
Introduction
The media bundle provide an api to handle and store files. With the file entity, it is easy to reference files in others entities. The bundle provide also function to change images.
Installation
$ composer require enhavo/media-bundle
$ yarn add @enhavo/media
# assets/admin/container.di.yaml
imports:
- path: '@enhavo/media/services/admin/*'
# assets/theme/container.di.yaml
imports:
- path: '@enhavo/media/services/theme/*'
File entity
The File
entity or FileInterface
represents a single file. As it is an entity, it is easy to attach a file to other entities. Just add a doctrine mapping.
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Enhavo\Bundle\MediaBundle\Model\FileInterface;
#[ORM\Entity]
class Book
{
#[ORM\ManyToOne(targetEntity: FileInterface::class, cascade: ['all'])]
public FileInterface $cover;
#[ORM\ManyToMany(targetEntity: FileInterface::class, cascade: ['all'])]
#[ORM\JoinTable(name: 'app_book_images')]
public Collection $images;
public function __construct() {
$this->images = new ArrayCollection();
}
}
Warning
Because the owning side should always be the entity that reference the file, you can't use oneToMany
. For multiple files you should use ManyToMany
instead!
If a file should be uploaded by a user, you can easily use the Media
form type.
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Enhavo\Bundle\MediaBundle\Form\Type\MediaType;
class BookType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('cover', MediaType::class);
$builder->add('images', MediaType::class, [
'multiple' => true,
])
}
}
Or use the FileFactory
to create a file and store it an entity. The Factory comes with a few functions to create a File
from different sources. If you need the FileFactory
in a service, you can just inject it.
use App\Entity\Book;
use Enhavo\Bundle\MediaBundle\Factory\FileFactory;
use Enhavo\Bundle\MediaBundle\Model\FileInterface;
use Enhavo\Bundle\ResourceBundle\Resource\ResourceManager;
/** @var FileFactory $fileFactory */
/** @var FileInterface $otherFile */
/** @var ResourceManager $resourceManager */
/** @var Book $book */
// download a file
$file = $fileFactory->createFromUri('https://domain.tld/file.png');
// create from path
$file = $fileFactory->createFromPath('/path/to/file.png');
// copy from another file
$file = $fileFactory->createFromFile($otherFile);
// attach file to entity
$book->cover = $file;
// save the book
$resourceManager->save($book);
// to store only the file you can save the file
// directly with the resource manager
$resourceManager->save($file);
Storage
As we already learn, the file entity represents a single file and therefor it can be saved to the database, but where are the content of the file will be stored? First of all, if you create a file entity, weather by the factory or form, it will never touch or move the original file. If the file entity will be saved to the database, the storage will copy the file to an internal storage and then the file entity reference to that stored file. If you retrieve a file entity from the database, it will reference to the stored file automatically. This is all done by doctrine hooks, so this happens also if you work with doctrine directly.
Format
File formats are variants of media files. In order to keep the original file untouched, we use formats to change the content of files and save them separate.
To create a format we apply filters on the original file. If we want to use a set of different filters, we chain them together.
Enhavo comes already with a set of filters, that covers most use cases. That includes resizing, compression and preview images out of pdfs and videos. For a full list of all filters check reference
Define formats under enhavo_media.formats
config.
# config/packages/enhavo_media.yaml
enhavo_media:
formats:
# single type
header:
type: image
width: 800
height: 350
format: jpg
# chained types
hero:
-
type: image
max_width: 1920
-
type: image_compression
Twig
The media bundle provide the media_url
function to get the image url. The first parameter is the normalized file, the second the name of the format or null, if you want to use the original file. With third parameter tells if url is absolute or the path is absolute or relative.
<!-- url to original file -->
<img src="{{ media_url(file) }}">
<!-- url to the format header -->
<img src="{{ media_url(file, "header") }}">
<!-- absolute url to the original file -->
<img src="{{ media_url(file, null, constant('Symfony\\Component\\Routing\\Generator::ABSOLUTE_URL')) }}">
Further functions are media_filename
, media_parameter
or media_is_picture
<!-- print the filename -->
<p>{{ media_filename(file) }}</p>
<!-- print the alt parameter -->
<img alt="{{ media_parameter(file, "alt") }}" src="..." />
<!-- check if the file is a picture -->
{% if media_is_picture(file) %}<img src="..." />{% else %}<a href="..." />{% endif %s}
FormType
The media bundle comes with the MediaType
form type, to make it easy to build a upload form.
use Enhavo\Bundle\MediaBundle\Form\Type\MediaType;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', MediaType::class);
}
Configuration
By default, the MediaType
uses the default
configuration, which you can change to your own needs. You can also use multiple configurations and attach these configs to the MediaType
.
# config/packages/enhavo_media.yaml
enhavo_media:
form:
# default config, which can be overwritten
default:
upload: true
route: enhavo_media_admin_api_file_upload
actions_file:
download:
type: media_download
format:
type: media_format
actions: []
parameters_type: Enhavo\Bundle\MediaBundle\Form\Type\FileParametersType
parameters_options: []
# add your own config key
my_custom_config:
parameters_type: App\Form\Type\FileParametersType
Use the config key my_custom_config
as option of MediaType
.
use Enhavo\Bundle\MediaBundle\Form\Type\MediaType;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', MediaType::class, [
'config' => 'my_custom_config'
]);
}
It is also possible to directly overwrite the config in MediaType
.
use Enhavo\Bundle\MediaBundle\Form\Type\MediaType;
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file', MediaType::class, [
'config' => 'my_custom_config',
'upload' => false,
'actions_file' => [],
]);
}
Commands
The Media bundle provide a few command line tools.
Refreshing
If you change filter setting or the code was changed. You need to refresh your formats.
app/console enhavo:media:refresh-format --format="myFormatName"
You can also use the --id
option to target a file.