ranky/media-bundle

为 Symfony 提供的完整且友好的媒体文件管理器

资助包维护!
chiqui3d

安装: 561

依赖者: 0

建议者: 0

安全: 0

星星: 54

关注者: 5

分支: 13

开放问题: 5

类型:symfony-bundle

v3.0.1 2024-08-09 22:12 UTC

README

CI

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

Dockerfile

案例 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

Dockerfile

安装

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。

示例: /uploadshttps://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 集成

TinyMCE Ranky Media Bundle

需要 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 文件

捐赠