Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for new dynamic folder mode parameter on Cloudinary #110

Open
wants to merge 12 commits into
base: upgrade-cloudinary-php-api
Choose a base branch
from
129 changes: 105 additions & 24 deletions bundle/Controller/Callback/Cloudinary/Notify.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
use Cloudinary\Api\Upload\UploadApi;
use Doctrine\ORM\EntityManagerInterface;
use Netgen\RemoteMedia\API\ProviderInterface;
use Netgen\RemoteMedia\API\Values\Folder;
use Netgen\RemoteMedia\API\Values\RemoteResource;
use Netgen\RemoteMedia\Core\Provider\Cloudinary\CacheableGatewayInterface;
use Netgen\RemoteMedia\Core\Provider\Cloudinary\CloudinaryProvider;
use Netgen\RemoteMedia\Core\Provider\Cloudinary\CloudinaryRemoteId;
use Netgen\RemoteMedia\Core\Provider\Cloudinary\GatewayInterface;
use Netgen\RemoteMedia\Core\RequestVerifierInterface;
Expand All @@ -31,35 +33,23 @@ final class Notify extends AbstractController
{
private const RESOURCE_UPLOAD = 'upload';
private const RESOURCE_DELETE = 'delete';
private const RESOURCE_MOVE = 'move';
private const RESOURCE_TAGS_CHANGED = 'resource_tags_changed';
private const RESOURCE_CONTEXT_CHANGED = 'resource_context_changed';
private const RESOURCE_RENAME = 'rename';
private const RESOURCE_DISPLAY_NAME_CHANGED = 'resource_display_name_changed';
private const FOLDER_CREATE = 'create_folder';
private const FOLDER_DELETE = 'delete_folder';

private GatewayInterface $gateway;

private ProviderInterface $provider;

private RequestVerifierInterface $signatureVerifier;

private EntityManagerInterface $entityManager;

private EventDispatcherInterface $eventDispatcher;
private const FOLDER_MOVE_RENAME = 'move_or_rename_asset_folder';

public function __construct(
GatewayInterface $gateway,
ProviderInterface $provider,
RequestVerifierInterface $signatureVerifier,
EntityManagerInterface $entityManager,
EventDispatcherInterface $eventDispatcher,
) {
$this->gateway = $gateway;
$this->provider = $provider;
$this->signatureVerifier = $signatureVerifier;
$this->entityManager = $entityManager;
$this->eventDispatcher = $eventDispatcher;
}
private GatewayInterface $gateway,
private ProviderInterface $provider,
private RequestVerifierInterface $signatureVerifier,
private EntityManagerInterface $entityManager,
private EventDispatcherInterface $eventDispatcher,
private string $folderMode,
) {}

public function __invoke(Request $request): Response
{
Expand All @@ -84,6 +74,11 @@ public function __invoke(Request $request): Response

break;

case self::RESOURCE_MOVE:
$this->handleResourceMoved($requestContent);

break;

case self::RESOURCE_TAGS_CHANGED:
$this->handleTagsChanged($requestContent);

Expand All @@ -99,8 +94,14 @@ public function __invoke(Request $request): Response

break;

case self::RESOURCE_DISPLAY_NAME_CHANGED:
$this->handleDisplayNameChanged($requestContent);

break;

case self::FOLDER_CREATE:
case self::FOLDER_DELETE:
case self::FOLDER_MOVE_RENAME:
$this->handleFoldersChanged();

break;
Expand Down Expand Up @@ -140,7 +141,7 @@ private function handleResourceUploaded(array $requestContent): void

$resource
->setUrl($this->gateway->getDownloadLink($cloudinaryRemoteId))
->setName(pathinfo($cloudinaryRemoteId->getResourceId(), PATHINFO_FILENAME))
->setName($this->resolveName($requestContent))
->setVersion((string) $requestContent['version'])
->setSize($requestContent['bytes'])
->setTags($requestContent['tags']);
Expand Down Expand Up @@ -176,6 +177,42 @@ private function handleResourceDeleted(array $requestContent): void
}
}

private function handleResourceMoved(array $requestContent): void
{
if ($this->folderMode !== CloudinaryProvider::FOLDER_MODE_DYNAMIC) {
return;
}

if ($this->gateway instanceof CacheableGatewayInterface) {
$this->gateway->invalidateResourceListCache();
$this->gateway->invalidateFoldersCache();
}

foreach ($requestContent['resources'] ?? [] as $publicId => $resourceData) {
$cloudinaryRemoteId = new CloudinaryRemoteId(
$resourceData['type'],
$resourceData['resource_type'],
(string) $publicId,
);

$this->gateway->invalidateResourceCache($cloudinaryRemoteId);

try {
$resource = $this->provider->loadByRemoteId($cloudinaryRemoteId->getRemoteId());
} catch (RemoteResourceNotFoundException $e) {
continue;
}

$resource->setFolder(Folder::fromPath($resourceData['to_asset_folder']));

if (($resourceData['display_name'] ?? null) !== null) {
$resource->setName($resourceData['display_name']);
}

$this->provider->store($resource);
}
}

