bgillieron/yii2-cloudinary

A Yii2-friendly wrapper for Cloudinary’s PHP SDK: upload widget, responsive images, and media management.

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

Type:yii2-extension

v1.0.0 2025-07-15 08:16 UTC

This package is auto-updated.

Last update: 2025-07-15 08:45:33 UTC


README

Cloudinary integration for the Yii2 PHP Framework.

This extension provides a Yii2-friendly wrapper around the official Cloudinary PHP SDK, enabling seamless uploads, media management, and responsive image rendering in Yii2 projects.

πŸ“ Project Structure

yii2-cloudinary/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ assets/
β”‚   β”‚   β”œβ”€β”€ photoswipe/
β”‚   β”‚   β”‚   β”œβ”€β”€ photoswipe-lightbox.esm.min.js
β”‚   β”‚   β”‚   β”œβ”€β”€ photoswipe.esm.min.js
β”‚   β”‚   β”‚   β”œβ”€β”€ photoswipe.css
β”‚   β”‚   └── PhotoSwipeAsset.php
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   └── Yii2CloudinaryComponent.php
β”‚   β”œβ”€β”€ controllers/
β”‚   β”‚   └── Yii2CloudinaryController.php
β”‚   β”œβ”€β”€ messages/
β”‚   β”‚   β”œβ”€β”€ en/
β”‚   β”‚   β”‚   └── uploadWidget.php
β”‚   β”‚   └── text.json
β”‚   β”œβ”€β”€ migrations/
β”‚   β”‚   └── m250430_120000_create_cloudinary_media_tables.php
β”‚   β”œβ”€β”€ models/
β”‚   β”‚   β”œβ”€β”€ CloudinaryImageMeta.php
β”‚   β”‚   β”œβ”€β”€ CloudinaryMedia.php
β”‚   β”‚   β”œβ”€β”€ CloudinaryMediaDesc.php
β”‚   β”‚   └── Module.php
β”œβ”€β”€ cloudinary-media-migrations.md
β”œβ”€β”€ composer.json
β”œβ”€β”€ LICENSE
β”œβ”€β”€ README.md
β”œβ”€β”€ render-responsive-image.md
└── upload-widget-localization.md

πŸ›  Features

  • Upload images and files to Cloudinary with a single call
  • Automatically configure credentials via Yii component
  • Drop-in Upload Widget integration with runtime options
  • Responsive image rendering with automatic srcset
  • Orientation-aware rendering via image meta
  • PhotoSwipe support for lightbox galleries
  • Database schema for multilingual media metadata
  • Easily relate uploaded media to your own models
  • Fully translatable Upload Widget UI

πŸ“¦ Installation

Install the extension via Composer:

composer require bgillieron/yii2-cloudinary

πŸ”§ Configuration

Add the module and component to your Yii2 config:

'modules' => [
    'cloudinary' => [
        'class' => 'yii2cloudinary\Module',
    ],
],
'components' => [
    'yii2cloudinary' => [
        'class' => \yii2cloudinary\components\Yii2CloudinaryComponent::class,
        'cloudName' => $_ENV['CLOUDINARY_CLOUD_NAME'],
        'apiKey' => $_ENV['CLOUDINARY_API_KEY'],
        'apiSecret' => $_ENV['CLOUDINARY_API_SECRET'],
        'uploadPreset' => $_ENV['CLOUDINARY_UPLOAD_PRESET'],
        'uploadHandlerUrl' => '/cloudinary/yii2-cloudinary/upload-handler',
        'db_defaultPublished' => false,
        'db_defaultOrder' => 500,
        'relationSaverMap' => [
            'test-widget' => function ($media) {
                Yii::$app->db->createCommand()->insert('test_media_relation', [
                    'media_id' => $media->id,
                    'label' => 'Uploaded from test widget',
                ])->execute();
            },
        ],
    ],
],

🧱 Migrations

To create the necessary tables for storing Cloudinary media and metadata, run:

php yii migrate --migrationPath=@yii2cloudinary/migrations

This will create:

  • cloudinary_media
  • cloudinary_media_desc
  • cloudinary_image_meta

πŸ“– For full details on table structure and purpose, see Cloudinary Media Migrations.

πŸš€ Media Usage

Uploading Files (Server-Side)

Yii::$app->yii2cloudinary->upload('/path/to/image.jpg', [
    'folder' => 'my-uploads',
    'tags' => ['profile', 'gallery'],
    'relationKey' => 'post-image',
]);

This method:

  • Uploads the file to Cloudinary
  • Saves the cloudinary_media record
  • If relationKey is provided and defined in your config, invokes the matching relation handler

πŸ” Saving Upload Result & Creating Relations

