Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
PatternPreset
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 6
306
0.00% covered (danger)
0.00%
0 / 1
 getSummary
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getSources
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
42
 calculateDependencies
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 getSourceManager
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 fillNodeId
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 slotSourceProxy
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder\Entity;
6
7use Drupal\Core\Config\Entity\ConfigEntityBase;
8use Drupal\Core\Entity\Attribute\ConfigEntityType;
9use Drupal\Core\Entity\EntityDeleteForm;
10use Drupal\Core\StringTranslation\TranslatableMarkup;
11use Drupal\display_builder\Form\PatternPresetForm;
12use Drupal\display_builder\PatternPresetInterface;
13use Drupal\display_builder\SlotSourceProxy;
14use Drupal\display_builder_ui\PatternPresetListBuilder;
15use Drupal\ui_patterns\SourcePluginManager;
16
17/**
18 * Defines the Pattern preset entity type.
19 */
20#[ConfigEntityType(
21  id: 'pattern_preset',
22  label: new TranslatableMarkup('Pattern preset'),
23  label_collection: new TranslatableMarkup('Pattern presets'),
24  label_singular: new TranslatableMarkup('Pattern preset'),
25  label_plural: new TranslatableMarkup('Pattern presets'),
26  entity_keys: [
27    'id' => 'id',
28    'label' => 'label',
29    'theme' => 'theme',
30    'description' => 'description',
31    'group' => 'group',
32    'sources' => 'sources',
33  ],
34  handlers: [
35    'list_builder' => PatternPresetListBuilder::class,
36    'form' => [
37      'add' => PatternPresetForm::class,
38      'edit' => PatternPresetForm::class,
39      'delete' => EntityDeleteForm::class,
40    ],
41  ],
42  links: [
43    'add-form' => '/admin/structure/display-builder/preset/add',
44    'edit-form' => '/admin/structure/display-builder/preset/{pattern_preset}',
45    'delete-form' => '/admin/structure/display-builder/preset/{pattern_preset}/delete',
46    'collection' => '/admin/structure/display-builder/preset',
47  ],
48  admin_permission: 'administer Pattern preset',
49  constraints: [
50    'ImmutableProperties' => [
51      'id',
52    ],
53  ],
54  config_export: [
55    'id',
56    'label',
57    'description',
58    'group',
59    'sources',
60  ],
61)]
62final class PatternPreset extends ConfigEntityBase implements PatternPresetInterface {
63
64  /**
65   * The preset ID.
66   */
67  protected string $id;
68
69  /**
70   * The preset label.
71   */
72  protected string $label;
73
74  /**
75   * The preset description.
76   */
77  protected string $description;
78
79  /**
80   * The preset group.
81   */
82  protected string $group;
83
84  /**
85   * The preset sources.
86   */
87  protected array $sources;
88
89  /**
90   * Slot source proxy.
91   */
92  protected SlotSourceProxy $slotSourceProxy;
93
94  /**
95   * {@inheritdoc}
96   *
97   * @see \Drupal\display_builder\PatternPresetInterface
98   */
99  public function getSummary(): string {
100    $contexts = [];
101    $data = $this->getSources($contexts, FALSE);
102    $data = $this->slotSourceProxy()->getLabelWithSummary($data);
103
104    return $data['summary'] ?: $data['label'];
105  }
106
107  /**
108   * {@inheritdoc}
109   *
110   * @see \Drupal\display_builder\PatternPresetInterface
111   */
112  public function getSources(array $contexts = [], bool $fillNodeId = TRUE): array {
113    $data = $this->get('sources') ?? [];
114
115    if (isset($data[0]) && \count($data) === 1) {
116      $data = \reset($data);
117    }
118
119    if (empty($data) || !isset($data['source_id'])) {
120      return [];
121    }
122
123    if ($fillNodeId) {
124      self::fillNodeId($data);
125    }
126
127    return $data;
128  }
129
130  /**
131   * {@inheritdoc}
132   *
133   * @see \Drupal\Core\Config\Entity\ConfigEntityInterface
134   */
135  public function calculateDependencies() {
136    parent::calculateDependencies();
137    // The root level is a single nestable source plugin.
138    $source = $this->sources;
139
140    if (!isset($source['source_id'])) {
141      return $this;
142    }
143    // This will automatically be done by parent::calculateDependencies() if we
144    // implement EntityWithPluginCollectionInterface.
145    $configuration = [
146      'settings' => $source['source'] ?? [],
147    ];
148    /** @var \Drupal\ui_patterns\SourceInterface $source */
149    $source = $this->getSourceManager()->createInstance($source['source_id'], $configuration);
150    $this->addDependencies($source->calculateDependencies());
151
152    return $this;
153  }
154
155  /**
156   * Gets the source plugin manager.
157   *
158   * @return \Drupal\ui_patterns\SourcePluginManager
159   *   The source plugin manager.
160   */
161  protected static function getSourceManager(): SourcePluginManager {
162    return \Drupal::service('plugin.manager.ui_patterns_source');
163  }
164
165  /**
166   * Recursively fill the _node_id key.
167   *
168   * @param array $array
169   *   The array reference.
170   */
171  private static function fillNodeId(array &$array): void {
172    if (isset($array['source_id']) && !isset($array['_node_id'])) {
173      $array['_node_id'] = \uniqid();
174    }
175
176    foreach ($array as &$value) {
177      if (\is_array($value)) {
178        self::fillNodeId($value);
179      }
180    }
181  }
182
183  /**
184   * Slot source proxy.
185   */
186  private function slotSourceProxy(): SlotSourceProxy {
187    return $this->slotSourceProxy ??= \Drupal::service('display_builder.slot_sources_proxy');
188  }
189
190}