diff --git a/composer.json b/composer.json index 22cb30b..b186a58 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ "psr/http-message": "*", "ramsey/uuid": "^4.1", "ramsey/uuid-doctrine": "^1.6", - "symfony/validator": "4.4.*" + "symfony/validator": "4.4.*", + "vich/uploader-bundle": "^1.16" }, "require-dev": { "codeception/codeception": "^2.5", diff --git a/src/Application/Cms/MediaFile/Service/MediaFilePathResolver.php b/src/Application/Cms/MediaFile/Service/MediaFilePathResolver.php new file mode 100644 index 0000000..6524966 --- /dev/null +++ b/src/Application/Cms/MediaFile/Service/MediaFilePathResolver.php @@ -0,0 +1,49 @@ +'; + private const VIDEO_HTML_MASK = ''; + private const PDF_HTML_MASK = ''; + + /** + * @var UploaderHelper + */ + private $uploaderHelper; + + public function __construct(UploaderHelper $uploaderHelper) + { + $this->uploaderHelper = $uploaderHelper; + } + + public function getFileUrl(MediaFile $file): ?string + { + return $this->uploaderHelper->asset($file, 'file'); + } + + public function getFileHtml(MediaFile $file): ?string + { + $url = $this->getFileUrl($file); + + if ($file->getType()->isImage()) { + return sprintf(self::IMAGE_HTML_MASK, $url, $file->getTitle()); + } + + if ($file->getType()->isVideo()) { + return sprintf(self::VIDEO_HTML_MASK, $url); + } + + if ($file->getType()->isPdf()) { + return sprintf(self::PDF_HTML_MASK, $url); + } + + return null; + } +} diff --git a/src/Application/Cms/MediaFile/Service/MediaFileTypeResolver.php b/src/Application/Cms/MediaFile/Service/MediaFileTypeResolver.php new file mode 100644 index 0000000..86b879e --- /dev/null +++ b/src/Application/Cms/MediaFile/Service/MediaFileTypeResolver.php @@ -0,0 +1,43 @@ +getMimeType(); + + if ($mimeType === self::PDF_MIME_TYPE) { + return new MediaFileType(MediaFileType::PDF_TYPE); + } + + if (in_array($mimeType, self::IMAGE_MIME_TYPES, true)) { + return new MediaFileType(MediaFileType::IMAGE_TYPE); + } + + if (in_array($mimeType, self::VIDEO_MIME_TYPES, true)) { + return new MediaFileType(MediaFileType::VIDEO_TYPE); + } + + throw new ApplicationException('Mime type ' . $mimeType . ' is not supported'); + } +} diff --git a/src/Application/EventListener/MediaFileUpdatedListener.php b/src/Application/EventListener/MediaFileUpdatedListener.php new file mode 100644 index 0000000..5eec497 --- /dev/null +++ b/src/Application/EventListener/MediaFileUpdatedListener.php @@ -0,0 +1,60 @@ +mediaFileTypeResolver = $mediaFileTypeResolver; + $this->fileMappingFactory = $fileMappingFactory; + } + + public function preUpdate(LifecycleEventArgs $args): void + { + $this->handleEventArgs($args); + } + + public function prePersist(LifecycleEventArgs $args): void + { + $this->handleEventArgs($args); + } + + private function handleEventArgs(LifecycleEventArgs $args): void + { + $object = $args->getObject(); + + if (!$object instanceof MediaFile) { + return; + } + + if (!$object->getFile()) { + return; + } + + $object->setType($this->mediaFileTypeResolver->getMediaFileTypeByFile($object->getFile())); + $mapping = $this->fileMappingFactory->fromField($object, 'file'); + + if ($mapping) { + $object->setStorage(new MediaFileStorage($mapping->getUploadDestination())); + } + } +} diff --git a/src/Domain/Entity/MediaCatalog.php b/src/Domain/Entity/MediaCatalog.php new file mode 100644 index 0000000..0a82234 --- /dev/null +++ b/src/Domain/Entity/MediaCatalog.php @@ -0,0 +1,46 @@ +id = $id; + $this->name = $name; + } + + public function __toString() + { + return $this->name; + } + + public function getId(): Id + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): void + { + $this->name = $name; + } +} diff --git a/src/Domain/Entity/MediaFile.php b/src/Domain/Entity/MediaFile.php new file mode 100644 index 0000000..58c8c2f --- /dev/null +++ b/src/Domain/Entity/MediaFile.php @@ -0,0 +1,146 @@ +id = $id; + $this->catalog = $catalog; + $this->title = $title; + $this->type = $type; + $this->name = $name; + $this->storage = $storage; + $this->originalName = $originalName; + } + + public function getId(): Id + { + return $this->id; + } + + public function getCatalog(): MediaCatalog + { + return $this->catalog; + } + + public function setCatalog(MediaCatalog $catalog): void + { + $this->catalog = $catalog; + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): void + { + $this->title = $title; + } + + public function getType(): MediaFileType + { + return $this->type; + } + + public function setType(MediaFileType $type): void + { + $this->type = $type; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(?string $name): void + { + $this->name = $name; + } + + public function getStorage(): MediaFileStorage + { + return $this->storage; + } + + public function setStorage(MediaFileStorage $storage): void + { + $this->storage = $storage; + } + + public function getFile(): ?File + { + return $this->file; + } + + public function setFile(?File $file): void + { + $this->file = $file; + } + + public function getOriginalName(): ?string + { + return $this->originalName; + } + + public function setOriginalName(?string $originalName): void + { + $this->originalName = $originalName; + } +} diff --git a/src/Domain/Entity/ValueObject/MediaFileStorage.php b/src/Domain/Entity/ValueObject/MediaFileStorage.php new file mode 100644 index 0000000..b8030cd --- /dev/null +++ b/src/Domain/Entity/ValueObject/MediaFileStorage.php @@ -0,0 +1,31 @@ + self::S3_STORAGE, + self::NFS_STORAGE => self::NFS_STORAGE, + ]; + + use ValueObjectTrait; + + public function isS3(): bool + { + return $this->value === self::S3_STORAGE; + } + + public function isNfs(): bool + { + return $this->value === self::NFS_STORAGE; + } +} diff --git a/src/Domain/Entity/ValueObject/MediaFileType.php b/src/Domain/Entity/ValueObject/MediaFileType.php new file mode 100644 index 0000000..795579a --- /dev/null +++ b/src/Domain/Entity/ValueObject/MediaFileType.php @@ -0,0 +1,45 @@ + self::IMAGE_TYPE, + self::PDF_TYPE => self::PDF_TYPE, + self::VIDEO_TYPE => self::VIDEO_TYPE, + ]; + + use ValueObjectTrait; + + protected function checkValue(string $value): void + { + if (!in_array($value, self::AVAILABLE_TYPES)) { + throw new IncorrectValueObjectException('This media file type is not supported'); + } + } + + public function isPdf(): bool + { + return $this->value === self::PDF_TYPE; + } + + public function isImage(): bool + { + return $this->value === self::IMAGE_TYPE; + } + + public function isVideo(): bool + { + return $this->value === self::VIDEO_TYPE; + } +} diff --git a/src/Domain/Repository/MediaCatalogRepository/Exception/MediaCatalogNotFoundException.php b/src/Domain/Repository/MediaCatalogRepository/Exception/MediaCatalogNotFoundException.php new file mode 100644 index 0000000..8db7064 --- /dev/null +++ b/src/Domain/Repository/MediaCatalogRepository/Exception/MediaCatalogNotFoundException.php @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/Infrastructure/Doctrine/Entity/mapping/MediaFile.orm.xml b/src/Infrastructure/Doctrine/Entity/mapping/MediaFile.orm.xml new file mode 100644 index 0000000..2375790 --- /dev/null +++ b/src/Infrastructure/Doctrine/Entity/mapping/MediaFile.orm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Infrastructure/Doctrine/Repository/MediaCatalogRepository.php b/src/Infrastructure/Doctrine/Repository/MediaCatalogRepository.php new file mode 100644 index 0000000..a22e4cb --- /dev/null +++ b/src/Infrastructure/Doctrine/Repository/MediaCatalogRepository.php @@ -0,0 +1,55 @@ +toString()); + } + + public function getAll(): array + { + try { + return $this->findAll(); + } catch (Exception $e) { + throw new MediaCatalogRepositoryException($e->getMessage(), $e->getCode(), $e); + } + } + + public function getFirst(): MediaCatalog + { + try { + $catalog = $this->findOneBy([], ['id' => 'desc']); + + if ($catalog === null) { + throw new MediaCatalogNotFoundException(); + } + + return $catalog; + } catch (MediaCatalogNotFoundException $e) { + throw $e; + } catch (Exception $e) { + throw new MediaCatalogRepositoryException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/src/Infrastructure/Doctrine/Repository/MediaFileRepository.php b/src/Infrastructure/Doctrine/Repository/MediaFileRepository.php new file mode 100644 index 0000000..5dc3226 --- /dev/null +++ b/src/Infrastructure/Doctrine/Repository/MediaFileRepository.php @@ -0,0 +1,38 @@ +toString()); + } + + public function getByCatalog(MediaCatalog $catalog): array + { + try { + return $this->findBy(['catalog' => $catalog]); + } catch (Exception $e) { + throw new MediaFileRepositoryException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/src/Infrastructure/Doctrine/Type/MediaFileStorageType.php b/src/Infrastructure/Doctrine/Type/MediaFileStorageType.php new file mode 100644 index 0000000..6101f44 --- /dev/null +++ b/src/Infrastructure/Doctrine/Type/MediaFileStorageType.php @@ -0,0 +1,28 @@ +getVarcharTypeDeclarationSQL($fieldDeclaration); + } + + public function getName(): string + { + return 'cms_media_file_storage'; + } +} diff --git a/src/Infrastructure/Doctrine/Type/MediaFileType.php b/src/Infrastructure/Doctrine/Type/MediaFileType.php new file mode 100644 index 0000000..9b56055 --- /dev/null +++ b/src/Infrastructure/Doctrine/Type/MediaFileType.php @@ -0,0 +1,28 @@ +getVarcharTypeDeclarationSQL($fieldDeclaration); + } + + public function getName(): string + { + return 'cms_media_file_type'; + } +} diff --git a/src/Infrastructure/Symfony/Form/ComponentTypes/HTMLComponentType.php b/src/Infrastructure/Symfony/Form/ComponentTypes/HTMLComponentType.php index 05669a3..c61effd 100644 --- a/src/Infrastructure/Symfony/Form/ComponentTypes/HTMLComponentType.php +++ b/src/Infrastructure/Symfony/Form/ComponentTypes/HTMLComponentType.php @@ -13,7 +13,12 @@ class HTMLComponentType extends AbstractType implements DataTransformerInterface { public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('html', TextareaType::class); + $builder->add('html', TextareaType::class, [ + 'attr' => [ + 'styles' => 'height: auto;', + 'rows' => 10, + ] + ]); $builder->resetViewTransformers(); $builder->addViewTransformer($this); diff --git a/src/Infrastructure/Symfony/Form/Fields/VichFileField.php b/src/Infrastructure/Symfony/Form/Fields/VichFileField.php new file mode 100644 index 0000000..57fb690 --- /dev/null +++ b/src/Infrastructure/Symfony/Form/Fields/VichFileField.php @@ -0,0 +1,23 @@ +setProperty($propertyName) + ->setTemplatePath('') + ->setLabel($label) + ->setFormType(VichFileType::class); + } +} diff --git a/src/Infrastructure/Symfony/Form/PageComponentType.php b/src/Infrastructure/Symfony/Form/PageComponentType.php index 144059b..7ce06a9 100644 --- a/src/Infrastructure/Symfony/Form/PageComponentType.php +++ b/src/Infrastructure/Symfony/Form/PageComponentType.php @@ -13,6 +13,8 @@ use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,15 +46,38 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'required' => true, 'label' => 'Позиция', 'attr' => [ - 'positionable' => 'positionable' + 'positionable' => 'positionable', + 'value' => 1, ], ]) ->add('isPublished', CheckboxType::class, [ - 'label' => 'Компонент активен' + 'label' => 'Компонент активен', + 'attr' => [ + 'checked' => 'checked', + ], ]) ->add('data', HTMLComponentType::class, [ 'label' => 'Данные' ]); + + $builder->addEventListener(FormEvents::PRE_SET_DATA, static function (FormEvent $event) { + $component = $event->getData(); + $form = $event->getForm(); + + if ($component instanceof PageComponent) { + $form + ->add('isPublished', CheckboxType::class, [ + 'label' => 'Компонент активен' + ]) + ->add('order', IntegerType::class, [ + 'required' => true, + 'label' => 'Позиция', + 'attr' => [ + 'positionable' => 'positionable', + ], + ]); + } + }); } public function configureOptions(OptionsResolver $resolver): void diff --git a/src/Resources/config/packages/doctrine.yaml b/src/Resources/config/packages/doctrine.yaml index 6a5bb6e..a39a587 100644 --- a/src/Resources/config/packages/doctrine.yaml +++ b/src/Resources/config/packages/doctrine.yaml @@ -7,6 +7,8 @@ doctrine: cms_content_type: 'Skyeng\MarketingCmsBundle\Infrastructure\Doctrine\Type\ContentType' cms_cache_time: 'Skyeng\MarketingCmsBundle\Infrastructure\Doctrine\Type\CacheTimeType' page_component_name: 'Skyeng\MarketingCmsBundle\Infrastructure\Doctrine\Type\PageComponentNameType' + cms_media_file_storage: 'Skyeng\MarketingCmsBundle\Infrastructure\Doctrine\Type\MediaFileStorageType' + cms_media_file_type: 'Skyeng\MarketingCmsBundle\Infrastructure\Doctrine\Type\MediaFileType' orm: entity_managers: diff --git a/src/Resources/config/packages/prod/vich_uploader.yaml b/src/Resources/config/packages/prod/vich_uploader.yaml new file mode 100644 index 0000000..9acf8ff --- /dev/null +++ b/src/Resources/config/packages/prod/vich_uploader.yaml @@ -0,0 +1,4 @@ +vich_uploader: + mappings: + cms_media_files: + upload_destination: 'uploads.s3' diff --git a/src/Resources/config/packages/vich_uploader.yaml b/src/Resources/config/packages/vich_uploader.yaml new file mode 100644 index 0000000..7169b8a --- /dev/null +++ b/src/Resources/config/packages/vich_uploader.yaml @@ -0,0 +1,9 @@ +parameters: + env(UPLOADS_BASE_URL): '/uploads' + +vich_uploader: + mappings: + cms_media_files: + uri_prefix: '%env(UPLOADS_BASE_URL)%' + upload_destination: 'uploads.nfs' + namer: Vich\UploaderBundle\Naming\SmartUniqueNamer diff --git a/src/Resources/config/services.yaml b/src/Resources/config/services.yaml index cbe353b..1e1eead 100644 --- a/src/Resources/config/services.yaml +++ b/src/Resources/config/services.yaml @@ -11,3 +11,9 @@ services: - '../../Domain/{Exception,Traits,Entity,Event}' - '../../Domain/{Exception,Traits,Entity,Event}/*.php' - '../../Domain/{Exception,Traits,Entity,Event}/**/*.php' + + marketing_cms_bundle.listener.media_file_updated_listener: + class: Skyeng\MarketingCmsBundle\Application\EventListener\MediaFileUpdatedListener + tags: + - { name: doctrine.event_listener, event: preUpdate, method: preUpdate } + - { name: doctrine.event_listener, event: prePersist, method: prePersist } diff --git a/src/Resources/config/validator/validation.yaml b/src/Resources/config/validator/validation.yaml index fdfb938..10208f6 100644 --- a/src/Resources/config/validator/validation.yaml +++ b/src/Resources/config/validator/validation.yaml @@ -41,3 +41,16 @@ Skyeng\MarketingCmsBundle\Domain\Entity\Page: - Valid: ~ customMetaTags: - Valid: ~ + +# Media + +Skyeng\MarketingCmsBundle\Domain\Entity\MediaCatalog: + constraints: + - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: name + +Skyeng\MarketingCmsBundle\Domain\Entity\MediaFile: + properties: + file: + - File: { maxSize: 20M, mimeTypes: [ image/jpeg, image/png, image/gif, application/pdf, video/mp4 ] } + catalog: + - NotBlank: ~ diff --git a/src/Resources/config/vich_uploader/Domain.Entity.MediaFile.yml b/src/Resources/config/vich_uploader/Domain.Entity.MediaFile.yml new file mode 100644 index 0000000..b9e44e9 --- /dev/null +++ b/src/Resources/config/vich_uploader/Domain.Entity.MediaFile.yml @@ -0,0 +1,5 @@ +Skyeng\MarketingCmsBundle\Domain\Entity\MediaFile: + file: + mapping: cms_media_files + filename_property: name + original_name: originalName diff --git a/src/Resources/public/ea-copy-actions.js b/src/Resources/public/ea-copy-actions.js new file mode 100644 index 0000000..a0f578f --- /dev/null +++ b/src/Resources/public/ea-copy-actions.js @@ -0,0 +1,17 @@ +$('body').on('click', 'a.copy-action-ea', function (event) { + event.preventDefault(); + + var $temp = $(''); + $('body').append($temp); + $temp.val($(this).attr('href')).select(); + document.execCommand('copy'); + $temp.remove(); + + var $childrenIcon = $(this).children('.action-icon'); + + $childrenIcon.removeClass('fa-copy').addClass('fa-check'); + + setTimeout(function () { + $childrenIcon.removeClass('fa-check').addClass('fa-copy'); + }, 1000); +}); diff --git a/src/UI/Controller/Admin/MediaCatalogCrudController.php b/src/UI/Controller/Admin/MediaCatalogCrudController.php new file mode 100644 index 0000000..54485fa --- /dev/null +++ b/src/UI/Controller/Admin/MediaCatalogCrudController.php @@ -0,0 +1,65 @@ +mediaCatalogRepository = $mediaCatalogRepository; + } + + public static function getEntityFqcn(): string + { + return MediaCatalog::class; + } + + public function configureCrud(Crud $crud): Crud + { + return $crud + ->setPageTitle(Crud::PAGE_INDEX, 'Каталог') + ->setPageTitle(Crud::PAGE_DETAIL, 'Каталог') + ->setPageTitle(Crud::PAGE_NEW, 'Создать каталог') + ->setPageTitle(Crud::PAGE_EDIT, 'Каталог'); + } + + public function configureActions(Actions $actions): Actions + { + $actions->remove(Crud::PAGE_INDEX, Action::DELETE); + return $actions; + } + + public function configureFields(string $pageName): iterable + { + $name = TextField::new('name', 'Название'); + + if (in_array($pageName, [Crud::PAGE_INDEX, Crud::PAGE_DETAIL], true)) { + return [$name]; + } + + return [$name]; + } + + public function createEntity(string $entityFqcn): MediaCatalog + { + return new MediaCatalog( + $this->mediaCatalogRepository->getNextIdentity(), + '', + ); + } +} diff --git a/src/UI/Controller/Admin/MediaFileCrudController.php b/src/UI/Controller/Admin/MediaFileCrudController.php new file mode 100644 index 0000000..7273617 --- /dev/null +++ b/src/UI/Controller/Admin/MediaFileCrudController.php @@ -0,0 +1,154 @@ +mediaFileRepository = $mediaFileRepository; + $this->mediaCatalogRepository = $mediaCatalogRepository; + $this->mediaFilePathResolver = $mediaFilePathResolver; + } + + public static function getEntityFqcn(): string + { + return MediaFile::class; + } + + public function configureFilters(Filters $filters): Filters + { + return $filters + ->add( + ChoiceFilter::new('type', 'Тип файла')->setChoices([MediaFileType::AVAILABLE_TYPES]) + ); + } + + public function configureCrud(Crud $crud): Crud + { + return $crud + ->setPageTitle(Crud::PAGE_INDEX, 'Медиа файлы') + ->setPageTitle(Crud::PAGE_DETAIL, 'Медиа файл') + ->setPageTitle(Crud::PAGE_NEW, 'Создать медиа файл') + ->setPageTitle(Crud::PAGE_EDIT, 'Медиа файл'); + } + + public function configureAssets(Assets $assets): Assets + { + $hideMediaCatalogSelectorClearButton = '#MediaFile_catalog + .select2 .select2-selection__clear {display:none;}'; + + return $assets + ->addHtmlContentToHead("") + ->addJsFile('bundles/marketingcms/ea-copy-actions.js'); + } + + public function configureActions(Actions $actions): Actions + { + $actions->update(Crud::PAGE_INDEX, Action::NEW, function (Action $action) { + return $action->setLabel('Создать медиа файл'); + }); + + $getFileLink = Action::new('getFileLink', 'Ссылка', 'fa fa-copy') + ->linkToUrl(function (MediaFile $file) { + return $this->mediaFilePathResolver->getFileUrl($file); + }) + ->addCssClass('copy-action-ea'); + + $getFileHtml = Action::new('getFileHtml', 'Html', 'fa fa-copy') + ->linkToUrl(function (MediaFile $file) { + return $this->mediaFilePathResolver->getFileHtml($file); + }) + ->addCssClass('copy-action-ea'); + + $actions->add(Crud::PAGE_INDEX, $getFileLink); + $actions->add(Crud::PAGE_INDEX, $getFileHtml); + + try { + $this->mediaCatalogRepository->getFirst(); + } catch (MediaCatalogNotFoundException $e) { + $actions->remove(Crud::PAGE_INDEX, Action::NEW); + } + + return $actions; + } + + public function getFileHtml(AdminContext $context) + { + $mediaFile = $context->getEntity()->getInstance(); + + return $mediaFile->getName(); + } + + public function configureFields(string $pageName): iterable + { + $title = TextField::new('title', 'Заголовок файла'); + $file = VichFileField::new('file', 'Файл')->setFormTypeOptions([ + 'allow_delete' => false, + ]); + $catalog = AssociationField::new('catalog', 'Каталог')->setRequired(true); + $originalName = TextField::new('originalName', 'Название файла'); + + if (in_array($pageName, [Crud::PAGE_INDEX, Crud::PAGE_DETAIL], true)) { + return [$originalName, $title, $catalog]; + } + + if ($pageName === Crud::PAGE_NEW) { + $file->setRequired(true); + } + + return [$catalog, $title, $file]; + } + + public function createEntity(string $entityFqcn): MediaFile + { + return new MediaFile( + $this->mediaFileRepository->getNextIdentity(), + $this->mediaCatalogRepository->getFirst(), + '', + new MediaFileType(MediaFileType::IMAGE_TYPE), + '', + new MediaFileStorage(MediaFileStorage::NFS_STORAGE), + '', + ); + } +} diff --git a/src/UI/Controller/Admin/PageCrudController.php b/src/UI/Controller/Admin/PageCrudController.php index 7af9b41..38fec4f 100644 --- a/src/UI/Controller/Admin/PageCrudController.php +++ b/src/UI/Controller/Admin/PageCrudController.php @@ -4,6 +4,11 @@ namespace Skyeng\MarketingCmsBundle\UI\Controller\Admin; +use EasyCorp\Bundle\EasyAdminBundle\Config\Action; +use EasyCorp\Bundle\EasyAdminBundle\Config\Actions; +use EasyCorp\Bundle\EasyAdminBundle\Config\Option\EA; +use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator; +use Skyeng\MarketingCmsBundle\Domain\Entity\MediaFile; use Skyeng\MarketingCmsBundle\Domain\Entity\Page; use Skyeng\MarketingCmsBundle\Domain\Entity\PageOpenGraphData; use Skyeng\MarketingCmsBundle\Domain\Entity\PageSeoData; @@ -38,10 +43,19 @@ class PageCrudController extends AbstractCrudController */ private $pageRepository; - public function __construct(ResourceRepositoryInterface $resourceRepository, PageRepositoryInterface $pageRepository) - { + /** + * @var AdminUrlGenerator + */ + private $adminUrlGenerator; + + public function __construct( + ResourceRepositoryInterface $resourceRepository, + PageRepositoryInterface $pageRepository, + AdminUrlGenerator $adminUrlGenerator + ) { $this->resourceRepository = $resourceRepository; $this->pageRepository = $pageRepository; + $this->adminUrlGenerator = $adminUrlGenerator; } public static function getEntityFqcn(): string @@ -59,6 +73,25 @@ public function configureCrud(Crud $crud): Crud ->setPaginatorUseOutputWalkers(true); } + public function configureActions(Actions $actions): Actions + { + $mediaFilesAction = Action::new('mediaFiles', 'Медиа библиотека', 'fa fa-image') + ->linkToUrl( + $this->adminUrlGenerator + ->setController(MediaFileCrudController::class) + ->setAction('index') + ->generateUrl() + ) + ->setHtmlAttributes(['target' => '_blank']) + ->addCssClass('btn') + ->addCssClass('btn-secondary'); + + $actions->add(Crud::PAGE_EDIT, $mediaFilesAction); + $actions->add(Crud::PAGE_NEW, $mediaFilesAction); + + return $actions; + } + public function configureFields(string $pageName): iterable { $resource = ResourceField::new('resource.uri', 'Ссылка');