FieldValueManager::getTextBundles()   B
last analyzed

Complexity

Conditions 6
Paths 9

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 9
nop 1
dl 0
loc 24
ccs 15
cts 15
cp 1
crap 6
rs 8.5125
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\paragraphs_editor\EditorFieldValue;
4
5
use Drupal\Core\Entity\EntityFieldManagerInterface;
6
use Drupal\Core\Entity\EntityTypeManagerInterface;
7
use Drupal\Core\Field\FieldDefinitionInterface;
8
use Drupal\Core\Field\FieldStorageDefinitionInterface;
9
use Drupal\entity_reference_revisions\EntityReferenceRevisionsFieldItemList;
10
use Drupal\paragraphs\ParagraphInterface;
11
use Drupal\paragraphs_editor\Utility\TypeUtility;
12
13
/**
14
 * Manages the paragraphs editor field values.
15
 */
16
class FieldValueManager implements FieldValueManagerInterface {
17
18
  /**
19
   * The storage plugin for the paragraph entity type.
20
   *
21
   * @var \Drupal\Core\Entity\EntityStorageInterface
22
   */
23
  protected $storage;
24
25
  /**
26
   * The storage plugin for the paragraph type config entity type.
27
   *
28
   * @var \Drupal\Core\Entity\EntityStorageInterface
29
   */
30
  protected $bundleStorage;
31
32
  /**
33
   * The field value manager service for collecting field information.
34
   *
35
   * @var \Drupal\Core\Entity\EntityFieldManagerInterface
36
   */
37
  protected $entityFieldManager;
38
39
  /**
40
   * Element definitions for custom elements that can occur in an editor field.
41
   *
42
   * @var array
43
   */
44
  protected $elements;
45
46
  /**
47
   * A static cache of paragraph revisions.
48
   *
49
   * @var \Drupal\paragraphs\ParagraphInterface[]
50
   */
51
  protected $revisionCache = [];
52
53
  /**
54
   * Creates a field value manager object.
55
   *
56
   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
57
   *   The field manager service.
58
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
59
   *   The entity type manager service.
60
   * @param array $elements
61
   *   An array of widget binder element definitions.
62
   */
63 18
  public function __construct(EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, array $elements) {
64 18
    $this->entityFieldManager = $entity_field_manager;
65 18
    $this->storage = $entity_type_manager->getStorage('paragraph');
66 18
    $this->bundleStorage = $entity_type_manager->getStorage('paragraphs_type');
67 18
    $this->elements = $elements;
68 18
  }
69
70
  /**
71
   * {@inheritdoc}
72
   */
73 5
  public function getReferencedEntities(EntityReferenceRevisionsFieldItemList $items) {
74 5
    $entities = [];
75 5
    foreach ($items as $item) {
76 4
      $value = $item->getValue();
77 4
      if (!empty($value['entity']) && $value['entity'] instanceof ParagraphInterface) {
78 4
        $entities[] = $item->entity;
79
      }
80 1
      elseif ($item->target_revision_id !== NULL) {
81 1
        if (!empty($this->revisionCache[$item->target_revision_id])) {
82 1
          $entities[] = $this->revisionCache[$item->target_revision_id];
83
        }
84
        else {
85 1
          $entity = $this->storage->loadRevision($item->target_revision_id);
86 1
          $entity = TypeUtility::ensureParagraph($entity);
87 1
          $this->revisionCache[$item->target_revision_id] = $entity;
88 4
          $entities[] = $entity;
89
        }
90
      }
91
    }
92 5
    return $entities;
93
  }
94
95
  /**
96
   * {@inheritdoc}
97
   */
98 4
  public function wrapItems(EntityReferenceRevisionsFieldItemList $items) {
99 4
    $field_definition = TypeUtility::ensureFieldConfig($items->getFieldDefinition());
100 4
    if (!$this->isParagraphsEditorField($field_definition)) {
101
      throw new \Exception('Attempt to wrap non-paragraphs editor field.');
102
    }
103
104
    // Build a list of refrenced entities and filter out the text entities.
105 4
    $settings = $field_definition->getThirdPartySettings('paragraphs_editor');
106 4
    $markup = '';
107 4
    $entities = [];
108 4
    $text_entity = NULL;
109
110 4
    foreach ($this->getReferencedEntities($items) as $entity) {
111 3
      if ($entity->bundle() == $settings['text_bundle']) {
112 2
        $markup .= $entity->{$settings['text_field']}->value;
113 2
        if (!$text_entity) {
114 2
          $text_entity = $entity;
115
        }
116
      }
117
      else {
118 3
        $entities[$entity->uuid()] = $entity;
119
      }
120
    }
121
122
    // If there is no text entity we need to create one.
123 4
    if (!$text_entity) {
124 2
      $text_entity = TypeUtility::ensureParagraph($this->storage->create([
125 2
        'type' => $settings['text_bundle'],
126
      ]));
127
    }
128
129
    // Reset the text entity markup in case we merged multiple text entities.
130 4
    $text_entity->{$settings['text_field']}->value = $markup;
131 4
    if (empty($text_entity->{$settings['text_field']}->format) && !empty($settings['filter_format'])) {
132 2
      $text_entity->{$settings['text_field']}->format = $settings['filter_format'];
133
    }
134
135 4
    return new FieldValueWrapper($field_definition, $text_entity, $entities);
136
  }
137
138
  /**
139
   * {@inheritdoc}
140
   */
141 2
  public function prepareEntityForSave($entity, $new_revision, $langcode) {
142 2
    $entity->setNewRevision($new_revision);
143
144 2
    if (isset($langcode) && $entity->get('langcode') != $langcode) {
145 1
      if ($entity->hasTranslation($langcode)) {
146
        $entity = $entity->getTranslation($langcode);
147
      }
148
      else {
149 1
        $entity->set('langcode', $langcode);
150
      }
151
    }
152
153 2
    $entity->setNeedsSave(TRUE);
154
155 2
    return $entity;
156
  }
157
158
  /**
159
   * {@inheritdoc}
160
   */
161 1
  public function setItems(EntityReferenceRevisionsFieldItemList $items, array $entities, $new_revision = FALSE, $langcode = NULL) {
162 1
    $values = [];
163 1
    $delta = 0;
164 1
    foreach ($entities as $entity) {
165 1
      $entity = $this->prepareEntityForSave($entity, $new_revision, $langcode);
166 1
      $values[$delta]['entity'] = $entity;
167 1
      $values[$delta]['target_id'] = $entity->id();
168 1
      $values[$delta]['target_revision_id'] = $entity->getRevisionId();
169 1
      $delta++;
170
    }
171
172 1
    $items->setValue($values);
173 1
    $items->filterEmptyItems();
174 1
    return $items;
175
  }
176
177
  /**
178
   * {@inheritdoc}
179
   */
180 1
  public function getTextBundles(array $allowed_bundles = []) {
181
182 1
    if (empty($allowed_bundles)) {
183 1
      $results = $this->bundleStorage->getQuery()->execute();
184 1
      if (is_array($results)) {
185 1
        foreach ($results as $name) {
186 1
          $allowed_bundles[$name] = [
187 1
            'label' => $this->bundleStorage->load($name)->label(),
188
          ];
189
        }
190
      }
191
    }
192
193 1
    $bundles = [];
194 1
    foreach ($allowed_bundles as $name => $type) {
195 1
      $text_fields = $this->getTextFields($name);
196 1
      if (count($text_fields) == 1) {
197 1
        $bundles[$name] = [
198 1
          'label' => $type['label'],
199 1
          'text_field' => reset($text_fields),
200
        ];
201
      }
202
    }
203 1
    return $bundles;
204
  }
205
206
  /**
207
   * {@inheritdoc}
208
   */
209 10
  public function isParagraphsField(FieldDefinitionInterface $field_definition) {
210 10
    if ($field_definition->getType() != 'entity_reference_revisions') {
211 2
      return FALSE;
212
    }
213 8
    $field_definition = TypeUtility::ensureFieldConfig($field_definition);
214
215 8
    $target_type = $field_definition->getFieldStorageDefinition()->getSetting('target_type');
216 8
    return $target_type == 'paragraph';
217
  }
218
219
  /**
220
   * {@inheritdoc}
221
   */
222 7
  public function isParagraphsEditorField(FieldDefinitionInterface $field_definition) {
223 7
    if (!$this->isParagraphsField($field_definition)) {
224 1
      return FALSE;
225
    }
226 6
    $field_definition = TypeUtility::ensureFieldConfig($field_definition);
227
228
    // We only every allow this widget to be applied to fields that have
229
    // unlimited cardinality. Otherwise we'd have to deal with keeping track of
230
    // how many paragraphs are in the Editor instance.
231 6
    $cardinality = $field_definition->getFieldStorageDefinition()->getCardinality();
232 6
    if ($cardinality != FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) {
233
      return FALSE;
234
    }
235
236
    // Make sure it is a pragraphs editor enabled field.
237 6
    $settings = $field_definition->getThirdPartySettings('paragraphs_editor');
238 6
    return !empty($settings['enabled']);
239
  }
240
241
  /**
242
   * {@inheritdoc}
243
   */
244 1
  public function getTextFields($bundle_name) {
245 1
    $matches = [];
246 1
    $field_definitions = $this->entityFieldManager->getFieldDefinitions('paragraph', $bundle_name);
247 1
    foreach ($field_definitions as $field_definition) {
248 1
      if ($this->isTextField($field_definition)) {
249 1
        $matches[] = $field_definition->getName();
250
      }
251
    }
252 1
    return $matches;
253
  }
254
255
  /**
256
   * {@inheritdoc}
257
   */
258 4
  public function getElement($element_name) {
259 4
    return isset($this->elements[$element_name]) ? $this->elements[$element_name] : NULL;
260
  }
261
262
  /**
263
   * {@inheritdoc}
264
   */
265 1
  public function getAttributeName($element_name, $attribute_name) {
266 1
    $element = $this->getElement($element_name);
267 1
    if (!empty($element['attributes'])) {
268 1
      $map = array_flip($element['attributes']);
269 1
      $key = !empty($map[$attribute_name]) ? $map[$attribute_name] : NULL;
270 1
      return $key;
271
    }
272
    else {
273 1
      return NULL;
274
    }
275
  }
276
277
  /**
278
   * {@inheritdoc}
279
   */
280 1
  public function getSelector($element_name) {
281 1
    $element = $this->getElement($element_name);
282 1
    $selector = !empty($element['tag']) ? $element['tag'] : '';
283 1
    if (!empty($element['attributes']['class'])) {
284 1
      $classes = explode(' ', $element['attributes']['class']);
285 1
      $selector .= '.' . implode('.', $classes);
286
    }
287 1
    return $selector;
288
  }
289
290
  /**
291
   * Helper function to check if a field is a text field.
292
   *
293
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
294
   *   The field to check.
295
   *
296
   * @return bool
297
   *   TRUE if it's a paragraphs editor approved text field, FALSE otherwise.
298
   */
299 1
  protected function isTextField(FieldDefinitionInterface $field_definition) {
300 1
    return $field_definition->getType() == 'text_long';
301
  }
302
303
}
304