Skip to content

Commit

Permalink
Merge pull request #110 from netgen/feature/folder-mode
Browse files Browse the repository at this point in the history
Add support for new dynamic folder mode parameter on Cloudinary
  • Loading branch information
RandyCupic authored Nov 28, 2024
2 parents d2b6144 + 25c5acf commit 20a85b7
Show file tree
Hide file tree
Showing 39 changed files with 1,261 additions and 202 deletions.
8 changes: 4 additions & 4 deletions bundle/Command/RefreshStoredResourcesCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class RefreshStoredResourcesCommand extends Command

private int $batchSize = 500;

/** @var \Netgen\RemoteMedia\API\Values\RemoteResource[] */
/** @var RemoteResource[] */
private array $resourcesToDelete;

public function __construct(
Expand Down Expand Up @@ -97,15 +97,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}

/**
* @return \Netgen\RemoteMedia\API\Values\RemoteResource[]
* @return RemoteResource[]
*/
private function getBatch(int $limit, int $offset): array
{
return $this->resourceRepository->findBy([], null, $limit, $offset);
}

/**
* @param \Netgen\RemoteMedia\API\Values\RemoteResource[] $resources
* @param RemoteResource[] $resources
*/
private function refreshResources(array $resources): void
{
Expand Down Expand Up @@ -135,7 +135,7 @@ private function refreshResources(array $resources): void
/**
* @param string[] $remoteIds
*
* @return array<string, \Netgen\RemoteMedia\API\Values\RemoteResource>
* @return array<string, RemoteResource>
*/
private function getRemoteBatch(array $remoteIds): array
{
Expand Down
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);
}
}
11 changes: 9 additions & 2 deletions 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 @@ -51,7 +52,7 @@ protected function formatResource(RemoteResource $resource): array
}

/**
* @param \Netgen\RemoteMedia\API\Values\RemoteResource[] $resources
* @param RemoteResource[] $resources
*/
protected function formatResources(array $resources): array
{
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']]
Loading

0 comments on commit 20a85b7

Please sign in to comment.