Completed
Push — 8.x-1.x ( bf307f...ed6653 )
by Janez
02:46
created

View::calculateDependencies()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 8
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\entity_browser\Plugin\EntityBrowser\Widget;
4
5
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
6
use Drupal\Core\Form\FormStateInterface;
7
use Drupal\Core\Render\Element;
8
use Drupal\entity_browser\WidgetBase;
9
use Drupal\Core\Url;
10
use Drupal\entity_browser\WidgetValidationManager;
11
use Drupal\views\Entity\View as ViewEntity;
12
use Drupal\views\Views;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
use Drupal\Core\Session\AccountInterface;
15
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
16
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
17
use Drupal\Core\Entity\EntityTypeManagerInterface;
18
19
/**
20
 * Uses a view to provide entity listing in a browser's widget.
21
 *
22
 * @EntityBrowserWidget(
23
 *   id = "view",
24
 *   label = @Translation("View"),
25
 *   provider = "views",
26
 *   description = @Translation("Uses a view to provide entity listing in a browser's widget.")
27
 * )
28
 */
29
class View extends WidgetBase implements ContainerFactoryPluginInterface {
30
31
  /**
32
   * The current user.
33
   *
34
   * @var \Drupal\Core\Session\AccountInterface
35
   */
36
  protected $currentUser;
37
38
  /**
39
   * {@inheritdoc}
40
   */
41
  public function defaultConfiguration() {
42
    return array(
43
      'view' => NULL,
44
      'view_display' => NULL,
45
    ) + parent::defaultConfiguration();
46
  }
47
48
  /**
49
   * {@inheritdoc}
50
   */
51 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...
52
    return new static(
53
      $configuration,
54
      $plugin_id,
55
      $plugin_definition,
56
      $container->get('event_dispatcher'),
57
      $container->get('entity_type.manager'),
58
      $container->get('plugin.manager.entity_browser.widget_validation'),
59
      $container->get('current_user')
60
    );
61
  }
62
63
  /**
64
   * Constructs a new View object.
65
   *
66
   * @param array $configuration
67
   *   A configuration array containing information about the plugin instance.
68
   * @param string $plugin_id
69
   *   The plugin_id for the plugin instance.
70
   * @param mixed $plugin_definition
71
   *   The plugin implementation definition.
72
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
73
   *   Event dispatcher service.
74
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
75
   *   The entity type manager.
76
   * @param \Drupal\entity_browser\WidgetValidationManager $validation_manager
77
   *   The Widget Validation Manager service.
78
   * @param \Drupal\Core\Session\AccountInterface $current_user
79
   *   The current user.
80
   */
81
  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, EntityTypeManagerInterface $entity_type_manager, WidgetValidationManager $validation_manager, AccountInterface $current_user) {
82
    parent::__construct($configuration, $plugin_id, $plugin_definition, $event_dispatcher, $entity_type_manager, $validation_manager);
83
    $this->currentUser = $current_user;
84
  }
85
86
  /**
87
   * {@inheritdoc}
88
   */
89
  public function getForm(array &$original_form, FormStateInterface $form_state, array $additional_widget_parameters) {
90
    $form = parent::getForm($original_form, $form_state, $additional_widget_parameters);
91
    // TODO - do we need better error handling for view and view_display (in case
92
    // either of those is nonexistent or display not of correct type)?
93
    $form['#attached']['library'] = ['entity_browser/view'];
94
95
    /** @var \Drupal\views\ViewExecutable $view */
96
    $view = $this->entityTypeManager
97
      ->getStorage('view')
98
      ->load($this->configuration['view'])
99
      ->getExecutable();
100
101
    // Check if the current user has access to this view.
102
    if (!$view->access($this->configuration['view_display'])) {
103
      return [
104
        '#markup' => $this->t('You do not have access to this View.'),
105
      ];
106
    }
107
108
    if (!empty($this->configuration['arguments'])) {
109
      if (!empty($additional_widget_parameters['path_parts'])) {
110
        $arguments = [];
111
        // Map configuration arguments with original path parts.
112
        foreach ($this->configuration['arguments'] as $argument) {
113
          $arguments[] = isset($additional_widget_parameters['path_parts'][$argument]) ? $additional_widget_parameters['path_parts'][$argument] : '';
114
        }
115
        $view->setArguments(array_values($arguments));
116
      }
117
    }
118
119
    $form['view'] = $view->executeDisplay($this->configuration['view_display']);
120
121
    if (empty($view->field['entity_browser_select'])) {
122
      $url = Url::fromRoute('entity.view.edit_form', ['view' => $this->configuration['view']])->toString();
123
      if ($this->currentUser->hasPermission('administer views')) {
124
        return [
125
          '#markup' => $this->t('Entity browser select form field not found on a view. <a href=":link">Go fix it</a>!', [':link' => $url]),
126
        ];
127
      }
128
      else {
129
        return [
130
          '#markup' => $this->t('Entity browser select form field not found on a view. Go fix it!'),
131
        ];
132
      }
133
    }
134
135
    // When rebuilding makes no sense to keep checkboxes that were previously
136
    // selected.
137
    if (!empty($form['view']['entity_browser_select']) && $form_state->isRebuilding()) {
138
      foreach (Element::children($form['view']['entity_browser_select']) as $child) {
139
        $form['view']['entity_browser_select'][$child]['#process'][] = ['\Drupal\entity_browser\Plugin\EntityBrowser\Widget\View', 'processCheckbox'];
140
        $form['view']['entity_browser_select'][$child]['#process'][] = ['\Drupal\Core\Render\Element\Checkbox', 'processAjaxForm'];
141
        $form['view']['entity_browser_select'][$child]['#process'][] = ['\Drupal\Core\Render\Element\Checkbox', 'processGroup'];
142
      }
143
    }
144
145
    $form['view']['view'] = [
146
      '#markup' => \Drupal::service('renderer')->render($form['view']['view']),
147
    ];
148
149
    return $form;
150
  }
