Completed
Push — 8.x-1.x ( c06a92...2f666a )
by Janez
02:31
created

Modal::addAjax()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 9
nc 1
nop 1
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\entity_browser\Plugin\EntityBrowser\Display;
4
5
use Drupal\Component\Utility\Html;
6
use Drupal\Component\Utility\NestedArray;
7
use Drupal\Component\Uuid\UuidInterface;
8
use Drupal\Core\Ajax\OpenDialogCommand;
9
use Drupal\Core\Entity\EntityInterface;
10
use Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface;
11
use Drupal\Core\Routing\RouteMatchInterface;
12
use Drupal\Core\Url;
13
use Drupal\entity_browser\DisplayBase;
14
use Drupal\entity_browser\DisplayRouterInterface;
15
use Drupal\entity_browser\Events\Events;
16
use Drupal\entity_browser\Events\RegisterJSCallbacks;
17
use Symfony\Component\DependencyInjection\ContainerInterface;
18
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
19
use Drupal\Core\Path\CurrentPathStack;
20
use Drupal\Core\Ajax\AjaxResponse;
21
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
22
use Drupal\Core\Form\FormStateInterface;
23
use Symfony\Component\HttpFoundation\Request;
24
use Symfony\Component\HttpFoundation\Response;
25
use Drupal\entity_browser\Events\AlterEntityBrowserDisplayData;
26
27
/**
28
 * Presents entity browser in an Modal.
29
 *
30
 * @EntityBrowserDisplay(
31
 *   id = "modal",
32
 *   label = @Translation("Modal"),
33
 *   description = @Translation("Displays the entity browser in a modal window."),
34
 *   uses_route = TRUE
35
 * )
36
 */
37
class Modal extends DisplayBase implements DisplayRouterInterface {
38
39
  /**
40
   * Current route match service.
41
   *
42
   * @var \Drupal\Core\Routing\RouteMatchInterface
43
   */
44
  protected $currentRouteMatch;
45
46
  /**
47
   * Current path.
48
   *
49
   * @var \Drupal\Core\Path\CurrentPathStack
50
   */
51
  protected $currentPath;
52
53
  /**
54
   * Current request.
55
   *
56
   * @var \Symfony\Component\HttpFoundation\Request
57
   */
58
  protected $request;
59
60
  /**
61
   * Constructs display plugin.
62
   *
63
   * @param array $configuration
64
   *   A configuration array containing information about the plugin instance.
65
   * @param string $plugin_id
66
   *   The plugin_id for the plugin instance.
67
   * @param mixed $plugin_definition
68
   *   The plugin implementation definition.
69
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
70
   *   Event dispatcher service.
71
   * @param \Drupal\Component\Uuid\UuidInterface $uuid
72
   *   UUID generator interface.
73
   * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $selection_storage
74
   *   The selection storage.
75
   * @param \Drupal\Core\Routing\RouteMatchInterface $current_route_match
76
   *   The currently active route match object.
77
   * @param \Drupal\Core\Path\CurrentPathStack $current_path
78
   *   The current path.
79
   * @param \Symfony\Component\HttpFoundation\Request $request
80
   *   Current request.
81
   */
82
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, UuidInterface $uuid, KeyValueStoreExpirableInterface $selection_storage, RouteMatchInterface $current_route_match, CurrentPathStack $current_path, Request $request) {
83
    parent::__construct($configuration, $plugin_id, $plugin_definition, $event_dispatcher, $uuid, $selection_storage);
84
    $this->currentRouteMatch = $current_route_match;
85
    $this->currentPath = $current_path;
86
    $this->request = $request;
87
  }
88
89
  /**
90
   * {@inheritdoc}
91
   */
92 View Code Duplication
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
    return new static(
94
      $configuration,
95
      $plugin_id,
96
      $plugin_definition,
97
      $container->get('event_dispatcher'),
98
      $container->get('uuid'),
99
      $container->get('entity_browser.selection_storage'),
100
      $container->get('current_route_match'),
101
      $container->get('path.current'),
102
      $container->get('request_stack')->getCurrentRequest()
103
    );
