├── .github └── workflows │ ├── coding_standards.yml │ └── tests.yml ├── .gitignore ├── .php-cs-fixer.php ├── .travis.yml ├── LICENCE ├── README.md ├── bundle ├── Command │ ├── AddImageRemoteMediaCommand.php │ ├── AddRemoteMediaFieldCommand.php │ ├── MigrateEzImageCommand.php │ ├── RefreshEzFieldsCommand.php │ └── ShowApiUsageCommand.php ├── Controller │ └── EzAdminUI │ │ ├── BrowseController.php │ │ ├── Editor │ │ ├── FetchController.php │ │ └── InsertController.php │ │ ├── Facets │ │ └── Load.php │ │ └── Folder │ │ ├── Create.php │ │ └── Load.php ├── Converter │ └── XmlText │ │ └── NgRemoteMediaPreConverter.php ├── Core │ ├── FieldType │ │ └── RemoteMedia │ │ │ ├── AdminInputValue.php │ │ │ ├── FormMapper.php │ │ │ ├── InputValue.php │ │ │ ├── RemoteMediaStorage.php │ │ │ ├── RemoteMediaStorage │ │ │ ├── Gateway.php │ │ │ └── Gateway │ │ │ │ └── LegacyStorage.php │ │ │ ├── SearchField.php │ │ │ ├── Type.php │ │ │ ├── UpdateFieldHelper.php │ │ │ ├── Value.php │ │ │ └── Variation.php │ └── Persistence │ │ └── Legacy │ │ └── Content │ │ └── FieldValue │ │ └── Converter │ │ └── RemoteMediaConverter.php ├── DependencyInjection │ ├── Compiler │ │ ├── TransformationHandlersCompilerPass.php │ │ └── XslRegisterPass.php │ ├── Configuration.php │ └── NetgenRemoteMediaExtension.php ├── Entity │ └── RemoteMediaFieldLink.php ├── Exception │ ├── MimeCategoryParseException.php │ ├── TransformationHandlerFailedException.php │ └── TransformationHandlerNotFoundException.php ├── Form │ └── FieldType │ │ ├── FieldValueTransformer.php │ │ └── RemoteMediaFieldType.php ├── NetgenRemoteMediaBundle.php ├── OpenGraph │ └── Handler │ │ └── RemoteMediaHandler.php ├── RemoteMedia │ ├── Helper.php │ ├── NextCursorResolver.php │ ├── Provider │ │ └── Cloudinary │ │ │ ├── CloudinaryProvider.php │ │ │ ├── Gateway.php │ │ │ ├── Gateway │ │ │ ├── Cache │ │ │ │ └── Psr6CachedGateway.php │ │ │ └── CloudinaryApiGateway.php │ │ │ ├── Search │ │ │ ├── Query.php │ │ │ └── Result.php │ │ │ └── TransformationHandler │ │ │ ├── Crop.php │ │ │ ├── Effect.php │ │ │ ├── Fill.php │ │ │ ├── Fit.php │ │ │ ├── Format.php │ │ │ ├── Lfill.php │ │ │ ├── Limit.php │ │ │ ├── Lpad.php │ │ │ ├── Mfit.php │ │ │ ├── Mpad.php │ │ │ ├── NamedTransformation.php │ │ │ ├── Pad.php │ │ │ ├── Quality.php │ │ │ ├── Resize.php │ │ │ └── Scale.php │ ├── RemoteMediaProvider.php │ ├── Transformation │ │ ├── HandlerInterface.php │ │ └── Registry.php │ ├── UploadFile.php │ └── VariationResolver.php ├── Resources │ ├── config │ │ ├── config.yml.example │ │ ├── default_parameters.yml │ │ ├── default_settings.yml │ │ ├── doctrine │ │ │ └── RemoteMediaFieldLink.orm.yml │ │ ├── ezadminui │ │ │ ├── controllers.yml │ │ │ ├── custom_tags.yml │ │ │ ├── ezrichtext.yml │ │ │ ├── routing.yml │ │ │ └── twig.yml │ │ ├── ezpublish.yml │ │ ├── fieldtypes.yml │ │ ├── legacy.yml │ │ ├── opengraph.yml │ │ ├── routing.yml │ │ ├── services.yml │ │ ├── storage │ │ │ └── cache_psr6.yml │ │ ├── templating.yml │ │ └── transformation_handlers.yml │ ├── encore │ │ └── ez.config.manager.js │ ├── public │ │ ├── css │ │ │ ├── remotemedia-vendors.css │ │ │ └── remotemedia.css │ │ ├── img │ │ │ └── cloud-upload-alt.svg │ │ └── js │ │ │ ├── alloyeditor │ │ │ ├── buttons │ │ │ │ └── ngremotemedia.js │ │ │ └── plugins │ │ │ │ └── ngremotemedia.js │ │ │ ├── remotemedia-vendors.js │ │ │ └── remotemedia.js │ ├── sql │ │ └── schema.sql │ ├── translations │ │ ├── custom_tags.en.yml │ │ ├── custom_tags.no.yml │ │ ├── ngremotemedia.en.yml │ │ └── ngremotemedia.no.yml │ ├── views │ │ ├── ezadminui │ │ │ ├── field │ │ │ │ ├── edit │ │ │ │ │ └── ngremotemedia.html.twig │ │ │ │ └── view │ │ │ │ │ └── ngremotemedia.html.twig │ │ │ ├── field_definition │ │ │ │ └── view │ │ │ │ │ └── ngremotemedia.html.twig │ │ │ ├── field_type │ │ │ │ └── ezrichtext │ │ │ │ │ └── custom_tag │ │ │ │ │ └── ngremotemedia.html.twig │ │ │ ├── javascripts.html.twig │ │ │ ├── js_config.html.twig │ │ │ ├── parts │ │ │ │ └── edit │ │ │ │ │ ├── editor_insert.html.twig │ │ │ │ │ ├── ezrichtext.html.twig │ │ │ │ │ └── ngrm_field.html.twig │ │ │ └── stylesheets.html.twig │ │ └── ngremotemedia_content_field.html.twig │ └── xsl │ │ └── ezxml_ngremotemedia.xsl ├── Templating │ ├── Converter │ │ └── RemoteMediaValueConverter.php │ └── Twig │ │ └── Extension │ │ └── NetgenRemoteMediaExtension.php └── ezpublish_legacy │ └── ngremotemedia │ ├── .jshintrc │ ├── autoloads │ └── eztemplateautoload.php │ ├── classes │ └── ezlimitationloader.php │ ├── datatypes │ └── ngremotemedia │ │ └── ngremotemediatype.php │ ├── design │ └── standard │ │ ├── images │ │ └── .gitkeep │ │ ├── javascript │ │ ├── plugins │ │ │ └── ngremotemedia │ │ │ │ └── editor_plugin.js │ │ ├── remotemedia-vendors.js │ │ └── remotemedia.js │ │ ├── stylesheets │ │ ├── remotemedia-vendors.css │ │ └── remotemedia.css │ │ └── templates │ │ ├── content │ │ └── datatype │ │ │ ├── edit │ │ │ └── ngremotemedia.tpl │ │ │ └── view │ │ │ ├── ezxmltags │ │ │ └── ngremotemedia.tpl │ │ │ └── ngremotemedia.tpl │ │ └── ezxml_init.tpl │ ├── extension.xml │ ├── settings │ ├── content.ini.append.php │ ├── datatype.ini.append.php │ ├── datetime.ini.append.php │ ├── design.ini.append.php │ ├── ezoe.ini.append.php │ ├── ngremotemedia.ini │ └── site.ini.append.php │ ├── template_operator │ └── ngremotemediaoperator.php │ └── translations │ ├── nor-NO │ └── translation.ts │ └── untranslated │ └── translation.ts ├── codecov.yml ├── composer.json ├── docs ├── CHANGELOG.md ├── FRONTEND.md ├── INSTALL.md ├── TRANSFORMATIONS.md ├── UPGRADE.md └── USAGE.md ├── frontend ├── .browserslistrc ├── .env ├── .eslintrc.js ├── babel.config.js ├── copyFiles.js ├── copyFilesDev.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ └── index.html ├── src │ ├── components │ │ ├── Crop.vue │ │ ├── CropModal.vue │ │ ├── CropSizes.vue │ │ ├── EditorInsertModal.vue │ │ ├── Interactions.vue │ │ ├── MediaFacets.vue │ │ ├── MediaGalery.vue │ │ ├── MediaModal.vue │ │ ├── Modal.vue │ │ ├── Preview.vue │ │ ├── SelectFolder.vue │ │ └── UploadModal.vue │ ├── constants │ │ └── facets.js │ ├── font │ │ ├── fa-ngrm.eot │ │ ├── fa-ngrm.svg │ │ ├── fa-ngrm.ttf │ │ ├── fa-ngrm.woff │ │ └── fa-ngrm.woff2 │ ├── main.js │ ├── scss │ │ ├── _iconfont.scss │ │ ├── _variables.scss │ │ └── ngremotemedia.scss │ └── utility │ │ ├── directives.js │ │ ├── functional.js │ │ ├── polyfills.js │ │ ├── predicates.js │ │ └── utility.js └── vue.config.js ├── package-lock.json ├── package.json ├── phpunit.xml ├── tests ├── Core │ ├── FieldType │ │ └── RemoteMedia │ │ │ ├── InputValueTest.php │ │ │ ├── RemoteMediaStorage │ │ │ └── Gateway │ │ │ │ └── LegacyStorageTest.php │ │ │ ├── RemoteMediaStorageTest.php │ │ │ ├── TypeTest.php │ │ │ ├── ValueTest.php │ │ │ └── VariationTest.php │ └── Persistence │ │ └── Legacy │ │ └── Content │ │ └── FieldValue │ │ └── Converter │ │ └── RemoteMediaConverterTest.php ├── DependencyInjection │ ├── Compiler │ │ ├── TransformationHandlersCompilerPassTest.php │ │ └── XslRegisterPassTest.php │ ├── ConfigurationTest.php │ └── NetgenRemoteMediaExtensionTest.php ├── Entity │ └── RemoteMediaFieldLinkTest.php ├── Exception │ ├── MimeCategoryParseExceptionTest.php │ ├── TransformationHandlerFailedExceptionTest.php │ └── TransformationHandlerNotFoundExceptionTest.php ├── OpenGraph │ └── Handler │ │ └── RemoteMediaHandlerTest.php ├── RemoteMedia │ ├── NextCursorResolverTest.php │ ├── Provider │ │ └── Cloudinary │ │ │ ├── CloudinaryProviderTest.php │ │ │ ├── Gateway │ │ │ └── CloudinaryApiGatewayTest.php │ │ │ └── TransformationHandler │ │ │ ├── BaseTest.php │ │ │ ├── CropTest.php │ │ │ ├── EffectTest.php │ │ │ ├── FillTest.php │ │ │ ├── FitTest.php │ │ │ ├── FormatTest.php │ │ │ ├── LfillTest.php │ │ │ ├── LimitTest.php │ │ │ ├── LpadTest.php │ │ │ ├── MfitTest.php │ │ │ ├── MpadTest.php │ │ │ ├── NamedTransformationTest.php │ │ │ ├── PadTest.php │ │ │ ├── QualityTest.php │ │ │ ├── ResizeTest.php │ │ │ └── ScaleTest.php │ ├── Transformation │ │ └── RegistryTest.php │ ├── UploadFileTest.php │ └── VariationResolverTest.php └── Templating │ ├── Converter │ └── RemoteMediaValueConverterTest.php │ └── Twig │ └── Extension │ └── NetgenRemoteMediaExtensionTest.php ├── travis.php.ini └── update └── database └── migrate-data_text4-to-data_text5.sql /.github/workflows/coding_standards.yml: -------------------------------------------------------------------------------- 1 | name: Coding standards 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | pull_request: ~ 8 | 9 | jobs: 10 | php-cs-fixer: 11 | name: PHP CS Fixer 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: OskarStark/php-cs-fixer-ga@2.19.0 17 | with: 18 | args: --diff --dry-run 19 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | pull_request: ~ 8 | 9 | jobs: 10 | tests: 11 | name: ${{ matrix.php }} / ${{ matrix.symfony }} 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | php: ['7.2', '7.3', '7.4'] 18 | symfony: ['~3.4.0'] 19 | deps: ['normal'] 20 | include: 21 | - php: '7.2' 22 | symfony: '~3.4.0' 23 | deps: 'low' 24 | 25 | steps: 26 | - uses: actions/checkout@v2 27 | - uses: shivammathur/setup-php@v2 28 | with: 29 | php-version: ${{ matrix.php }} 30 | coverage: none 31 | 32 | - run: composer --version 33 | - run: composer validate --strict 34 | 35 | # Install Flex as a global dependency to enable usage of extra.symfony.require 36 | # while keeping Flex recipes from applying 37 | - run: composer global config --no-plugins allow-plugins.symfony/flex true 38 | - run: composer global require --no-scripts symfony/flex 39 | 40 | # Install eZ Publish legacy installer as a global dependency 41 | - run: composer config --no-plugins allow-plugins.ezsystems/ezpublish-legacy-installer true 42 | 43 | - run: composer config extra.symfony.require ${{ matrix.symfony }} 44 | 45 | - 46 | run: composer update --prefer-dist 47 | if: ${{ matrix.deps != 'low' }} 48 | 49 | - 50 | run: composer update --prefer-dist --prefer-lowest --prefer-stable 51 | if: ${{ matrix.deps == 'low' }} 52 | 53 | - run: vendor/bin/phpunit -c phpunit.xml --colors=always 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | vendor/ 3 | var/ 4 | ezpublish_legacy/ 5 | composer.phar 6 | composer.lock 7 | phpunit.phar 8 | .php_cs.cache 9 | **/.sass-cache 10 | npm-debug.log 11 | node_modules 12 | *.css.map 13 | build 14 | .DS_Store 15 | frontend/dist/ 16 | 17 | # local env files 18 | .env.local 19 | .env.*.local 20 | 21 | # Log files 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # Editor directories and files 27 | .vscode 28 | *.suo 29 | *.ntvs* 30 | *.njsproj 31 | *.sln 32 | *.sw? 33 | -------------------------------------------------------------------------------- /.php-cs-fixer.php: -------------------------------------------------------------------------------- 1 | setRiskyAllowed(true) 8 | ->setRules([ 9 | '@Symfony' => true, 10 | '@Symfony:risky' => true, 11 | '@PSR12' => true, 12 | '@PSR12:risky' => true, 13 | '@PhpCsFixer' => true, 14 | '@PhpCsFixer:risky' => true, 15 | 16 | // Overrides for rules included in PhpCsFixer rule sets 17 | 'array_syntax' => ['syntax' => 'short'], 18 | 'cast_spaces' => ['space' => 'single'], 19 | 'concat_space' => ['spacing' => 'one'], 20 | 'method_chaining_indentation' => false, 21 | 'multiline_whitespace_before_semicolons' => false, 22 | 'native_function_invocation' => ['include' => ['@all']], 23 | 'no_superfluous_phpdoc_tags' => false, 24 | 'no_alias_functions' => true, 25 | 'no_unset_on_property' => false, 26 | 'ordered_imports' => ['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha'], 27 | 'php_unit_internal_class' => false, 28 | 'php_unit_method_casing' => false, 29 | 'php_unit_strict' => false, 30 | 'php_unit_test_annotation' => false, 31 | 'php_unit_test_case_static_method_calls' => ['call_type' => 'self'], 32 | 'php_unit_test_class_requires_covers' => false, 33 | 'phpdoc_align' => false, 34 | 'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'], 35 | 'return_assignment' => false, 36 | 'self_accessor' => false, 37 | 'single_line_comment_style' => false, 38 | 'space_after_semicolon' => false, 39 | 'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false], 40 | 41 | // Additional rules 42 | 'declare_strict_types' => true, 43 | 'date_time_immutable' => true, 44 | 'global_namespace_import' => [ 45 | 'import_classes' => null, 46 | 'import_constants' => true, 47 | 'import_functions' => true, 48 | ], 49 | 'heredoc_indentation' => ['indentation' => 'same_as_start'], 50 | 'list_syntax' => ['syntax' => 'short'], 51 | 'mb_str_functions' => true, 52 | 'native_constant_invocation' => true, 53 | 'nullable_type_declaration_for_default_null_value' => true, 54 | 'static_lambda' => true, 55 | 'ternary_to_null_coalescing' => true, 56 | 'use_arrow_functions' => false, 57 | ]) 58 | ->setFinder( 59 | PhpCsFixer\Finder::create() 60 | ->exclude(['vendor', 'docs', 'ezpublish_legacy']) 61 | ->in(__DIR__) 62 | ) 63 | ; 64 | 65 | return $config; 66 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | # cache directories 4 | cache: 5 | directories: 6 | - vendor 7 | - $HOME/.composer/cache/files 8 | 9 | matrix: 10 | # mark as finished before allow_failures are run 11 | fast_finish: true 12 | include: 13 | - php: 7.0 14 | - php: 7.1 15 | - php: 7.2 16 | 17 | # test only master (+ pull requests) 18 | branches: 19 | only: 20 | - master 21 | - 1.1-release 22 | 23 | # make sure to update composer to latest available version 24 | before_install: 25 | - composer self-update 26 | - phpenv config-add travis.php.ini 27 | 28 | # install dependencies 29 | install: 30 | - travis_wait composer install --no-interaction --no-progress --prefer-dist 31 | 32 | # execute phpunit as the script command 33 | script: 34 | - ./vendor/bin/phpunit -d memory_limit=-1 --colors -c phpunit.xml.dist --coverage-clover=coverage.xml 35 | 36 | # disable mail notifications 37 | notification: 38 | email: false 39 | 40 | # reduce depth (history) of git checkout 41 | git: 42 | depth: 30 43 | 44 | # we don't need sudo 45 | sudo: false 46 | 47 | # enable scrutinizer 48 | after_script: 49 | - wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover 50 | 51 | # send coverage to codecov.io 52 | after_success: 53 | - bash <(curl -s https://codecov.io/bash) 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netgen Remote Media Bundle 2 | 3 | [![Build Status](https://img.shields.io/travis/netgen/NetgenRemoteMediaBundle.svg?style=flat-square)](https://travis-ci.org/netgen/NetgenRemoteMediaBundle) 4 | [![Code Coverage](https://img.shields.io/codecov/c/github/netgen/NetgenRemoteMediaBundle.svg?style=flat-square)](https://codecov.io/gh/netgen/NetgenRemoteMediaBundle) 5 | [![Downloads](https://img.shields.io/packagist/dt/netgen/remote-media-bundle.svg?style=flat-square)](https://packagist.org/packages/netgen/remote-media-bundle) 6 | [![Latest stable](https://img.shields.io/packagist/v/netgen/remote-media-bundle.svg?style=flat-square)](https://packagist.org/packages/netgen/remote-media-bundle) 7 | [![License](https://img.shields.io/github/license/netgen/NetgenRemoteMediaBundle.svg?style=flat-square)](LICENCE) 8 | 9 | Netgen Remote Media Bundle is an eZ Publish bundle providing field type which supports remote resource providers, primarily [Cloudinary](http://cloudinary.com/). 10 | 11 | This repository contains field type (and legacy data type) implementation and provides the interface for the legacy administration. It also contains integration for eZ XML and Richtext fields (as a custom tag). 12 | 13 | ## Features 14 | 15 | - field type support for remote resources (only Cloudinary supported at the moment) 16 | - eZ XML field custom tag 17 | - eZ Richtext field custom tag 18 | - support for images, videos, audio files, documents and raw files upload 19 | - images cropping editor 20 | - support for both legacy and new stack administrations 21 | 22 | ## Licence and installation instructions 23 | 24 | [Licence](LICENCE) 25 | 26 | [Installation instructions](docs/INSTALL.md) 27 | 28 | [Upgrade instructions](docs/UPGRADE.md) 29 | 30 | ## Documentation 31 | 32 | For usage documentation see [USAGE.md](docs/USAGE.md) 33 | 34 | For transformations usage see [TRANSFORMATIONS.md](docs/TRANSFORMATIONS.md) 35 | 36 | ## Changelog 37 | 38 | For changes in specific versions see [CHANGELOG.md](docs/CHANGELOG.md) 39 | 40 | ## Contributing 41 | 42 | For frontend development see [FRONTEND.md][docs/frontend.md] 43 | 44 | ## Copyright 45 | 46 | - Copyright (C) 2021 Keyteq. All rights reserved. 47 | - Copyright (C) 2021 Netgen. All rights reserved. 48 | -------------------------------------------------------------------------------- /bundle/Command/ShowApiUsageCommand.php: -------------------------------------------------------------------------------- 1 | provider = $provider; 24 | 25 | parent::__construct(null); 26 | } 27 | 28 | protected function configure() 29 | { 30 | $this 31 | ->setName('netgen:ngremotemedia:usage') 32 | ->setDescription('Show API usage (rate limits etc.)'); 33 | } 34 | 35 | protected function execute(InputInterface $input, OutputInterface $output) 36 | { 37 | $usage = $this->provider->usage(); 38 | 39 | foreach ($usage as $key => $value) { 40 | $output->writeln($this->getPrettyKey($key) . ': ' . $value . ''); 41 | } 42 | 43 | return 0; 44 | } 45 | 46 | private function getPrettyKey(string $key): string 47 | { 48 | return ucfirst(str_replace('_', ' ', $key)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /bundle/Controller/EzAdminUI/BrowseController.php: -------------------------------------------------------------------------------- 1 | remoteMediaProvider = $remoteMediaProvider; 26 | $this->remoteMediaHelper = $remoteMediaHelper; 27 | } 28 | 29 | public function __invoke(Request $request) 30 | { 31 | $limit = 25; 32 | $userQuery = $request->get('q', ''); 33 | $tag = $request->get('tag', 'all'); 34 | $type = $request->get('mediatype', 'all'); 35 | $folder = $request->get('folder', 'all'); 36 | $type = $type !== 'all' ? $type : null; 37 | $folder = $folder !== 'all' ? $folder : null; 38 | $tag = $tag !== 'all' ? $tag : null; 39 | 40 | switch ($folder) { 41 | case '(all)': 42 | $folder = null; 43 | 44 | break; 45 | 46 | case '(root)': 47 | $folder = ''; 48 | 49 | break; 50 | } 51 | 52 | $nextCursor = $request->get('next_cursor', null); 53 | if ($nextCursor === 'null') { 54 | $nextCursor = null; 55 | } 56 | 57 | $query = new Query( 58 | $userQuery, 59 | $type, 60 | $limit, 61 | $folder, 62 | $tag, 63 | $nextCursor, 64 | ); 65 | 66 | $results = $this->remoteMediaProvider->searchResources($query); 67 | $list = $results->getResults(); 68 | 69 | $result = [ 70 | 'hits' => $this->remoteMediaHelper->formatBrowseList($list), 71 | 'load_more' => $results->getNextCursor() !== null, 72 | 'next_cursor' => $results->getNextCursor(), 73 | ]; 74 | 75 | return new JsonResponse($result); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /bundle/Controller/EzAdminUI/Editor/FetchController.php: -------------------------------------------------------------------------------- 1 | remoteMediaProvider = $remoteMediaProvider; 29 | $this->remoteMediaHelper = $remoteMediaHelper; 30 | } 31 | 32 | public function __invoke(Request $request): Response 33 | { 34 | if (!$request->query->has('resource_id') && !$request->query->has('resource_type')) { 35 | throw new BadRequestHttpException('Request has to contain parameters "resource_id" and "resource_type"'); 36 | } 37 | 38 | $resourceId = $request->query->get('resource_id'); 39 | $resourceType = $request->query->get('resource_type'); 40 | 41 | $resource = $this->remoteMediaProvider->getRemoteResource($resourceId, $resourceType); 42 | 43 | return new JsonResponse($this->remoteMediaHelper->formatBrowseItem($resource)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bundle/Controller/EzAdminUI/Editor/InsertController.php: -------------------------------------------------------------------------------- 1 | updateFieldHelper = $updateFieldHelper; 36 | $this->remoteMediaProvider = $remoteMediaProvider; 37 | $this->remoteMediaHelper = $remoteMediaHelper; 38 | } 39 | 40 | public function __invoke(Request $request): Response 41 | { 42 | $oldValue = new Value(); 43 | 44 | if ($request->request->get('new_file') === null) { 45 | $oldValue = $this->remoteMediaProvider->getRemoteResource($request->request->get('resource_id')); 46 | } 47 | 48 | $hash = $request->request->all(); 49 | $hash['new_file'] = $request->files->get('new_file'); 50 | 51 | $adminInputValue = AdminInputValue::fromHash($hash); 52 | $updatedValue = $this->updateFieldHelper->updateValue($oldValue, $adminInputValue); 53 | 54 | $selectedVariation = $request->request->get('variation'); 55 | 56 | $variation = null; 57 | if ($selectedVariation && $updatedValue->mediaType === Value::TYPE_IMAGE) { 58 | $variation = $this->remoteMediaProvider->buildVariation($updatedValue, 'embedded', $selectedVariation); 59 | } 60 | 61 | $thumbnailUrl = null; 62 | $videoTag = null; 63 | if ($updatedValue->resourceType === 'video') { 64 | $thumbnailUrl = $this->remoteMediaProvider->getVideoThumbnail($updatedValue); 65 | $videoTag = $this->remoteMediaProvider->generateVideoTag($updatedValue, 'embedded', $selectedVariation); 66 | } 67 | 68 | $data = $this->remoteMediaHelper->formatBrowseItem($updatedValue); 69 | $data['selected_variation'] = $selectedVariation; 70 | $data['variation_url'] = $variation->url ?? null; 71 | $data['image_variations'] = $adminInputValue->getVariations(); 72 | $data['thumbnail_url'] = $thumbnailUrl; 73 | $data['video_tag'] = $videoTag; 74 | 75 | return new JsonResponse($data); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /bundle/Controller/EzAdminUI/Facets/Load.php: -------------------------------------------------------------------------------- 1 | remoteMediaProvider = $remoteMediaProvider; 21 | } 22 | 23 | public function __invoke(): Response 24 | { 25 | $folders = $this->remoteMediaProvider->listFolders(); 26 | $tags = $this->remoteMediaProvider->listTags(); 27 | 28 | $formattedFolders = []; 29 | foreach ($folders as $folder) { 30 | $formattedFolders[] = [ 31 | 'id' => $folder['path'], 32 | 'label' => $folder['name'], 33 | 'children' => null, 34 | ]; 35 | } 36 | 37 | $formattedTags = []; 38 | foreach ($tags as $tag) { 39 | $formattedTags[] = [ 40 | 'name' => $tag, 41 | 'id' => $tag, 42 | ]; 43 | } 44 | 45 | $result = [ 46 | 'folders' => $formattedFolders, 47 | 'tags' => $formattedTags, 48 | ]; 49 | 50 | return new JsonResponse($result); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bundle/Controller/EzAdminUI/Folder/Create.php: -------------------------------------------------------------------------------- 1 | remoteMediaProvider = $remoteMediaProvider; 21 | } 22 | 23 | public function __invoke(Request $request): Response 24 | { 25 | $parent = $request->request->get('parent'); 26 | $folder = $request->request->get('folder'); 27 | 28 | $folderPath = $folder; 29 | if ($parent !== 'null') { 30 | $folderPath = $parent . '/' . $folderPath; 31 | } 32 | 33 | $this->remoteMediaProvider->createFolder($folderPath); 34 | 35 | return new Response(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /bundle/Controller/EzAdminUI/Folder/Load.php: -------------------------------------------------------------------------------- 1 | remoteMediaProvider = $remoteMediaProvider; 22 | } 23 | 24 | public function __invoke(Request $request): Response 25 | { 26 | $folder = $request->query->get('folder'); 27 | 28 | if ($folder === '(root)') { 29 | $folder = null; 30 | } 31 | 32 | $folders = $folder === null 33 | ? $this->remoteMediaProvider->listFolders() 34 | : $this->remoteMediaProvider->listSubFolders($folder); 35 | 36 | $formattedFolders = []; 37 | foreach ($folders as $folder) { 38 | $formattedFolders[] = [ 39 | 'id' => $folder['path'], 40 | 'label' => $folder['name'], 41 | 'children' => null, 42 | ]; 43 | } 44 | 45 | return new JsonResponse($formattedFolders); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bundle/Converter/XmlText/NgRemoteMediaPreConverter.php: -------------------------------------------------------------------------------- 1 | remoteMediaProvider = $remoteMediaProvider; 25 | } 26 | 27 | public function convert(DOMDocument $xmlDoc) 28 | { 29 | $xpath = new DOMXPath($xmlDoc); 30 | $tags = $xpath->query("//custom[@name='ngremotemedia']"); 31 | 32 | /** @var \DOMElement $tag */ 33 | foreach ($tags as $tag) { 34 | $src = ''; 35 | $videoTag = ''; 36 | $filename = ''; 37 | 38 | $resourceId = $tag->getAttributeNS(self::CUSTOMTAG_NAMESPACE, 'resourceId'); 39 | $resourceType = $tag->getAttributeNS(self::CUSTOMTAG_NAMESPACE, 'resourceType') !== '' 40 | ? $tag->getAttributeNS(self::CUSTOMTAG_NAMESPACE, 'resourceType') 41 | : 'image'; 42 | $imageVariations = $tag->getAttributeNS(self::CUSTOMTAG_NAMESPACE, 'coords'); 43 | $variation = $tag->getAttributeNS(self::CUSTOMTAG_NAMESPACE, 'variation'); 44 | 45 | $resource = $this->remoteMediaProvider->getRemoteResource($resourceId, $resourceType); 46 | $resource->variations = json_decode($imageVariations, true); 47 | 48 | switch ($resource->mediaType) { 49 | case 'video': 50 | $videoTag = $this->remoteMediaProvider->generateVideoTag($resource, 'embedded', $variation); 51 | $src = $this->remoteMediaProvider->getVideoThumbnail($resource); 52 | 53 | break; 54 | 55 | case 'image': 56 | $src = $resource->secure_url; 57 | 58 | if ($variation !== '') { 59 | $variation = $this->remoteMediaProvider->buildVariation($resource, 'embedded', $variation); 60 | $src = $variation->url; 61 | } 62 | 63 | break; 64 | 65 | default: 66 | $src = $this->remoteMediaProvider->generateDownloadLink($resource); 67 | } 68 | 69 | $tag->setAttributeNS(self::CUSTOMTAG_NAMESPACE, 'src', $src); 70 | $tag->setAttributeNS(self::CUSTOMTAG_NAMESPACE, 'videoTag', $videoTag); 71 | $tag->setAttributeNS(self::CUSTOMTAG_NAMESPACE, 'alt', $resource->metaData['alt_text'] ?? ''); 72 | $tag->setAttributeNS(self::CUSTOMTAG_NAMESPACE, 'mediaType', $resource->mediaType ?? ''); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /bundle/Core/FieldType/RemoteMedia/FormMapper.php: -------------------------------------------------------------------------------- 1 | add( 20 | $fieldForm->getConfig()->getFormFactory()->createBuilder() 21 | ->create( 22 | 'value', 23 | RemoteMediaFieldType::class, 24 | [ 25 | 'required' => $data->fieldDefinition->isRequired, 26 | 'label' => $data->fieldDefinition->getName(), 27 | 'field' => $data->field, 28 | ], 29 | ) 30 | ->setAutoInitialize(false) 31 | ->getForm(), 32 | ); 33 | } 34 | 35 | public function mapFieldDefinitionForm(FormInterface $fieldDefinitionForm, FieldDefinitionData $data) 36 | { 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /bundle/Core/FieldType/RemoteMedia/InputValue.php: -------------------------------------------------------------------------------- 1 | value->data['url'] ?? null, 29 | new StringField(), 30 | ), 31 | ]; 32 | } 33 | 34 | /** 35 | * Get index field types for search backend. 36 | * 37 | * @return \eZ\Publish\SPI\Search\FieldType[] 38 | */ 39 | public function getIndexDefinition() 40 | { 41 | return [ 42 | 'value' => new StringField(), 43 | ]; 44 | } 45 | 46 | /** 47 | * Get name of the default field to be used for matching. 48 | * 49 | * As field types can index multiple fields (see MapLocation field type's 50 | * implementation of this interface), this method is used to define default 51 | * field for matching. Default field is typically used by Field criterion. 52 | * 53 | * @return string 54 | */ 55 | public function getDefaultMatchField() 56 | { 57 | return 'value'; 58 | } 59 | 60 | /** 61 | * Get name of the default field to be used for sorting. 62 | * 63 | * As field types can index multiple fields (see MapLocation field type's 64 | * implementation of this interface), this method is used to define default 65 | * field for sorting. Default field is typically used by Field sort clause. 66 | * 67 | * @return string 68 | */ 69 | public function getDefaultSortField() 70 | { 71 | return $this->getDefaultMatchField(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /bundle/Core/FieldType/RemoteMedia/Variation.php: -------------------------------------------------------------------------------- 1 | 0, 'y' => 0]; 16 | 17 | /** 18 | * Returns a string representation of the field value. 19 | * 20 | * @return string 21 | */ 22 | public function __toString() 23 | { 24 | return json_encode($this); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bundle/Core/Persistence/Legacy/Content/FieldValue/Converter/RemoteMediaConverter.php: -------------------------------------------------------------------------------- 1 | dataText = json_encode($value->data); 31 | } 32 | 33 | /** 34 | * Converts data from $value to $fieldValue. 35 | */ 36 | public function toFieldValue(StorageFieldValue $value, FieldValue $fieldValue) 37 | { 38 | $fieldValue->data = json_decode($value->dataText, true); 39 | } 40 | 41 | /** 42 | * Converts field definition data in $fieldDef into $storageFieldDef. 43 | */ 44 | public function toStorageFieldDefinition(FieldDefinition $fieldDef, StorageFieldDefinition $storageDef) 45 | { 46 | } 47 | 48 | /** 49 | * Converts field definition data in $storageDef into $fieldDef. 50 | */ 51 | public function toFieldDefinition(StorageFieldDefinition $storageDef, FieldDefinition $fieldDef) 52 | { 53 | } 54 | 55 | /** 56 | * Returns the name of the index column in the attribute table. 57 | * 58 | * @return string 59 | */ 60 | public function getIndexColumn() 61 | { 62 | return 'data_text'; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /bundle/DependencyInjection/Compiler/TransformationHandlersCompilerPass.php: -------------------------------------------------------------------------------- 1 | hasDefinition('netgen_remote_media.handler_registry')) { 20 | return; 21 | } 22 | 23 | $handlerRegistry = $container->getDefinition('netgen_remote_media.handler_registry'); 24 | 25 | foreach ($container->findTaggedServiceIds('netgen_remote_media.transformation_handler') as $serviceId => $transformationHandler) { 26 | if (!isset($transformationHandler[0]['alias'])) { 27 | throw new LogicException('netgen_remote_media.transformation_handler service tag needs an "alias" attribute to identify the handler. None given.'); 28 | } 29 | 30 | if (!isset($transformationHandler[0]['provider'])) { 31 | throw new LogicException('netgen_remote_media.transformation_handler service tag needs an "provider" attribute to identify which providers it supports. None given.'); 32 | } 33 | 34 | $handlerRegistry->addMethodCall( 35 | 'addHandler', 36 | [ 37 | $transformationHandler[0]['provider'], 38 | $transformationHandler[0]['alias'], 39 | new Reference($serviceId), 40 | ] 41 | ); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bundle/DependencyInjection/Compiler/XslRegisterPass.php: -------------------------------------------------------------------------------- 1 | hasParameter('ezpublish.siteaccess.list')) { 24 | return; 25 | } 26 | 27 | $scopes = array_merge( 28 | [ConfigResolver::SCOPE_DEFAULT], 29 | $container->getParameter('ezpublish.siteaccess.list') 30 | ); 31 | 32 | if (empty($scopes)) { 33 | return; 34 | } 35 | 36 | foreach ($scopes as $scope) { 37 | if (!$container->hasParameter(sprintf('ezsettings.%s.fieldtypes.ezxml.custom_xsl', $scope))) { 38 | continue; 39 | } 40 | 41 | $xslConfig = $container->getParameter(sprintf('ezsettings.%s.fieldtypes.ezxml.custom_xsl', $scope)); 42 | $xslConfig[] = ['path' => __DIR__ . '/../../Resources/xsl/ezxml_ngremotemedia.xsl', 'priority' => 5000]; 43 | $container->setParameter(sprintf('ezsettings.%s.fieldtypes.ezxml.custom_xsl', $scope), $xslConfig); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bundle/Entity/RemoteMediaFieldLink.php: -------------------------------------------------------------------------------- 1 | contentId = $contentId; 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * Returns eZ Publish content ID. 50 | * 51 | * @return int 52 | */ 53 | public function getContentId() 54 | { 55 | return $this->contentId; 56 | } 57 | 58 | /** 59 | * Sets eZ Publish field ID. 60 | * 61 | * @param mixed $fieldId 62 | * 63 | * @return \Netgen\Bundle\RemoteMediaBundle\Entity\RemoteMediaFieldLink 64 | */ 65 | public function setFieldId($fieldId) 66 | { 67 | $this->fieldId = $fieldId; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Returns eZ Publish field ID. 74 | * 75 | * @return mixed 76 | */ 77 | public function getFieldId() 78 | { 79 | return $this->fieldId; 80 | } 81 | 82 | /** 83 | * @param mixed $versionId 84 | * 85 | * @return \Netgen\Bundle\RemoteMediaBundle\Entity\RemoteMediaFieldLink 86 | */ 87 | public function setVersionId($versionId) 88 | { 89 | $this->versionId = $versionId; 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * @return mixed 96 | */ 97 | public function getVersionId() 98 | { 99 | return $this->versionId; 100 | } 101 | 102 | /** 103 | * Sets remote resource id. 104 | * 105 | * @param string $resourceId 106 | * 107 | * @return \Netgen\Bundle\RemoteMediaBundle\Entity\RemoteMediaFieldLink 108 | */ 109 | public function setResourceId($resourceId) 110 | { 111 | $this->resourceId = $resourceId; 112 | 113 | return $this; 114 | } 115 | 116 | /** 117 | * Returns remote resource id. 118 | * 119 | * @return string 120 | */ 121 | public function getResourceId() 122 | { 123 | return $this->resourceId; 124 | } 125 | 126 | /** 127 | * Sets remote provider identifier. 128 | * 129 | * @param string $provider 130 | * 131 | * @return \Netgen\Bundle\RemoteMediaBundle\Entity\RemoteMediaFieldLink 132 | */ 133 | public function setProvider($provider) 134 | { 135 | $this->provider = $provider; 136 | 137 | return $this; 138 | } 139 | 140 | /** 141 | * Returns remote provider identifier. 142 | * 143 | * @return string 144 | */ 145 | public function getProvider() 146 | { 147 | return $this->provider; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /bundle/Exception/MimeCategoryParseException.php: -------------------------------------------------------------------------------- 1 | fieldType = $fieldType; 42 | $this->field = $field; 43 | $this->remoteMediaProvider = $remoteMediaProvider; 44 | $this->updateHelper = $updateFieldHelper; 45 | } 46 | 47 | /** 48 | * @param \Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\Value $value 49 | * 50 | * @return array|null 51 | */ 52 | public function transform($value) 53 | { 54 | if (!$value instanceof Value) { 55 | return null; 56 | } 57 | 58 | return [ 59 | 'resource_id' => $value->resourceId, 60 | 'alt_text' => $value->metaData['alt_text'] ?? '', 61 | 'tags' => is_array($value->metaData['tags']) ? $value->metaData['tags'] : [], 62 | 'image_variations' => json_encode($value->variations), 63 | 'type' => $value->mediaType, 64 | ]; 65 | } 66 | 67 | /** 68 | * @param array|null $value 69 | * 70 | * @return \Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\Value 71 | */ 72 | public function reverseTransform($value) 73 | { 74 | if ($value === null) { 75 | return $this->fieldType->getEmptyValue(); 76 | } 77 | 78 | $oldValue = $this->field->value; 79 | if ($oldValue === null) { 80 | $oldValue = $this->fieldType->getEmptyValue(); 81 | } 82 | 83 | $adminInputValue = AdminInputValue::fromHash($value); 84 | 85 | return $this->updateHelper->updateValue($oldValue, $adminInputValue); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /bundle/NetgenRemoteMediaBundle.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new XslRegisterPass()); 22 | $container->addCompilerPass(new TransformationHandlersCompilerPass()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/NextCursorResolver.php: -------------------------------------------------------------------------------- 1 | cache = $cache; 51 | $this->ttl = $ttl; 52 | } 53 | 54 | /** 55 | * @throws \Psr\Cache\InvalidArgumentException 56 | */ 57 | public function resolve(Query $query, int $offset): string 58 | { 59 | $cacheKey = $this->getCacheKey($query, $offset); 60 | $cacheItem = $this->cache->getItem($cacheKey); 61 | 62 | if ($cacheItem->isHit()) { 63 | return $cacheItem->get(); 64 | } 65 | 66 | throw new RuntimeException("Can't get cursor key for query: " . (string) $query . " with offset: {$offset}"); 67 | } 68 | 69 | /** 70 | * @throws \Psr\Cache\InvalidArgumentException 71 | */ 72 | public function save(Query $query, int $offset, string $cursor): void 73 | { 74 | $cacheKey = $this->getCacheKey($query, $offset); 75 | $cacheItem = $this->cache->getItem($cacheKey); 76 | 77 | $cacheItem->set($cursor); 78 | $cacheItem->expiresAfter($this->ttl); 79 | 80 | $this->cache->save($cacheItem); 81 | } 82 | 83 | private function getCacheKey(Query $query, int $offset): string 84 | { 85 | $queryVars = [ 86 | $query->getQuery(), 87 | is_array($query->getResourceType()) ? implode(',', $query->getResourceType()) : $query->getResourceType(), 88 | $query->getLimit(), 89 | $query->getFolder(), 90 | $query->getTag(), 91 | http_build_query($query->getSortBy(), '', ','), 92 | ]; 93 | 94 | return $this->washKey( 95 | implode('-', [self::PROJECT_KEY, self::PROVIDER_KEY, self::NEXT_CURSOR, implode('|', $queryVars), $offset]) 96 | ); 97 | } 98 | 99 | private function washKey($key) 100 | { 101 | $forbiddenCharacters = ['{', '}', '(', ')', '/', '\\', '@']; 102 | foreach ($forbiddenCharacters as $char) { 103 | $key = str_replace($char, '_', trim($key, $char)); 104 | } 105 | 106 | return $key; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/Search/Result.php: -------------------------------------------------------------------------------- 1 | totalCount = $totalCount; 23 | $this->nextCursor = $nextCursor; 24 | $this->results = $results; 25 | } 26 | 27 | public static function fromResponse(Response $response): self 28 | { 29 | $totalCount = $response['total_count']; 30 | $nextCursor = $response['next_cursor'] ?? null; 31 | $results = $response['resources']; 32 | 33 | return new Result($totalCount, $nextCursor, $results); 34 | } 35 | 36 | public function getTotalCount(): int 37 | { 38 | return $this->totalCount; 39 | } 40 | 41 | /** 42 | * @return string 43 | */ 44 | public function getNextCursor(): ?string 45 | { 46 | return $this->nextCursor; 47 | } 48 | 49 | public function getResults(): array 50 | { 51 | return $this->results; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Crop.php: -------------------------------------------------------------------------------- 1 | variations)) { 34 | $coords = $value->variations[$variationName]; 35 | 36 | $options[] = [ 37 | 'x' => (int) $coords['x'], 38 | 'y' => (int) $coords['y'], 39 | 'width' => (int) $coords['w'], 40 | 'height' => (int) $coords['h'], 41 | 'crop' => 'crop', 42 | ]; 43 | 44 | return $options; 45 | } 46 | 47 | throw new TransformationHandlerFailedException(self::class); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Effect.php: -------------------------------------------------------------------------------- 1 | $config[0], 42 | ]; 43 | } 44 | 45 | return [ 46 | 'effect' => $config[0] . ':' . $config[1], 47 | ]; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Fill.php: -------------------------------------------------------------------------------- 1 | 'fill', 33 | ]; 34 | 35 | if (isset($config[0]) && $config[0] !== 0) { 36 | $options['width'] = $config[0]; 37 | } 38 | 39 | if (isset($config[1]) && $config[1] !== 0) { 40 | $options['height'] = $config[1]; 41 | } 42 | 43 | return $options; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Fit.php: -------------------------------------------------------------------------------- 1 | 'fit', 31 | ]; 32 | 33 | if (isset($config[0]) && $config[0] !== 0) { 34 | $options['width'] = $config[0]; 35 | } 36 | 37 | if (isset($config[1]) && $config[1] !== 0) { 38 | $options['height'] = $config[1]; 39 | } 40 | 41 | return $options; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Format.php: -------------------------------------------------------------------------------- 1 | $config[0], 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Lfill.php: -------------------------------------------------------------------------------- 1 | 'lfill', 36 | ]; 37 | 38 | if (isset($config[0]) && $config[0] !== 0) { 39 | $options['width'] = $config[0]; 40 | } 41 | 42 | if (isset($config[1]) && $config[1] !== 0) { 43 | $options['height'] = $config[1]; 44 | } 45 | 46 | return $options; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Limit.php: -------------------------------------------------------------------------------- 1 | 'limit', 35 | ]; 36 | 37 | if (isset($config[0]) && $config[0] !== 0) { 38 | $options['width'] = $config[0]; 39 | } 40 | 41 | if (isset($config[1]) && $config[1] !== 0) { 42 | $options['height'] = $config[1]; 43 | } 44 | 45 | return $options; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Lpad.php: -------------------------------------------------------------------------------- 1 | 'lpad', 36 | ]; 37 | 38 | if (isset($config[0]) && $config[0] !== 0) { 39 | $options['width'] = $config[0]; 40 | } 41 | 42 | if (isset($config[1]) && $config[1] !== 0) { 43 | $options['height'] = $config[1]; 44 | } 45 | 46 | if (!empty($config[2])) { 47 | $options['background'] = $config[2]; 48 | } 49 | 50 | return $options; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Mfit.php: -------------------------------------------------------------------------------- 1 | 'mfit', 35 | ]; 36 | 37 | if (isset($config[0]) && $config[0] !== 0) { 38 | $options['width'] = $config[0]; 39 | } 40 | 41 | if (isset($config[1]) && $config[1] !== 0) { 42 | $options['height'] = $config[1]; 43 | } 44 | 45 | return $options; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Mpad.php: -------------------------------------------------------------------------------- 1 | 'mpad', 37 | ]; 38 | 39 | if (isset($config[0]) && $config[0] !== 0) { 40 | $options['width'] = $config[0]; 41 | } 42 | 43 | if (isset($config[1]) && $config[1] !== 0) { 44 | $options['height'] = $config[1]; 45 | } 46 | 47 | return $options; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/NamedTransformation.php: -------------------------------------------------------------------------------- 1 | $config[0], 42 | ]; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Pad.php: -------------------------------------------------------------------------------- 1 | 'pad', 33 | ]; 34 | 35 | if (isset($config[0]) && $config[0] !== 0) { 36 | $options['width'] = $config[0]; 37 | } 38 | 39 | if (isset($config[1]) && $config[1] !== 0) { 40 | $options['height'] = $config[1]; 41 | } 42 | 43 | if (!empty($config[2])) { 44 | $options['background'] = $config[2]; 45 | } 46 | 47 | return $options; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Quality.php: -------------------------------------------------------------------------------- 1 | $config[0], 52 | ]; 53 | } 54 | 55 | if ($config[0] === 'auto') { 56 | return [ 57 | 'quality' => $config[0] . ':' . $config[1], 58 | ]; 59 | } 60 | 61 | throw new TransformationHandlerFailedException(self::class); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Provider/Cloudinary/TransformationHandler/Resize.php: -------------------------------------------------------------------------------- 1 | 'scale', 33 | ]; 34 | 35 | if (isset($config[0]) && $config[0] !== 0) { 36 | $options['width'] = $config[0]; 37 | } 38 | 39 | if (isset($config[1]) && $config[1] !== 0) { 40 | $options['height'] = $config[1]; 41 | } 42 | 43 | return $options; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/Transformation/HandlerInterface.php: -------------------------------------------------------------------------------- 1 | transformationHandlers[$provider][$identifier])) { 26 | $this->transformationHandlers[$provider][$identifier] = $transformationHandler; 27 | } 28 | } 29 | 30 | /** 31 | * Returns handler by its identifier. 32 | * 33 | * @param string $identifier 34 | * @param string $provider 35 | * 36 | * @throws \Netgen\Bundle\RemoteMediaBundle\Exception\TransformationHandlerNotFoundException If the handler is not found 37 | * 38 | * @return \Netgen\Bundle\RemoteMediaBundle\RemoteMedia\Transformation\HandlerInterface 39 | */ 40 | public function getHandler($identifier, $provider) 41 | { 42 | if (isset($this->transformationHandlers[$provider][$identifier])) { 43 | return $this->transformationHandlers[$provider][$identifier]; 44 | } 45 | 46 | throw new TransformationHandlerNotFoundException($provider, $identifier); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/UploadFile.php: -------------------------------------------------------------------------------- 1 | uri = $uri; 38 | $uploadFile->originalFilename = pathinfo($uri, PATHINFO_FILENAME); 39 | $uploadFile->originalExtension = pathinfo($uri, PATHINFO_EXTENSION); 40 | 41 | return $uploadFile; 42 | } 43 | 44 | /** 45 | * Constructs UploadFile from given eZHTTPFile (usually uploaded through the legacy admin). 46 | * 47 | * @return UploadFile 48 | */ 49 | public static function fromZHTTPFile(eZHTTPFile $file) 50 | { 51 | $uploadFile = new self(); 52 | 53 | $uploadFile->uri = $file->Filename; 54 | $uploadFile->originalFilename = pathinfo($file->OriginalFilename, PATHINFO_FILENAME); 55 | $uploadFile->originalExtension = pathinfo($file->OriginalFilename, PATHINFO_EXTENSION); 56 | 57 | return $uploadFile; 58 | } 59 | 60 | public static function fromUploadedFile(UploadedFile $file) 61 | { 62 | $uploadFile = new self(); 63 | 64 | $uploadFile->uri = $file->getRealPath(); 65 | $uploadFile->originalFilename = $file->getClientOriginalName(); 66 | $uploadFile->originalExtension = $file->getClientOriginalExtension(); 67 | 68 | return $uploadFile; 69 | } 70 | 71 | /** 72 | * Constructs UploadFile from given eZImage field Value. 73 | * 74 | * @param $webRoot 75 | * 76 | * @return UploadFile 77 | */ 78 | public static function fromEzImageValue(Value $value, $webRoot) 79 | { 80 | $uploadFile = new self(); 81 | 82 | $uploadFile->uri = $webRoot . $value->uri; 83 | $uploadFile->originalFilename = pathinfo($value->fileName, PATHINFO_FILENAME); 84 | $uploadFile->originalExtension = pathinfo($value->fileName, PATHINFO_EXTENSION); 85 | 86 | return $uploadFile; 87 | } 88 | 89 | /** 90 | * @return string 91 | */ 92 | public function uri() 93 | { 94 | return $this->uri; 95 | } 96 | 97 | /** 98 | * @return string 99 | */ 100 | public function originalFilename() 101 | { 102 | return $this->originalFilename; 103 | } 104 | 105 | /** 106 | * @return string 107 | */ 108 | public function originalExtension() 109 | { 110 | return $this->originalExtension; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /bundle/RemoteMedia/VariationResolver.php: -------------------------------------------------------------------------------- 1 | variations = $variations; 21 | } 22 | 23 | /** 24 | * Return merged variations defined for a provided content type and default ones. 25 | * 26 | * @param string $contentTypeIdentifier 27 | * 28 | * @return array 29 | */ 30 | public function getVariationsForContentType($contentTypeIdentifier) 31 | { 32 | $defaultVariations = $this->variations['default'] ?? []; 33 | $contentTypeVariations = $this->variations[$contentTypeIdentifier] ?? []; 34 | 35 | return array_merge($defaultVariations, $contentTypeVariations); 36 | } 37 | 38 | /** 39 | * Returns variations for a provided content type which have 'crop' transformation configured. 40 | * 41 | * @param $contentTypeIdentifier 42 | * 43 | * @return array 44 | */ 45 | public function getCroppbableVariations($contentTypeIdentifier) 46 | { 47 | $variations = $this->getVariationsForContentType($contentTypeIdentifier); 48 | 49 | $croppableVariations = []; 50 | foreach ($variations as $variationName => $variationOptions) { 51 | if (isset($variationOptions['transformations']['crop'])) { 52 | $croppableVariations[$variationName] = $variationOptions; 53 | } 54 | } 55 | 56 | return $croppableVariations; 57 | } 58 | 59 | /** 60 | * Returns variations to be used when embedding image into ezxml text. 61 | * 62 | * @return array 63 | */ 64 | public function getEmbedVariations() 65 | { 66 | $variations = $this->variations['embedded'] ?? []; 67 | 68 | $croppableVariations = []; 69 | foreach ($variations as $variationName => $variationOptions) { 70 | if (isset($variationOptions['transformations']['crop'])) { 71 | $croppableVariations[$variationName] = $variationOptions; 72 | } 73 | } 74 | 75 | return $croppableVariations; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /bundle/Resources/config/config.yml.example: -------------------------------------------------------------------------------- 1 | # Remote Media Configuration 2 | netgen_remote_media: 3 | provider: cloudinary # available options: cloudinary 4 | account_name: cloudname 5 | account_key: cloudinary_key 6 | account_secret: cloudinary_secret_key 7 | 8 | # If set to true, resources that are not connected to any eZ content objects 9 | # will be removed from the remote provider 10 | remove_unused: false 11 | -------------------------------------------------------------------------------- /bundle/Resources/config/default_parameters.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | netgen_remote_media.parameters.use_subdomains: true 3 | netgen_remote_media.cloudinary.internal_limit: 500 4 | netgen_remote_media.cloudinary.cache_ttl: 7200 5 | netgen_remote_media.default.parameters.audio.enable_waveform: false 6 | -------------------------------------------------------------------------------- /bundle/Resources/config/default_settings.yml: -------------------------------------------------------------------------------- 1 | system: 2 | default: 3 | image_variations: 4 | default: 5 | admin_preview: 6 | transformations: 7 | - { name: limit, params: [400,400] } 8 | ng_article: 9 | test: 10 | transformations: 11 | - { name: crop, params: [1600, 900] } 12 | - { name: resize, params: [1600, 900] } 13 | embedded: 14 | small: 15 | transformations: 16 | - { name: crop, params: [200, 200] } 17 | - { name: resize, params: [200, 200] } 18 | medium: 19 | transformations: 20 | - { name: crop, params: [800, 450] } 21 | - { name: resize, params: [800, 450] } 22 | large: 23 | transformations: 24 | - { name: crop, params: [1600, 900] } 25 | - { name: resize, params: [1600, 900] } 26 | -------------------------------------------------------------------------------- /bundle/Resources/config/doctrine/RemoteMediaFieldLink.orm.yml: -------------------------------------------------------------------------------- 1 | Netgen\Bundle\RemoteMediaBundle\Entity\RemoteMediaFieldLink: 2 | type: entity 3 | table: ngremotemedia_field_link 4 | id: 5 | fieldId: 6 | type: integer 7 | column: field_id 8 | versionId: 9 | type: integer 10 | column: version 11 | resourceId: 12 | type: string 13 | column: resource_id 14 | provider: 15 | type: string 16 | column: provider 17 | fields: 18 | contentId: 19 | type: integer 20 | column: contentobject_id 21 | -------------------------------------------------------------------------------- /bundle/Resources/config/ezadminui/controllers.yml: -------------------------------------------------------------------------------- 1 | services: 2 | netgen_remote_media.controllers.ezadminui.facets.load: 3 | class: Netgen\Bundle\RemoteMediaBundle\Controller\EzAdminUI\Facets\Load 4 | arguments: 5 | - '@netgen_remote_media.provider' 6 | 7 | netgen_remote_media.controllers.ezadminui.folder.load: 8 | class: Netgen\Bundle\RemoteMediaBundle\Controller\EzAdminUI\Folder\Load 9 | arguments: 10 | - '@netgen_remote_media.provider' 11 | 12 | netgen_remote_media.controllers.ezadminui.folder.create: 13 | class: Netgen\Bundle\RemoteMediaBundle\Controller\EzAdminUI\Folder\Create 14 | arguments: 15 | - '@netgen_remote_media.provider' 16 | 17 | netgen_remote_media.controllers.ezadminui.browse: 18 | class: Netgen\Bundle\RemoteMediaBundle\Controller\EzAdminUI\BrowseController 19 | arguments: 20 | - '@netgen_remote_media.provider' 21 | - '@netgen_remote_media.helper' 22 | 23 | netgen_remote_media.controllers.ezadminui.editor.fetch: 24 | class: Netgen\Bundle\RemoteMediaBundle\Controller\EzAdminUI\Editor\FetchController 25 | arguments: 26 | - '@netgen_remote_media.provider' 27 | - '@netgen_remote_media.helper' 28 | 29 | netgen_remote_media.controllers.ezadminui.editor.insert: 30 | class: Netgen\Bundle\RemoteMediaBundle\Controller\EzAdminUI\Editor\InsertController 31 | arguments: 32 | - '@netgen_remote_media.admin.field_update.helper' 33 | - '@netgen_remote_media.provider' 34 | - '@netgen_remote_media.helper' 35 | -------------------------------------------------------------------------------- /bundle/Resources/config/ezadminui/custom_tags.yml: -------------------------------------------------------------------------------- 1 | ezpublish: 2 | system: 3 | default: 4 | fieldtypes: 5 | ezrichtext: 6 | custom_tags: [ngremotemedia] 7 | 8 | ezrichtext: 9 | custom_tags: 10 | ngremotemedia: 11 | template: '@NetgenRemoteMedia/ezadminui/field_type/ezrichtext/custom_tag/ngremotemedia.html.twig' 12 | attributes: 13 | resourceId: 14 | type: string 15 | required: true 16 | resourceType: 17 | type: string 18 | required: true 19 | coords: 20 | type: string 21 | required: false 22 | variation: 23 | type: string 24 | required: false 25 | caption: 26 | type: string 27 | required: false 28 | cssclass: 29 | type: string 30 | required: false 31 | -------------------------------------------------------------------------------- /bundle/Resources/config/ezadminui/ezrichtext.yml: -------------------------------------------------------------------------------- 1 | alloy_editor: 2 | extra_plugins: [ngremotemedia] 3 | extra_buttons: 4 | paragraph: [ngremotemedia] 5 | ngremotemedia: [ngremotemedia] 6 | -------------------------------------------------------------------------------- /bundle/Resources/config/ezadminui/routing.yml: -------------------------------------------------------------------------------- 1 | netgen_remote_media_ezadmin_facets_load: 2 | path: /facets/load 3 | defaults: 4 | _controller: netgen_remote_media.controllers.ezadminui.facets.load 5 | 6 | netgen_remote_media_ezadmin_folder_load: 7 | path: /folder/load 8 | defaults: 9 | _controller: netgen_remote_media.controllers.ezadminui.folder.load 10 | 11 | netgen_remote_media_ezadmin_folder_create: 12 | path: /folder/create 13 | defaults: 14 | _controller: netgen_remote_media.controllers.ezadminui.folder.create 15 | 16 | netgen_remote_media_ezadmin_browse: 17 | path: /browse 18 | defaults: 19 | _controller: netgen_remote_media.controllers.ezadminui.browse 20 | 21 | netgen_remote_media_ezadmin_editor_fetch: 22 | path: /editor/fetch 23 | defaults: 24 | _controller: netgen_remote_media.controllers.ezadminui.editor.fetch 25 | 26 | netgen_remote_media_ezadmin_editor_insert: 27 | path: /editor/insert 28 | defaults: 29 | _controller: netgen_remote_media.controllers.ezadminui.editor.insert 30 | -------------------------------------------------------------------------------- /bundle/Resources/config/ezadminui/twig.yml: -------------------------------------------------------------------------------- 1 | form_themes: 2 | - '@NetgenRemoteMedia/ezadminui/field/edit/ngremotemedia.html.twig' 3 | -------------------------------------------------------------------------------- /bundle/Resources/config/ezpublish.yml: -------------------------------------------------------------------------------- 1 | system: 2 | admin_group: 3 | field_templates: 4 | - {template: "@NetgenRemoteMedia/ezadminui/field/view/ngremotemedia.html.twig", priority: 1} 5 | default: 6 | field_templates: 7 | - { template: "NetgenRemoteMediaBundle::ngremotemedia_content_field.html.twig", priority: 0 } 8 | fielddefinition_settings_templates: 9 | - {template: "NetgenRemoteMediaBundle:ezadminui/field_definition/view:ngremotemedia.html.twig", priority: 0} 10 | -------------------------------------------------------------------------------- /bundle/Resources/config/fieldtypes.yml: -------------------------------------------------------------------------------- 1 | services: 2 | ezpublish.fieldType.ngremotemedia: 3 | class: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\Type 4 | parent: ezpublish.fieldType 5 | tags: 6 | - {name: ezpublish.fieldType, alias: ngremotemedia} 7 | 8 | ezpublish.fieldType.ngremotemedia.converter: 9 | class: Netgen\Bundle\RemoteMediaBundle\Core\Persistence\Legacy\Content\FieldValue\Converter\RemoteMediaConverter 10 | tags: 11 | - {name: ezpublish.storageEngine.legacy.converter, alias: ngremotemedia} 12 | 13 | ezpublish.fieldType.ngremotemedia.externalStorage: 14 | class: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\RemoteMediaStorage 15 | arguments: 16 | - "@ezpublish.api.service.content" 17 | - "@netgen_remote_media.provider" 18 | calls: 19 | - [setDeleteUnused, ["%netgen_remote_media.remove_unused_resources%"]] 20 | tags: 21 | - {name: ezpublish.fieldType.externalStorageHandler, alias: ngremotemedia} 22 | 23 | ezpublish.fieldType.ngremotemedia.storage_gateway: 24 | class: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\RemoteMediaStorage\Gateway\LegacyStorage 25 | tags: 26 | - {name: ezpublish.fieldType.externalStorageHandler.gateway, alias: ngremotemedia, identifier: LegacyStorage} 27 | 28 | ezpublish.fieldType.indexable.netgen_remote_media: 29 | class: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\SearchField 30 | tags: 31 | - {name: ezpublish.fieldType.indexable, alias: ngremotemedia} 32 | 33 | ezpublish.ezadminui.form.ngremotemedia_field_type: 34 | class: Netgen\Bundle\RemoteMediaBundle\Form\FieldType\RemoteMediaFieldType 35 | public: false 36 | arguments: 37 | - "@ezpublish.api.service.field_type" 38 | - "@netgen_remote_media.provider" 39 | - "@netgen_remote_media.admin.field_update.helper" 40 | tags: 41 | - { name: form.type } 42 | 43 | netgen_remote_media.admin.field_update.helper: 44 | class: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\UpdateFieldHelper 45 | arguments: 46 | - "@netgen_remote_media.provider" 47 | 48 | ezpublish.fieldtype.ngremotemedia.form_mapper: 49 | class: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\FormMapper 50 | arguments: 51 | - '@ezpublish.api.service.field_type' 52 | tags: 53 | - {name: ez.fieldFormMapper.value, fieldType: ngremotemedia} 54 | -------------------------------------------------------------------------------- /bundle/Resources/config/legacy.yml: -------------------------------------------------------------------------------- 1 | services: 2 | netgen_remote_media.templating.converter.ngremotemedia: 3 | class: Netgen\Bundle\RemoteMediaBundle\Templating\Converter\RemoteMediaValueConverter 4 | tags: 5 | - {name: ezpublish_legacy.templating.converter, for: Netgen\Bundle\RemoteMediaBundle\Core\FieldType\RemoteMedia\Value} 6 | -------------------------------------------------------------------------------- /bundle/Resources/config/opengraph.yml: -------------------------------------------------------------------------------- 1 | services: 2 | netgen_remote_media.open_graph_handler: 3 | class: Netgen\Bundle\RemoteMediaBundle\OpenGraph\Handler\RemoteMediaHandler 4 | parent: netgen_open_graph.handler.field_type.abstract 5 | arguments: 6 | - "@netgen_remote_media.provider" 7 | - "@ezpublish.api.service.content_type" 8 | - "@request_stack" 9 | - "@?logger" 10 | lazy: true 11 | tags: 12 | - { name: netgen_open_graph.meta_tag_handler, alias: field_type/ngremotemedia } 13 | -------------------------------------------------------------------------------- /bundle/Resources/config/routing.yml: -------------------------------------------------------------------------------- 1 | netgen_remote_media_ezadmin: 2 | resource: "ezadminui/routing.yml" 3 | prefix: /ngremotemedia 4 | -------------------------------------------------------------------------------- /bundle/Resources/config/storage/cache_psr6.yml: -------------------------------------------------------------------------------- 1 | services: 2 | netgen_remote_media.provider.cloudinary.gateway.cached: 3 | class: Netgen\Bundle\RemoteMediaBundle\RemoteMedia\Provider\Cloudinary\Gateway\Cache\Psr6CachedGateway 4 | arguments: 5 | - "@netgen_remote_media.provider.cloudinary.gateway" 6 | - "@ezpublish.cache_pool" 7 | - "%netgen_remote_media.cloudinary.cache_ttl%" 8 | -------------------------------------------------------------------------------- /bundle/Resources/config/templating.yml: -------------------------------------------------------------------------------- 1 | services: 2 | netgen_remote_media.templating.twig.extension: 3 | class: Netgen\Bundle\RemoteMediaBundle\Templating\Twig\Extension\NetgenRemoteMediaExtension 4 | arguments: 5 | - "@netgen_remote_media.provider" 6 | - "@ezpublish.translation_helper" 7 | - "@ezpublish.api.service.content_type" 8 | - "@netgen_remote_media.variation.resolver" 9 | tags: 10 | - { name: twig.extension } 11 | -------------------------------------------------------------------------------- /bundle/Resources/encore/ez.config.manager.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = (eZConfig, eZConfigManager) => { 4 | eZConfigManager.add({ 5 | eZConfig, 6 | entryName: 'ezplatform-admin-ui-alloyeditor-js', 7 | newItems: [ 8 | path.resolve(__dirname, '../public/js/alloyeditor/buttons/ngremotemedia.js'), 9 | path.resolve(__dirname, '../public/js/alloyeditor/plugins/ngremotemedia.js'), 10 | ] 11 | }); 12 | }; 13 | -------------------------------------------------------------------------------- /bundle/Resources/public/img/cloud-upload-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bundle/Resources/public/js/alloyeditor/buttons/ngremotemedia.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import AlloyEditor from 'alloyeditor'; 3 | import EzButton 4 | from '../../../../../../../../../vendor/ezsystems/ezplatform-admin-ui/src/bundle/Resources/public/js/alloyeditor/src/base/ez-button.js'; 5 | 6 | export default class BtnNgRemoteMedia extends EzButton { 7 | static get key() { 8 | return 'ngremotemedia'; 9 | } 10 | 11 | InsertMedia(data) { 12 | this.execCommand(data); 13 | } 14 | 15 | render() { 16 | const title = 'Netgen Remote Media'; 17 | 18 | return ( 19 | 26 | ); 27 | } 28 | } 29 | 30 | AlloyEditor.Buttons[BtnNgRemoteMedia.key] = AlloyEditor.BtnNgRemoteMedia = BtnNgRemoteMedia; 31 | eZ.addConfig('ezAlloyEditor.BtnNgRemoteMedia', BtnNgRemoteMedia); 32 | 33 | BtnNgRemoteMedia.propTypes = { 34 | command: PropTypes.string, 35 | }; 36 | 37 | BtnNgRemoteMedia.defaultProps = { 38 | command: 'InsertMedia', 39 | }; 40 | -------------------------------------------------------------------------------- /bundle/Resources/public/js/alloyeditor/plugins/ngremotemedia.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | if (CKEDITOR.plugins.get('ngremotemedia')) { 3 | return; 4 | } 5 | 6 | var currentEditorInstance = null; 7 | 8 | function InsertMediaCallback(data, caption, align, cssClass) { 9 | let alignAttr = ''; 10 | 11 | if (typeof align !== 'undefined' && align !== '') { 12 | alignAttr = ' data-ezalign="'+align+'"'; 13 | } 14 | 15 | let html = '
' + 19 | '
' + 23 | ' ' + 24 | ' ' + data.resourceId + '' + 25 | ' ' + data.type + '' + 26 | ' ' + JSON.stringify(data.image_variations) + '' + 27 | ' ' + data.selected_variation + '' + 28 | ' ' + caption + '' + 29 | ' ' + cssClass +'' + 30 | ' ' + 31 | '
' + 32 | '
'; 33 | 34 | currentEditorInstance.insertHtml(html); 35 | } 36 | 37 | const InsertMedia = { 38 | exec: function (editor) { 39 | var data = {}; 40 | window[`remoteMedia_ezrichtext`].setEditorInsertCallback(InsertMediaCallback); 41 | window[`remoteMedia_ezrichtext`].openEditorInsertModal(data); 42 | currentEditorInstance = editor; 43 | }, 44 | }; 45 | 46 | global.CKEDITOR.plugins.add('ngremotemedia', { 47 | init: (editor) => editor.addCommand('InsertMedia', InsertMedia), 48 | }); 49 | })(window); 50 | -------------------------------------------------------------------------------- /bundle/Resources/sql/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `ngremotemedia_field_link` ( 2 | `field_id` int(11) NOT NULL, 3 | `version` int(11) NOT NULL, 4 | `resource_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 5 | `provider` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 6 | `contentobject_id` int(11) NOT NULL, 7 | PRIMARY KEY (`field_id`,`version`,`resource_id`,`provider`) 8 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 9 | -------------------------------------------------------------------------------- /bundle/Resources/translations/custom_tags.en.yml: -------------------------------------------------------------------------------- 1 | ezrichtext.custom_tags.ngremotemedia.label: Netgen Remote Media 2 | ezrichtext.custom_tags.ngremotemedia.description: '' 3 | ezrichtext.custom_tags.ngremotemedia.attributes.resourceId.label: Resource ID 4 | ezrichtext.custom_tags.ngremotemedia.attributes.resourceType.label: Resource type 5 | ezrichtext.custom_tags.ngremotemedia.attributes.coords.label: Image variations 6 | ezrichtext.custom_tags.ngremotemedia.attributes.variation.label: Selected variation 7 | ezrichtext.custom_tags.ngremotemedia.attributes.caption.label: Caption 8 | ezrichtext.custom_tags.ngremotemedia.attributes.cssclass.label: CSS class 9 | -------------------------------------------------------------------------------- /bundle/Resources/translations/custom_tags.no.yml: -------------------------------------------------------------------------------- 1 | ezrichtext.custom_tags.ngremotemedia.label: Netgen Remote Media 2 | ezrichtext.custom_tags.ngremotemedia.description: '' 3 | ezrichtext.custom_tags.ngremotemedia.attributes.resourceId.label: Ressurs-ID 4 | ezrichtext.custom_tags.ngremotemedia.attributes.resourceType.label: Ressurstype 5 | ezrichtext.custom_tags.ngremotemedia.attributes.coords.label: Bildevariasjoner 6 | ezrichtext.custom_tags.ngremotemedia.attributes.variation.label: Valgt variasjon 7 | ezrichtext.custom_tags.ngremotemedia.attributes.caption.label: Bildetekst 8 | ezrichtext.custom_tags.ngremotemedia.attributes.cssclass.label: CSS-klasse 9 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/field/edit/ngremotemedia.html.twig: -------------------------------------------------------------------------------- 1 | {% block ezplatform_fieldtype_ngremotemedia_widget %} 2 | {% set field = form.parent.vars.value.field %} 3 | 4 | {% set input_fields = {} %} 5 | {% for child in form %} 6 | {% set input_fields = input_fields|merge({(child.vars.name): child.vars.full_name}) %} 7 | {% endfor %} 8 | 9 | {% set content_type_identifier = app.request.attributes.get('contentType').identifier|default(null) %} 10 | 11 | {% include '@NetgenRemoteMedia/ezadminui/parts/edit/ngrm_field.html.twig' with { 12 | 'content_type_identifier': content_type_identifier, 13 | 'field_id': field.id, 14 | 'field_value': field.value, 15 | 'input_fields': input_fields, 16 | } %} 17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/field/view/ngremotemedia.html.twig: -------------------------------------------------------------------------------- 1 | {% extends '@NetgenRemoteMedia/ngremotemedia_content_field.html.twig' %} 2 | 3 | {% block ngremotemedia_field %} 4 | {% set parameters = {format: 'admin_preview'} %} 5 | {{ parent() }} 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/field_definition/view/ngremotemedia.html.twig: -------------------------------------------------------------------------------- 1 | {% block ngremotemedia_settings %} 2 | {% endblock %} 3 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/field_type/ezrichtext/custom_tag/ngremotemedia.html.twig: -------------------------------------------------------------------------------- 1 | {% set css_class = params.cssclass|default(null) %} 2 | {% set resource_id = params.resourceId|default(null) %} 3 | {% set resource_type = params.resourceType|default(null) %} 4 | {% set coords = params.coords|default('[]') %} 5 | {% set variation = params.variation|default(null) %} 6 | {% set caption = params.caption|default(null) %} 7 | {% set align = align|default(null) %} 8 | {% set css_class = params.cssclass|default(null) %} 9 | 10 | {% if resource_id and resource_type %} 11 | {% set resource = netgen_remote_media_embed(resource_id, resource_type, coords) %} 12 | 13 |
14 | {% if resource.mediaType == 'image' %} 15 | {% set image_url = resource.secure_url %} 16 | {% if variation %} 17 | {% set variation = netgen_remote_variation_embed(resource, variation) %} 18 | {% set image_url = variation.url %} 19 | {% endif %} 20 | 21 | {{ resource.metaData.alt_text }} 22 | {% elseif resource.mediaType == 'video' %} 23 | {{ netgen_remote_video_embed(resource, variation)|raw }} 24 | {% else %} 25 | {{ resource.resourceId }} 26 | {% endif %} 27 | 28 | {% if caption %} 29 |
{{ caption }}
30 | {% endif %} 31 |
32 | {% endif %} 33 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/javascripts.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/parts/edit/editor_insert.html.twig: -------------------------------------------------------------------------------- 1 | 34 | 35 |
36 | 48 |
49 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/parts/edit/ezrichtext.html.twig: -------------------------------------------------------------------------------- 1 | {% set has_richtext = false %} 2 | {% for field in contentType.fieldDefinitions %} 3 | {% if field.fieldTypeIdentifier == 'ezrichtext' %} 4 | {% set has_richtext = true %} 5 | {% endif %} 6 | {% endfor %} 7 | 8 | {% if has_richtext %} 9 | {% include '@NetgenRemoteMedia/ezadminui/js_config.html.twig' %} 10 | 11 | {% include '@NetgenRemoteMedia/ezadminui/parts/edit/editor_insert.html.twig' with { 12 | 'field_id': '_ezrichtext' 13 | } %} 14 | {% endif %} 15 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/parts/edit/ngrm_field.html.twig: -------------------------------------------------------------------------------- 1 | {% include '@NetgenRemoteMedia/ezadminui/js_config.html.twig' %} 2 | 3 | 40 | 41 |
42 | 47 |
48 | -------------------------------------------------------------------------------- /bundle/Resources/views/ezadminui/stylesheets.html.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /bundle/Resources/xsl/ezxml_ngremotemedia.xsl: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 |
14 | remote-image-inline remote- 15 | 16 | 17 | 18 | object-center 19 | 20 | 21 | 22 | object- 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
49 |
50 |
51 |
52 | -------------------------------------------------------------------------------- /bundle/Templating/Converter/RemoteMediaValueConverter.php: -------------------------------------------------------------------------------- 1 | 'extension/ngremotemedia/template_operator/ngremotemediaoperator.php', 7 | 'class' => 'NgRemoteMediaOperator', 8 | 'operator_names' => array('ngremotemedia', 'ng_remote_resource', 'ng_remote_croppable', 'ng_image_variations', 'scaling_format', 'list_format') 9 | ); 10 | 11 | ?> 12 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/classes/ezlimitationloader.php: -------------------------------------------------------------------------------- 1 | 'Browse', 'id' => 'browse' ); 15 | 16 | return $returnArray; 17 | } 18 | } 19 | ?> 20 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/design/standard/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netgen/NetgenRemoteMediaBundle/61615a8ae0e3c286f4c2bc4f024c77413f6112d6/bundle/ezpublish_legacy/ngremotemedia/design/standard/images/.gitkeep -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/design/standard/javascript/plugins/ngremotemedia/editor_plugin.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-arrow-callback */ 2 | (function (tinymce) { 3 | function insertMediaCallback(data, caption, align, cssClass) { 4 | var imageUrl = ''; 5 | if (data.mediaType === 'image') { 6 | if (data.variation_url !== null) { 7 | imageUrl = data.variation_url; 8 | } else if (data.url !== null) { 9 | imageUrl = data.url; 10 | } 11 | } else if (data.mediaType === 'video' && data.thumbnail_url !== null && data.thumbnail_url !== '') { 12 | imageUrl = data.thumbnail_url; 13 | } 14 | 15 | let previewUrl = imageUrl !== '' ? imageUrl : '/extension/ezoe/design/standard/images/tango/mail-attachment.png'; 16 | let elementClass = "ezoeItemCustomTag ngremotemedia"; 17 | let alignAttr = ''; 18 | 19 | if (typeof align !== 'undefined' && align !== '') { 20 | elementClass += (' ezoeAlign' + align); 21 | alignAttr = 'align="'+align+'"'; 22 | } 23 | 24 | let html = ''; 30 | 31 | tinymce.execCommand('mceInsertContent', false, html); 32 | } 33 | 34 | tinymce.PluginManager.add("ngremotemedia", function (editor) { 35 | const fieldId = editor.settings.ez_attribute_id; 36 | 37 | window[`remoteMedia` + fieldId].setEditorInsertCallback(insertMediaCallback); 38 | 39 | // Add a button that opens a modal 40 | editor.addButton("ngremotemedia", { 41 | title: "Insert remote media", 42 | image: "/bundles/netgenremotemedia/img/cloud-upload-alt.svg", 43 | onclick() { 44 | let attributeType = tinymce.activeEditor.selection.getNode().getAttribute('type'); 45 | let attributeString = tinymce.activeEditor.selection.getNode().getAttribute('customattributes'); 46 | let hasNgrmClass = tinymce.activeEditor.selection.getNode().classList.contains('ngremotemedia'); 47 | 48 | var data = {}; 49 | if (attributeType === 'custom' && hasNgrmClass === true && attributeString) { 50 | data.align = tinymce.activeEditor.selection.getNode().getAttribute('align'); 51 | let attributes = attributeString.split('attribute_separation'); 52 | 53 | attributes.forEach(function (attribute) { 54 | let attributeKey = attribute.split('|')[0]; 55 | let attributeValue = attribute.split('|')[1]; 56 | 57 | if (attributeKey === 'coords' || attributeKey === 'image_variations') { 58 | try { 59 | data['image_variations'] = JSON.parse(attributeValue); 60 | } catch(e) { 61 | data['image_variations'] = {}; 62 | } 63 | 64 | return; 65 | } 66 | 67 | data[attributeKey] = attributeValue; 68 | }); 69 | } 70 | 71 | window[`remoteMedia` + fieldId].openEditorInsertModal(data); 72 | }, 73 | }); 74 | 75 | return { 76 | getMetadata() { 77 | return { 78 | name: "Netgen remote media", 79 | url: "https://github.com/netgen/NetgenRemoteMediaBundle", 80 | }; 81 | }, 82 | }; 83 | }); 84 | })(tinymce); 85 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/design/standard/templates/content/datatype/edit/ngremotemedia.tpl: -------------------------------------------------------------------------------- 1 | {def $base='ContentObjectAttribute'} 2 | {def $remote_value = $attribute.content} 3 | {def $field_id = $attribute.id} 4 | 5 | {def $input_fields = hash( 6 | 'alt_text', concat($base, '_alttext_', $field_id), 7 | 'image_variations', concat($base, '_image_variations_', $field_id), 8 | 'media_type', concat($base, '_media_type_', $field_id), 9 | 'new_file', concat($base, '_new_file_', $field_id), 10 | 'resource_id', concat($base, '_media_id_', $field_id), 11 | 'tags', concat($base, '_tags_', $field_id, '[]') 12 | )} 13 | 14 | {symfony_include( 15 | '@NetgenRemoteMedia/ezadminui/parts/edit/ngrm_field.html.twig', 16 | hash( 17 | 'content_type_identifier', $attribute.object.class_identifier, 18 | 'field_id', $field_id, 19 | 'field_value', $remote_value, 20 | 'input_fields', $input_fields 21 | ) 22 | )} 23 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/design/standard/templates/content/datatype/view/ezxmltags/ngremotemedia.tpl: -------------------------------------------------------------------------------- 1 | {if not(and(is_set($resourceType), is_string($resourceType), not($resourceType|compare(''))))} 2 | {def $resourceType = 'image'} 3 | {/if} 4 | 5 | {if and($resourceId, $resourceId|is_null|not)} 6 | {def $resource = ng_remote_resource($resourceType, $resourceId, $coords)} 7 | {/if} 8 | 9 | {if and(resource, $resource.resourceId|is_null|not)} 10 | 11 | {if eq($resource.mediaType, 'image')} 12 | {def $image_url = $resource.secure_url} 13 | 14 | {def $image_url = ngremotemedia($resource, 'embedded', $variation).url} 15 | 16 | 20 | {elseif eq($resource.mediaType, 'video')} 21 | {ngremotevideo($resource, $variation, 'embedded')} 22 | {else} 23 | {$resourceId} 24 | {/if} 25 | 26 | {if and(is_set($caption), is_string($caption), not($caption|compare('')))}
{$caption|wash()}
{/if} 27 | 28 | {/if} 29 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/design/standard/templates/content/datatype/view/ngremotemedia.tpl: -------------------------------------------------------------------------------- 1 | {def $variations = ng_image_variations()} 2 | 3 | {def 4 | $value = $attribute.content 5 | } 6 | 7 | {if $value.resourceId} 8 | {def $format = 'admin_preview'} 9 | {if $value.mediaType|eq('image')} 10 | {def $variation = ngremotemedia($value, $attribute.object.class_identifier, $format)} 11 | 12 | {if not(is_set($alt_text))} 13 | {def $alt_text = $value.metaData.alt_text|default('')} 14 | {/if} 15 | 16 | {if not(is_set($title))} 17 | {def $title = $value.metaData.caption|default('')} 18 | {/if} 19 | 20 | 26 | {elseif $value.mediaType|eq('video')} 27 | 28 | {$value.resourceId} 29 | 30 |
31 | 32 | {def $thumbnail = videoThumbnail($value, hash('content_type_identifier', $attribute.object.class_identifier, 'variation_name', $format))} 33 | 34 | {else} 35 | 36 | 37 | {$value.resourceId} 38 | 39 | {/if} 40 | {else} 41 | No media selected 42 | {/if} 43 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/design/standard/templates/ezxml_init.tpl: -------------------------------------------------------------------------------- 1 | {symfony_include('@NetgenRemoteMedia/ezadminui/js_config.html.twig')} 2 | 3 | {foreach $content_attributes_grouped_data_map as $attribute_group => $content_attributes_grouped} 4 | {foreach $content_attributes_grouped as $attribute_identifier => $attribute} 5 | {if eq($attribute.data_type_string, 'ezxmltext')} 6 | {symfony_include('@NetgenRemoteMedia/ezadminui/parts/edit/editor_insert.html.twig', hash( 7 | 'field_id', $attribute.id 8 | ))} 9 | {/if} 10 | {/foreach} 11 | {/foreach} 12 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/extension.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Netgen Remote Media 5 | 2.0 6 | Copyright (C) 2019 Netgen d.o.o. All rights reserved. 7 | GPL 2.0 8 | http://netgen.io 9 | 10 | 11 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/settings/content.ini.append.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/translations/nor-NO/translation.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | extension/ngremotemedia/datatype 6 | 7 | RemoteMedia 8 | Datatype name 9 | RemoteMedia 10 | 11 | 12 | 13 | extension/ngremotemedia/interactions 14 | 15 | Search for media 16 | Søk etter media 17 | 18 | 19 | Load more 20 | last mer 21 | 22 | 23 | Upload new media 24 | Last opp nytt 25 | 26 | 27 | No results 28 | Ingen treff 29 | 30 | 31 | Alternate text 32 | Alternativ tekst 33 | 34 | 35 | CSS class 36 | CSS klasse 37 | 38 | 39 | Create new folder? 40 | 41 | 42 | 43 | Folder 44 | Mappe 45 | 46 | 47 | All 48 | Alle 49 | 50 | 51 | Add tag 52 | Legg til merkelapp 53 | 54 | 55 | Close 56 | Lukk 57 | 58 | 59 | Remove media 60 | Fjern media 61 | 62 | 63 | Manage media 64 | 65 | 66 | 67 | Quick upload 68 | Rask opplasting 69 | 70 | 71 | Scale 72 | Skalér 73 | 74 | 75 | Media type 76 | 77 | 78 | 79 | Image and documents 80 | Bilde og dokumenter 81 | 82 | 83 | Video 84 | 85 | 86 | 87 | Loading... 88 | Lasting... 89 | 90 | 91 | Cancel 92 | Avbryt 93 | 94 | 95 | Save all 96 | Lagre alt 97 | 98 | 99 | Generate 100 | Generere 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /bundle/ezpublish_legacy/ngremotemedia/translations/untranslated/translation.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | extension/ngremotemedia/datatype 6 | 7 | RemoteMedia 8 | Datatype name 9 | 10 | 11 | 12 | 13 | extension/ngremotemedia/interactions 14 | 15 | Search for media 16 | 17 | 18 | 19 | Load more 20 | 21 | 22 | 23 | Upload new media 24 | 25 | 26 | 27 | No results 28 | 29 | 30 | 31 | Alternate text 32 | 33 | 34 | 35 | CSS class 36 | 37 | 38 | 39 | Create new folder? 40 | 41 | 42 | 43 | Folder 44 | 45 | 46 | 47 | All 48 | 49 | 50 | 51 | Add tag 52 | 53 | 54 | 55 | Close 56 | 57 | 58 | 59 | Remove media 60 | 61 | 62 | 63 | Manage media 64 | 65 | 66 | 67 | Quick upload 68 | 69 | 70 | 71 | Scale 72 | 73 | 74 | 75 | Media type 76 | 77 | 78 | 79 | Image and documents 80 | 81 | 82 | 83 | Video 84 | 85 | 86 | 87 | Loading... 88 | 89 | 90 | 91 | Cancel 92 | 93 | 94 | 95 | Save all 96 | 97 | 98 | 99 | Generate 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | patch: false 4 | changes: false 5 | project: 6 | default: 7 | target: auto 8 | comment: off 9 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netgen/remote-media-bundle", 3 | "description": "Remote media field type implementation", 4 | "type": "ezplatform-bundle", 5 | "keywords": [ 6 | "ezpublish", 7 | "ezplatform", 8 | "remote media", 9 | "netgen", 10 | "remote-media-bundle" 11 | ], 12 | "homepage": "https://github.com/netgen/NetgenRemoteMediaBundle", 13 | "license": "GPL-2.0-only", 14 | "authors": [ 15 | { 16 | "name": "Netgen", 17 | "homepage": "http://netgen.io", 18 | "email": "info@netgen.io" 19 | }, 20 | { 21 | "name": "Ivan Herak", 22 | "email": "ivan@netgen.io" 23 | }, 24 | { 25 | "name": "Jurica Hladek", 26 | "email": "jurica@netgen.io" 27 | } 28 | ], 29 | "require": { 30 | "php": "^7.2", 31 | "ezsystems/ezpublish-kernel": "^7.4", 32 | "doctrine/orm": "^2.4", 33 | "cloudinary/cloudinary_php": "^1.10" 34 | }, 35 | "require-dev": { 36 | "ezsystems/legacy-bridge": "^2.0", 37 | "netgen/open-graph-bundle": "^1.2", 38 | "netgen/admin-ui-bundle": "^2.0", 39 | "matthiasnoback/symfony-dependency-injection-test": "^3.0", 40 | "mikey179/vfsstream": "^1.2", 41 | "phpunit/phpunit": "^7.0", 42 | "friendsofphp/php-cs-fixer": "^2.18", 43 | "rector/rector": "^0.5.22" 44 | }, 45 | "autoload": { 46 | "psr-4": { 47 | "Netgen\\Bundle\\RemoteMediaBundle\\": "bundle" 48 | } 49 | }, 50 | "autoload-dev": { 51 | "psr-4": { 52 | "Netgen\\Bundle\\Tests\\": "tests", 53 | "Netgen\\Bundle\\OpenGraphBundle\\Tests\\": "vendor/netgen/open-graph-bundle/tests" 54 | } 55 | }, 56 | "scripts": { 57 | "test": "@php vendor/bin/phpunit --colors=always", 58 | "fix": "@php vendor/bin/php-cs-fixer fix" 59 | }, 60 | "extra": { 61 | "ezpublish-legacy-dir": "ezpublish_legacy", 62 | "branch-alias": { 63 | "dev-master": "2.0.x-dev" 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /docs/TRANSFORMATIONS.md: -------------------------------------------------------------------------------- 1 | Table of supported transformations from Cloudinary. 2 | 3 | | Transformation name | Transformation alias | Description | 4 | |:-------------------:|:--------------------:|:-----------:| 5 | | Crop | crop | Crops the image if it has been cropped in the administration interface | 6 | | Effect | effect | Applies the effect to change the visual appearance | 7 | | Fill | fill | Exact given width and height while retaining the original aspect ratio, using only part of the image that fills the given dimensions if necessary | 8 | | Fit | fit | The image is resized so that it takes up as much space as possible within a bounding box defined by the given width and height parameters. The original aspect ratio is retained and all of the original image is visible. | 9 | | Format | format | Defines in format should the media be delivered. | 10 | | Lfill | lfill | Same as the fill mode but only if the original image is larger than the given limit (width and height). This mode doesn't scale up the image if your requested dimensions are bigger than the original image's | 11 | | Limit | limit | Same as the fit mode but only if the original image is larger than the given limit (width and height), in which case the image is scaled down. This mode doesn't scale up the image if your requested dimensions are larger than the original image's. | 12 | | Lpad | lpad | Same as the pad mode but only if the original image is larger than the given limit (width and height), in which case the image is scaled down to fill the given width and height while retaining the original aspect ratio. If the proportions of the original image do not match the given width and height, padding is added to the image to reach the required size. | 13 | | Mfit | mfit | Same as the fit mode but only if the original image is smaller than the given minimum (width and height), in which case the image is scaled up. All of the original image is visible. | 14 | | Mpad | mpad | Same as the pad mode but only if the original image is smaller than the given minimum (width and height), in which case the image is scaled up to fill the given width and height while retaining the original aspect ratio and with all of the original image visible. You can also specify the color of the background in the case that padding is added. | 15 | | Named transformation | transformation | A named transformation is a set of image transformations that has been given a custom name for easy reference. | 16 | | Pad | pad | Resize the image to fill the given width and height while retaining the original aspect ratio and with all of the original image visible. If the proportions of the original image do not match the given width and height, padding is added to the image to reach the required size. You can also specify the color of the background in the case that padding is added. | 17 | | Quality | quality | Set compression level to apply to an image as a value between 1 (smallest file size possible) and 100 (best visual quality). Automatic quality selection is also available | 18 | | Resize | resize | Change the size of the image | 19 | | Scale | scale | Change the size of the image exactly to the given width and height without necessarily retaining the original aspect ratio: all original image parts are visible but might be stretched or shrunk. | 20 | 21 | 22 | For additional details on each of the transformation, consult the Cloudinary [documentation](http://cloudinary.com/documentation/image_transformations) 23 | -------------------------------------------------------------------------------- /frontend/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /frontend/.env: -------------------------------------------------------------------------------- 1 | DEV_PROXY_SESSION_ID= -------------------------------------------------------------------------------- /frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: ['plugin:vue/essential'], 7 | rules: { 8 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 9 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 10 | }, 11 | parserOptions: { 12 | parser: 'babel-eslint' 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /frontend/copyFiles.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const mappings = [ 4 | { 5 | source: 'dist/js/app.js', 6 | targets: [ 7 | '../bundle/Resources/public/js/remotemedia.js', 8 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/javascript/remotemedia.js' 9 | ] 10 | }, 11 | { 12 | source: 'dist/js/chunk-vendors.js', 13 | targets: [ 14 | '../bundle/Resources/public/js/remotemedia-vendors.js', 15 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/javascript/remotemedia-vendors.js' 16 | ] 17 | }, 18 | { 19 | source: 'dist/css/app.css', 20 | targets: [ 21 | '../bundle/Resources/public/css/remotemedia.css', 22 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/stylesheets/remotemedia.css' 23 | ] 24 | }, 25 | { 26 | source: 'dist/css/chunk-vendors.css', 27 | targets: [ 28 | '../bundle/Resources/public/css/remotemedia-vendors.css', 29 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/stylesheets/remotemedia-vendors.css' 30 | ] 31 | } 32 | ]; 33 | 34 | const copyFile = source => destination => { 35 | fs.copyFile(source, destination, err => { 36 | if (err) throw err; 37 | console.log(`${source} copied to ${destination}`); 38 | }); 39 | }; 40 | 41 | mappings.forEach(map => { 42 | map.targets.forEach(copyFile(map.source)); 43 | }); 44 | -------------------------------------------------------------------------------- /frontend/copyFilesDev.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const mappings = [ 4 | { 5 | source: 'dist/app.js', 6 | targets: [ 7 | '../bundle/Resources/public/js/remotemedia.js', 8 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/javascript/remotemedia.js' 9 | ] 10 | } 11 | ]; 12 | 13 | const fakeFiles = [ 14 | { 15 | targets: [ 16 | '../bundle/Resources/public/js/remotemedia-vendors.js', 17 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/javascript/remotemedia-vendors.js' 18 | ] 19 | }, 20 | { 21 | targets: [ 22 | '../bundle/Resources/public/css/remotemedia.css', 23 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/stylesheets/remotemedia.css' 24 | ] 25 | }, 26 | { 27 | targets: [ 28 | '../bundle/Resources/public/css/remotemedia-vendors.css', 29 | '../bundle/ezpublish_legacy/ngremotemedia/design/standard/stylesheets/remotemedia-vendors.css' 30 | ] 31 | }, 32 | ]; 33 | 34 | const copyFile = source => destination => { 35 | fs.copyFile(source, destination, err => { 36 | if (err) throw err; 37 | console.log(`${source} copied to ${destination}`); 38 | }); 39 | }; 40 | 41 | const fakeFile = path => { 42 | fs.closeSync(fs.openSync(path, 'w')) 43 | console.log(`Faked ${path}`); 44 | } 45 | 46 | mappings.forEach(map => { 47 | map.targets.forEach(copyFile(map.source)); 48 | }); 49 | 50 | fakeFiles.forEach(fakes => { 51 | fakes.targets.forEach(fakeFile); 52 | }) 53 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "netgen-remote-media-bundle", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build && node copyFiles.js", 8 | "dev": "vue-cli-service build --mode development && node copyFilesDev.js", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "@riophae/vue-treeselect": "^0.4.0", 13 | "axios": "^0.21.1", 14 | "core-js": "^2.6.5", 15 | "cropperjs": "^1.5.5", 16 | "debounce": "^1.2.0", 17 | "pretty-bytes": "^5.6.0", 18 | "vue": "^2.6.10", 19 | "vue-select": "^3.2.0" 20 | }, 21 | "devDependencies": { 22 | "@vue/cli-plugin-babel": "^3.11.0", 23 | "@vue/cli-plugin-eslint": "^3.11.0", 24 | "@vue/cli-service": "^3.11.0", 25 | "@vue/eslint-config-prettier": "^5.0.0", 26 | "babel-eslint": "^10.0.1", 27 | "eslint": "^5.16.0", 28 | "eslint-plugin-prettier": "^3.1.0", 29 | "eslint-plugin-vue": "^5.0.0", 30 | "node-sass": "^4.9.0", 31 | "prettier": "^1.18.2", 32 | "sass-loader": "^7.1.0", 33 | "vue-template-compiler": "^2.6.10" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/components/Modal.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 28 | 29 | 30 | 74 | -------------------------------------------------------------------------------- /frontend/src/components/Preview.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 82 | -------------------------------------------------------------------------------- /frontend/src/components/UploadModal.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 47 | 48 | 49 | 73 | -------------------------------------------------------------------------------- /frontend/src/constants/facets.js: -------------------------------------------------------------------------------- 1 | export const TYPE_ALL = 'all'; 2 | export const TYPE_IMAGE = 'image'; 3 | export const TYPE_VIDEO = 'video'; 4 | export const TYPE_RAW = 'raw'; 5 | export const SEARCH_NAME = 'name'; 6 | export const FOLDER_ALL = '(all)'; 7 | export const FOLDER_ROOT = '(root)'; 8 | export const TAG_ALL = 'all'; 9 | -------------------------------------------------------------------------------- /frontend/src/font/fa-ngrm.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netgen/NetgenRemoteMediaBundle/61615a8ae0e3c286f4c2bc4f024c77413f6112d6/frontend/src/font/fa-ngrm.eot -------------------------------------------------------------------------------- /frontend/src/font/fa-ngrm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Copyright (C) 2019 by original authors @ fontello.com 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /frontend/src/font/fa-ngrm.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netgen/NetgenRemoteMediaBundle/61615a8ae0e3c286f4c2bc4f024c77413f6112d6/frontend/src/font/fa-ngrm.ttf -------------------------------------------------------------------------------- /frontend/src/font/fa-ngrm.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netgen/NetgenRemoteMediaBundle/61615a8ae0e3c286f4c2bc4f024c77413f6112d6/frontend/src/font/fa-ngrm.woff -------------------------------------------------------------------------------- /frontend/src/font/fa-ngrm.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netgen/NetgenRemoteMediaBundle/61615a8ae0e3c286f4c2bc4f024c77413f6112d6/frontend/src/font/fa-ngrm.woff2 -------------------------------------------------------------------------------- /frontend/src/scss/_iconfont.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'fa-ngrm'; 3 | src: url('../font/fa-ngrm.eot?75641014'); 4 | src: url('../font/fa-ngrm.eot?75641014#iefix') format('embedded-opentype'), 5 | url('../font/fa-ngrm.woff2?75641014') format('woff2'), 6 | url('../font/fa-ngrm.woff?75641014') format('woff'), 7 | url('../font/fa-ngrm.ttf?75641014') format('truetype'), 8 | url('../font/fa-ngrm.svg?75641014#fa-ngrm') format('svg'); 9 | font-weight: normal; 10 | font-style: normal; 11 | } 12 | 13 | [class^="ngrm-icon-"]:before, [class*=" ngrm-icon-"]:before { 14 | font-family: "fa-ngrm"; 15 | font-style: normal; 16 | font-weight: normal; 17 | speak: none; 18 | 19 | display: inline-block; 20 | text-decoration: inherit; 21 | width: 1em; 22 | margin-right: .2em; 23 | text-align: center; 24 | 25 | /* For safety - reset parent styles, that can break glyph codes*/ 26 | font-variant: normal; 27 | text-transform: none; 28 | 29 | /* fix buttons height, for twitter bootstrap */ 30 | line-height: 1em; 31 | 32 | margin-left: .2em; 33 | 34 | /* Font smoothing. That was taken from TWBS */ 35 | -webkit-font-smoothing: antialiased; 36 | -moz-osx-font-smoothing: grayscale; 37 | } 38 | 39 | .ngrm-icon-cancel:before { content: '\e800'; } /* '' */ 40 | .ngrm-icon-floppy:before { content: '\e801'; } /* '' */ 41 | .ngrm-icon-ok:before { content: '\e802'; } /* '' */ 42 | .ngrm-icon-ccw:before { content: '\e803'; } /* '' */ 43 | .ngrm-icon-folder:before { content: '\e804'; } /* '' */ 44 | .ngrm-icon-upload:before { content: '\e805'; } /* '' */ 45 | .ngrm-icon-play:before { content: '\e811'; } /* '' */ 46 | .ngrm-icon-trash:before { content: '\f1f8'; } /* '' */ 47 | -------------------------------------------------------------------------------- /frontend/src/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | $white: #FFFFFF; 3 | $mine-shaft: #333333; 4 | $wild-sand: #F5F5F5; 5 | $alto: #D7D7D7; 6 | $boulder: #757575; 7 | $mercury: #E4E4E4; 8 | $dusty-gray: #999999; 9 | $netgen-primary: #009AC7; 10 | $crimson: #A41034; 11 | -------------------------------------------------------------------------------- /frontend/src/utility/directives.js: -------------------------------------------------------------------------------- 1 | import { kebabToCamelCase } from './utility'; 2 | 3 | export const initDirective = { 4 | bind: function(el, binding, vnode) { 5 | const propertyName = kebabToCamelCase(binding.arg); 6 | 7 | vnode.context[propertyName] = binding.value; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /frontend/src/utility/functional.js: -------------------------------------------------------------------------------- 1 | export const objectMap = f => obj => { 2 | return Object.keys(obj).reduce((newObj, property) => { 3 | newObj[property] = f(obj[property], property); 4 | return newObj; 5 | }, {}); 6 | }; 7 | 8 | export const objectFilter = p => obj => { 9 | return Object.keys(obj).reduce((newObj, property) => { 10 | if (p(obj[property], property)) { 11 | newObj[property] = obj[property]; 12 | } 13 | return newObj; 14 | }, {}); 15 | }; 16 | 17 | export const constant = val => () => val; 18 | -------------------------------------------------------------------------------- /frontend/src/utility/polyfills.js: -------------------------------------------------------------------------------- 1 | if (!Array.prototype.difference) { 2 | Array.prototype.difference = function(other) { 3 | return this.filter(el => other.indexOf(el) < 0); 4 | }; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/src/utility/predicates.js: -------------------------------------------------------------------------------- 1 | export const not = f => item => !f(item); 2 | export const equal = value => item => value === item; 3 | export const truthy = value => !!value; 4 | export const notUndefined = not(equal(undefined)); 5 | -------------------------------------------------------------------------------- /frontend/src/utility/utility.js: -------------------------------------------------------------------------------- 1 | export const encodeQueryData = data => { 2 | const ret = []; 3 | for (let d in data) 4 | ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d])); 5 | return ret.join('&'); 6 | }; 7 | 8 | export const capitalizeFirstLetter = str => str[0].toUpperCase() + str.slice(1); 9 | 10 | export const kebabToCamelCase = str => { 11 | const [first, ...rest] = str.split('-'); 12 | return [first, ...rest.map(capitalizeFirstLetter)].join(''); 13 | }; 14 | 15 | export const format = (num, decimals) => { 16 | const multiplyer = Math.pow(10, decimals); 17 | return parseFloat(Math.round(num * multiplyer) / multiplyer).toFixed( 18 | decimals 19 | ); 20 | }; 21 | 22 | const sizeDimensionsMap = { 23 | B: 'KB', 24 | KB: 'MB', 25 | MB: 'GB', 26 | GB: 'TB' 27 | }; 28 | export const formatByteSize = (size, dim = 'B') => { 29 | const nextDim = sizeDimensionsMap[dim]; 30 | 31 | if (!nextDim || size < 1024) { 32 | return `${format(size, 2)} ${dim}`; 33 | } 34 | 35 | return formatByteSize(size / 1024, nextDim); 36 | }; 37 | -------------------------------------------------------------------------------- /frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | runtimeCompiler: true, 3 | devServer: { 4 | proxy: { 5 | '^/ngadminui': { 6 | target: 'http://remote-media.dev6.netgen.biz', 7 | changeOrigin: true, 8 | headers: { 9 | cookie: `eZSESSID=${process.env.DEV_PROXY_SESSION_ID};` 10 | } 11 | } 12 | } 13 | }, 14 | filenameHashing: false, 15 | configureWebpack: { 16 | entry: { 17 | app: './src/main.js', 18 | } 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RemoteMediaBundle", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "handlebars": { 8 | "version": "4.2.0", 9 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz", 10 | "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==", 11 | "requires": { 12 | "neo-async": "^2.6.0", 13 | "optimist": "^0.6.1", 14 | "source-map": "^0.6.1", 15 | "uglify-js": "^3.1.4" 16 | }, 17 | "dependencies": { 18 | "source-map": { 19 | "version": "0.6.1", 20 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 21 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 22 | } 23 | } 24 | }, 25 | "neo-async": { 26 | "version": "2.6.1", 27 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", 28 | "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" 29 | }, 30 | "optimist": { 31 | "version": "0.6.1", 32 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 33 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 34 | "requires": { 35 | "minimist": "~0.0.1", 36 | "wordwrap": "~0.0.2" 37 | }, 38 | "dependencies": { 39 | "minimist": { 40 | "version": "0.0.10", 41 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", 42 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" 43 | }, 44 | "wordwrap": { 45 | "version": "0.0.3", 46 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 47 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" 48 | } 49 | } 50 | }, 51 | "uglify-js": { 52 | "version": "3.4.10", 53 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", 54 | "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", 55 | "optional": true, 56 | "requires": { 57 | "commander": "~2.19.0", 58 | "source-map": "~0.6.1" 59 | }, 60 | "dependencies": { 61 | "commander": { 62 | "version": "2.19.0", 63 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", 64 | "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", 65 | "optional": true 66 | }, 67 | "source-map": { 68 | "version": "0.6.1", 69 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 70 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 71 | "optional": true 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RemoteMediaBundle", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "dependencies": { 7 | "handlebars": "^4.0.11" 8 | }, 9 | "devDependencies": { 10 | }, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git@bitbucket.org:netgen/netgenremotemedia.git" 17 | }, 18 | "author": "", 19 | "license": "ISC" 20 | } 21 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | tests 16 | 17 | 18 | 19 | 20 | bundle 21 | 22 | bundle/ezpublish_legacy 23 | bundle/Command 24 | bundle/Resources 25 | bundle/vendor 26 | bundle/update 27 | bundle/extension 28 | bundle/Core/FieldType/RemoteMedia/SearchField.php 29 | bundle/RemoteMedia/Provider/Cloudinary/Gateway/CachedGateway.php 30 | bundle/RemoteMedia/Helper.php 31 | bundle/NetgenRemoteMediaBundle.php 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/Core/FieldType/RemoteMedia/InputValueTest.php: -------------------------------------------------------------------------------- 1 | 'test/path/image.jpg', 23 | 'alt_text' => 'Test alt text', 24 | 'caption' => 'Test caption', 25 | 'variations' => [], 26 | ]; 27 | 28 | $inputValue = new InputValue($parameters); 29 | 30 | self::assertEquals(json_encode($parameters), (string) $inputValue); 31 | } 32 | 33 | public function testConstructionWithoutParameters() 34 | { 35 | $expectedResponseArray = [ 36 | 'input_uri' => null, 37 | 'alt_text' => '', 38 | 'caption' => '', 39 | 'variations' => [], 40 | ]; 41 | 42 | $inputValue = new InputValue(); 43 | 44 | self::assertEquals(json_encode($expectedResponseArray), (string) $inputValue); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/Core/FieldType/RemoteMedia/VariationTest.php: -------------------------------------------------------------------------------- 1 | 'test/path/image.jpg', 23 | 'width' => '150', 24 | 'height' => '200', 25 | 'coords' => [ 26 | 'x' => 20, 27 | 'y' => 30, 28 | ], 29 | ]; 30 | 31 | $variation = new Variation($parameters); 32 | 33 | self::assertEquals(json_encode($parameters), (string) $variation); 34 | } 35 | 36 | public function testConstructionWithoutParameters() 37 | { 38 | $expectedResponseArray = [ 39 | 'url' => null, 40 | 'width' => null, 41 | 'height' => null, 42 | 'coords' => [ 43 | 'x' => 0, 44 | 'y' => 0, 45 | ], 46 | ]; 47 | 48 | $variation = new Variation(); 49 | 50 | self::assertEquals(json_encode($expectedResponseArray), (string) $variation); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Core/Persistence/Legacy/Content/FieldValue/Converter/RemoteMediaConverterTest.php: -------------------------------------------------------------------------------- 1 | converter = new RemoteMediaConverter(); 27 | } 28 | 29 | public function testInstanceOfConverter() 30 | { 31 | self::assertInstanceOf(Converter::class, $this->converter); 32 | } 33 | 34 | public function testGetIndexColumn() 35 | { 36 | self::assertEquals('data_text', $this->converter->getIndexColumn()); 37 | } 38 | 39 | public function testCreate() 40 | { 41 | self::assertEquals($this->converter, RemoteMediaConverter::create()); 42 | } 43 | 44 | public function testToStorageValue() 45 | { 46 | $fieldValue = new FieldValue( 47 | [ 48 | 'data' => 'data', 49 | ] 50 | ); 51 | 52 | $storageFieldValue = new StorageFieldValue(); 53 | 54 | $this->converter->toStorageValue($fieldValue, $storageFieldValue); 55 | self::assertEquals($storageFieldValue->dataText, json_encode($fieldValue->data)); 56 | } 57 | 58 | public function testToFieldValue() 59 | { 60 | $storageFieldValue = new StorageFieldValue( 61 | [ 62 | 'dataText' => 'data', 63 | ] 64 | ); 65 | 66 | $fieldValue = new FieldValue(); 67 | 68 | $this->converter->toFieldValue($storageFieldValue, $fieldValue); 69 | self::assertEquals($fieldValue->data, json_decode($storageFieldValue->dataText, true)); 70 | } 71 | 72 | public function testToStorageFieldDefinition() 73 | { 74 | $fieldDefinition = new FieldDefinition(); 75 | $storageFieldDefinition = new StorageFieldDefinition(); 76 | 77 | self::assertNull($this->converter->toStorageFieldDefinition($fieldDefinition, $storageFieldDefinition)); 78 | } 79 | 80 | public function testToFieldDefinition() 81 | { 82 | $storageFieldDefinition = new StorageFieldDefinition(); 83 | $fieldDefinition = new FieldDefinition(); 84 | 85 | self::assertNull($this->converter->toFieldDefinition($storageFieldDefinition, $fieldDefinition)); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tests/DependencyInjection/Compiler/XslRegisterPassTest.php: -------------------------------------------------------------------------------- 1 | 'test/test1.xsl', 22 | 'priority' => 0, 23 | ], 24 | ]; 25 | $testXslConfig = [ 26 | [ 27 | 'path' => 'test/test.xsl', 28 | 'priority' => 5000, 29 | ], 30 | ]; 31 | 32 | $expectedInjectedParameter = [ 33 | 'path' => str_replace('tests/', 'bundle/', __DIR__) . '/../../Resources/xsl/ezxml_ngremotemedia.xsl', 34 | 'priority' => 5000, 35 | ]; 36 | 37 | $expectedXslConfig = array_merge($testXslConfig, [$expectedInjectedParameter]); 38 | 39 | $this->setParameter('ezsettings.default.fieldtypes.ezxml.custom_xsl', $testXslConfigDefault); 40 | $this->setParameter('ezpublish.siteaccess.list', $siteaccessList); 41 | 42 | foreach ($siteaccessList as $siteaccess) { 43 | $this->setParameter('ezsettings.' . $siteaccess . '.fieldtypes.ezxml.custom_xsl', $testXslConfig); 44 | } 45 | 46 | $this->compile(); 47 | 48 | foreach ($siteaccessList as $siteaccess) { 49 | $this->assertContainerBuilderHasParameter('ezsettings.' . $siteaccess . '.fieldtypes.ezxml.custom_xsl', $expectedXslConfig); 50 | } 51 | } 52 | 53 | public function testCompilerPassWithoutExistingXslConfig() 54 | { 55 | $siteaccessList = ['siteacc1', 'siteacc2']; 56 | 57 | $this->setParameter('ezpublish.siteaccess.list', $siteaccessList); 58 | 59 | $this->compile(); 60 | 61 | // Avoid detecting risky tests 62 | self::assertTrue(true); 63 | } 64 | 65 | protected function registerCompilerPass(ContainerBuilder $container) 66 | { 67 | $container->addCompilerPass(new XslRegisterPass()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/DependencyInjection/NetgenRemoteMediaExtensionTest.php: -------------------------------------------------------------------------------- 1 | setParameter('kernel.bundles', []); 15 | $this->load(); 16 | 17 | $this->assertContainerBuilderHasParameter('netgen_remote_media.parameters.testprovider.account_name', 'testname'); 18 | $this->assertContainerBuilderHasParameter('netgen_remote_media.parameters.testprovider.account_key', 'testkey'); 19 | $this->assertContainerBuilderHasParameter('netgen_remote_media.parameters.testprovider.account_secret', 'testsecret'); 20 | $this->assertContainerBuilderHasParameter('netgen_remote_media.remove_unused_resources', false); 21 | 22 | $this->assertContainerBuilderHasAlias('netgen_remote_media.provider', 'netgen_remote_media.provider.testprovider'); 23 | } 24 | 25 | /** 26 | * @expectedException \InvalidArgumentException 27 | */ 28 | public function testWithoutProviderParameter() 29 | { 30 | $this->load(['provider' => null]); 31 | } 32 | 33 | protected function getContainerExtensions() 34 | { 35 | return [ 36 | new NetgenRemoteMediaExtension(), 37 | ]; 38 | } 39 | 40 | protected function getMinimalConfiguration() 41 | { 42 | return [ 43 | 'provider' => 'testprovider', 44 | 'account_name' => 'testname', 45 | 'account_key' => 'testkey', 46 | 'account_secret' => 'testsecret', 47 | 'system' => [ 48 | 'default' => [ 49 | 'image_variations' => [ 50 | 'ng_frontpage' => [ 51 | 'small' => [ 52 | 'transformations' => [ 53 | 'name' => ['Crop'], 54 | 'params' => [200, 200], 55 | ], 56 | ], 57 | ], 58 | ], 59 | ], 60 | ], 61 | ]; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/Entity/RemoteMediaFieldLinkTest.php: -------------------------------------------------------------------------------- 1 | entity = new RemoteMediaFieldLink(); 20 | parent::setUp(); 21 | } 22 | 23 | public function testSettersAndGetters() 24 | { 25 | $this->entity 26 | ->setContentId(42) 27 | ->setFieldId(24) 28 | ->setVersionId(1) 29 | ->setResourceId('test') 30 | ->setProvider('testprovider'); 31 | 32 | self::assertEquals(42, $this->entity->getContentId()); 33 | self::assertEquals(24, $this->entity->getFieldId()); 34 | self::assertEquals(1, $this->entity->getVersionId()); 35 | self::assertEquals('test', $this->entity->getResourceId()); 36 | self::assertEquals('testprovider', $this->entity->getProvider()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/Exception/MimeCategoryParseExceptionTest.php: -------------------------------------------------------------------------------- 1 | value = new Value( 20 | [ 21 | 'resourceId' => 'testId', 22 | 'url' => 'http://cloudinary.com/some/url', 23 | 'secure_url' => 'https://cloudinary.com/some/url', 24 | 'variations' => [ 25 | 'small' => [ 26 | 'x' => 10, 27 | 'y' => 10, 28 | 'w' => 300, 29 | 'h' => 200, 30 | ], 31 | ], 32 | ] 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/CropTest.php: -------------------------------------------------------------------------------- 1 | crop = new Crop(); 21 | } 22 | 23 | public function testCrop() 24 | { 25 | self::assertEquals( 26 | [ 27 | [ 28 | 'x' => 10, 29 | 'y' => 10, 30 | 'width' => 300, 31 | 'height' => 200, 32 | 'crop' => 'crop', 33 | ], 34 | ], 35 | $this->crop->process($this->value, 'small') 36 | ); 37 | } 38 | 39 | public function testCropVariationDoesNotExist() 40 | { 41 | $this->expectException(TransformationHandlerFailedException::class); 42 | 43 | $this->crop->process($this->value, 'large'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/EffectTest.php: -------------------------------------------------------------------------------- 1 | effect = new Effect(); 21 | } 22 | 23 | public function testEffectSimple() 24 | { 25 | self::assertEquals( 26 | [ 27 | 'effect' => 'grayscale', 28 | ], 29 | $this->effect->process($this->value, 'small', ['grayscale']) 30 | ); 31 | } 32 | 33 | public function testEffect() 34 | { 35 | self::assertEquals( 36 | [ 37 | 'effect' => 'saturation:50', 38 | ], 39 | $this->effect->process($this->value, 'small', ['saturation', '50']) 40 | ); 41 | } 42 | 43 | public function testCropVariationDoesNotExist() 44 | { 45 | $this->expectException(TransformationHandlerFailedException::class); 46 | 47 | $this->effect->process($this->value, 'large'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/FillTest.php: -------------------------------------------------------------------------------- 1 | fill = new Fill(); 20 | } 21 | 22 | public function testFillSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'fill'], 26 | $this->fill->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testFillWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'fill', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->fill->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/FitTest.php: -------------------------------------------------------------------------------- 1 | fit = new Fit(); 20 | } 21 | 22 | public function testFitSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'fit'], 26 | $this->fit->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testFitWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'fit', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->fit->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/FormatTest.php: -------------------------------------------------------------------------------- 1 | format = new Format(); 21 | } 22 | 23 | public function testFormat() 24 | { 25 | self::assertEquals( 26 | ['fetch_format' => 'png'], 27 | $this->format->process($this->value, 'png_format', ['png']) 28 | ); 29 | } 30 | 31 | public function testMissingFormatConfiguration() 32 | { 33 | $this->expectException(TransformationHandlerFailedException::class); 34 | 35 | $this->format->process($this->value, 'png_format'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/LfillTest.php: -------------------------------------------------------------------------------- 1 | lfill = new Lfill(); 20 | } 21 | 22 | public function testLfillSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'lfill'], 26 | $this->lfill->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testLfillWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'lfill', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->lfill->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/LimitTest.php: -------------------------------------------------------------------------------- 1 | limit = new Limit(); 20 | } 21 | 22 | public function testLimitSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'limit'], 26 | $this->limit->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testLimitWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'limit', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->limit->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/LpadTest.php: -------------------------------------------------------------------------------- 1 | lpad = new Lpad(); 20 | } 21 | 22 | public function testLpadSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'lpad'], 26 | $this->lpad->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testLpadWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'lpad', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->lpad->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | 42 | public function testLpadWithDimensionsAndColour() 43 | { 44 | self::assertEquals( 45 | [ 46 | 'crop' => 'lpad', 47 | 'width' => 100, 48 | 'height' => 200, 49 | 'background' => 'red', 50 | ], 51 | $this->lpad->process($this->value, 'small', [100, 200, 'red']) 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/MfitTest.php: -------------------------------------------------------------------------------- 1 | mfit = new Mfit(); 20 | } 21 | 22 | public function testMfitSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'mfit'], 26 | $this->mfit->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testMfitWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'mfit', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->mfit->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/MpadTest.php: -------------------------------------------------------------------------------- 1 | mpad = new Mpad(); 20 | } 21 | 22 | public function testMpadSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'mpad'], 26 | $this->mpad->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testMpadWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'mpad', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->mpad->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/NamedTransformationTest.php: -------------------------------------------------------------------------------- 1 | namedTransformation = new NamedTransformation(); 21 | } 22 | 23 | public function testNamedTransformation() 24 | { 25 | self::assertEquals( 26 | ['transformation' => 'thisIsNamedTransformation'], 27 | $this->namedTransformation->process($this->value, 'named', ['thisIsNamedTransformation']) 28 | ); 29 | } 30 | 31 | public function testMissingNamedTransformationConfiguration() 32 | { 33 | $this->expectException(TransformationHandlerFailedException::class); 34 | 35 | $this->namedTransformation->process($this->value, 'named'); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/PadTest.php: -------------------------------------------------------------------------------- 1 | pad = new Pad(); 20 | } 21 | 22 | public function testPadSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'pad'], 26 | $this->pad->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testPadWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'pad', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->pad->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | 42 | public function testPadWithDimensionsAndColour() 43 | { 44 | self::assertEquals( 45 | [ 46 | 'crop' => 'pad', 47 | 'width' => 100, 48 | 'height' => 200, 49 | 'background' => 'red', 50 | ], 51 | $this->pad->process($this->value, 'small', [100, 200, 'red']) 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/QualityTest.php: -------------------------------------------------------------------------------- 1 | quality = new Quality(); 21 | } 22 | 23 | public function testQualitySimple() 24 | { 25 | self::assertEquals( 26 | ['quality' => 80], 27 | $this->quality->process($this->value, 'test', [80]) 28 | ); 29 | } 30 | 31 | public function testQualityWithAutoType() 32 | { 33 | self::assertEquals( 34 | [ 35 | 'quality' => 'auto:best', 36 | ], 37 | $this->quality->process($this->value, 'test', ['auto', 'best']) 38 | ); 39 | } 40 | 41 | public function testQualityWithNonAutoType() 42 | { 43 | $this->expectException(TransformationHandlerFailedException::class); 44 | 45 | $this->quality->process($this->value, 'test', ['test', 'best']); 46 | } 47 | 48 | public function testMissingNamedTransformationConfiguration() 49 | { 50 | $this->expectException(TransformationHandlerFailedException::class); 51 | 52 | $this->quality->process($this->value, 'test'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/ResizeTest.php: -------------------------------------------------------------------------------- 1 | resize = new Resize(); 21 | } 22 | 23 | public function testResizeWithDimensions() 24 | { 25 | self::assertEquals( 26 | [ 27 | 'width' => 100, 28 | 'height' => 200, 29 | ], 30 | $this->resize->process($this->value, 'small', [100, 200]) 31 | ); 32 | } 33 | 34 | public function testMissingResizeConfiguration() 35 | { 36 | $this->expectException(TransformationHandlerFailedException::class); 37 | 38 | $this->resize->process($this->value, 'named'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Provider/Cloudinary/TransformationHandler/ScaleTest.php: -------------------------------------------------------------------------------- 1 | scale = new Scale(); 20 | } 21 | 22 | public function testScaleSimple() 23 | { 24 | self::assertEquals( 25 | ['crop' => 'scale'], 26 | $this->scale->process($this->value, 'small') 27 | ); 28 | } 29 | 30 | public function testScaleWithDimensions() 31 | { 32 | self::assertEquals( 33 | [ 34 | 'crop' => 'scale', 35 | 'width' => 100, 36 | 'height' => 200, 37 | ], 38 | $this->scale->process($this->value, 'small', [100, 200]) 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/RemoteMedia/Transformation/RegistryTest.php: -------------------------------------------------------------------------------- 1 | registry = new Registry(); 30 | 31 | $this->cropTransformation = new Crop(); 32 | $this->resizeTransformation = new Resize(); 33 | $this->otherProviderCropTransformation = new Fit(); 34 | 35 | $this->registry->addHandler('cloudinary', 'crop', $this->cropTransformation); 36 | $this->registry->addHandler('cloudinary', 'resize', $this->resizeTransformation); 37 | $this->registry->addHandler('otherprovider', 'crop', $this->otherProviderCropTransformation); 38 | } 39 | 40 | public function testGetHandler() 41 | { 42 | self::assertEquals( 43 | $this->cropTransformation, 44 | $this->registry->getHandler('crop', 'cloudinary') 45 | ); 46 | } 47 | 48 | public function testNoHandler() 49 | { 50 | $this->expectException(TransformationHandlerNotFoundException::class); 51 | 52 | $this->registry->getHandler('cloudinary', 'something'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/RemoteMedia/UploadFileTest.php: -------------------------------------------------------------------------------- 1 | uri()); 21 | self::assertEquals('image', $uploadFile->originalFilename()); 22 | self::assertEquals('jpg', $uploadFile->originalExtension()); 23 | } 24 | 25 | public function testFromZHTTPFile(): void 26 | { 27 | $eZHTTPFile = new eZHTTPFile( 28 | 'upload_image', 29 | [ 30 | 'name' => 'image.jpg', 31 | 'type' => 'image/jpg', 32 | 'tmp_name' => 'oji939i.jpg', 33 | 'size' => 100, 34 | ] 35 | ); 36 | 37 | $uploadFile = UploadFile::fromZHTTPFile($eZHTTPFile); 38 | 39 | self::assertEquals('oji939i.jpg', $uploadFile->uri()); 40 | self::assertEquals('image', $uploadFile->originalFilename()); 41 | self::assertEquals('jpg', $uploadFile->originalExtension()); 42 | } 43 | 44 | public function testFromUploadedFile(): void 45 | { 46 | $uri = '/var/www/remote-media/image.jpg'; 47 | 48 | $fileMock = $this->createMock(UploadedFile::class); 49 | 50 | $fileMock 51 | ->expects(self::once()) 52 | ->method('getRealPath') 53 | ->willReturn($uri); 54 | 55 | $fileMock 56 | ->expects(self::once()) 57 | ->method('getClientOriginalName') 58 | ->willReturn('image'); 59 | 60 | $fileMock 61 | ->expects(self::once()) 62 | ->method('getClientOriginalExtension') 63 | ->willReturn('jpg'); 64 | 65 | $uploadFile = UploadFile::fromUploadedFile($fileMock); 66 | 67 | self::assertEquals($uri, $uploadFile->uri()); 68 | self::assertEquals('image', $uploadFile->originalFilename()); 69 | self::assertEquals('jpg', $uploadFile->originalExtension()); 70 | } 71 | 72 | public function testFromEzImageValue(): void 73 | { 74 | $webRoot = '/var/www/remote-media'; 75 | $uri = '/image.jpg'; 76 | 77 | $value = new Value([ 78 | 'uri' => $uri, 79 | 'fileName' => 'image.jpg', 80 | ]); 81 | 82 | $uploadFile = UploadFile::fromEzImageValue($value, $webRoot); 83 | 84 | self::assertEquals($webRoot . $uri, $uploadFile->uri()); 85 | self::assertEquals('image', $uploadFile->originalFilename()); 86 | self::assertEquals('jpg', $uploadFile->originalExtension()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tests/Templating/Converter/RemoteMediaValueConverterTest.php: -------------------------------------------------------------------------------- 1 | converter = new RemoteMediaValueConverter(); 18 | } 19 | 20 | public function testConvert() 21 | { 22 | $object = new Value(); 23 | 24 | self::assertEquals($object, $this->converter->convert($object)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /travis.php.ini: -------------------------------------------------------------------------------- 1 | [PHP] 2 | 3 | memory_limit = 5G 4 | -------------------------------------------------------------------------------- /update/database/migrate-data_text4-to-data_text5.sql: -------------------------------------------------------------------------------- 1 | UPDATE ezcontentclass_attribute SET data_text5=data_text4 where data_type_string= 'ngremotemedia'; 2 | 3 | --------------------------------------------------------------------------------