Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
0.00% |
0 / 61 |
|
0.00% |
0 / 29 |
|
0.00% |
0 / 47 |
|
0.00% |
0 / 8 |
CRAP | |
0.00% |
0 / 1 |
| ApiPreviewController | |
0.00% |
0 / 61 |
|
0.00% |
0 / 29 |
|
0.00% |
0 / 47 |
|
0.00% |
0 / 8 |
420 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
n/a |
0 / 0 |
n/a |
0 / 0 |
|
0.00% |
0 / 1 |
2 | |||||
| getBlockPreview | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getPresetPreview | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getComponentPreview | |
0.00% |
0 / 15 |
|
0.00% |
0 / 6 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| generateBlock | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| generateStory | |
0.00% |
0 / 9 |
|
0.00% |
0 / 4 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| generateComponent | |
0.00% |
0 / 12 |
|
0.00% |
0 / 13 |
|
0.00% |
0 / 36 |
|
0.00% |
0 / 1 |
90 | |||
| renderSource | |
0.00% |
0 / 5 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Drupal\display_builder\Controller; |
| 6 | |
| 7 | use Drupal\Core\Controller\ControllerBase; |
| 8 | use Drupal\Core\Render\HtmlResponse; |
| 9 | use Drupal\Core\Render\RendererInterface; |
| 10 | use Drupal\Core\Theme\ComponentPluginManager; |
| 11 | use Drupal\display_builder\RenderableBuilderTrait; |
| 12 | use Drupal\ui_patterns_library\StoryPluginManager; |
| 13 | use Symfony\Component\DependencyInjection\Attribute\Autowire; |
| 14 | |
| 15 | /** |
| 16 | * Returns preview responses for Display builder routes. |
| 17 | */ |
| 18 | class ApiPreviewController extends ControllerBase { |
| 19 | |
| 20 | use RenderableBuilderTrait; |
| 21 | |
| 22 | /** |
| 23 | * The Pattern preset storage. |
| 24 | * |
| 25 | * @var \Drupal\Core\Entity\EntityStorageInterface |
| 26 | */ |
| 27 | protected $presetConfigStorage; |
| 28 | |
| 29 | public function __construct( |
| 30 | #[Autowire(service: 'plugin.manager.component_story')] |
| 31 | private StoryPluginManager $storyPluginManager, |
| 32 | #[Autowire(service: 'plugin.manager.sdc')] |
| 33 | private ComponentPluginManager $componentManager, |
| 34 | private RendererInterface $renderer, |
| 35 | ) { |
| 36 | $this->presetConfigStorage = $this->entityTypeManager()->getStorage('pattern_preset'); |
| 37 | } |
| 38 | |
| 39 | /** |
| 40 | * Get block preview. |
| 41 | * |
| 42 | * @param string $block_id |
| 43 | * Block ID. |
| 44 | * |
| 45 | * @return \Drupal\Core\Render\HtmlResponse |
| 46 | * The HTML response. |
| 47 | */ |
| 48 | public function getBlockPreview(string $block_id): HtmlResponse { |
| 49 | $build = $this->generateBlock($block_id); |
| 50 | |
| 51 | $html = $this->renderer->renderRoot($build); |
| 52 | $response = new HtmlResponse(); |
| 53 | $response->setContent($html); |
| 54 | |
| 55 | return $response; |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Get preset preview. |
| 60 | * |
| 61 | * @param string $preset_id |
| 62 | * Preset ID. |
| 63 | * |
| 64 | * @return \Drupal\Core\Render\HtmlResponse |
| 65 | * The HTML response. |
| 66 | */ |
| 67 | public function getPresetPreview(string $preset_id): HtmlResponse { |
| 68 | /** @var \Drupal\display_builder\PatternPresetInterface $preset */ |
| 69 | $preset = $this->presetConfigStorage->load($preset_id); |
| 70 | $data = $preset->getSources([], FALSE); |
| 71 | |
| 72 | $build = $this->renderSource($data); |
| 73 | |
| 74 | $html = $this->renderer->renderRoot($build); |
| 75 | $response = new HtmlResponse(); |
| 76 | $response->setContent($html); |
| 77 | |
| 78 | return $response; |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * Get component preview, only HTML without specific css or js. |
| 83 | * |
| 84 | * @param string $component_id |
| 85 | * Component ID. |
| 86 | * @param string $variant_id |
| 87 | * Component variant ID. |
| 88 | * |
| 89 | * @return \Drupal\Core\Render\HtmlResponse |
| 90 | * The HTML response. |
| 91 | */ |
| 92 | public function getComponentPreview(string $component_id, string $variant_id): HtmlResponse { |
| 93 | $ui_patterns_library = $this->moduleHandler()->moduleExists('ui_patterns_library'); |
| 94 | |
| 95 | $build = []; |
| 96 | |
| 97 | if (!$ui_patterns_library) { |
| 98 | $build = $this->generateComponent($component_id); |
| 99 | } |
| 100 | else { |
| 101 | $stories = $this->storyPluginManager->getComponentStories($component_id); |
| 102 | |
| 103 | if (empty($stories)) { |
| 104 | $build = $this->generateComponent($component_id); |
| 105 | } |
| 106 | else { |
| 107 | $story = []; |
| 108 | $first_story = \reset($stories); |
| 109 | $story[$first_story['machineName'] ?? 'default'] = $first_story; |
| 110 | $build = $this->generateStory($component_id, $variant_id, $story); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | $html = $this->renderer->renderRoot($build); |
| 115 | $response = new HtmlResponse(); |
| 116 | $response->setContent($html); |
| 117 | |
| 118 | return $response; |
| 119 | } |
| 120 | |
| 121 | /** |
| 122 | * Build renderable block. |
| 123 | * |
| 124 | * @param string $block_id |
| 125 | * The block id to preview. |
| 126 | * |
| 127 | * @return array |
| 128 | * A renderable array. |
| 129 | */ |
| 130 | protected function generateBlock(string $block_id): array { |
| 131 | $data = [ |
| 132 | 'source_id' => 'block', |
| 133 | 'source' => [ |
| 134 | 'plugin_id' => $block_id, |
| 135 | ], |
| 136 | ]; |
| 137 | |
| 138 | return $this->renderSource($data); |
| 139 | } |
| 140 | |
| 141 | /** |
| 142 | * Generate a story. |
| 143 | * |
| 144 | * @param string $component_id |
| 145 | * The component id. |
| 146 | * @param string $variant_id |
| 147 | * The component variant id. |
| 148 | * @param array $stories |
| 149 | * The stories. |
| 150 | * |
| 151 | * @return array |
| 152 | * The render array |
| 153 | */ |
| 154 | private function generateStory(string $component_id, string $variant_id, array $stories): array { |
| 155 | $html = []; |
| 156 | |
| 157 | foreach (\array_keys($stories) as $story_id) { |
| 158 | $html[$story_id] = [ |
| 159 | '#type' => 'component', |
| 160 | '#component' => $component_id, |
| 161 | '#story' => $story_id, |
| 162 | '#props' => ['variant' => $variant_id], |
| 163 | ]; |
| 164 | } |
| 165 | |
| 166 | return $html; |
| 167 | } |
| 168 | |
| 169 | /** |
| 170 | * Generate a content even with empty story or no library module. |
| 171 | * |
| 172 | * @param string $component_id |
| 173 | * The component id. |
| 174 | * |
| 175 | * @return array |
| 176 | * The render array |
| 177 | * |
| 178 | * @todo Remove when https://www.drupal.org/project/ui_patterns/issues/3414774 is merged |
| 179 | */ |
| 180 | private function generateComponent(string $component_id): array { |
| 181 | $definition = $this->componentManager->getDefinition($component_id); |
| 182 | $html = [ |
| 183 | '#type' => 'component', |
| 184 | '#component' => $component_id, |
| 185 | ]; |
| 186 | |
| 187 | foreach ($definition['slots'] ?? [] as $slot_id => $slot) { |
| 188 | if (isset($slot['examples']) && \is_array($slot['examples']) && !empty($slot['examples'])) { |
| 189 | $html['#slots'][$slot_id] = $slot['examples'][0]; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | foreach ($definition['props']['properties'] ?? [] as $prop_id => $prop) { |
| 194 | if (isset($prop['examples']) && \is_array($prop['examples']) && !empty($prop['examples'])) { |
| 195 | $html['#props'][$prop_id] = $prop['examples'][0]; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | return $html; |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * Get renderable array for a slot source. |
| 204 | * |
| 205 | * @param array $data |
| 206 | * The slot source data array containing: |
| 207 | * - source_id: The source ID |
| 208 | * - source: Array of source configuration. |
| 209 | * |
| 210 | * @return array |
| 211 | * The renderable array for this slot source. |
| 212 | */ |
| 213 | private function renderSource(array $data): array { |
| 214 | /** @var \Drupal\ui_patterns\Element\ComponentElementBuilder $builder */ |
| 215 | $builder = \Drupal::service('ui_patterns.component_element_builder'); // @phpcs:ignore |
| 216 | |
| 217 | try { |
| 218 | $build = $builder->buildSource([], 'content', [], $data, []) ?? []; |
| 219 | |
| 220 | return $build['#slots']['content'][0] ?? []; |
| 221 | } |
| 222 | catch (\Throwable $th) { |
| 223 | return []; |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | } |
Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not
necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once.
Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 130 | protected function generateBlock(string $block_id): array { |
| 131 | $data = [ |
| 132 | 'source_id' => 'block', |
| 133 | 'source' => [ |
| 134 | 'plugin_id' => $block_id, |
| 135 | ], |
| 136 | ]; |
| 137 | |
| 138 | return $this->renderSource($data); |
| 180 | private function generateComponent(string $component_id): array { |
| 181 | $definition = $this->componentManager->getDefinition($component_id); |
| 182 | $html = [ |
| 183 | '#type' => 'component', |
| 184 | '#component' => $component_id, |
| 185 | ]; |
| 186 | |
| 187 | foreach ($definition['slots'] ?? [] as $slot_id => $slot) { |
| 187 | foreach ($definition['slots'] ?? [] as $slot_id => $slot) { |
| 187 | foreach ($definition['slots'] ?? [] as $slot_id => $slot) { |
| 188 | if (isset($slot['examples']) && \is_array($slot['examples']) && !empty($slot['examples'])) { |
| 188 | if (isset($slot['examples']) && \is_array($slot['examples']) && !empty($slot['examples'])) { |
| 188 | if (isset($slot['examples']) && \is_array($slot['examples']) && !empty($slot['examples'])) { |
| 187 | foreach ($definition['slots'] ?? [] as $slot_id => $slot) { |
| 188 | if (isset($slot['examples']) && \is_array($slot['examples']) && !empty($slot['examples'])) { |
| 189 | $html['#slots'][$slot_id] = $slot['examples'][0]; |
| 187 | foreach ($definition['slots'] ?? [] as $slot_id => $slot) { |
| 188 | if (isset($slot['examples']) && \is_array($slot['examples']) && !empty($slot['examples'])) { |
| 189 | $html['#slots'][$slot_id] = $slot['examples'][0]; |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | foreach ($definition['props']['properties'] ?? [] as $prop_id => $prop) { |
| 193 | foreach ($definition['props']['properties'] ?? [] as $prop_id => $prop) { |
| 193 | foreach ($definition['props']['properties'] ?? [] as $prop_id => $prop) { |
| 194 | if (isset($prop['examples']) && \is_array($prop['examples']) && !empty($prop['examples'])) { |
| 194 | if (isset($prop['examples']) && \is_array($prop['examples']) && !empty($prop['examples'])) { |
| 194 | if (isset($prop['examples']) && \is_array($prop['examples']) && !empty($prop['examples'])) { |
| 193 | foreach ($definition['props']['properties'] ?? [] as $prop_id => $prop) { |
| 194 | if (isset($prop['examples']) && \is_array($prop['examples']) && !empty($prop['examples'])) { |
| 195 | $html['#props'][$prop_id] = $prop['examples'][0]; |
| 193 | foreach ($definition['props']['properties'] ?? [] as $prop_id => $prop) { |
| 194 | if (isset($prop['examples']) && \is_array($prop['examples']) && !empty($prop['examples'])) { |
| 195 | $html['#props'][$prop_id] = $prop['examples'][0]; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | return $html; |
| 154 | private function generateStory(string $component_id, string $variant_id, array $stories): array { |
| 155 | $html = []; |
| 156 | |
| 157 | foreach (\array_keys($stories) as $story_id) { |
| 157 | foreach (\array_keys($stories) as $story_id) { |
| 157 | foreach (\array_keys($stories) as $story_id) { |
| 158 | $html[$story_id] = [ |
| 159 | '#type' => 'component', |
| 157 | foreach (\array_keys($stories) as $story_id) { |
| 158 | $html[$story_id] = [ |
| 159 | '#type' => 'component', |
| 160 | '#component' => $component_id, |
| 161 | '#story' => $story_id, |
| 162 | '#props' => ['variant' => $variant_id], |
| 163 | ]; |
| 164 | } |
| 165 | |
| 166 | return $html; |
| 48 | public function getBlockPreview(string $block_id): HtmlResponse { |
| 49 | $build = $this->generateBlock($block_id); |
| 50 | |
| 51 | $html = $this->renderer->renderRoot($build); |
| 52 | $response = new HtmlResponse(); |
| 53 | $response->setContent($html); |
| 54 | |
| 55 | return $response; |
| 92 | public function getComponentPreview(string $component_id, string $variant_id): HtmlResponse { |
| 93 | $ui_patterns_library = $this->moduleHandler()->moduleExists('ui_patterns_library'); |
| 94 | |
| 95 | $build = []; |
| 96 | |
| 97 | if (!$ui_patterns_library) { |
| 97 | if (!$ui_patterns_library) { |
| 98 | $build = $this->generateComponent($component_id); |
| 101 | $stories = $this->storyPluginManager->getComponentStories($component_id); |
| 102 | |
| 103 | if (empty($stories)) { |
| 103 | if (empty($stories)) { |
| 104 | $build = $this->generateComponent($component_id); |
| 107 | $story = []; |
| 108 | $first_story = \reset($stories); |
| 109 | $story[$first_story['machineName'] ?? 'default'] = $first_story; |
| 110 | $build = $this->generateStory($component_id, $variant_id, $story); |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | $html = $this->renderer->renderRoot($build); |
| 114 | $html = $this->renderer->renderRoot($build); |
| 115 | $response = new HtmlResponse(); |
| 116 | $response->setContent($html); |
| 117 | |
| 118 | return $response; |
| 67 | public function getPresetPreview(string $preset_id): HtmlResponse { |
| 68 | /** @var \Drupal\display_builder\PatternPresetInterface $preset */ |
| 69 | $preset = $this->presetConfigStorage->load($preset_id); |
| 70 | $data = $preset->getSources([], FALSE); |
| 71 | |
| 72 | $build = $this->renderSource($data); |
| 73 | |
| 74 | $html = $this->renderer->renderRoot($build); |
| 75 | $response = new HtmlResponse(); |
| 76 | $response->setContent($html); |
| 77 | |
| 78 | return $response; |
| 213 | private function renderSource(array $data): array { |
| 214 | /** @var \Drupal\ui_patterns\Element\ComponentElementBuilder $builder */ |
| 215 | $builder = \Drupal::service('ui_patterns.component_element_builder'); // @phpcs:ignore |
| 216 | |
| 217 | try { |
| 218 | $build = $builder->buildSource([], 'content', [], $data, []) ?? []; |
| 219 | |
| 220 | return $build['#slots']['content'][0] ?? []; |
| 222 | catch (\Throwable $th) { |
| 223 | return []; |