layout_builder_kit-8.x-1.x-dev/src/Plugin/Block/LBKVideo/LBKVideo.php
src/Plugin/Block/LBKVideo/LBKVideo.php
<?php
namespace Drupal\layout_builder_kit\Plugin\Block\LBKVideo;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigManagerInterface;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Field\TypedData\FieldItemDataDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Plugin\Context\EntityContext;
use Drupal\Core\Routing\CurrentRouteMatch;
use Drupal\entity\BundleFieldDefinition;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\FieldConfigInterface;
use Drupal\file\Entity\File;
use Drupal\layout_builder_kit\Plugin\Block\LBKBaseComponent;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\Core\Entity\EntityTypeBundleInfoTest;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\layout_builder\Plugin\SectionStorage\DefaultsSectionStorage;
use Drupal\layout_builder\Plugin\SectionStorage\OverridesSectionStorage;
use Drupal\Core\Entity\Plugin\DataType\ConfigEntityAdapter;
use Drupal\Core\Entity\Plugin\DataType\EntityAdapter;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
use Drupal\Core\Entity\EntityTypeBundleInfo;
use Drupal\Core\Field\FieldDefinition;
/**
* Provides a 'LBKVideo' block.
*
* @Block(
* id = "lbk_video",
* admin_label = @Translation("Video (LBK)"),
* )
*/
class LBKVideo extends LBKBaseComponent implements ContainerFactoryPluginInterface {
/**
* Drupal\Core\Entity\EntityTypeManagerInterface definition.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Drupal\Core\Config\ConfigManagerInterface definition.
*
* @var \Drupal\Core\Config\ConfigManagerInterface
*/
protected $configManager;
/**
* Drupal\Core\Routing\CurrentRouteMatch class.
*
* @var \Drupal\Core\Routing\CurrentRouteMatch
*/
protected $currentRouteMatch;
/**
* Drupal\Core\Entity\EntityFieldManager definition.
*
* @var \Drupal\Core\Entity\EntityFieldManager
*/
protected $entityFieldManager;
/**
* Drupal\Core\Entity\EntityTypeBundleInfo class.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfo
*/
protected $entityTypeBundleInfo;
/**
* Constructs a new video object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $pluginId
* The plugin_id for the plugin instance.
* @param string $pluginDefinition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
* The EntityTypeManagerInterface service.
* @param \Drupal\Core\Config\ConfigManagerInterface $configManager
* The ConfigManagerInterface service.
* @param \Drupal\Core\Routing\CurrentRouteMatch $currentRouteMatch
* The CurrentRouteMatch service.
* @param \Drupal\Core\Entity\EntityFieldManager $entityFieldManager
* The EntityFieldManager service.
* @param \Drupal\Core\Entity\EntityTypeBundleInfo $entityTypeBundleInfo
* The EntityTypeBundleInfo service.
*/
public function __construct(
array $configuration,
$pluginId,
$pluginDefinition,
EntityTypeManagerInterface $entityTypeManager,
ConfigManagerInterface $configManager,
CurrentRouteMatch $currentRouteMatch,
EntityFieldManager $entityFieldManager,
EntityTypeBundleInfo $entityTypeBundleInfo
) {
parent::__construct($configuration, $pluginId, $pluginDefinition, $currentRouteMatch, $entityTypeBundleInfo);
$this->entityTypeManager = $entityTypeManager;
$this->configManager = $configManager;
$this->currentRouteMatch = $currentRouteMatch;
$this->entityFieldManager = $entityFieldManager;
$this->entityTypeBundleInfo = $entityTypeBundleInfo;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
return new static(
$configuration,
$pluginId,
$pluginDefinition,
$container->get('entity_type.manager'),
$container->get('config.manager'),
$container->get('current_route_match'),
$container->get('entity_field.manager'),
$container->get('entity_type.bundle.info')
);
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'video_component_fields' => [
'video_url' => '',
'video' => [],
'video_field' => [],
'video_radio_options' => [],
],
] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $formState) {
// Attach library to the form.
$form['#attached']['library'] = ['layout_builder_kit/video-styling'];
$currentValue = $this->configuration['video_component_fields']['video_radio_options'];
// Get default radio option.
if (empty($currentValue)) $currentValue = 0;
$form['video_radio_options'] = [
'#type' => 'radios',
'#default_value' => $currentValue,
'#options' => [
0 => $this->t('Video URL'),
2 => $this->t('Video Fields'),
],
'#id' => 'options_video',
'#title_display' => $this->t('title'),
'#weight' => 30,
'#prefix' => '<div class="video-container"><div class="video-radios--options">',
'#suffix' => '</div>',
];
$form['video_url'] = [
'#type' => 'textfield',
'#title' => $this->t('Video URL'),
'#maxlength' => 255,
'#default_value' => $this->configuration['video_component_fields']['video_url'],
'#required' => FALSE,
'#weight' => 40,
'#prefix' => '<div class="video-fields--options">',
];
$form['video_field'] = [
'#type' => 'select',
'#title' => $this->t('Video fields available'),
'#options' => $this->getVideosEmbedArray(),
'#default_value' => $this->configuration['video_component_fields']['video_field'],
'#weight' => 50,
'#suffix' => '</div></div>',
];
$form['#attached']['library'] = ['layout_builder_kit/video-styling'];
return $form;
}
/**
* {@inheritdoc}
*/
public function blockValidate($form, FormStateInterface $form_state) {
parent::blockValidate($form, $form_state);
$link = $form_state->getValue('video_url');
if (isset($link) && !empty($link)) {
$isValid = UrlHelper::isValid($link, TRUE);
if (!$isValid) $form_state->setErrorByName('link', $this->t('URL must be in form of http://www.url.com.'));
}
}
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $formState) {
$this->configuration['video_component_fields']['video_radio_options'] = $formState->getValue('video_radio_options');
if ($formState->getValue('video_radio_options') == 0) {
$this->configuration['video_component_fields']['video_url'] = $formState->getValue('video_url');
}
else {
$this->configuration['video_component_fields']['video_field'] = $formState->getValue('video_field');
}
}
/**
* {@inheritdoc}
*/
public function build() {
$build = parent::build();
$build['#theme'] = 'LBKVideo';
$build['#attached']['library'] = ['layout_builder_kit/video-styling'];
// TODO: Remove this block in the future, it does nothing.
if (!empty($this->configuration['video_component_fields']['video'])) {
$imageFileId = implode($this->configuration['video_component_fields']['video']);
$image = File::load($imageFileId);
if ($image != NULL) {
$image->setPermanent();
$image->save();
}
}
// Get bundle type.
$entityType = $this->getEntityType();
$entity = NULL;
$fieldOutput = [];
// Render fields.
// TODO: Add function for all kind of fields.
$field = !empty($this->configuration['video_component_fields']['video_field']) ? $this->getBundleField($this->configuration['video_component_fields']['video_field'], $entityType) : NULL;
if (isset($field) && $field !== "" && $entityType !== "") {
// Fields to render.
$fields = [
$field,
];
// Get the Node entity object.
if ($this->currentRouteMatch->getParameter($entityType)) {
$entity = $this->currentRouteMatch->getParameter($entityType);
}
else {
$currentRoute = $this->currentRouteMatch;
$sectionStorage = $currentRoute->getParameters()->get('section_storage');
if ($sectionStorage instanceof OverridesSectionStorage) {
$context = $sectionStorage->getContext('entity');
if ($context instanceof EntityContext) {
$contextData = $context->getContextData();
if ($contextData instanceof EntityAdapter) {
$entity = $contextData->getEntity();
}
}
}
}
// Get the view for this Node entity object.
$viewBuilder = $this->entityTypeManager->getViewBuilder($entityType);
// Build the Node array to render.
foreach ($fields as $field_name) {
if ($entity instanceof Node) {
if ($entity->hasField($field_name) && $entity->access('view')) {
$value = $entity->get($field_name);
if ($value instanceof FieldItemList) {
if (!empty($value->getValue())) {
$fieldOutput['value'] = $viewBuilder->viewField($value, ["label" => "hidden"]);
$fieldOutput['value']['#cache']['tags'] = $entity->getCacheTags();
} else {
$fieldOutput['text'] = $this->t('This field is empty.');
}
}
}
else {
$fieldOutput['text'] = $this->t('This field is not available for this content.');
}
}
else {
if ($entity instanceof Term) {
if ($entity->hasField($field_name) && $entity->access('view')) {
$value = $entity->get($field_name);
if ($value instanceof FieldItemList) {
if (!empty($value->getValue())) {
$fieldOutput['value'] = $viewBuilder->viewField($value, ["label" => "hidden"]);
$fieldOutput['value']['#cache']['tags'] = $entity->getCacheTags();
} else {
$fieldOutput['text'] = $this->t('This field is empty.');
}
}
}
else {
$fieldOutput['text'] = $this->t('This field is not available for this content.');
}
}
}
}
} else {
$fieldOutput['text'] = $this->t('Place this component inside a node page');
}
// Basic response at least handles tags.
$build['#video_field'] = $fieldOutput;
if (isset($build['#video_field']) && $entityType !== "") {
$currentVideoFieldType = $this->getVideoFieldType($field, $entityType);
$build['#field_type'] = $currentVideoFieldType;
if ($entity instanceof Node) {
switch ($currentVideoFieldType) {
case "string":
case "string_long":
if (isset($fieldOutput['value'][0]['#context']['value'])) {
$videoFieldPath = trim($fieldOutput['value'][0]['#context']['value']);
if ($videoFieldPath) $build['#video_field']['value'] = $this->getVideoEmbedUrl($videoFieldPath);
}
break;
case "text":
if (isset($fieldOutput['value'][0]['#text'])) {
$videoFieldPath = trim($fieldOutput['value'][0]['#text']);
if ($videoFieldPath) $build['#video_field']['value'] = $this->getVideoEmbedUrl($videoFieldPath);
}
break;
case "link":
if (isset($fieldOutput['value'][0]['#url'])) {
$videoFieldPath = $fieldOutput['value'][0]['#url']->getUri();
$build['#video_field']['value'] = $this->getVideoEmbedUrl($videoFieldPath);
}
break;
case "file":
$filePath = $fieldOutput['value'][0]['#file'];
if ($filePath) {
$videoFieldUri = $filePath->getFileUri();
$videoFieldPath = \Drupal::service('file_url_generator')->generateAbsoluteString($videoFieldUri);
$build['#video_field']['value'] = $videoFieldPath;
}
break;
case "video_embed_field":
break;
}
}
else {
if ($entity instanceof Term) {
switch ($currentVideoFieldType) {
case "string":
case "string_long":
if (isset($fieldOutput['value'][0]['#context']['value'])) {
$videoFieldPath = trim($fieldOutput['value'][0]['#context']['value']);
if ($videoFieldPath) $build['#video_field']['value'] = $this->getVideoEmbedUrl($videoFieldPath);
}
break;
case "text":
if (isset($fieldOutput['value'][0]['#text'])) {
$videoFieldPath = trim($fieldOutput['value'][0]['#text']);
if ($videoFieldPath) $build['#video_field']['value'] = $this->getVideoEmbedUrl($videoFieldPath);
}
break;
case "link":
if (isset($fieldOutput['value'][0]['#url'])) {
$videoFieldPath = $fieldOutput['value'][0]['#url']->getUri();
$build['#video_field']['value'] = $this->getVideoEmbedUrl($videoFieldPath);
}
break;
case "file":
$filePath = $fieldOutput['value'][0]['#file'];
if ($filePath) {
$videoFieldUri = $filePath->getFileUri();
$videoFieldPath = \Drupal::service('file_url_generator')->generateAbsoluteString($videoFieldUri);
$build['#video_field']['value'] = $videoFieldPath;
}
break;
case "video_embed_field":
break;
}
}
}
}
$build['#video_radio_options'] = $this->configuration['video_component_fields']['video_radio_options'];
$build['#video_url'] = $this->getVideoEmbedUrl($this->configuration['video_component_fields']['video_url']);
return $build;
}
/**
* Get fields from content type.
*
* @param string $contentType
* The Content Type.
*
* @return array
* Return an array of fields.
*/
public function getContentTypeFields($contentType) {
$fields = [];
if (!empty($contentType)) {
$fields = array_filter(
$this->entityFieldManager->getFieldDefinitions('node', $contentType), function ($fieldDefinition) {
return $fieldDefinition instanceof FieldConfigInterface;
}
);
}
return $fields;
}
/**
* Get videos embed array.
*
* @return array
* The video array.
*/
public function getVideosEmbedArray() {
$allFields = [];
// Get the Current Route Match.
$currentRoute = $this->currentRouteMatch;
if ($currentRoute instanceof CurrentRouteMatch) {
$sectionStorage = $currentRoute->getParameters()->get('section_storage');
// For content types without bundles.
if ($sectionStorage instanceof DefaultsSectionStorage) {
$availableContexts = $sectionStorage->getContexts();
$contextDisplay = $availableContexts['display'];
if ($contextDisplay instanceof EntityContext) {
$contextData = $contextDisplay->getContextData();
if ($contextData instanceof ConfigEntityAdapter) {
$contentInfo = $contextData->getEntity();
if ($contentInfo instanceof LayoutBuilderEntityViewDisplay) {
// Bundle 'page'.
$bundle = $contentInfo->getTargetBundle();
// Content Type 'node'.
$entityTypeId = $contentInfo->getTargetEntityTypeId();
$definitions = $this->entityFieldManager->getFieldDefinitions($entityTypeId, $bundle);
foreach ($definitions as $fieldName => $fieldDefinition) {
if (!empty($fieldDefinition->getTargetBundle()) && $fieldName !== 'layout_builder__layout') {
switch ($fieldDefinition->getType()) {
case "string":
case "string_long":
case "text":
case "link":
case "file":
case "video_embed_field":
$allFields[$bundle][$fieldName] = $fieldDefinition->getLabel();
break;
}
}
}
}
}
}
}
else {
// For bundles (Layout Builder overrides).
if ($sectionStorage instanceof OverridesSectionStorage) {
$context = $sectionStorage->getContext('entity');
if ($context instanceof EntityContext) {
$contextData = $context->getContextData();
if ($contextData instanceof EntityAdapter) {
$entity = $contextData->getEntity();
$entity_type = 'taxonomy_term';
if ($entity instanceof Node) $entity_type = 'node';
$bundle = $entity->bundle();
$definitions = $this->entityFieldManager->getFieldDefinitions($entity_type, $bundle);
foreach ($definitions as $fieldName => $fieldDefinition) {
if (!empty($fieldDefinition->getTargetBundle()) && $fieldName !== 'layout_builder__layout') {
switch ($fieldDefinition->getType()) {
case "string":
case "string_long":
case "text":
case "link":
case "file":
case "video_embed_field":
$allFields[$bundle][$fieldName] = $fieldDefinition->getLabel();
break;
}
}
}
}
}
}
else {
// Get fields for all bundles(Block Layout).
$entityType = "node";
$contentTypes = $this->entityTypeBundleInfo->getBundleInfo($entityType);
foreach ($contentTypes as $key => $value) {
$bundle = $key;
$definitions = $this->entityFieldManager->getFieldDefinitions($entityType, $bundle);
foreach ($definitions as $fieldName => $fieldDefinition) {
if (!empty($fieldDefinition->getTargetBundle())) {
switch ($fieldDefinition->getType()) {
case "string":
case "string_long":
case "text":
case "link":
case "file":
case "video_embed_field":
$allFields[$value['label']][$bundle . '_' . $fieldName] = $fieldDefinition->getLabel();
break;
}
}
}
}
}
}
}
return $allFields;
}
/**
* Get video embed URL.
*
* @param string $videoUrl
* The Video URL.
*
* @return string
* The URL.
*/
public function getVideoEmbedUrl($videoUrl) {
$finalVideoUrl = '';
if (strpos($videoUrl, 'vimeo.com/') !== FALSE) {
// It is Vimeo video.
$videoId = explode("vimeo.com/", $videoUrl)[1];
if (strpos($videoId, '&') !== FALSE) {
$videoId = explode("&", $videoId)[0];
}
$finalVideoUrl .= 'https://player.vimeo.com/video/' . $videoId;
}
elseif (strpos($videoUrl, 'youtube.com/watch') !== FALSE) {
// It is Youtube video.
$videoId = explode("v=", $videoUrl)[1];
if (strpos($videoId, '&') !== FALSE) {
$videoId = explode("&", $videoId)[0];
}
$finalVideoUrl .= 'https://www.youtube.com/embed/' . $videoId;
}
elseif (strpos($videoUrl, 'youtu.be/') !== FALSE) {
// It is Youtube video.
$videoId = explode("youtu.be/", $videoUrl)[1];
if (strpos($videoId, '&') !== FALSE) {
$videoId = explode("&", $videoId)[0];
}
$finalVideoUrl .= 'https://www.youtube.com/embed/' . $videoId;
}
elseif (strpos($videoUrl, 'youtube.com/embed') !== FALSE) {
// It is a valid Youtube embed video.
$finalVideoUrl .= $videoUrl;
}
return $finalVideoUrl;
}
/**
* Get video field type.
*
* @param string $fieldName
* The field machine name value.
*
* @return string
* The video field type.
*/
public function getVideoFieldType($fieldName, $entityType) {
$fieldType = '';
if (isset($fieldName) && !empty($fieldName)) {
$fieldConfig = FieldStorageConfig::loadByName($entityType, $fieldName);
$fieldType = $fieldConfig->getType();
}
return $fieldType;
}
public function getEntityType() {
$entityType = '';
$currentRoute = $this->currentRouteMatch;
if ($currentRoute instanceof CurrentRouteMatch) {
$sectionStorage = $currentRoute->getParameters()->get('section_storage');
// For content types without bundles.
if ($sectionStorage instanceof DefaultsSectionStorage) {
$availableContexts = $sectionStorage->getContexts();
$contextDisplay = $availableContexts['display'];
if ($contextDisplay instanceof EntityContext) {
$contextData = $contextDisplay->getContextData();
if ($contextData instanceof ConfigEntityAdapter) {
$contentInfo = $contextData->getEntity();
if ($contentInfo instanceof LayoutBuilderEntityViewDisplay) {
// Bundle 'page'.
$entityType = $contentInfo->getTargetEntityTypeId();
}
}
}
}
else {
// For bundles (Layout Builder overrides).
if ($sectionStorage instanceof OverridesSectionStorage) {
$context = $sectionStorage->getContext('entity');
if ($context instanceof EntityContext) {
$contextData = $context->getContextData();
if ($contextData instanceof EntityAdapter) {
$entity = $contextData->getEntity();
if ($entity instanceof Node) {
$entityType = $entity->getEntityTypeId();
}
else {
if ($entity instanceof Term) {
$entityType = $entity->getEntityTypeId();
}
}
}
}
}
else {
// Content page is built.
if ($currentRoute->getParameters()->get('node')) {
$entityType = $currentRoute->getParameters()->get('node')->getEntityTypeId();
}
else if($currentRoute->getParameters()->get('taxonomy_term')) {
$entityType = $currentRoute->getParameters()->get('taxonomy_term')->getEntityTypeId();
}
}
}
}
return $entityType;
}
public function getBundleField($fieldName, $entityType) {
$machineName = '';
// Get fields for all bundles.
$contentTypes = $this->entityTypeBundleInfo->getBundleInfo($entityType);
// TODO: Refactor this for all contexts.
foreach ($contentTypes as $key => $value) {
if (strpos($fieldName, $key . '_') !== FALSE) {
$machineName = str_replace($key . '_', '', $fieldName);
}
}
if ($machineName === '')
$machineName = $fieldName;
return $machineName;
}
}