/**
* This method is a bit hacky due to inconsistent Cloudinary API response.
*/
Expand Down Expand Up @@ -216,7 +253,7 @@ private function handleResourceRenamed(array $requestContent): void

$resource
->setRemoteId($cloudinaryRemoteId->getRemoteId())
->setName(pathinfo($cloudinaryRemoteId->getResourceId(), PATHINFO_FILENAME))
->setName($this->resolveName($requestContent))
->setUrl($this->gateway->getDownloadLink($cloudinaryRemoteId))
->setFolder($cloudinaryRemoteId->getFolder());

Expand All @@ -234,6 +271,41 @@ private function handleResourceRenamed(array $requestContent): void
}
}

private function handleDisplayNameChanged(array $requestContent): void
{
if ($this->folderMode !== CloudinaryProvider::FOLDER_MODE_DYNAMIC) {
return;
}

if ($this->gateway instanceof CacheableGatewayInterface) {
$this->gateway->invalidateResourceListCache();
}

foreach ($requestContent['resources'] ?? [] as $resourceData) {
$cloudinaryRemoteId = new CloudinaryRemoteId(
$resourceData['type'],
$resourceData['resource_type'],
(string) $resourceData['public_id'],
);

if ($this->gateway instanceof CacheableGatewayInterface) {
$this->gateway->invalidateResourceCache($cloudinaryRemoteId);
}

try {
$resource = $this->provider->loadByRemoteId(
$cloudinaryRemoteId->getRemoteId(),
);
} catch (RemoteResourceNotFoundException $e) {
continue;
}

$resource->setName($resourceData['new_display_name']);

$this->provider->store($resource);
}
}

private function handleTagsChanged(array $requestContent): void
{
if ($this->gateway instanceof CacheableGatewayInterface) {
Expand Down Expand Up @@ -382,4 +454,13 @@ private function handleFoldersChanged(): void
$this->gateway->invalidateFoldersCache();
}
}

private function resolveName(array $data): string
{
$cloudinaryRemoteId = CloudinaryRemoteId::fromCloudinaryData($data);

return $this->folderMode === CloudinaryProvider::FOLDER_MODE_FIXED
? pathinfo($cloudinaryRemoteId->getResourceId(), PATHINFO_FILENAME)
: $data['display_name'] ?? pathinfo($cloudinaryRemoteId->getResourceId(), PATHINFO_FILENAME);
}
}
9 changes: 8 additions & 1 deletion bundle/Controller/Resource/AbstractController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Symfony\Component\HttpFoundation\Response;

use function is_array;
use function str_starts_with;

abstract class AbstractController
{
Expand Down Expand Up @@ -83,11 +84,17 @@ private function resolveImageUrl(RemoteResource $resource, string $variationName
$variationName .= '_protected';
}

if ($resource->getType() === RemoteResource::TYPE_IMAGE) {
$variationName .= '_image';
}

$location = new RemoteResourceLocation($resource);

return match ($resource->getType()) {
RemoteResource::TYPE_IMAGE => $this->provider->buildVariation($location, 'ngrm_interface', $variationName)->getUrl(),
RemoteResource::TYPE_VIDEO => $this->provider->buildVideoThumbnailVariation($location, 'ngrm_interface', $variationName)->getUrl(),
RemoteResource::TYPE_VIDEO => str_starts_with($variationName, 'preview')
? $this->provider->buildVariation($location, 'ngrm_interface', $variationName)->getUrl()
: $this->provider->buildVideoThumbnailVariation($location, 'ngrm_interface', $variationName)->getUrl(),
default => '',
};
}
Expand Down
8 changes: 7 additions & 1 deletion bundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Netgen\Bundle\RemoteMediaBundle\DependencyInjection;

use Netgen\RemoteMedia\Core\Provider\Cloudinary\CloudinaryProvider;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
Expand Down Expand Up @@ -32,7 +33,8 @@ private function addProviderSection(ArrayNodeDefinition $rootNode): void
{
$rootNode
->children()
->scalarNode('provider')
->enumNode('provider')
->values(['cloudinary'])
->defaultValue('cloudinary')
->end()
->scalarNode('account_name')
Expand Down Expand Up @@ -161,6 +163,10 @@ private function addCloudinaryConfiguration(ArrayNodeDefinition $rootNode): void
->scalarNode('encryption_key')
->defaultNull()
->end()
->enumNode('folder_mode')
->values([CloudinaryProvider::FOLDER_MODE_DYNAMIC, CloudinaryProvider::FOLDER_MODE_FIXED])
->defaultValue(CloudinaryProvider::FOLDER_MODE_DYNAMIC)
->end()
->end()
->end()
->end();
Expand Down
10 changes: 5 additions & 5 deletions bundle/DependencyInjection/NetgenRemoteMediaExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Netgen\Bundle\RemoteMediaBundle\DependencyInjection;

use InvalidArgumentException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Loader\LoaderResolver;
Expand Down Expand Up @@ -40,10 +39,6 @@ public function load(array $configs, ContainerBuilder $container): void
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);

