3 namespace Drupal\paragraphs\Plugin\EntityReferenceSelection;
5 use Drupal\Core\Entity\EntityManagerInterface;
6 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
7 use Drupal\Core\Entity\Plugin\EntityReferenceSelection\DefaultSelection;
8 use Drupal\Core\Extension\ModuleHandlerInterface;
9 use Drupal\Core\Session\AccountInterface;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\Component\Utility\NestedArray;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
16 * Default plugin implementation of the Entity Reference Selection plugin.
18 * @EntityReferenceSelection(
19 * id = "default:paragraph",
20 * label = @Translation("Paragraphs"),
22 * entity_types = {"paragraph"},
26 class ParagraphSelection extends DefaultSelection {
29 * Entity type bundle info service.
31 * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
33 public $entityTypeBundleInfo;
36 * ParagraphSelection constructor.
38 * @param array $configuration
39 * A configuration array containing information about the plugin instance.
40 * @param string $plugin_id
41 * The plugin_id for the plugin instance.
42 * @param mixed $plugin_definition
43 * The plugin implementation definition.
44 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
45 * The entity manager service.
46 * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
47 * The module handler service.
48 * @param \Drupal\Core\Session\AccountInterface $current_user
50 * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
51 * Entity type bundle info service.
53 public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityManagerInterface $entity_manager, ModuleHandlerInterface $module_handler, AccountInterface $current_user, EntityTypeBundleInfoInterface $entity_type_bundle_info) {
54 parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_manager, $module_handler, $current_user);
56 $this->entityTypeBundleInfo = $entity_type_bundle_info;
62 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
67 $container->get('entity.manager'),
68 $container->get('module_handler'),
69 $container->get('current_user'),
70 $container->get('entity_type.bundle.info')
77 public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
78 $entity_type_id = $this->configuration['target_type'];
79 $selection_handler_settings = $this->configuration['handler_settings'] ?: array();
80 $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type_id);
82 // Merge-in default values.
83 $selection_handler_settings += array(
84 'target_bundles' => array(),
86 'target_bundles_drag_drop' => array(),
89 $bundle_options = array();
90 $bundle_options_simple = array();
92 // Default weight for new items.
93 $weight = count($bundles) + 1;
95 foreach ($bundles as $bundle_name => $bundle_info) {
96 $bundle_options_simple[$bundle_name] = $bundle_info['label'];
97 $bundle_options[$bundle_name] = array(
98 'label' => $bundle_info['label'],
99 'enabled' => isset($selection_handler_settings['target_bundles_drag_drop'][$bundle_name]['enabled']) ? $selection_handler_settings['target_bundles_drag_drop'][$bundle_name]['enabled'] : FALSE,
100 'weight' => isset($selection_handler_settings['target_bundles_drag_drop'][$bundle_name]['weight']) ? $selection_handler_settings['target_bundles_drag_drop'][$bundle_name]['weight'] : $weight,
105 // Do negate the selection.
109 1 => $this->t('Exclude the selected below'),
110 0 => $this->t('Include the selected below'),
112 '#title' => $this->t('Which Paragraph types should be allowed?'),
113 '#default_value' => isset($selection_handler_settings['negate']) ? $selection_handler_settings['negate'] : 0,
116 // Kept for compatibility with other entity reference widgets.
117 $form['target_bundles'] = array(
118 '#type' => 'checkboxes',
119 '#options' => $bundle_options_simple,
120 '#default_value' => isset($selection_handler_settings['target_bundles']) ? $selection_handler_settings['target_bundles'] : array(),
124 if ($bundle_options) {
125 $form['target_bundles_drag_drop'] = [
126 '#element_validate' => [[__CLASS__, 'targetTypeValidate']],
135 '#prefix' => '<h5>' . $this->t('Paragraph types') . '</h5>',
136 '#suffix' => '<div class="description">' . $this->t('Selection of Paragraph types for this field. Select none to allow all Paragraph types.') . '</div>',
139 $form['target_bundles_drag_drop']['#tabledrag'][] = [
141 'relationship' => 'sibling',
142 'group' => 'bundle-weight',
146 uasort($bundle_options, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
148 $weight_delta = $weight;
150 // Default weight for new items.
151 $weight = count($bundles) + 1;
152 foreach ($bundle_options as $bundle_name => $bundle_info) {
153 $form['target_bundles_drag_drop'][$bundle_name] = array(
154 '#attributes' => array(
155 'class' => array('draggable'),
159 $form['target_bundles_drag_drop'][$bundle_name]['enabled'] = array(
160 '#type' => 'checkbox',
161 '#title' => $bundle_info['label'],
162 '#title_display' => 'after',
163 '#default_value' => $bundle_info['enabled'],
166 $form['target_bundles_drag_drop'][$bundle_name]['weight'] = array(
168 '#default_value' => (int) $bundle_info['weight'],
169 '#delta' => $weight_delta,
170 '#title' => $this->t('Weight for type @type', array('@type' => $bundle_info['label'])),
171 '#title_display' => 'invisible',
172 '#attributes' => array(
173 'class' => array('bundle-weight', 'bundle-weight-' . $bundle_name),
179 if (!count($bundle_options)) {
180 $form['allowed_bundles_explain'] = [
182 '#markup' => $this->t('You did not add any Paragraph types yet, click <a href=":here">here</a> to add one.', [':here' => Url::fromRoute('paragraphs.type_add')->toString()]),
190 * Validate helper to have support for other entity reference widgets.
193 * @param FormStateInterface $form_state
196 public static function targetTypeValidate($element, FormStateInterface $form_state, $form) {
197 $values = &$form_state->getValues();
198 $element_values = NestedArray::getValue($values, $element['#parents']);
199 $bundle_options = array();
201 if ($element_values) {
203 foreach ($element_values as $machine_name => $bundle_info) {
204 if (isset($bundle_info['enabled']) && $bundle_info['enabled']) {
205 $bundle_options[$machine_name] = $machine_name;
210 // All disabled = all enabled.
211 if ($enabled === 0) {
212 $bundle_options = NULL;
216 // New value parents.
217 $parents = array_merge(array_slice($element['#parents'], 0, -1), array('target_bundles'));
218 NestedArray::setValue($values, $parents, $bundle_options);
222 * Returns the sorted allowed types for the field.
225 * A list of arrays keyed by the paragraph type machine name
226 * with the following properties.
227 * - label: The label of the paragraph type.
228 * - weight: The weight of the paragraph type.
230 public function getSortedAllowedTypes() {
231 $return_bundles = [];
233 $bundles = $this->entityTypeBundleInfo->getBundleInfo('paragraph');
234 if (!empty($this->configuration['handler_settings']['target_bundles'])) {
235 if (isset($this->configuration['handler_settings']['negate']) && $this->configuration['handler_settings']['negate'] == '1') {
236 $bundles = array_diff_key($bundles, $this->configuration['handler_settings']['target_bundles']);
239 $bundles = array_intersect_key($bundles, $this->configuration['handler_settings']['target_bundles']);
243 // Support for the paragraphs reference type.
244 if (!empty($this->configuration['handler_settings']['target_bundles_drag_drop'])) {
245 $drag_drop_settings = $this->configuration['handler_settings']['target_bundles_drag_drop'];
246 $max_weight = count($bundles);
248 foreach ($drag_drop_settings as $bundle_info) {
249 if (isset($bundle_info['weight']) && $bundle_info['weight'] && $bundle_info['weight'] > $max_weight) {
250 $max_weight = $bundle_info['weight'];
254 // Default weight for new items.
255 $weight = $max_weight + 1;
256 foreach ($bundles as $machine_name => $bundle) {
257 $return_bundles[$machine_name] = [
258 'label' => $bundle['label'],
259 'weight' => isset($drag_drop_settings[$machine_name]['weight']) ? $drag_drop_settings[$machine_name]['weight'] : $weight,
267 foreach ($bundles as $machine_name => $bundle) {
268 $return_bundles[$machine_name] = [
269 'label' => $bundle['label'],
276 uasort($return_bundles, 'Drupal\Component\Utility\SortArray::sortByWeightElement');
278 return $return_bundles;
284 public function validateReferenceableNewEntities(array $entities) {
285 $bundles = array_keys($this->getSortedAllowedTypes());
286 return array_filter($entities, function ($entity) {
287 if (isset($bundles)) {
288 return in_array($entity->bundle(), $bundles);
297 protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
298 $target_type = $this->configuration['target_type'];
299 $handler_settings = $this->configuration['handler_settings'];
300 $entity_type = $this->entityManager->getDefinition($target_type);
302 $query = $this->entityManager->getStorage($target_type)->getQuery();
304 // If 'target_bundles' is NULL, all bundles are referenceable, no further
305 // conditions are needed.
306 if (isset($handler_settings['target_bundles']) && is_array($handler_settings['target_bundles'])) {
307 $target_bundles = array_keys($this->getSortedAllowedTypes());
309 // If 'target_bundles' is an empty array, no bundle is referenceable,
310 // force the query to never return anything and bail out early.
311 if ($target_bundles === []) {
312 $query->condition($entity_type->getKey('id'), NULL, '=');
316 $query->condition($entity_type->getKey('bundle'), $target_bundles, 'IN');
320 if (isset($match) && $label_key = $entity_type->getKey('label')) {
321 $query->condition($label_key, $match, $match_operator);
324 // Add entity-access tag.
325 $query->addTag($target_type . '_access');
327 // Add the Selection handler for system_query_entity_reference_alter().
328 $query->addTag('entity_reference');
329 $query->addMetaData('entity_reference_selection_handler', $this);
331 // Add the sort option.
332 if (!empty($handler_settings['sort'])) {
333 $sort_settings = $handler_settings['sort'];
334 if ($sort_settings['field'] != '_none') {
335 $query->sort($sort_settings['field'], $sort_settings['direction']);