Created
December 12, 2019 23:43
-
-
Save hussainweb/960b43f7b32ba54942ffcb85ca453996 to your computer and use it in GitHub Desktop.
/web/modules/custom/axl_ks_topics/src/Plugin/EntityReferenceSelection/TopicsSelection.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Drupal\axl_ks_topics\Plugin\EntityReferenceSelection; | |
use Drupal\Component\Utility\Html; | |
use Drupal\Core\Database\Connection; | |
use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginBase; | |
use Drupal\Core\Entity\EntityTypeManagerInterface; | |
use Drupal\Core\Entity\Query\QueryInterface; | |
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; | |
use Symfony\Component\DependencyInjection\ContainerInterface; | |
/** | |
* Provides an entity reference selection for topics. | |
* | |
* @EntityReferenceSelection( | |
* id = "axl_ks_topics", | |
* label = @Translation("Unscheduled topics for an event"), | |
* entity_types = {"node"}, | |
* group = "axl_ks_topics", | |
* weight = 0 | |
* ) | |
*/ | |
class TopicsSelection extends SelectionPluginBase implements ContainerFactoryPluginInterface { | |
/** | |
* The entity type manager. | |
* | |
* @var \Drupal\Core\Entity\EntityTypeManagerInterface | |
*/ | |
protected $entityTypeManager; | |
/** | |
* Active database connection. | |
* | |
* @var \Drupal\Core\Database\Connection | |
*/ | |
protected $database; | |
/** | |
* Constructs a new selection object. | |
* | |
* @param array $configuration | |
* A configuration array containing information about the plugin instance. | |
* @param string $plugin_id | |
* The plugin_id for the plugin instance. | |
* @param mixed $plugin_definition | |
* The plugin implementation definition. | |
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager | |
* The entity manager service. | |
* @param \Drupal\Core\Database\Connection $database | |
* The database connection to be used. | |
*/ | |
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entityTypeManager, Connection $database) { | |
parent::__construct($configuration, $plugin_id, $plugin_definition); | |
$this->entityTypeManager = $entityTypeManager; | |
$this->database = $database; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { | |
return new static( | |
$configuration, | |
$plugin_id, | |
$plugin_definition, | |
$container->get('entity_type.manager'), | |
$container->get('database') | |
); | |
} | |
/** | |
* Builds an EntityQuery to get referenceable topic entities. | |
* | |
* @param string|null $match | |
* Text to match the label against. | |
* @param string $match_operator | |
* The operation the matching should be done with. | |
* @param int $eventId | |
* The current enitity id. | |
* | |
* @return \Drupal\Core\Entity\Query\QueryInterface | |
* The query object that can query the given entity type. | |
*/ | |
protected function buildEntityQueryForTopics($match = NULL, $match_operator = 'CONTAINS', int $eventId = 0): QueryInterface { | |
$query = $this->entityTypeManager->getStorage('node')->getQuery(); | |
$query->condition('type', 'topic'); | |
$topics = $this->getReferenceableTopics($eventId); | |
if (!$topics) { | |
// If there are no topics, force the query to return an empty result. | |
$query->condition('nid', NULL, '='); | |
return $query; | |
} | |
$query->condition('nid', $topics, 'IN'); | |
if (isset($match)) { | |
$query->condition('title', $match, $match_operator); | |
} | |
// Add entity-access tag. | |
$query->addTag('node_access'); | |
// Add the Selection handler for system_query_entity_reference_alter(). | |
$query->addTag('entity_reference'); | |
$query->addMetaData('entity_reference_selection_handler', $this); | |
return $query; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) { | |
$query = $this->buildEntityQueryForTopics($match, $match_operator, $this->getParentEntityId()); | |
if ($limit > 0) { | |
$query->range(0, $limit); | |
} | |
$result = $query->execute(); | |
if (empty($result)) { | |
return []; | |
} | |
$options = []; | |
$entities = $this->entityTypeManager->getStorage('node')->loadMultiple($result); | |
$termStorage = $this->entityTypeManager->getStorage('taxonomy_term'); | |
$userStorage = $this->entityTypeManager->getStorage('user'); | |
foreach ($entities as $entity_id => $entity) { | |
$topic_type = $termStorage->load($entity->get('field_topic_type')->target_id); | |
$presenter = $userStorage->load($entity->get('field_topic_presenters')->target_id); | |
$duration = $entity->get('field_topic_duration')->value; | |
$options['topic'][$entity_id] = Html::escape(sprintf("%s - %s (%d mins, %s)", $entity->label(), $presenter->label(), $duration, $topic_type->label())); | |
} | |
return $options; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') { | |
$query = $this->buildEntityQueryForTopics($match, $match_operator, $this->getParentEntityId()); | |
return $query | |
->count() | |
->execute(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validateReferenceableEntities(array $ids) { | |
$result = []; | |
if ($ids) { | |
$query = $this->buildEntityQueryForTopics(NULL, NULL, $this->getParentEntityId()); | |
$result = $query | |
->condition('nid', $ids, 'IN') | |
->execute(); | |
} | |
return $result; | |
} | |
/** | |
* Gets the list of topic referenceable entities. | |
* | |
* @param int $eventId | |
* The event ID for which topics are allowed to be referenced. | |
* | |
* @return mixed | |
* The query result. | |
*/ | |
protected function getReferenceableTopics(int $eventId) { | |
// @todo: Convert this to a dynamic query. | |
$eventTypeTid = $this->getEventTypeTermId(); | |
if ($eventTypeTid) { | |
$eventTypeSql = " AND topic_type.field_topic_type_target_id = '$eventTypeTid' "; | |
} | |
$sql = <<<SQL | |
SELECT topic.nid FROM {node_field_data} topic | |
LEFT JOIN {node__field_topic_type} topic_type ON topic_type.entity_id = topic.nid | |
LEFT JOIN {node__field_event_topics} event_topic ON event_topic.field_event_topics_target_id = topic.nid | |
WHERE topic.type = 'topic' | |
$eventTypeSql | |
AND (event_topic.field_event_topics_target_id IS NULL OR event_topic.entity_id = :event_id) | |
SQL; | |
$result = $this->database->query($sql, [':event_id' => $eventId]); | |
$nids = $result->fetchCol(); | |
return $nids; | |
} | |
/** | |
* Get the entity ID of the node with the ER plugin. | |
* | |
* @return int | |
* Entity ID of the parent or 0 if there is no stored entity yet. | |
*/ | |
protected function getParentEntityId(): int { | |
$config = $this->getConfiguration(); | |
/** @var \Drupal\Core\Entity\EntityInterface $entity */ | |
$entity = $config['entity']; | |
return $entity ? (int) $entity->id() : 0; | |
} | |
/** | |
* Get the term ID for the event type of the currently loaded event. | |
* | |
* @return int|null | |
* Event type term-id of the current entity. | |
*/ | |
protected function getEventTypeTermId(): ?int { | |
$config = $this->getConfiguration(); | |
/** @var \Drupal\Core\Entity\EntityInterface $entity */ | |
$entity = $config['entity']; | |
if (!$entity) { | |
return NULL; | |
} | |
$event_topic_type = $entity->get('field_event_topic_type')->getValue(); | |
return $event_topic_type[0]['target_id'] ?? NULL; | |
} | |
} |
For Ref:
Create a custom plugin, and override default Plugin.
`<?php
namespace Drupal\my_custom\Plugin\EntityReferenceSelection;
use Drupal\node\Plugin\EntityReferenceSelection\NodeSelection;
use Drupal\node\NodeInterface;
/**
- Provides an entity reference selection for topics.
- @EntityReferenceSelection(
- id = "default:my_custom",
- label = @translation("Remove unpublished node"),
- entity_types = {"node"},
- group = "default",
- weight = 10
- )
*/
class CustomNodeSelection extends NodeSelection {
/**
- {@inheritdoc}
*/
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
$query = parent::buildEntityQuery($match, $match_operator);
$query->condition('status', NodeInterface::PUBLISHED);
return $query;
}
}
`
& then,
`/**
- Implements hook_field_widget_form_alter().
*/
function my_custom_field_widget_form_alter(&$element, FormStateInterface $form_state, $context) {
if ($context['items']->getFieldDefinition()->getType() == 'entity_reference' && $context['items']->getFieldDefinition()->getSettings()['handler'] == 'default:node') {
if ($element['target_id']['#type'] == 'entity_autocomplete') {
$element['target_id']['#selection_handler'] = 'default:my_custom';
}
}
}
`
I hope this will help someone. Please refer attached files.
Thanks
Harsh
Yes, some years later, but your article was really helpful. I have one key question:
Like you, I need context for my use case to work. I see you pull that from $context['entity'], but where does that value get set? Who puts that convenient entity into $context so you can read it?
Many thanks.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @hussainweb,
My requirement was different I had to filter out the unpublished nodes on all fields using entity reference.
Thanks, for the great Article, It was of good help.
Harsh