cloudflare_stream-8.x-1.0/src/Plugin/Field/FieldType/CloudflareVideoItem.php
src/Plugin/Field/FieldType/CloudflareVideoItem.php
<?php
namespace Drupal\cloudflare_stream\Plugin\Field\FieldType;
use Drupal\cloudflare_stream\Service\CloudflareStreamApiInterface;
use Drupal\cloudflare_stream\Service\CloudflareStreamInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\TempStore\PrivateTempStore;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\TraversableTypedDataInterface;
use Drupal\file\Entity\File;
use Drupal\file\FileUsage\FileUsageInterface;
use Drupal\file\Plugin\Field\FieldType\FileItem;
/**
* Plugin implementation of the 'cloudflareVideo' field type.
*
* @FieldType(
* id = "cloudflarevideo",
* label = @Translation("Cloudflare Video"),
* description = @Translation("This field stores the ID of an cloudflare video."),
* category = @Translation("Cloudflare"),
* default_widget = "cloudflarevideo_default",
* default_formatter = "cloudflarevideo_default",
* list_class = "\Drupal\file\Plugin\Field\FieldType\FileFieldItemList",
* constraints = {"ReferenceAccess" = {}, "FileValidation" = {}}
* )
*/
class CloudflareVideoItem extends FileItem {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected EntityTypeManagerInterface $entityTypeManager;
/**
* The file system.
*
* @var \Drupal\Core\File\FileSystemInterface
*/
protected FileSystemInterface $fileSystem;
/**
* The Cloudflare Stream service.
*
* @var \Drupal\cloudflare_stream\Service\CloudflareStreamInterface
*/
protected CloudflareStreamInterface $cloudflareStream;
/**
* The Cloudflare Stream API service.
*
* @var \Drupal\cloudflare_stream\Service\CloudflareStreamApiInterface
*/
protected CloudflareStreamApiInterface $cloudflareStreamApi;
/**
* The file usage service.
*
* @var \Drupal\file\FileUsage\FileUsageInterface
*/
protected FileUsageInterface $fileUsage;
/**
* Key-value store to hold video ID for our field widget.
*/
protected PrivateTempStore $tempStore;
/**
* {@inheritdoc}
*/
public static function createInstance($definition, $name = NULL, TraversableTypedDataInterface $parent = NULL) {
// @todo refactor when https://www.drupal.org/project/drupal/issues/3294266
// is resolved.
$instance = parent::createInstance($definition, $name, $parent);
$instance->entityTypeManager = \Drupal::service('entity_type.manager');
$instance->fileSystem = \Drupal::service('file_system');
$instance->fileUsage = \Drupal::service('file.usage');
$instance->cloudflareStream = \Drupal::service('cloudflare_stream');
$instance->cloudflareStreamApi = \Drupal::service('cloudflare_stream.api');
$factory = \Drupal::service('tempstore.private');
$instance->tempStore = $factory->get('cloudflare_stream');
return $instance;
}
/**
* {@inheritdoc}
*/
public static function defaultStorageSettings() {
$default = parent::defaultStorageSettings();
$default['uri_scheme'] = 'cfstream';
return $default;
}
/**
* {@inheritdoc}
*/
public function storageSettingsForm(array &$form, FormStateInterface $form_state, $has_data) {
$element = parent::storageSettingsForm($form, $form_state, $has_data);
$settings = self::defaultStorageSettings();
$element['uri_scheme'] = [
'#type' => 'item',
'#title' => $this->t('Upload destination'),
'#default_value' => $settings['uri_scheme'],
'#description' => $this->t('Cloudflare Video fields always use CloudflareStream storage.'),
];
return $element;
}
/**
* {@inheritdoc}
*/
public static function defaultFieldSettings() {
$fieldSettings = parent::defaultFieldSettings();
$cloudflareStream = \Drupal::service('cloudflare_stream');
$fieldSettings['file_extensions'] = $cloudflareStream->listAllowedFileExtensions();
$fieldSettings['file_directory'] = '';
return $fieldSettings;
}
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition) {
$schema = parent::schema($field_definition);
$schema['columns']['cloudflareStreamVideoID'] = [
'type' => 'text',
'length' => 512,
'not null' => FALSE,
];
$schema['columns']['thumbnail'] = [
'type' => 'text',
'length' => 512,
'not null' => FALSE,
];
return $schema;
}
/**
* {@inheritdoc}
*/
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
$form = parent::fieldSettingsForm($form, $form_state);
$form['file_extensions']['#description'] = $this->t('Separate extensions with a space or comma and do not include the leading dot.<br>Cloudflare Stream supports following extensions: MP4, MKV, MOV, AVI, FLV, MPEG-2 TS, MPEG-2 PS, MXF, LXF, GXF, 3GP, WebM, MPG, QuickTime');
// Directory is not supported.
unset($form['file_directory']);
return $form;
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties = parent::propertyDefinitions($field_definition);
$properties['cloudflareStreamVideoID'] = DataDefinition::create('string')
->setLabel(t('Cloudflare Video ID'));
$properties['thumbnail'] = DataDefinition::create('string')
->setLabel(t('Cloudflare Video thumbnail'));
return $properties;
}
/**
* {@inheritdoc}
*/
public function preSave(): void {
$entity = $this->getEntity();
if (is_null($this->getValue()['cloudflareStreamVideoID'])) {
$fileID = $this->get('target_id')->getValue();
$file = $this->entityTypeManager->getStorage('file')->load($fileID);
if ($file instanceof File) {
$videoId = $this->tempStore->get($file->getFileUri());
$details = $this->cloudflareStreamApi->getDetails($videoId);
if (isset($videoId)) {
$oldVideoId = $this->getOldVideoId($entity, $this->name);
if (isset($oldVideoId)) {
$this->cloudflareStreamApi->deleteVideo($oldVideoId);
}
$this->setValue(
[
'target_id' => $this->getValue()['target_id'],
'display' => $this->getValue()['display'],
'description' => $this->getValue()['description'],
'cloudflareStreamVideoID' => $videoId,
'thumbnail' => $details['thumbnail'],
]
);
$scheme = parse_url($file->getFileUri(), PHP_URL_SCHEME);
$file->setFileUri("$scheme://$videoId");
$this->fileUsage->add($file, 'cloudflare_stream', 'cloudflarevideo', \Drupal::currentUser()->id());
$file->setPermanent();
$file->save();
}
}
}
else {
$fieldName = $this->getParent()->getName();
$newFieldData = $this->getEntity()->get($fieldName)->getValue();
$originalFieldData = $entity->get($fieldName)->getValue();
$videoIds = array_filter($this->getRemovedIds($originalFieldData, $newFieldData), function ($element) {
if ($element !== NULL) {
return $element;
}
});
foreach ($videoIds as $videoId) {
$this->cloudflareStreamApi->deleteVideo($videoId);
}
}
}
/**
* Return the old video ID.
*/
protected function getOldVideoId($entity, $delta) {
$oldVideoID = NULL;
if ($entity) {
$fieldName = $this->getParent()->getName();
$oldVideoID = $entity->get($fieldName)->getValue()[$delta]['cloudflareStreamVideoID'] ? $entity->get($fieldName)->getValue()[$delta]['cloudflareStreamVideoID'] : NULL;
}
return $oldVideoID;
}
/**
* Get the removed video IDs from cloudflare stream.
*
* @param array $originalFieldData
* Contains the original video data.
* @param array $newFieldData
* Contains the new video data.
*
* @return array
* The removed video IDs.
*/
protected function getRemovedIds(array $originalFieldData, array $newFieldData) {
$removedIds = [];
foreach ($originalFieldData as $key => $originalFieldDatum) {
foreach ($newFieldData as $newFieldDatum) {
if ($originalFieldDatum['cloudflareStreamVideoID'] === $newFieldDatum['cloudflareStreamVideoID']) {
$removedIds[$key] = NULL;
break;
}
$removedIds[$key] = $originalFieldDatum['cloudflareStreamVideoID'];
}
}
return $removedIds;
}
/**
* {@inheritdoc}
*/
public function delete() {
$this->cloudflareStreamApi->deleteVideo($this->getValue()['cloudflareStreamVideoID']);
}
}