104
  }
105
106
  /**
107
   * {@inheritdoc}
108
   */
109 View Code Duplication
  public function defaultConfiguration() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
110
    return [
111
      'width' => '650',
112
      'height' => '500',
113
      'link_text' => $this->t('Select entities'),
114
      'auto_open' => FALSE,
115
    ] + parent::defaultConfiguration();
116
  }
117
118
  /**
119
   * {@inheritdoc}
120
   */
121
  public function displayEntityBrowser(array $element, FormStateInterface $form_state, array &$complete_form, array $persistent_data = []) {
122
    parent::displayEntityBrowser($element, $form_state, $complete_form, $persistent_data);
123
    $js_event_object = new RegisterJSCallbacks($this->configuration['entity_browser_id'], $this->getUuid());
124
    $js_event_object->registerCallback('Drupal.entityBrowser.selectionCompleted');
125
    $js_event = $this->eventDispatcher->dispatch(Events::REGISTER_JS_CALLBACKS, $js_event_object);
126
    $original_path = $this->currentPath->getPath();
127
128
    $data = [
129
      'query_parameters' => [
130
        'query' => [
131
          'uuid' => $this->getUuid(),
132
          'original_path' => $original_path,
133
        ],
134
      ],
135
      'attributes' => [
136
        'data-uuid' => $this->getUuid(),
137
      ],
138
    ];
139
    $event_object = new AlterEntityBrowserDisplayData($this->configuration['entity_browser_id'], $this->getUuid(), $this->getPluginDefinition(), $form_state, $data);
140
    $event = $this->eventDispatcher->dispatch(Events::ALTER_BROWSER_DISPLAY_DATA, $event_object);
141
    $data = $event->getData();
142
    return [
143
      '#theme_wrappers' => ['container'],
144
      'path' => [
145
        '#type' => 'hidden',
146
        '#value' => Url::fromRoute('entity_browser.' . $this->configuration['entity_browser_id'], [], $data['query_parameters'])->toString(),
147
      ],
148
      'open_modal' => [
149
        '#type' => 'submit',
150
        '#value' => $this->configuration['link_text'],
151
        '#limit_validation_errors' => [],
152
        '#submit' => [],
153
        '#name' => implode('_', $element['#eb_parents']),
154
        '#ajax' => [
155
          'callback' => [$this, 'openModal'],
156
          'event' => 'click',
157
        ],
158
        '#executes_submit_callback' => FALSE,
159
        '#attributes' => $data['attributes'],
160
        '#attached' => [
161
          'library' => ['core/drupal.dialog.ajax', 'entity_browser/modal'],
162
          'drupalSettings' => [
163
            'entity_browser' => [
164
              'modal' => [
165
                $this->getUuid() => [
166
                  'uuid' => $this->getUuid(),
167
                  'js_callbacks' => $js_event->getCallbacks(),
168
                  'original_path' => $original_path,
169
                  'auto_open' => $this->configuration['auto_open'],
170
                ],
171
              ],
172
            ],
173
          ],
174
        ],
175
      ],
176
    ];
177
  }
178
179
  /**
180
   * Generates the content and opens the modal.
181
   *
182
   * @param array $form
183
   *   The form array.
184
   * @param \Drupal\Core\Form\FormStateInterface $form_state
185
   *   The form state object.
186
   *
187
   * @return \Drupal\Core\Ajax\AjaxResponse
188
   *   An ajax response.
189
   */
