View source
<?php
namespace Drupal\social_content_block;
use Drupal\block_content\BlockContentInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
class ContentBuilder implements ContentBuilderInterface {
use StringTranslationTrait;
protected $entityTypeManager;
protected $moduleHandler;
protected $connection;
protected $contentBlockManager;
public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $connection, ModuleHandlerInterface $module_handler, TranslationInterface $string_translation, ContentBlockManagerInterface $content_block_manager) {
$this->entityTypeManager = $entity_type_manager;
$this->connection = $connection;
$this->moduleHandler = $module_handler;
$this
->setStringTranslation($string_translation);
$this->contentBlockManager = $content_block_manager;
}
protected function getEntities(BlockContentInterface $block_content) {
$plugin_id = $block_content->field_plugin_id->value;
$definition = $this->contentBlockManager
->getDefinition($plugin_id);
if ($block_content->field_plugin_field
->isEmpty()) {
$field_names = array_filter($definition['fields'], static function ($field_name) use ($block_content) {
return $block_content
->hasField($field_name);
});
}
else {
$field_names = [
$block_content->field_plugin_field->value,
];
}
$fields = [];
foreach ($field_names as $field_name) {
$field = $block_content
->get($field_name);
if ($field instanceof EntityReferenceFieldItemListInterface && !$field
->isEmpty()) {
$fields[$field_name] = array_map(function ($item) {
return $item['target_id'];
}, $field
->getValue());
}
elseif (!$field
->isEmpty()) {
$fields[$field_name] = $field
->getValue();
}
}
$plugin = $this->contentBlockManager
->createInstance($plugin_id);
$entity_type = $this->entityTypeManager
->getDefinition($definition['entityTypeId']);
$query = $this->connection
->select($entity_type
->getDataTable(), 'base_table')
->fields('base_table', [
$entity_type
->getKey('id'),
]);
if (isset($definition['bundle'])) {
$query
->condition('base_table.' . $entity_type
->getKey('bundle'), $definition['bundle']);
}
if ($fields) {
$plugin
->query($query, $fields);
}
$this->moduleHandler
->alter('social_content_block_query', $query, $block_content);
$this
->sortBy($query, $entity_type, $block_content->field_sorting->value);
$query
->range(0, $block_content->field_item_amount->value);
$entities = $query
->execute()
->fetchAllKeyed(0, 0);
if ($entities) {
$entities = $this->entityTypeManager
->getStorage($definition['entityTypeId'])
->loadMultiple($entities);
return $this->entityTypeManager
->getViewBuilder($definition['entityTypeId'])
->viewMultiple($entities, 'small_teaser');
}
return [
'#markup' => '<div class="card__block">' . $this
->t('No matching content found') . '</div>',
];
}
protected function getLink(BlockContentInterface $block_content) : array {
$field = $block_content->field_link;
if (!$field
->isEmpty()) {
$url = Url::fromUri($field->uri);
$attributes = [
'class' => [
'btn',
'btn-flat',
],
];
$url
->setOption('attributes', $attributes);
return Link::fromTextAndUrl($field->title, $url)
->toRenderable();
}
return [];
}
public function build($entity_id, $entity_type_id, $entity_bundle) : array {
if ($entity_type_id !== 'block_content' || $entity_bundle !== 'custom_content_list') {
return [];
}
$block_content = $this->entityTypeManager
->getStorage('block_content')
->load($entity_id);
if (!$block_content instanceof BlockContentInterface || $block_content
->bundle() !== $entity_bundle) {
return [];
}
$build['content'] = [];
$build['content']['entities'] = $this
->getEntities($block_content);
if (!isset($build['content']['entities']['#markup'])) {
$build['content']['entities']['#prefix'] = '<div class="content-list__items">';
$build['content']['entities']['#suffix'] = '</div>';
}
$link = $this
->getLink($block_content);
if (!empty($link)) {
$build['content']['link'] = [
'#type' => 'inline_template',
'#template' => '<footer class="card__actionbar">{{link}}</footer>',
'#context' => [
'link' => $link,
],
];
}
return $build;
}
public static function processBlockForm(array $element, FormStateInterface $form_state) {
$content_block_manager = \Drupal::service('plugin.manager.content_block');
$selector = $content_block_manager
->getSelector('field_plugin_id', 'value');
foreach ($content_block_manager
->getDefinitions() as $plugin_id => $plugin_definition) {
$fields =& $element['field_plugin_field']['widget'][0][$plugin_id]['#options'];
foreach ($fields as $field_name => $field_title) {
if ($field_name === $field_title) {
if (isset($element[$field_name]['widget']['target_id'])) {
$fields[$field_name] = $element[$field_name]['widget']['target_id']['#title'];
}
else {
$fields[$field_name] = $element[$field_name]['widget']['#title'];
}
$element[$field_name]['#states'] = [
'visible' => [
$selector => [
'value' => $plugin_id,
],
$content_block_manager
->getSelector('field_plugin_field', $plugin_id) => [
[
'value' => 'all',
],
[
'value' => $field_name,
],
],
],
];
}
}
}
$element['field_plugin_id']['widget'][0]['value']['#ajax'] = [
'callback' => [
self::class,
'updateFormSortingOptions',
],
'wrapper' => 'social-content-block-sorting-options',
];
$parents = array_merge($element['field_plugin_id']['widget']['#field_parents'], [
'field_plugin_id',
]);
$value_parents = array_merge($parents, [
'0',
'value',
]);
$selected_plugin = $form_state
->getValue($value_parents);
if ($selected_plugin === NULL) {
$input = $form_state
->getUserInput();
$field = $element['field_plugin_id']['widget'][0]['value'];
if (NestedArray::keyExists($input, $value_parents)) {
$input_value = NestedArray::getValue($input, $value_parents);
if (!empty($input_value) && isset($field['#options'][$input_value])) {
$selected_plugin = $input_value;
}
}
if (empty($selected_plugin)) {
$selected_plugin = $field['#default_value'];
}
}
$element['field_sorting']['widget']['#options'] = $content_block_manager
->createInstance($selected_plugin)
->supportedSortOptions();
$element['field_sorting']['#prefix'] = '<div id="social-content-block-sorting-options">';
$element['field_sorting']['#suffix'] = '</div>';
return $element;
}
public function updateFormSortingOptions($form, FormStateInterface $form_state) {
$parents = [
'field_sorting',
];
if ($form_state
->has('layout_builder__component')) {
$parents = array_merge([
'settings',
'block_form',
], $parents);
}
$value_parents = array_merge($parents, [
'0',
'value',
]);
$sort_value = $form_state
->getValue($value_parents);
$options = NestedArray::getValue($form, array_merge($parents, [
'widget',
'#options',
]));
if ($sort_value === NULL || !isset($options[$sort_value])) {
$form_state
->clearErrors();
$form_state
->setValue($value_parents, key($options));
}
return NestedArray::getValue($form, $parents);
}
protected function sortBy(SelectInterface $query, EntityTypeInterface $entity_type, string $sort_by) : void {
$popularity_time_start = strtotime('-90 days');
$entity_type_id = $entity_type
->id();
$entity_id_key = $entity_type
->getKey('id');
switch ($sort_by) {
case 'most_commented':
if ($entity_type_id === 'group') {
$query
->leftJoin('post__field_recipient_group', 'pfrg', "base_table.{$entity_id_key} = pfrg.field_recipient_group_target_id");
$query
->leftJoin('group_content_field_data', 'gfd', "base_table.{$entity_id_key} = gfd.gid AND gfd.type LIKE '%-group_node-%'");
$query
->leftJoin('comment_field_data', 'cfd', "(base_table.{$entity_id_key} = cfd.entity_id AND cfd.entity_type=:entity_type) OR (pfrg.entity_id = cfd.entity_id AND cfd.entity_type='post') OR (gfd.entity_id = cfd.entity_id AND cfd.entity_type='node')", [
'entity_type' => $entity_type_id,
]);
}
else {
$query
->leftJoin('comment_field_data', 'cfd', "base_table.{$entity_id_key} = cfd.entity_id AND cfd.entity_type=:entity_type", [
'entity_type' => $entity_type_id,
]);
}
$query
->addExpression('COUNT(cfd.cid)', 'comment_count');
$query
->condition('cfd.status', 1, '=')
->condition('cfd.created', $popularity_time_start, '>')
->groupBy("base_table.{$entity_id_key}")
->orderBy('comment_count', 'DESC');
break;
case 'most_liked':
if ($entity_type_id === 'group') {
$query
->leftJoin('post__field_recipient_group', 'pfrg', "base_table.{$entity_id_key} = pfrg.field_recipient_group_target_id");
$query
->leftJoin('group_content_field_data', 'gfd', "base_table.{$entity_id_key} = gfd.gid AND gfd.type LIKE '%-group_node-%'");
$query
->leftJoin('votingapi_vote', 'vv', "(base_table.{$entity_id_key} = vv.entity_id AND vv.entity_type=:entity_type) OR (pfrg.entity_id = vv.entity_id AND vv.entity_type = 'post') OR (gfd.entity_id = vv.entity_id AND vv.entity_type = 'node')", [
'entity_type' => $entity_type_id,
]);
}
else {
$query
->leftJoin('votingapi_vote', 'vv', "base_table.{$entity_id_key} = vv.entity_id AND vv.entity_type=:entity_type", [
'entity_type' => $entity_type_id,
]);
}
$query
->addExpression('COUNT(vv.id)', 'vote_count');
$query
->condition('vv.type', 'like')
->condition('vv.timestamp', $popularity_time_start, '>')
->groupBy("base_table.{$entity_id_key}")
->orderBy('vote_count', 'DESC');
break;
case 'last_interacted':
if ($entity_type_id === 'group') {
$query
->leftJoin('group_content_field_data', 'gfd', "base_table.{$entity_id_key} = gfd.gid");
$query
->leftjoin('post__field_recipient_group', 'pst', "base_table.{$entity_id_key} = pst.field_recipient_group_target_id");
$query
->leftjoin('post_field_data', 'pfd', 'pst.entity_id = pfd.id');
$query
->leftjoin('comment_field_data', 'cfd', "pfd.id = cfd.entity_id AND cfd.entity_type = 'post'");
$query
->leftJoin('votingapi_vote', 'vv', "pfd.id = vv.entity_id AND vv.entity_type = 'post'");
$query
->leftjoin('node_field_data', 'nfd', 'gfd.entity_id = nfd.nid');
$query
->addExpression('GREATEST(COALESCE(MAX(gfd.changed), 0),
COALESCE(MAX(vv.timestamp), 0),
COALESCE(MAX(cfd.changed), 0),
COALESCE(MAX(nfd.changed), 0),
COALESCE(MAX(pfd.changed), 0))', 'newest_timestamp');
$query
->groupBy("base_table.{$entity_id_key}");
$query
->orderBy('newest_timestamp', 'DESC');
}
elseif ($entity_type_id === 'node') {
$query
->leftJoin('node_field_data', 'nfd', "base_table.{$entity_id_key} = nfd.nid");
$query
->leftjoin('comment_field_data', 'cfd', 'nfd.nid = cfd.entity_id');
$query
->leftjoin('votingapi_vote', 'vv', '(nfd.nid = vv.entity_id AND vv.entity_type = :entity_type_id) OR (cfd.cid = vv.entity_id)', [
'entity_type_id' => $entity_type_id,
]);
$query
->addExpression('GREATEST(COALESCE(MAX(vv.timestamp), 0),
COALESCE(MAX(cfd.changed), 0),
COALESCE(MAX(nfd.changed), 0))', 'newest_timestamp');
$query
->groupBy("base_table.{$entity_id_key}");
$query
->orderBy('newest_timestamp', 'DESC');
}
break;
case 'event_date':
$nfed_alias = $query
->leftJoin('node__field_event_date', 'nfed', "base_table.{$entity_id_key} = %alias.entity_id");
$query
->orderBy("{$nfed_alias}.field_event_date_value", 'ASC');
break;
default:
$query
->orderBy("base_table.{$sort_by}", 'DESC');
}
}
}