Completed
Push — 8.x-1.x ( b1a253...362da1 )
by Janez
03:13
created

EntityBrowser::preview()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
 * "entity_browser_display" is a custom property, used with
17
 * \Drupal\views\Views::getApplicableViews() to retrieve all views with a
18
 * 'Entity Browser' display.
19
 *
20
 * @ingroup views_display_plugins
21
 *
22
 * @ViewsDisplay(
23
 *   id = "entity_browser",
24
 *   title = @Translation("Entity browser"),
25
 *   help = @Translation("Displays a view as Entity browser widget."),
26
 *   theme = "views_view",
27
 *   admin = @Translation("Entity browser"),
28
 *   entity_browser_display = TRUE
29
 * )
30
 */
31
class EntityBrowser extends DisplayPluginBase {
32
33
  /**
34
   * {@inheritdoc}.
35
   */
36
  public function execute() {
37
    parent::execute();
38
    $render = ['view' => $this->view->render()];
39
    $this->handleForm($render);
40
    return $render;
41
  }
42
43
  /**
44
   * {@inheritdoc}
45
   */
46
  public function ajaxEnabled() {
47
    // Force AJAX as this Display Plugin will almost always be embedded inside
48
    // EntityBrowserForm, which breaks normal exposed form submits.
49
    return TRUE;
50
  }
51
52
  /**
53
   * {@inheritdoc}
54
   */
55
  protected function defineOptions() {
56
    $options = parent::defineOptions();
57
    $options['use_ajax']['default'] = TRUE;
58
    return $options;
59
  }
60
61
  /**
62
   * {@inheritdoc}
63
   */
64
  public function optionsSummary(&$categories, &$options) {
65
    parent::optionsSummary($categories, $options);
66
    if (isset($options['use_ajax'])) {
67
      $options['use_ajax']['value'] = $this->t('Yes (Forced)');
68
    }
69
  }
70
71
  /**
72
   * {@inheritdoc}
73
   */
74
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
75
    parent::buildOptionsForm($form, $form_state);
76
    // Disable the ability to toggle AJAX support, as we forcibly enable AJAX
77
    // in our ajaxEnabled() implementation.
78
    if (isset($form['use_ajax'])) {
79
      $form['use_ajax'] = [
80
        '#description' => $this->t('Entity Browser requires Views to use AJAX.'),
81
        '#type' => 'checkbox',
82
        '#title' => $this->t('Use AJAX'),
83
        '#default_value' => 1,
84
        '#disabled' => TRUE,
85
      ];
86
    }
87
  }
88
89
  /**
90
   * {@inheritdoc}.
91
   */
92
  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...
93
    return $this->execute();
94
  }
95
96
  /**
97
   * Pre render callback for a view. Based on DisplayPluginBase::elementPreRender()
98
   * except that we removed form part which need to handle by our own.
99
   */
100
  public function elementPreRender(array $element) {
101
    $view = $element['#view'];
102
    $empty = empty($view->result);
103
104
    // Force a render array so CSS/JS can be attached.
105
    if (!is_array($element['#rows'])) {
106
      $element['#rows'] = ['#markup' => $element['#rows']];
107
    }
108
109
    $element['#header'] = $view->display_handler->renderArea('header', $empty);
110
    $element['#footer'] = $view->display_handler->renderArea('footer', $empty);
111
    $element['#empty'] = $empty ? $view->display_handler->renderArea('empty', $empty) : [];
112
    $element['#exposed'] = !empty($view->exposed_widgets) ? $view->exposed_widgets : [];
113
    $element['#more'] = $view->display_handler->renderMoreLink();
114
    $element['#feed_icons'] = !empty($view->feedIcons) ? $view->feedIcons : [];
115
116
    if ($view->display_handler->renderPager()) {
117
      $exposed_input = isset($view->exposed_raw_input) ? $view->exposed_raw_input : NULL;
118
      $element['#pager'] = $view->renderPager($exposed_input);
119
    }
120
121
    if (!empty($view->attachment_before)) {
122
      $element['#attachment_before'] = $view->attachment_before;
123
    }
124
    if (!empty($view->attachment_after)) {
125
      $element['#attachment_after'] = $view->attachment_after;
126
    }
127
128
    return $element;
129
  }
130
131
  /**
132
   * Handles form elements on a view.
133
   */
134
  protected function handleForm(&$render) {
135
    if (!empty($this->view->field['entity_browser_select'])) {
136
      /** @var \Drupal\entity_browser\Plugin\views\field\SelectForm $select */
137
      $select = $this->view->field['entity_browser_select'];
138
      $select->viewsForm($render);
139
140
      $render['#post_render'][] = [get_class($this), 'postRender'];
141
      $substitutions = [];
142
      foreach ($this->view->result as $row) {
143
        $form_element_row_id = $select->getRowId($row);
144
145
        $substitutions[] = [
146
          'placeholder' => '<!--form-item-entity_browser_select--' . $form_element_row_id . '-->',
147
          'field_name' => 'entity_browser_select',
148
          'row_id' => $form_element_row_id,
149
        ];
150
      }
151
152
      $render['#substitutions'] = [
153
        '#type' => 'value',
154
        '#value' => $substitutions,
155
      ];
156
    }
157
  }
158
159
  /**
160
   * Post render callback that moves form elements into the view.
161
   *
162
   * Form elements need to be added out of view to be correctly detected by Form
163
   * API and then added into the view afterwards. Views use the same approach for
164
   * bulk operations.
165
   */
166
  public static function postRender($content, $element) {
167
    // Placeholders and their substitutions (usually rendered form elements).
168
    $search = $replace = [];
169
170
    // Add in substitutions provided by the form.
171
    foreach ($element['#substitutions']['#value'] as $substitution) {
172
      $field_name = $substitution['field_name'];
173
      $row_id = $substitution['row_id'];
174
175
      $search[] = $substitution['placeholder'];
176
      $replace[] = isset($element[$field_name][$row_id]) ? drupal_render($element[$field_name][$row_id]) : '';
177
    }
178
    // Add in substitutions from hook_views_form_substitutions().
179
    $substitutions = \Drupal::moduleHandler()->invokeAll('views_form_substitutions');
180
    foreach ($substitutions as $placeholder => $substitution) {
181
      $search[] = $placeholder;
182
      $replace[] = $substitution;
183
    }
184
185
    // We cannot render exposed form within the View, as nested forms are not
186
    // standard and will break entity selection.
187
    $search[] = '<form';
188
    $replace[] = '<div';
189
    $search[] = '</form>';
190
    $replace[] = '</div>';
191
192
    $content = str_replace($search, $replace, $content);
193
194
    return $content;
195
  }
196
}
197