Completed
Pull Request — 8.x-1.x (#129)
by Samuel
03:23
created

EntityBrowser::buildOptionsForm()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
rs 9.4286
cc 2
eloc 9
nc 2
nop 2
1
<?php
2
3
/**
4
 * @file
5
 * Definition of Drupal\entity_browser\Plugin\views\display\EntityBrowser.
6
 */
7
8
namespace Drupal\entity_browser\Plugin\views\display;
9
10
use Drupal\Core\Form\FormStateInterface;
11
use Drupal\views\Plugin\views\display\DisplayPluginBase;
12
13
/**
14
 * The plugin that handles entity browser display.
15
 *
16
 * @ingroup views_display_plugins
17
 *
18
 * @ViewsDisplay(
19
 *   id = "entity_browser",
20
 *   title = @Translation("Entity browser"),
21
 *   help = @Translation("Displays a view as Entity browser widget."),
22
 *   theme = "views_view",
23
 *   admin = @Translation("Entity browser")
24
 * )
25
 */
26
class EntityBrowser extends DisplayPluginBase {
27
28
  /**
29
   * {@inheritdoc}.
30
   */
31
  public function execute() {
32
    parent::execute();
33
    $render = ['view' => $this->view->render()];
34
    $this->handleForm($render);
35
    return $render;
36
  }
37
38
  /**
39
   * {@inheritdoc}
40
   */
41
  public function ajaxEnabled() {
42
    // Force AJAX as this Display Plugin will almost always be embedded inside
43
    // EntityBrowserForm, which breaks normal exposed form submits.
44
    return TRUE;
45
  }
46
47
  /**
48
   * {@inheritdoc}
49
   */
50
  protected function defineOptions() {
51
    $options = parent::defineOptions();
52
    $options['use_ajax']['default'] = TRUE;
53
    return $options;
54
  }
55
56
  /**
57
   * {@inheritdoc}
58
   */
59
  public function optionsSummary(&$categories, &$options) {
60
    parent::optionsSummary($categories, $options);
61
    if (isset($options['use_ajax'])) {
62
      $options['use_ajax']['value'] = $this->t('Yes (Forced)');
63
    }
64
  }
65
66
  /**
67
   * {@inheritdoc}
68
   */
69
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
70
    parent::buildOptionsForm($form, $form_state);
71
    // Disable the ability to toggle AJAX support, as we forcibly enable AJAX
72
    // in our ajaxEnabled() implementation.
73
    if (isset($form['use_ajax'])) {
74
      $form['use_ajax'] = [
75
        '#description' => $this->t('Entity Browser requires Views to use AJAX.'),
76
        '#type' => 'checkbox',
77
        '#title' => $this->t('Use AJAX'),
78
        '#default_value' => 1,
79
        '#disabled' => TRUE,
80
      ];
81
    }
82
  }
83
84
  /**
85
   * {@inheritdoc}.
86
   */
87
  function preview() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
88
    return $this->execute();
89
  }
90
91
  /**
92
   * Pre render callback for a view. Based on DisplayPluginBase::elementPreRender()
93
   * except that we removed form part which need to handle by our own.
94
   */
95
  public function elementPreRender(array $element) {
96
    $view = $element['#view'];
97
    $empty = empty($view->result);
98
99
    // Force a render array so CSS/JS can be attached.
100
    if (!is_array($element['#rows'])) {
101
      $element['#rows'] = ['#markup' => $element['#rows']];
102
    }
103
104
    $element['#header'] = $view->display_handler->renderArea('header', $empty);
105
    $element['#footer'] = $view->display_handler->renderArea('footer', $empty);
106
    $element['#empty'] = $empty ? $view->display_handler->renderArea('empty', $empty) : [];
107
    $element['#exposed'] = !empty($view->exposed_widgets) ? $view->exposed_widgets : [];
108
    $element['#more'] = $view->display_handler->renderMoreLink();
109
    $element['#feed_icons'] = !empty($view->feedIcons) ? $view->feedIcons : [];
110
111
    if ($view->display_handler->renderPager()) {
112
      $exposed_input = isset($view->exposed_raw_input) ? $view->exposed_raw_input : NULL;
113
      $element['#pager'] = $view->renderPager($exposed_input);
114
    }
115
116
    if (!empty($view->attachment_before)) {
117
      $element['#attachment_before'] = $view->attachment_before;
118
    }
119
    if (!empty($view->attachment_after)) {
120
      $element['#attachment_after'] = $view->attachment_after;
121
    }
122
123
    return $element;
124
  }
125
126
  /**
127
   * Handles form elements on a view.
128
   */
129
  protected function handleForm(&$render) {
130
    if (!empty($this->view->field['entity_browser_select'])) {
131
      $this->view->field['entity_browser_select']->viewsForm($render);
132
133
      $render['#post_render'][] = [get_class($this), 'postRender'];
134
      $substitutions = [];
135
      foreach ($this->view->result as $row_id => $row) {
136
        $form_element_row_id = $row_id;
137
138
        $substitutions[] = [
139
          'placeholder' => '<!--form-item-entity_browser_select--' . $form_element_row_id . '-->',
140
          'field_name' => 'entity_browser_select',
141
          'row_id' => $form_element_row_id,
142
        ];
143
      }
144
145
      $render['#substitutions'] = [
146
        '#type' => 'value',
147
        '#value' => $substitutions,
148
      ];
149
    }
150
  }
151
152
  /**
153
   * Post render callback that moves form elements into the view.
154
   *
155
   * Form elements need to be added out of view to be correctly detected by Form
156
   * API and then added into the view afterwards. Views use the same approach for
157
   * bulk operations.
158
   */
159
  public static function postRender($content, $element) {
160
    // Placeholders and their substitutions (usually rendered form elements).
161
    $search = $replace = [];
162
163
    // Add in substitutions provided by the form.
164
    foreach ($element['#substitutions']['#value'] as $substitution) {
165
      $field_name = $substitution['field_name'];
166
      $row_id = $substitution['row_id'];
167
168
      $search[] = $substitution['placeholder'];
169
      $replace[] = isset($element[$field_name][$row_id]) ? drupal_render($element[$field_name][$row_id]) : '';
170
    }
171
    // Add in substitutions from hook_views_form_substitutions().
172
    $substitutions = \Drupal::moduleHandler()->invokeAll('views_form_substitutions');
173
    foreach ($substitutions as $placeholder => $substitution) {
174
      $search[] = $placeholder;
175
      $replace[] = $substitution;
176
    }
177
178
    // We cannot render exposed form within the View, as nested forms are not
179
    // standard and will break entity selection.
180
    $search[] = '<form';
181
    $replace[] = '<div';
182
    $search[] = '</form>';
183
    $replace[] = '</div>';
184
185
    $content = str_replace($search, $replace, $content);
186
187
    return $content;
188
  }
189
}
190