ranky / media-bundle
为 Symfony 提供的完整且友好的媒体文件管理器
Requires
- php: >=8.1
- ext-xml: *
- doctrine/doctrine-bundle: ^2.0
- doctrine/orm: ^2.6
- intervention/image: ^2.4
- ranky/shared-bundle: ^2.1
- spatie/image-optimizer: ^1.1
- symfony/form: ^5.4 || ^6.0 || ^7.0
- symfony/framework-bundle: ^5.4 || ^6.0 || ^7.0
- symfony/mime: ^5.4 || ^6.0 || ^7.0
- symfony/monolog-bundle: ^3.8.0
- symfony/security-bundle: ^5.4 || ^6.0 || ^7.0
- symfony/translation: ^5.4 || ^6.0 || ^7.0
- symfony/twig-bundle: ^5.4 || ^6.0 || ^7.0
- symfony/uid: ^5.4 || ^6.0 || ^7.0
- symfony/validator: ^5.4 || ^6.0 || ^7.0
- symfony/webpack-encore-bundle: ^1.16 || ^2.0
Requires (Dev)
- dg/bypass-finals: ^1.4
- doctrine/doctrine-fixtures-bundle: ^3.4
- friends-of-behat/mink-browserkit-driver: ^1.6
- friends-of-behat/mink-extension: ^2.7
- friends-of-behat/symfony-extension: ^2.3
- mtdowling/jmespath.php: ^2.6
- phpunit/phpunit: ^9.5
- psr/log: ^1.0 | ^2.0
- symfony/dotenv: ^5.4 || ^6.0 || ^7.0
- symfony/http-kernel: ^5.4 || ^6.0 || ^7.0
- symfony/phpunit-bridge: ^5.4 || ^6.0 || ^7.0
Suggests
- ext-exif: required to read EXIF metadata from images and required to use the GD driver
- ext-gd: required to use the GD driver
- ext-imagick: Recommended and required to use the Imagick driver
This package is auto-updated.
Last update: 2024-09-09 22:27:40 UTC
README
MediaBundle 是一个带有 REST API 和管理界面(React)的用于 Symfony 的媒体文件管理器包。它提供了一种干净且用户友好的方式来上传、编辑和删除文件。它支持多种格式。您可以上传图片、视频、音频、文档、zip 文件等。
MediaBundle 会自动压缩您的媒体文件以减小其大小,同时不牺牲质量。此外,它还提供了调整媒体文件大小的功能,以适应特定的尺寸(断点),这使得确保您的图片大小适合您的网站变得很容易。
MediaBundle 还与您的数据库集成,以高效地存储和管理媒体文件。这意味着您可以在一个地方跟踪所有媒体资产,类似于 WordPress 管理媒体文件的方式。这样,您就可以在一个地方组织和管理所有媒体文件。
目录
视频
ranky-media-bundle-compress.mp4
ranky-media-bundle-easyadmin.mp4
优点
- 在具有 Symfony 5.4, ^6.0 和 7.0 的项目中进行了测试(需要修复一些弃用项)
- 用于简单集成的 Symfony 表单类型
- EasyAdmin 集成
- TinyMCE 集成
特性
- 用户友好的界面
- 提供广泛的配置选项,允许您根据需要自定义其行为
- 单次或多次上传
- 拖放
- 列表或网格视图
- 编辑 alt、标题和名称
- 单次和批量删除
- 搜索过滤器
- 使用不同的表单类型选择单个或多个媒体
- 按日期排序。不久我将添加更多排序选项
- 防止媒体文件名重复
- 上传时调整图像大小,支持
- Imagick 扩展
- GD 扩展
- 图像压缩,支持
- Jpegoptim
- Optipng
- Pngquant
- Gifsicle
- Svgo
- Cwebp
- 使用以下默认大小生成 4 种类型的断点(响应式格式)的缩略图
- 大号: [1024],我只放宽度,因为这样可以自动按比例计算高度。尽管您可以更改它,但您可以在 配置 中看到它
- 中号 [768]
- 小号 [576]
- 超小号 [130, 130]
要求
- PHP 8.1 或更高版本
- Symfony 5.4 或更高版本
- Doctrine ORM(MySQL、MariaDB、SQLite、PostgreSQL)
- Imagick 或 GD 扩展:**推荐 Imagick 扩展**,因为它支持的格式比 GD 扩展更多
- 可选压缩工具
- Jpegoptim
- Optipng
- Pngquant
- Gifsicle
- Svgo
- Cwebp
Imagick 扩展
要求
Imagick 扩展需要您的系统上安装了 imagemagick
库。如果您不打算使用 Docker,请注意许多发行版都带有过时的 imagemagick
和没有 WebP
支持的版本。您很可能会需要手动编译它
Ubuntu 示例
sudo apt-get update sudo apt-get install build-essential
sudo apt-get install pkg-config libx11-dev libxext-dev libxt-dev liblcms2-dev libwmf-dev libjpeg-dev libpng-dev libgif-dev libfreetype6-dev libtiff5-dev libwebp-dev libzip-dev
wget https://imagemagick.org.cn/download/ImageMagick.tar.gz tar xvzf ImageMagick.tar.gz cd ImageMagick-7.* ./configure make sudo make install identify -version identify -version | grep webp
Docker: Dockerfile
安装 Imagick 扩展
案例 Docker
案例 Pecl
sudo pecl install imagick
如果未自动启用,请启用该扩展 👀
; php.ini extension=imagick.so
验证安装
php -m | grep imagick php -r 'phpinfo();' | grep imagick php -r 'phpinfo();' | grep ImageMagick
压缩工具
这些工具中没有任何一个是强制性的;它是否需要优化镜像取决于需求。
sudo apt-get install jpegoptim sudo apt-get install optipng sudo apt-get install pngquant sudo apt-get install gifsicle sudo apt-get install webp
安装
composer require ranky/media-bundle
当我在创建 Symfony Flex 的配方时,以下是需要遵循的步骤
步骤 1:在内核中启用捆绑包
尽管这一步应该自动完成。
# config/bundles.php return [ // ... Ranky\MediaBundle\RankyMediaBundle::class => ['all' => true], ];
步骤 2:导入路由
YAML
# config/routes/ranky_media.yaml ranky_media: resource: "@RankyMediaBundle/config/routes.php" prefix: /admin # Optional: The same prefix you use when importing the routes must be the "api_prefix" in the bundle options.
PHP
# config/routes/ranky_media.php use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator; return static function (RoutingConfigurator $routes) { $routes ->import('@RankyMediaBundle/config/routes.php') // annotation or attributes ->prefix('/admin') ; };
步骤 3:创建以下文件,并为您自己的应用程序进行配置。
提供的最小配置已在配置中,您将看到所有选项。
YAML
# config/packages/ranky_media.yaml ranky_media: media_entity: App\Entity\Media user_entity: App\Entity\User api_prefix: /admin
PHP
# config/packages/ranky_media.php return static function (RankyMediaConfig $rankyMediaConfig) { $rankyMediaConfig ->mediaEntity(Media::class) ->userEntity(User::class) ->apiPrefix('/admin') // Optional: The same prefix you use when importing the routes must be the same here ; };
步骤 4:媒体实体和仓库
# src/Entity/Media.php use Doctrine\ORM\Mapping as ORM; use Ranky\MediaBundle\Domain\Model\Media as BaseMedia; #[ORM\Table(name: 'ranky_media')] #[ORM\Entity(repositoryClass: MediaRepository::class)] class Media extends BaseMedia { }
# src/Repository/MediaRepository.php class MediaRepository extends DoctrineOrmMediaRepository { public function __construct( ManagerRegistry $registry, DoctrineCriteriaBuilderFactory $doctrineCriteriaBuilderFactory, UidMapperPlatform $uidMapperPlatform, ) { parent::__construct( $registry, $doctrineCriteriaBuilderFactory, $uidMapperPlatform, Media::class ); } }
步骤 5(可选):添加自定义 Dbal 类型
目前,LoadClassMetadata
事件负责加载自定义 DBAL 类型。如果此事件不起作用,您可以使用以下示例手动添加自定义函数
注意:此事件订阅者可能在未来被移除。
PHP
// config/packages/doctrine.php // Sqlite use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Sqlite\MimeSubType; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Sqlite\MimeType; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Sqlite\Month; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Sqlite\Year; // MySQL use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Mysql\MimeSubType; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Mysql\MimeType; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Mysql\Month; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Mysql\Year; // Postgres use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\MimeSubTypee; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\MimeType; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\Month; use Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\Year; use Symfony\Config\DoctrineConfig; return static function (DoctrineConfig $doctrineConfig): void { // ... $orm = $doctrineConfig->orm(); $em = $orm->entityManager('default'); $dql = $em->dql(); $dql->stringFunction('MIME_TYPE', MimeType::class); $dql->stringFunction('MIME_SUBTYPE', MimeSubType::class); $dql->datetimeFunction('YEAR', Year::class); $dql->datetimeFunction('MONTH', Month::class); }
YAML
# config/packages/doctrine.yaml doctrine: orm: dql: string_functions: MIME_TYPE: Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\MimeType MIME_SUBTYPE: Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\MimeSubType datetime_functions: YEAR: Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\Year MONTH: Ranky\MediaBundle\Infrastructure\Persistence\Dql\Postgresql\Month
步骤 5:架构更新和资产安装
php bin/console doctrine:schema:update --force php bin/console assets:install
配置
带有默认值的完整配置
所有选项都是可选的,但如果不希望包含访客用户在用户过滤器中,则必须配置 user_entity
。另外,也需要 media_entity
。默认值为 App\Entity\Media
,利用此选项,您可以使用自己的实体。
# config/packages/ranky_media.php return static function (RankyMediaConfig $rankyMediaConfig) { $rankyMediaConfig ->mediaEntity(Media::class) ->userEntity(User::class) ->userIdentifierProperty('username') ->apiPrefix(null) ->uploadDirectory('%kernel.project_dir%/public/uploads') ->uploadUrl('/uploads') ->paginationLimit(30) ->dateTimeFormat('Y-m-d H:i') ->mimeTypes([]) ->maxFileSize(7340032) ->disableCompression(false) ->compressOnlyOriginal(false) ; $rankyMediaConfig->image() ->resizeDriver(ImageResizeDriver::IMAGICK->value) ->resizeGifDriver(GifResizeDriver::NONE->value) ->quality(80) ->originalMaxWidth(1920) ->breakpoints() ->large([1024]) ->medium([768]) ->small([576]) ->xsmall([130, 130]) ; };
配置说明
user_entity(字符串,默认:App\Entity\User
)
这是用户实体类的完全限定名称(FQCN)。如果您使用不同的 UserIdentifier,则需要此名称以获取用户名,并且因此能够通过用户筛选媒体。
示例: User::class
media_entity(字符串,默认:App\Entity\Media
)这是媒体实体类的完全限定名称(FQCN)。为了使用自己的实体,这是必需的。
user_identifier_property(字符串,默认:username
)
这是包含用户标识符的用户实体属性。如果与 username
不同,则需要此属性。
date_time_format(字符串,默认:Y-m-d H:i
)
这是在列表视图和媒体模态中显示媒体创建和更新日期的格式。
api_prefix(字符串,默认:null
)
如果您想带有前缀(如 "/admin")导入捆绑包路由,以遵循某些类型的约定在您的管理或面板中,则此选项是必需的。
请参阅安全部分了解更多信息
此配置还将创建一个全局 twig 变量(ranky_media_api_prefix
),您可以在模板中稍后使用它。
示例: /admin
upload_directory(字符串,默认:%kernel.project_dir%/public/uploads
)
这是上传文件将存储的目录。
示例: %kernel.project_dir%/public/uploads
upload_url(字符串,默认:/uploads
)
这是上传文件可访问的 URL。
示例: /uploads
或 https://mydomain.test/uploads
mime_types(数组,默认:[]
)
这是一个允许的 MIME 类型的数组。空数组表示允许所有 MIME 类型。
示例
- []
- ['image/jpeg', 'image/png', 'application/pdf']
- ['image/*']
- ['.jpg', '.pdf']
disable_compression(布尔值,默认:false
)
这允许您禁用压缩,以避免在调整大小后产生的小开销。
compress_only_original(布尔值,默认:false
)
这将仅压缩原始图像,并将忽略缩略图。这是一个不错的选择,因为缩略图已经相当小,有时可能没有必要压缩它们。
max_file_size(整数,默认:7340032
)
这是允许的最大文件大小(字节)。默认值是 7340032(7 MB)。
pagination_limit(整数,默认:30
)
这是在媒体文件管理器中每页显示的项目数。默认值是 30。
image
这是图像设置的配置。
resize_driver(枚举,默认:ImageResizeDriver::IMAGICK->value
)
这是用于图像缩放的驱动程序。可用的驱动程序有
- imagick
ImageResizeDriver::IMAGICK->value
- gd
ImageResizeDriver::GD->value
resize_gif_driver(枚举,默认:GifResizeDriver::NONE->value
)
这是用于 GIF 图像缩放的驱动程序。可用的驱动程序有
- 无
GifResizeDriver::NONE->value
- ffmpeg
GifResizeDriver::FFMPEG->value
- gifsicle
GifResizeDriver::GIFSICLE->value
- imagick
GifResizeDriver::IMAGICK->value
quality(整数,默认:80
)
这是图像压缩的质量。默认值是 80。
original_max_width(整数,默认:1920
)
这是原始文件的最大宽度。这将防止原始文件以大量的兆字节存储。空值不会调整图像大小。
breakpoints(数组,默认:['large' => [1024], 'medium' => [768], 'small' => [576], 'xsmall' => [130, 130]]
)
这是一个数组,将用于生成不同大小的缩略图。可用的断点有
- 大
Breakpoint::LARGE->dimensions()
[1024] - 中
Breakpoint::MEDIUM->dimensions()
[768] - 小
Breakpoint::SMALL->dimensions()
[576] - 超小
Breakpoint::XSMALL->dimensions()
[130, 130]
每个断点都有自己的默认尺寸,但可以通过在配置中指定自定义尺寸来覆盖这些尺寸。
使用
安全
这个包中的所有路由都以/ranky/media
开头,没有任何安全措施。但我们都知道在 Symfony 中,保护路由非常容易,例如
# config/packages/security.yaml # Note: Only the *first* access control that matches will be used access_control: # additional security lives in the controllers - { path: ^/ranky/media, roles: ROLE_USER } - { path: ^/admin, roles: ROLE_USER } - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN } - { path: ^/login$, roles: PUBLIC_ACCESS } - { path: /, roles: PUBLIC_ACCESS }
使用此配置,您已经使用ROLE_USER
角色保护了媒体文件管理器。
正如我们之前所看到的,您还想以/admin
的前缀导入此包的路由,那么您需要做的只是将前缀放入安全路径中
# Note: Only the *first* access control that matches will be used access_control: - { path: ^/admin/ranky/media, roles: ROLE_USER } - { path: ^/admin, roles: ROLE_USER } - { path: ^/admin/users, roles: ROLE_SUPER_ADMIN }
别忘了在包配置中设置路由前缀。
媒体文件管理器
安装后,您可以访问我为快速访问媒体文件管理器创建的路由。路径是/ranky/media/embed
。
但想法是在您的管理中创建一个页面。
示例
- router:
/admin/media
- 模板:
media.html.twig
{# media.html.twig #} {# Note that it is not mandatory to use blocks, you can import the assets as you prefer #} {% block stylesheets %} {{- parent() -}} {{ encore_entry_link_tags('ranky_media', null, 'ranky_media') }} {% endblock %} {% block javascripts %} {{- parent() -}} {{ encore_entry_script_tags('ranky_media', null, 'ranky_media', attributes={ defer: true }) }} {% endblock %} {% block body %} <div class="ranky-media" data-api-prefix="{{ ranky_media_api_prefix }}"></div> {% endblock %}
表单类型
只有一个表单类型,但有4种方式将数据存储到数据库中
1. 单选选择。存储 mediaId(Ulid)而不关联
media_id
类型是 Doctrine ULID 类型
#[ORM\Column(name: 'media_id', type: 'media_id', nullable: true)] private ?MediaId $mediaId;
use Ranky\MediaBundle\Presentation\Form\RankyMediaFileManagerType; class MyFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('mediaId', RankyMediaFileManagerType::class, [ 'label' => 'Media Id', 'modal_title' => 'Featured image', ]) ; } }
2. 多选选择。存储 mediaId(json)数组而不关联
#[ORM\Column(name: 'gallery', type: Types::JSON, nullable: true)] private ?array $gallery;
use Ranky\MediaBundle\Presentation\Form\RankyMediaFileManagerType; class MyFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('gallery', RankyMediaFileManagerType::class, [ 'label' => 'Array of Ids', 'multiple' => true, 'modal_title' => 'Gallery', ]) ; } }
3. 单选选择。存储路径而不关联
#[ORM\Column(name: 'image', type: Types::STRING, nullable: true)] public string $image;
use Ranky\MediaBundle\Presentation\Form\RankyMediaFileManagerType; class MyFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('image', RankyMediaFileManagerType::class, [ 'label' => 'Image', 'save_path' => true, 'modal_title' => 'Select image', ]) ; } }
4. 多选选择。存储路径数组而不关联
#[ORM\Column(name: 'gallery', type: Types::JSON, nullable: true)] private ?array $gallery;
use Ranky\MediaBundle\Presentation\Form\RankyMediaFileManagerType; class MyFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('gallery', RankyMediaFileManagerType::class, [ 'label' => 'Array of paths', 'multiple' => true, 'save_path' => true, 'modal_title' => 'Gallery', ]) ; } }
5. 单选选择。存储带有 ManyToOne 关联的 mediaId(Ulid)
#[ORM\ManyToOne(targetEntity: Media::class)] #[ORM\JoinColumn(name: 'media', referencedColumnName: 'id', nullable: true, onDelete: 'SET NULL')] private ?Media $media;
use Ranky\MediaBundle\Presentation\Form\RankyMediaFileManagerType; class MyFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('media', RankyMediaFileManagerType::class, [ 'label' => 'Media ManyToOne', 'association' => true, 'modal_title' => 'Featured image', ]) ; } }
6. 多选选择。存储带有 ManyToMany 关联的媒体集合
#[ORM\JoinTable(name: 'pages_medias')] #[ORM\JoinColumn(name: 'page_id', referencedColumnName: 'id', onDelete: 'CASCADE')] #[ORM\InverseJoinColumn(name: 'media_id', referencedColumnName: 'id', onDelete: 'CASCADE')] #[ORM\ManyToMany(targetEntity: Media::class)] #[ORM\OrderBy(["createdAt" => "DESC"])] private ?Collection $medias; public function __construct() { $this->medias = new ArrayCollection(); }
use Ranky\MediaBundle\Presentation\Form\RankyMediaFileManagerType; class MyFormType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('medias', RankyMediaFileManagerType::class, [ 'label' => 'Media Collection', 'association' => true, 'modal_title' => 'Gallery', 'multiple_selection' => true, ]) ; } }
在 Twig 中检索媒体文件
要检索媒体文件,您有一个全局 twig 服务将帮助您。让我们按与查看表单类型相同的顺序查看示例。
服务: ranky_media
RankyMediaTwigExtension
- findById: 通过 MediaId 获取媒体响应
- findByIds: 通过 MediaId 数组获取媒体响应集合
- findByPath: 通过路径获取媒体响应
- findByPaths: 通过路径数组获取媒体响应集合
- mediaToResponse: 将媒体实体转换为媒体响应
- mediaCollectionToArrayResponse: 将媒体实体集合转换为媒体响应集合
扩展
* ranky_media_url: Twig 函数,用于获取媒体文件的 URL * ranky_media_thumbnail_url: Twig 函数,用于获取缩略图的 URL
示例
{# @var media \Ranky\MediaBundle\Application\DataTransformer\Response\MediaResponse #} {% set media = ranky_media.findById(page.mediaId) %} {# {% set medias = ranky_media.findByIds(page.gallery) %} #} {{ dump(media) }} {% if media %} <p> <img src="{{ media.file.url }}" alt="{{ media.description.alt }}" title="{{ media.description.title }}" /> </p> <p>{{ ranky_media_url(media) }}</p> <p>Thumbnails</p> {% for thumbnail in media.thumbnails %} {# @var thumbnail \Ranky\MediaBundle\Application\DataTransformer\Response\ThumbnailResponse #} <p>Thumbnail breakpoint: {{ thumbnail.breakpoint }} {{ thumbnail.dimension.asString }}</p> <img src="{{ thumbnail.url }}" alt="{{ media.description.alt }}" title="{{ media.description.title }}" /> <p>{{ ranky_media_url(thumbnail.url) }}</p> <p>{{ ranky_media_thumbnail_url(thumbnail.path, thumbnail.breakpoint) }}</p> {% endfor %} {% endif %}
使用 Twig 宏的响应式图片
{% import '@RankyMedia/macros.html.twig' as rankyMedia %} {% set media = ranky_media.findById(page.mediaId) %} {{ rankyMedia.reponsive_image(media) }}
独立按钮以选择模式打开媒体文件管理器
您可以使用与 表单 中相同的选项。请记住先导入资源
{{ encore_entry_script_tags('ranky_media', null, 'ranky_media', attributes={ defer: true }) }} {{ encore_entry_link_tags('ranky_media', null, 'ranky_media') }}
需要 ranky-media-open-modal
类,以便不与表单类型冲突。
<button class="ranky-media-open-modal" data-api-prefix="{{ranky_media_api_prefix}}" data-modal-title="Media File Manager" data-multiple-selection="true"> Media File Manager </button>
document.addEventListener('DOMContentLoaded', () => { [...document.querySelectorAll('.ranky-media-open-modal')].forEach((element) => { element.addEventListener('ranky-media:selected-media',(event) => { console.log(event.detail); }) }); });
TinyMCE 集成
需要 ranky-media-open-modal
类。
<div class="form-group"> <button type="button" data-multiple-selection="true" data-api-prefix="{{ ranky_media_api_prefix }}" class="btn btn-alt-primary ranky-media-open-modal"> <i class="fas fa-photo-video"></i> Media File Manager </button> {# Textarea with TinyMCE #} {{ form_row(form.content) }} </div>
document.addEventListener('DOMContentLoaded', () => { [...document.querySelectorAll('.ranky-media-open-modal')].forEach((element) => { element.addEventListener('ranky-media:selected-media',(event) => { event.detail.medias?.forEach((media) => { if (media.file.mimeType === 'image') { const imageTag = `<img width="500" src="${media.file.url}" alt="${media.description.alt}" title="${media.description.title}" />`; tinymce.activeEditor.insertContent(imageTag); } }) }) }); });
EasyAdmin 集成
为 EasyAdmin 创建了一个 字段,它集成了在 表单类型 中先前解释的相同功能
这里,我展示了六个变体的示例
use Ranky\MediaBundle\Presentation\Form\EasyAdmin\EARankyMediaFileManagerField; // ... public function configureFields(string $pageName): iterable { // ... yield EARankyMediaFileManagerField::new('path')->savePath(); yield EARankyMediaFileManagerField::new('paths')->multipleSelection()->savePath(); yield EARankyMediaFileManagerField::new('mediaId'); yield EARankyMediaFileManagerField::new('gallery')->multipleSelection()->modalTitle('Gallery'); yield EARankyMediaFileManagerField::new('media')->association(); yield EARankyMediaFileManagerField::new('medias')->association()->multipleSelection(); }
事件
- PreCreateEvent::NAME
- PostCreateEvent::NAME
- PreUpdateEvent::NAME
- PostUpdateEvent::NAME
- DeleteEvent::PRE_DELETE
- DeleteEvent::POST_DELETE
use Ranky\MediaBundle\Infrastructure\Event\PreCreateEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; class MyEventSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return [ PreCreateEvent::NAME => 'onPreCreate', ]; } public function onPreCreate(PreCreateEvent $event) { // do something } }
注意事项
- 目前,使用 Uppy 通过媒体文件管理器支持文件上传,它需要 SSL 证书 或通过 localhost 可用。更多信息请参阅 transloadit/uppy#4133
- 如果您正在使用 React,您将遇到问题,因为此包添加了 React,您可能在同一页面上有 React 的两个版本。这将在我将包注册到 NPM 中后立即修复。
- Doctrine ORM 支持 PostgreSQL、MariaDB、MySQL 和 SQLite。目前不支持 Doctrine MongoDB ODM。
额外
演示
几天后将有完整的演示。现在,您可以观看 视频
安装本地证书
mkcert -install
mkcert "*.example.test"
更多信息 https://github.com/FiloSottile/mkcert
Docker
您可以在 Dockerfile 中看到如何通过 Docker 安装 PHP 扩展和压缩工具,这是我用于测试的。
待办事项
- 私有媒体文件
-
食谱 - 文件存储适配器 S3、Azure、Google Cloud 等
- 支持 php-vips (libvips) https://github.com/libvips/php-vips
- 图像编辑器
- 创建 NPM 包,这样您就可以使用/导入 React,而不会有多余的版本
-
WHERE IN
子句中的ORDER BY FIELD
- 添加更多排序过滤器
- 使用 Ghostscript 进行 PDF 压缩
- 使用 FFmpeg 进行视频压缩和缩放
- 音频压缩
- 创建、查看和编辑 EXIF 数据
- 目录的创建和组织
- 添加更多测试
许可
MediaBundle 在 MIT 许可证下授权 – 详细信息请参阅 LICENSE 文件