151
152
  /**
153
   * Sets the #checked property when rebuilding form.
154
   *
155
   * Every time when we rebuild we want all checkboxes to be unchecked.
156
   *
157
   * @see \Drupal\Core\Render\Element\Checkbox::processCheckbox()
158
   */
159
  public static function processCheckbox(&$element, FormStateInterface $form_state, &$complete_form) {
160
    $element['#checked'] = FALSE;
161
    return $element;
162
  }
163
164
  /**
165
   * {@inheritdoc}
166
   */
167
  public function validate(array &$form, FormStateInterface $form_state) {
168
    $user_input = $form_state->getUserInput();
169
    if (isset($user_input['entity_browser_select'])) {
170
      $selected_rows = array_values(array_filter($user_input['entity_browser_select']));
171
      foreach ($selected_rows as $row) {
172
        // Verify that the user input is a string and split it.
173
        // Each $row is in the format entity_type:id.
174
        if (is_string($row) && $parts = explode(':', $row, 2)) {
175
          // Make sure we have a type and id present.
176
          if (count($parts) == 2) {
177
            try {
178
              $storage = $this->entityTypeManager->getStorage($parts[0]);
179
              if (!$storage->load($parts[1])) {
180
                $message = $this->t('The @type Entity @id does not exist.', [
181
                  '@type' => $parts[0],
182
                  '@id' => $parts[1],
183
                ]);
184
                $form_state->setError($form['widget']['view']['entity_browser_select'], $message);
185
              }
186
            }
187
            catch (PluginNotFoundException $e) {
0 ignored issues
show
Bug introduced by
The class Drupal\Component\Plugin\...PluginNotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
188
              $message = $this->t('The Entity Type @type does not exist.', [
189
                '@type' => $parts[0],
190
              ]);
191
              $form_state->setError($form['widget']['view']['entity_browser_select'], $message);
192
            }
193
          }
194
        }
195
      }
196
197
      // If there weren't any errors set, run the normal validators.
198
      if (empty($form_state->getErrors())) {
199
        parent::validate($form, $form_state);
200
      }
201
    }
202
  }
203
204
  /**
205
   * {@inheritdoc}
206
   */
207
  protected function prepareEntities(array $form, FormStateInterface $form_state) {
208
    $selected_rows = array_values(array_filter($form_state->getUserInput()['entity_browser_select']));
209
    $entities = [];
210
    foreach ($selected_rows as $row) {
211
      list($type, $id) = explode(':', $row);
212
      $storage = $this->entityTypeManager->getStorage($type);
213
      if ($entity = $storage->load($id)) {
214
        $entities[] = $entity;
215
      }
216
    }
217
    return $entities;
218
  }
219
220
  /**
221
   * {@inheritdoc}
222
   */
223
  public function submit(array &$element, array &$form, FormStateInterface $form_state) {
224
    $entities = $this->prepareEntities($form, $form_state);
225
    $this->selectEntities($entities, $form_state);
226
  }
227
228
  /**
229
   * {@inheritdoc}
230
   */
231
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
232
    $form = parent::buildConfigurationForm($form, $form_state);
233
234
    $options = [];
235
    // Get only those enabled Views that have entity_browser displays.
236
    $displays = Views::getApplicableViews('entity_browser_display');
237
    foreach ($displays as $display) {
238
      list($view_id, $display_id) = $display;
239
      $view = $this->entityTypeManager->getStorage('view')->load($view_id);
240
      $options[$view_id . '.' . $display_id] = $this->t('@view : @display', array('@view' => $view->label(), '@display' => $view->get('display')[$display_id]['display_title']));
241
    }
242
243
    $form['view'] = [
244
      '#type' => 'select',
245
      '#title' => $this->t('View : View display'),
246
      '#default_value' => $this->configuration['view'] . '.' . $this->configuration['view_display'],
247
      '#options' => $options,
248
      '#empty_option' => $this->t('- Select a view -'),
249
      '#required' => TRUE,
250
    ];
251
252
    return $form;
253
  }
254
255
  /**
256
   * {@inheritdoc}
257
   */
258
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
259
    $values = $form_state->getValues()['table'][$this->uuid()]['form'];
260
    $this->configuration['submit_text'] = $values['submit_text'];
261 View Code Duplication
    if (!empty($values['view'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
262
      list($view_id, $display_id) = explode('.', $values['view']);
263
      $this->configuration['view'] = $view_id;
264
      $this->configuration['view_display'] = $display_id;
265
    }
266
  }
267
268
  /**
269
   * {@inheritdoc}
270
   */
271 View Code Duplication
  public function calculateDependencies() {
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...
272
    $dependencies = [];
273
    if ($this->configuration['view']) {
274
      $view = ViewEntity::load($this->configuration['view']);
275
      $dependencies[$view->getConfigDependencyKey()] = [$view->getConfigDependencyName()];
276
    }
277
    return $dependencies;
278
  }
279
280
}
281