190
  public function openModal(array &$form, FormStateInterface $form_state) {
191
    $triggering_element = $form_state->getTriggeringElement();
192
    $parents = $triggering_element['#parents'];
193
    array_pop($parents);
194
    $parents = array_merge($parents, ['path']);
195
    $input = $form_state->getUserInput();
196
    $src = NestedArray::getValue($input, $parents);
197
198
    $field_name = $triggering_element['#parents'][0];
199
    $element_name = $this->configuration['entity_browser_id'];
200
    $name = 'entity_browser_iframe_' . $element_name;
201
    $content = [
202
      '#type' => 'html_tag',
203
      '#tag' => 'iframe',
204
      '#attributes' => [
205
        'src' => $src,
206
        'class' => 'entity-browser-modal-iframe',
207
        'width' => '100%',
208
        'height' => $this->configuration['height'] - 90,
209
        'frameborder' => 0,
210
        'style' => 'padding:0',
211
        'name' => $name,
212
        'id' => $name,
213
      ],
214
    ];
215
    $html = drupal_render($content);
216
217
    $response = new AjaxResponse();
218
    $response->addCommand(new OpenDialogCommand('#' . Html::getUniqueId($field_name . '-' . $element_name . '-dialog'), $this->configuration['link_text'], $html, [
219
      'width' => 'auto',
220
      'height' => 'auto',
221
      'modal' => TRUE,
222
      'maxWidth' => $this->configuration['width'],
223
      'maxHeight' => $this->configuration['height'],
224
      'fluid' => 1,
225
      'autoResize' => 0,
226
      'resizable' => 0,
227
    ]));
228
    return $response;
229
  }
230
231
  /**
232
   * KernelEvents::RESPONSE listener.
233
   *
234
   * Intercepts default response and injects
235
   * response that will trigger JS to propagate selected entities upstream.
236
   *
237
   * @param FilterResponseEvent $event
238
   *   Response event.
239
   */
240 View Code Duplication
  public function propagateSelection(FilterResponseEvent $event) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
241
    $render = [
242
      'labels' => [
243
        '#markup' => 'Labels: ' . implode(', ', array_map(function (EntityInterface $item) {
244
          return $item->label();
245
        }, $this->entities)),
246
        '#attached' => [
247
          'library' => ['entity_browser/modal_selection'],
248
          'drupalSettings' => [
249
            'entity_browser' => [
250
              'modal' => [
251
                'entities' => array_map(function (EntityInterface $item) {
252
                  return [$item->id(), $item->uuid(), $item->getEntityTypeId()];
253
                }, $this->entities),
254
                'uuid' => $this->request->query->get('uuid'),
255
              ],
256
            ],
257
          ],
258
        ],
259
      ],
260
    ];
261
262
    $event->setResponse(new Response(\Drupal::service('bare_html_page_renderer')->renderBarePage($render, 'Entity browser', 'page')));
263
  }
264
265
  /**
266
   * {@inheritdoc}
267
   */
268
  public function path() {
269
    return '/entity-browser/modal/' . $this->configuration['entity_browser_id'];
270
  }
271
272
  /**
273
   * {@inheritdoc}
274
   */
275
  public function __sleep() {
276
    return ['configuration'];
277
  }
278
279
  /**
280
   * {@inheritdoc}
281
   */
282
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
283
    $configuration = $this->getConfiguration();
284
    $form['width'] = [
285
      '#type' => 'number',
286
      '#title' => $this->t('Width of the modal'),
287
      '#default_value' => $configuration['width'],
288
      '#description' => $this->t('Empty value for responsive width.'),
289
    ];
290
    $form['height'] = [
291
      '#type' => 'number',
292
      '#title' => $this->t('Height of the modal'),
293
      '#default_value' => $configuration['height'],
294
      '#description' => $this->t('Empty value for responsive height.'),
295
    ];
296
    $form['link_text'] = [
297
      '#type' => 'textfield',
298
      '#title' => $this->t('Link text'),
299
      '#default_value' => $configuration['link_text'],
300
    ];
301
    $form['auto_open'] = [
302
      '#type' => 'checkbox',
303
      '#title' => $this->t('Auto open entity browser'),
304
      '#default_value' => $configuration['auto_open'],
305
      '#description' => $this->t('Will open Entity browser modal as soon as page is loaded, which might cause unwanted results. Should be used only in very specific cases such as Inline entity form integration. It is also advised not to use Entity browsers with this option enabled more than once per page.'),
306
    ];
307
    return $form;
308
  }
309
310
}
311