cloudinary-8.x-1.x-dev/modules/cloudinary_video/src/Element/CloudinaryVideo.php
modules/cloudinary_video/src/Element/CloudinaryVideo.php
<?php
namespace Drupal\cloudinary_video\Element;
use Cloudinary\Asset\DeliveryType;
use Cloudinary\Tag\VideoTag;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Render\Element\RenderElement;
use Drupal\Core\Render\Markup;
use Drupal\Core\Url;
/**
* Provides a render element to render cloudinary video.
*
* Properties:
* - #public_id: Public ID of the asset to render.
* - #player_type: Override default player type.
* - #muted: Mute the video.
* - #controls: Whether to show controls.
* - #autoplay: Autoplay video.
* - #loop: Loop video.
* - #player: Override default cloudinary player configuration.
* - #responsive: Whether to display responsive video.
* - #width: Width of the video (applicable if video is not responsive).
* - #height: Height of the video (applicable if video is not responsive).
* - #delivery_type: Delivery type of the asset.
* - #sources: Override default sources.
* - #default_transformation: Whether to apply default video transformation.
* - #attributes: Apply custom attributes to the video.
* - #raw_transformation: Optional string of URL transformation.
* e.g. 'e_progressbar:width_5'.
*
* Usage Example:
* @code
* $build['video'] = [
* '#type' => 'cloudinary_video',
* '#public_id' => 'samples/cld-sample-video',
* '#raw_transformation' => 'e_progressbar:width_5',
* '#width' => '100%',
* '#attributes' => ['class' => ['demo-video']],
* ];
* @endcode
*
* @RenderElement("cloudinary_video")
*/
class CloudinaryVideo extends RenderElement {
/**
* {@inheritdoc}
*/
public function getInfo() {
return [
'#width' => 854,
'#height' => 480,
'#autoplay' => FALSE,
'#raw_transformation' => NULL,
'#sources' => NULL,
'#responsive' => TRUE,
'#resource_type' => 'video',
'#player_type' => 'auto',
'#delivery_type' => DeliveryType::UPLOAD,
'#attributes' => [],
'#muted' => FALSE,
'#controls' => FALSE,
'#loop' => FALSE,
'#default_transformation' => TRUE,
'#pre_render' => [
[get_class($this), 'preRenderVideoElement'],
],
];
}
/**
* Build an url for cloudinary player iframe.
*
* @param array $element
* The element array.
*
* @return \Drupal\Core\Url
* The source iframe url.
*/
protected static function buildUrl(array $element): Url {
$sdk_config = \Drupal::config('cloudinary_sdk.settings');
$video_config = \Drupal::config('cloudinary_video.settings');
// Define required params for the source url.
$query = [
'cloud_name' => $sdk_config->get('cloudinary_sdk_cloud_name'),
'public_id' => $element['#public_id'],
];
// Use cname option in the url.
if ($cname = $sdk_config->get('cloudinary_sdk_cname')) {
$query['cloudinary'] = [
'secure_distribution' => $cname,
'private_cdn' => TRUE,
];
}
// Override default player settings.
$player = $element['#player'] ?? [];
if ($player_settings = $video_config->get('cloudinary_video_player_config')) {
$player += Json::decode($player_settings);
}
if ($player) {
$query['player'] = $player;
}
// Force the controls visibility option.
$query['player']['controls'] = $element['#controls'] ? 'true' : 'false';
// Force the loop option.
$query['player']['loop'] = $element['#loop'] ? 'true' : 'false';
// Force the muted option.
$query['player']['muted'] = $element['#muted'] ? 'true' : 'false';
// Force autoplay option for the player.
if ($element['#autoplay']) {
$query['player']['autoplay'] = 'true';
$query['player']['autoplayMode'] = 'always';
}
// Apply default transformation.
$transformations = [];
if ($element['#default_transformation']) {
if ($transformation = $video_config->get('cloudinary_video_optimizations')) {
$transformations[] = $transformation;
}
}
// Apply custom transformation.
if ($element['#raw_transformation']) {
$transformations[] = $element['#raw_transformation'];
}
if ($transformations) {
$query['source']['transformation']['raw_transformation'] = implode('/', $transformations);
}
return Url::fromUri('https://player.cloudinary.com/embed/', [
'query' => $query,
]);
}
/**
* Cloudinary video element process callback.
*/
public static function preRenderVideoElement($element) {
$video_config = \Drupal::config('cloudinary_video.settings');
$player_type = $element['#player_type'] === 'auto'
? $video_config->get('cloudinary_default_player')
: $element['#player_type'];
$element['#player_type'] = $player_type;
$element['#theme'] = 'cloudinary_video_player';
switch ($player_type) {
case 'cloudinary':
$url = static::buildUrl($element);
$default_attributes = [
'src' => $url->toString(),
'frameborder' => 0,
'scrolling' => FALSE,
'allow' => 'autoplay; fullscreen; encrypted-media; picture-in-picture',
'allowfullscreen' => 'true',
];
if (!$element['#responsive']) {
$default_attributes['width'] = $element['#width'];
$default_attributes['height'] = $element['#height'];
}
$element['#children'] = [
'#type' => 'html_tag',
'#tag' => 'iframe',
'#attributes' => $element['#attributes'] + $default_attributes,
];
break;
case 'html5':
$video_tag = new VideoTag($element['#public_id'], $element['#sources']);
$default_attributes = [];
// Set up global player settings.
if ($player_attributes = $video_config->get('cloudinary_default_player_config')) {
foreach (explode(' ', $player_attributes) as $attribute) {
$data = explode('=', $attribute);
$default_attributes[$data[0]] = $data[1] ?? $data[0];
}
}
// Force height and width for non-responsive video.
if (!$element['#responsive']) {
$default_attributes['width'] = $element['#width'];
$default_attributes['height'] = $element['#height'];
}
// Override attributes with custom one.
if (isset($element['#attributes']['class'])) {
$video_tag->addClass($element['#attributes']['class']);
unset($element['#attributes']['class']);
}
$attributes = $element['#attributes'] + $default_attributes;
$video_tag->setAttributes($attributes);
$video_tag->fallback(t('Your browser does not support HTML5 video tags'));
$video_tag->deliveryType($element['#delivery_type']);
// Apply default transformation.
if ($element['#default_transformation']) {
if ($transformation = $video_config->get('cloudinary_video_optimizations')) {
$video_tag->addTransformation($transformation);
}
}
// Apply custom transformation.
if ($element['#raw_transformation']) {
$video_tag->addTransformation($element['#raw_transformation']);
}
$optional_attributes = [
'loop',
'muted',
'controls',
'autoplay',
];
foreach ($optional_attributes as $attribute) {
if (!empty($element["#{$attribute}"])) {
$video_tag->setAttribute($attribute, $attribute);
}
}
$element += [
'#children' => Markup::create((string) $video_tag),
];
break;
}
$tags = $element['#cache']['tags'] ?? [];
$element['#cache']['tags'] = Cache::mergeTags($tags, $video_config->getCacheTags());
return $element;
}
}