if (!isset($config['provider'])) {
throw new InvalidArgumentException('The "provider" option must be set');
}

$container->setParameter('netgen_remote_media.remove_unused_resources', $config['remove_unused']);
$container->setAlias('netgen_remote_media.provider', 'netgen_remote_media.provider.' . $config['provider']);

Expand Down Expand Up @@ -100,6 +95,11 @@ public function load(array $configs, ContainerBuilder $container): void

$container->setAlias('netgen_remote_media.provider.cloudinary.gateway', $cloudinaryGatewayAlias);

$container->setParameter(
'netgen_remote_media.cloudinary.folder_mode',
$config['cloudinary']['folder_mode'],
);

$loader->load('default_parameters.yaml');
$loader->load('services/**/*.yaml', 'glob');
}
Expand Down
25 changes: 24 additions & 1 deletion bundle/Resources/config/default_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,43 @@ image_variations:
transformations:
- { name: limit, params: [500, 500] }
- { name: quality, params: ['auto', 'eco'] }
preview_image:
transformations:
- { name: limit, params: [500, 500] }
- { name: quality, params: ['auto', 'eco'] }
- { name: format, params: ['jpg'] }
preview_protected:
transformations:
- { name: limit, params: [500, 500] }
- { name: quality, params: ['auto', 'eco'] }
- { name: effect, params: ['pixelate', 4] }
preview_protected_image:
transformations:
- { name: limit, params: [500, 500] }
- { name: quality, params: ['auto', 'eco'] }
- { name: format, params: ['jpg'] }
- { name: effect, params: ['pixelate', 4] }
browse:
transformations:
- { name: crop, params: [174, 100] }
- { name: fill, params: [174, 100] }
- { name: quality, params: ['auto', 'eco'] }

browse_image:
transformations:
- { name: crop, params: [174, 100] }
- { name: fill, params: [174, 100] }
- { name: quality, params: ['auto', 'eco'] }
- { name: format, params: ['jpg'] }
browse_protected:
transformations:
- { name: crop, params: [174, 100] }
- { name: fill, params: [174, 100] }
- { name: quality, params: ['auto', 'eco'] }
- { name: effect, params: ['pixelate', 1] }
browse_protected_image:
transformations:
- { name: crop, params: [174, 100] }
- { name: fill, params: [174, 100] }
- { name: quality, params: ['auto', 'eco'] }
- { name: format, params: ['jpg'] }
- { name: effect, params: ['pixelate', 1] }
1 change: 1 addition & 0 deletions bundle/Resources/config/services/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ services:
- '@netgen_remote_media.provider.cloudinary.verifier.controller.signature'
- '@doctrine.orm.entity_manager'
- '@event_dispatcher'
- '%netgen_remote_media.cloudinary.folder_mode%'
calls:
- [setContainer, ['@service_container']]
5 changes: 5 additions & 0 deletions bundle/Resources/config/services/core.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ services:
arguments:
- "@netgen_remote_media.provider.cloudinary.gateway.inner"
- "@netgen_remote_media.cache.pool"
- "%netgen_remote_media.cloudinary.folder_mode%"
- "%netgen_remote_media.cache.ttl%"

netgen_remote_media.provider.cloudinary.gateway.logged:
Expand All @@ -48,6 +49,7 @@ services:
- "@netgen_remote_media.provider.cloudinary.resolver.upload_options"
- "%netgen_remote_media.named_remote_resources%"
- "%netgen_remote_media.named_remote_resource_locations%"
- '%netgen_remote_media.cloudinary.folder_mode%'
- "@?logger"

netgen_remote_media.provider.cloudinary.converter.resource_type:
Expand Down Expand Up @@ -79,6 +81,7 @@ services:
- '@netgen_remote_media.provider.cloudinary.converter.resource_type'
- '@netgen_remote_media.provider.cloudinary.converter.visibility_type'
- '@netgen_remote_media.factory.md5_file_hash'
- '%netgen_remote_media.cloudinary.folder_mode%'

netgen_remote_media.provider.cloudinary.factory.search_result:
class: Netgen\RemoteMedia\Core\Provider\Cloudinary\Factory\SearchResult
Expand All @@ -97,13 +100,15 @@ services:
public: false
arguments:
- '@netgen_remote_media.provider.cloudinary.converter.visibility_type'
- '%netgen_remote_media.cloudinary.folder_mode%'

netgen_remote_media.provider.cloudinary.resolver.search_expression:
class: Netgen\RemoteMedia\Core\Provider\Cloudinary\Resolver\SearchExpression
public: false
arguments:
- '@netgen_remote_media.provider.cloudinary.converter.resource_type'
- '@netgen_remote_media.provider.cloudinary.converter.visibility_type'
- '%netgen_remote_media.cloudinary.folder_mode%'

netgen_remote_media.factory.date_time:
class: Netgen\RemoteMedia\Core\Factory\DateTime
Expand Down
2 changes: 1 addition & 1 deletion bundle/Resources/public/css/remotemedia.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion bundle/Resources/public/js/remotemedia.js

Large diffs are not rendered by default.

Loading
Loading