When a file is uploaded to Cloudinary, the extension automatically saves a corresponding record in the database (cloudinary_media) β€” but in most real-world projects, you’ll also want to associate that file with a specific model (like Post, Product, User, etc.).

To keep your application logic clean and flexible, this extension introduces the concept of relation callbacks, defined via the relationSaverMap.

🧠 Why Use relationSaverMap?

  • You may need different logic for different upload contexts (e.g. a product image, an avatar, a gallery).
  • Each upload (or widget instance) can pass a relationKey to identify which logic should run.
  • You configure these mappings once in your app config β€” no need to pass closures at runtime.

πŸ—‚οΈ Define Any Number of Relation Handlers

'relationSaverMap' => [
    'product-gallery' => function ($media) {
        Yii::$app->db->createCommand()->insert('product_media', [
            'media_id' => $media->id,
            'product_id' => 123,
            'position' => 1,
        ])->execute();
    },
    'user-avatar' => fn($media) => Yii::$app->user->identity->link('avatar', $media),
    'post-image' => fn($media) => Post::findOne(5)->link('media', $media),
],

Each callable will be invoked automatically after a successful upload, only if the relationKey matches.

Rendering a Responsive Image

echo Yii::$app->yii2cloudinary->renderResponsiveImage($media, [400, 800], [
    'class' => 'img-fluid',
]);
  • Generates <img> tag with optimized Cloudinary srcset
  • Optional aspect ratio detection (e.g. '4:3', '1:1')
  • Orientation-aware layout using image meta (landscape vs portrait)
  • Lazy loading and format auto-selection supported

πŸ“– See Render Responsive Image for advanced usage and options.

πŸ–Ό Upload Widget & UI

Rendering the Upload Widget

Yii::$app->yii2cloudinary->uploadWidget('upload_widget', [
    'relationKey' => 'test-widget', // πŸ‘ˆ this triggers your configured relationSaverMap callback
]);

This registers the Cloudinary Upload Widget and binds it to the DOM element with the given ID.

Key behaviors:

  • Automatically registers and loads Cloudinary’s JavaScript dependencies
  • Uploads files to Cloudinary and sends metadata to your configured uploadHandlerUrl endpoint, which persists the media and optionally links it using your relationSaverMap
  • If a relationKey is passed, it is forwarded to the server to trigger a matching callback from your relationSaverMap
  • You can also pass text overrides for localization

πŸ“Ž To attach uploaded media to a model, define your relation logic in relationSaverMap, and refer to it using relationKey.

πŸ” Upload Handler URL

When a file is uploaded via the widget, Cloudinary sends the file to their CDN,
then triggers a callback with metadata that is posted to your app’s upload handler.

By default, this handler is set to:

'uploadHandlerUrl' => '/yii2cloudinary/upload-handler',

You can override this in your component config if needed:

'uploadHandlerUrl' => '/custom/path/to/upload-handler',

This endpoint must match the route defined by your Yii2CloudinaryController::actionUploadHandler()
and is responsible for saving the uploaded media record and executing your relationSaverMap logic.
Only change this if absolutely necessary β€” overriding it incorrectly will break key functionality of this module.

🌍 Upload Widget Localization

This extension supports:

  • Default English UI via embedded translations
  • App-level language overrides via messages/<lang>/uploadWidget.php
  • Runtime text overrides passed to uploadWidget()

πŸ“– See Upload Widget Localization for a complete guide.

πŸ–Ό Lightbox Support (PhotoSwipe)

Register the ESM Asset Bundle

use yii2cloudinary\assets\PhotoSwipeAsset;

PhotoSwipeAsset::register($this);

Initialize in View

<?php $baseUrl = $this->assetManager->getBundle(\yii2cloudinary\assets\PhotoSwipeAsset::class)->baseUrl; ?>

<script type="module">
import PhotoSwipeLightbox from '<?= $baseUrl ?>/photoswipe-lightbox.esm.min.js';
import PhotoSwipe from '<?= $baseUrl ?>/photoswipe.esm.min.js';

const lightbox = new PhotoSwipeLightbox({
    gallery: '.my-gallery',
    children: 'a',
    pswpModule: PhotoSwipe,
    padding: 20,
    showHideAnimationType: 'zoom',
});

lightbox.init();
</script>

πŸ“Œ ES modules require explicit import and do not auto-run.

βš™οΈ Advanced Access

SDK Access

$cloudinary = Yii::$app->yii2cloudinary->getCloudinary();
$url = $cloudinary->image('your-public-id')->toUrl();

This returns the Cloudinary\Cloudinary instance for advanced transformations.

Model Reference

These models support multilingual metadata and responsive rendering:

πŸ“ License

MIT License
Β© Brendon GilliΓ©ron