diff --git a/src/Controller/OverviewController.php b/src/Controller/OverviewController.php index 14e91fa..7d7be15 100644 --- a/src/Controller/OverviewController.php +++ b/src/Controller/OverviewController.php @@ -30,7 +30,7 @@ class OverviewController extends ControllerBase { * * @var \Drupal\paragraphs_collection\GridLayoutDiscoveryInterface */ - protected $gridDiscovery; + protected $gridLayoutDiscovery; /** * The discovery service for style files. @@ -40,37 +40,40 @@ class OverviewController extends ControllerBase { protected $styleDiscovery; /** - * Discoverable items keyed by Paragraphs Types keyed by behavior plugins. + * A nested array of grid layout machine names. * - * The structure is: - * @code - * ['' => ['' => ]] - * @endcode + * The first level is keyed by Paragraphs Type IDs. The second-level keys have + * no meaning. The second-level values are machine names of the grid layouts + * that the first-level key Paragraphs Type has enabled. + * Exception: An empty second-level array means that all layouts are enabled + * for that Paragraphs Type. * - * Items: - * - * For the grid layout plugin, each Paragraphs Type has the machine names of - * all enabled layouts in an array. Exception: An empty array means that all - * layouts are enabled for that Paragraphs Type. + * @var array + */ + protected $gridLayoutsOrderedByParagraphsTypes; + + /** + * An array of style group machine names keyed by Paragraphs Type IDs. * - * For the style plugin, each Paragraphs Type has the machine name of the - * style group is uses as its value. Exception: An empty string means that all - * style groups are enabled for that Paragraphs Type. + * Each Paragraph Type has the style group is uses as the value. + * Exception: An empty string as the value means that all style groups are + * enabled for that Paragraphs Type. * * @var array */ - protected $itemsPerParagraphsTypesPerPlugins; + protected $styleGroupsOrderedByParagraphsTypes; + /** * Constructs a \Drupal\paragraphs_collection\Controller\OverviewController object. * - * @param \Drupal\paragraphs_collection\GridLayoutDiscoveryInterface $grid_discovery + * @param \Drupal\paragraphs_collection\GridLayoutDiscoveryInterface $grid_layout_discovery * The discovery service for grid layout files. * @param \Drupal\paragraphs_collection\StyleDiscoveryInterface $style_discovery * The discovery service for style files. */ - public function __construct(GridLayoutDiscoveryInterface $grid_discovery, StyleDiscoveryInterface $style_discovery) { - $this->gridDiscovery = $grid_discovery; + public function __construct(GridLayoutDiscoveryInterface $grid_layout_discovery, StyleDiscoveryInterface $style_discovery) { + $this->gridLayoutDiscovery = $grid_layout_discovery; $this->styleDiscovery = $style_discovery; } @@ -85,31 +88,51 @@ class OverviewController extends ControllerBase { } /** - * Lists Paragraphs Types with discoverable items they allow for a plugin. + * Lists Paragraphs Types with the grid layouts they allow. * - * @param string $plugin_id - * The ID of the behaviour plugin that the discoverable items belong to. - * Only "grid_layout" and "style" are currently supported. + * @return array + * A nested array. The first level is keyed by Paragraphs Type IDs. The + * second-level keys have no meaning. The second-level values are machine + * names of the grid layouts that the first-level key Paragraphs Type has + * enabled. + * Exception: An empty second-level array means that all layouts are enabled + * for that Paragraphs Type. + */ + protected function getGridLayoutsOrderedByParagraphsTypes() { + if (isset($this->gridLayoutsOrderedByParagraphsTypes)) { + return $this->gridLayoutsOrderedByParagraphsTypes; + } + + $paragraph_type_ids = \Drupal::entityQuery('paragraphs_type')->execute(); + $paragraphs_types_enabled = []; + foreach ($paragraph_type_ids as $paragraph_type_id) { + /** @var ParagraphsType $paragraphs_type */ + $paragraphs_type = ParagraphsType::load($paragraph_type_id); + $configuration = $paragraphs_type->getBehaviorPlugin('grid_layout')->getConfiguration(); + if (isset($configuration['enabled']) && $configuration['enabled']) { + $paragraphs_types_enabled[$paragraph_type_id] = []; + foreach ($configuration['available_grid_layouts'] as $key => $value) { + if ($value) { + $paragraphs_types_enabled[$paragraph_type_id][] = $key; + } + } + } + } + return $this->gridLayoutsOrderedByParagraphsTypes = $paragraphs_types_enabled; + } + + /** + * Lists Paragraphs Types with the style groups they use. * * @return array - * Discoverable items keyed by by Paragraphs Type IDs. The form of the items - * depends on the behaviour plugin. - * For the grid layout plugin, these are arrays of grid layout machine names - * keyed by the IDs of Paragraph Types which have them enabled. A Paragraphs - * Type ID with an empty array as its value means that all grid layouts are + * An array of style group machine names keyed by Paragraphs Type IDs. Each + * Paragraph Type has the style group is uses as the value. + * Exception: An empty string as the value means that all style groups are * enabled for that Paragraphs Type. - * For the style plugin, the items are style groups machine names keyed by - * the IDs of Paragraph Types which use them. A Paragraphs Type ID with an - * empty sting as its value means that all styles are enabled for that - * Paragraphs Type. - * For an an unsupported plugin, an empty array is returned. - * - * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException - * If the behaviour plugin ID is invalid. */ - public function getItemsPerParagraphsTypesPerPlugin($plugin_id) { - if (isset($this->itemsPerParagraphsTypesPerPlugins[$plugin_id])) { - return $this->itemsPerParagraphsTypesPerPlugins[$plugin_id]; + protected function getStyleGroupsOrderedByParagraphsTypes() { + if (isset($this->styleGroupsOrderedByParagraphsTypes)) { + return $this->styleGroupsOrderedByParagraphsTypes; } $paragraph_type_ids = \Drupal::entityQuery('paragraphs_type')->execute(); @@ -117,26 +140,12 @@ class OverviewController extends ControllerBase { foreach ($paragraph_type_ids as $paragraph_type_id) { /** @var ParagraphsType $paragraphs_type */ $paragraphs_type = ParagraphsType::load($paragraph_type_id); - $configuration = $paragraphs_type->getBehaviorPlugin($plugin_id)->getConfiguration(); + $configuration = $paragraphs_type->getBehaviorPlugin('style')->getConfiguration(); if (isset($configuration['enabled']) && $configuration['enabled']) { - switch ($plugin_id) { - case 'grid_layout': - $paragraphs_types_enabled[$paragraph_type_id] = []; - foreach ($configuration['available_grid_layouts'] as $key => $value) { - if ($value) { - $paragraphs_types_enabled[$paragraph_type_id][] = $key; - } - } - break; - case 'style': - $paragraphs_types_enabled[$paragraph_type_id] = $configuration['group']; - break; - default: - return $this->itemsPerParagraphsTypesPerPlugins[$plugin_id] = []; - } + $paragraphs_types_enabled[$paragraph_type_id] = $configuration['group']; } } - return $this->itemsPerParagraphsTypesPerPlugins[$plugin_id] = $paragraphs_types_enabled; + return $this->styleGroupsOrderedByParagraphsTypes = $paragraphs_types_enabled; } /** @@ -150,7 +159,7 @@ class OverviewController extends ControllerBase { */ public function getParagraphsTypesPerLayout($layout) { $paragraphs_types = []; - foreach ($this->getItemsPerParagraphsTypesPerPlugin('grid_layout') as $paragraphs_type => $enabled_layouts) { + foreach ($this->getGridLayoutsOrderedByParagraphsTypes() as $paragraphs_type => $enabled_layouts) { if ($enabled_layouts == [] || in_array($layout, $enabled_layouts)) { $paragraphs_types[] = $paragraphs_type; } @@ -170,7 +179,7 @@ class OverviewController extends ControllerBase { */ public function getParagraphsTypesPerStyle($style) { $paragraphs_types = []; - foreach ($this->getItemsPerParagraphsTypesPerPlugin('style') as $paragraphs_type => $used_style_group) { + foreach ($this->getStyleGroupsOrderedByParagraphsTypes() as $paragraphs_type => $used_style_group) { $enabled_styles = array_keys($this->styleDiscovery->getStyleOptions($used_style_group)); if (in_array($style, $enabled_styles)) { $paragraphs_types[] = $paragraphs_type; @@ -187,9 +196,101 @@ class OverviewController extends ControllerBase { * The output render array. */ public function layouts() { - return self::content('grid_layout'); + $header = [ + 'label' => $this->t('Grid layout'), + 'details' => $this->t('Details'), + 'use' => $this->t('Used in'), + ]; + + $layouts = $this->gridLayoutDiscovery->getGridLayouts(); + uasort($layouts, function ($layout1, $layout2) { + return strcasecmp($layout1['title'], $layout2['title']); + }); + + $rows =[]; + foreach ($layouts as $layout_id => $layout) { + $paragraphs_type_ids = $this->getParagraphsTypesPerLayout($layout_id); + + $paragraphs_type_link_list = []; + foreach ($paragraphs_type_ids as $paragraphs_type_id) { + $paragraphs_type = ParagraphsType::load($paragraphs_type_id); + + if($paragraphs_type_link_list != []) { + $paragraphs_type_link_list[] = ['#plain_text' => ', ']; + } + + $paragraphs_type_link_list[] = [ + '#type' => 'link', + '#title' => $paragraphs_type->label(), + '#url' => $paragraphs_type->toUrl(), + '#attributes' => [ + 'class' => ['table-filter-paragraphs-type-source'], + ], + ]; + } + + $row['label'] = [ + '#type' => 'markup', + '#markup' => Html::escape($layout['title']), + '#prefix' => '', + '#suffix' => '', + ]; + $row['details'] = [ + '#type' => 'details', + '#title' => $this->t($layout['description']) ?: $this->t('Details'), + '#open' => FALSE, + '#attributes' => ['class' => ['overview-details']], + ]; + $row['details']['id'] = [ + '#type' => 'item', + '#title' => $this->t('ID'), + '#markup' => ''. Html::escape($layout_id) . '', + '#prefix' => '
', + '#suffix' => '
', + ]; + $row['use'] = $paragraphs_type_link_list; + + $rows[] = $row; + } + + $table = [ + '#type' => 'table', + '#header' => $header, + '#sticky' => TRUE, + '#attributes' => [ + 'class' => ['paragraphs-collection-overview-table'], + ], + ]; + $table += $rows; + + $filters = [ + '#type' => 'fieldset', + '#attributes' => [ + 'class' => ['table-filter', 'js-show', 'form--inline'], + 'data-table' => '.paragraphs-collection-overview-table', + ], + '#weight' => -10, + '#title' => $this->t('Filter'), + ]; + $filters['text'] = [ + '#type' => 'search', + '#title' => $this->t('Grid layout label or ID'), + '#size' => 40, + '#attributes' => [ + 'class' => ['table-filter-text'], + 'autocomplete' => 'off', + 'title' => $this->t('Enter a part of the style label or ID to filter by.'), + ], + ]; + + $build['table'] = $table; + $build['filters'] = $filters; + $build['#attached']['library'] = ['paragraphs_collection/overview']; + + return $build; } + /** * Generates an overview page of available styles for the styles plugin. * @@ -197,66 +298,20 @@ class OverviewController extends ControllerBase { * The output render array. */ public function styles() { - return self::content('style'); - } - - /** - * Generates an overview page of available discoverable items for a plugin. - * - * Discoverable items are styles for the style plugin and layouts for the - * grid layout plugin. - * - * @param string $plugin_id - * The ID of the behaviour plugin that the discoverable items belong to. - * Only "grid_layout" and "style" are currently supported. - * - * @return array|null - * The output render array. NULL for invalid plugin IDs and unsupported - * behavior plugins. - */ - public function content($plugin_id) { - switch ($plugin_id) { - case 'grid_layout': - $label = $this->t('Grid layout'); - break; - case 'style': - $label = $this->t('Style'); - break; - default: - return NULL; - } $header = [ - 'label' => $label, + 'label' => $this->t('Style'), 'details' => $this->t('Details'), 'use' => $this->t('Used in'), ]; - switch ($plugin_id) { - case 'grid_layout': - $items = $this->gridDiscovery->getGridLayouts(); - break; - case 'style': - $items = $this->styleDiscovery->getStyles(); - break; - default: - return NULL; - } - uasort($items, function ($item1, $item2) { - return strcasecmp($item1['title'], $item2['title']); + $styles = $this->styleDiscovery->getStyles(); + uasort($styles, function ($style1, $style2) { + return strcasecmp($style1['title'], $style2['title']); }); $rows =[]; - foreach ($items as $item_id => $item) { - switch ($plugin_id) { - case 'grid_layout': - $paragraphs_type_ids = $this->getParagraphsTypesPerLayout($item_id); - break; - case 'style': - $paragraphs_type_ids = $this->getParagraphsTypesPerStyle($item_id); - break; - default: - return NULL; - } + foreach ($styles as $style_id => $style) { + $paragraphs_type_ids = $this->getParagraphsTypesPerStyle($style_id); $paragraphs_type_link_list = []; foreach ($paragraphs_type_ids as $paragraphs_type_id) { @@ -276,49 +331,45 @@ class OverviewController extends ControllerBase { ]; } + $group_list = []; + foreach ($style['groups'] as $group) { + if ($group_list != []) { + $group_list[] = ['#plain_text' => ', ']; + } + $group_list[] = [ + '#type' => 'markup', + '#markup' => Html::escape($group), + '#prefix' => '', + '#suffix' => '', + ]; + } + $row['label'] = [ '#type' => 'markup', - '#markup' => Html::escape($item['title']), + '#markup' => Html::escape($style['title']), '#prefix' => '', '#suffix' => '', ]; $row['details'] = [ '#type' => 'details', - '#title' => $this->t($item['description']) ?: $this->t('Details'), + '#title' => $this->t($style['description']) ?: $this->t('Details'), '#open' => FALSE, '#attributes' => ['class' => ['overview-details']], ]; $row['details']['id'] = [ '#type' => 'item', '#title' => $this->t('ID'), - '#markup' => ''. Html::escape($item_id) . '', + '#markup' => ''. Html::escape($style_id) . '', + '#prefix' => '
', + '#suffix' => '
', + ]; + $row['details']['groups'] = [ + '#type' => 'item', + '#title' => $this->t('Groups'), + 'item' => $group_list, '#prefix' => '
', '#suffix' => '
', ]; - switch ($plugin_id) { - case 'style': - $group_list = []; - foreach ($item['groups'] as $group) { - if ($group_list != []) { - $group_list[] = ['#plain_text' => ', ']; - } - $group_list[] = [ - '#type' => 'markup', - '#markup' => Html::escape($group), - '#prefix' => '', - '#suffix' => '', - ]; - } - $row['details']['groups'] = [ - '#type' => 'item', - '#title' => $this->t('Groups'), - 'item' => $group_list, - '#prefix' => '
', - '#suffix' => '
', - ]; - break; - default: - } $row['use'] = $paragraphs_type_link_list; $rows[] = $row; @@ -334,6 +385,10 @@ class OverviewController extends ControllerBase { ]; $table += $rows; + $group_options = $this->styleDiscovery->getStyleGroups(); + asort($group_options); + $empty_option = ['' => '- All -']; + $filters = [ '#type' => 'fieldset', '#attributes' => [ @@ -343,25 +398,17 @@ class OverviewController extends ControllerBase { '#weight' => -10, '#title' => $this->t('Filter'), ]; - switch ($plugin_id) { - case 'style': - $group_options = $this->styleDiscovery->getStyleGroups(); - asort($group_options); - $empty_option = ['' => '- All -']; - - $filters['group'] = [ - '#type' => 'select', - '#title' => $this->t('Group'), - '#options' => $empty_option + $group_options, - '#attributes' => [ - 'class' => ['table-filter-group-select'], - ], - ]; - break; - default: - } + $filters['group'] = [ + '#type' => 'select', + '#title' => $this->t('Group'), + '#options' => $empty_option + $group_options, + '#attributes' => [ + 'class' => ['table-filter-group-select'], + ], + ]; $filters['text'] = [ '#type' => 'search', + '#title' => $this->t('Style label or ID'), '#size' => 40, '#attributes' => [ 'class' => ['table-filter-text'], @@ -369,15 +416,6 @@ class OverviewController extends ControllerBase { 'title' => $this->t('Enter a part of the style label or ID to filter by.'), ], ]; - switch ($plugin_id) { - case 'grid_layout': - $filters['text']['#title'] = $this->t('Grid layout label or ID'); - break; - case 'style': - $filters['text']['#title'] = $this->t('Style label or ID'); - break; - default: - } $build['table'] = $table; $build['filters'] = $filters; diff --git a/src/Tests/ParagraphsCollectionOverviewTest.php b/src/Tests/ParagraphsCollectionOverviewTest.php new file mode 100644 index 0000000..65a2dcb --- /dev/null +++ b/src/Tests/ParagraphsCollectionOverviewTest.php @@ -0,0 +1,87 @@ +loginAsAdmin([ + 'administer paragraphs types', + 'access site reports', + ]); + + // Check the new link on the reports page. + $this->drupalGet('/admin/reports'); + $this->assertText('Overviews of items discoverable by behavior plugins.'); + $this->clickLink('Paragraphs Collection'); + + // Check the grid layouts overview. + $this->assertUrl('/admin/reports/paragraphs_collection/layouts'); + $this->assertTitle('Available grid layouts | Drupal'); + $this->assertText('Grid layout label or ID'); + $this->assertText('Details'); + $this->assertText('Used in'); + + // Check that a concrete grid layout is displayed. + $this->assertText('Two columns'); + $this->assertText('Defines a two column layout with 8-4 widths'); + $this->assertText('paragraphs_two_column'); + $this->assertLink('Grid'); + $this->assertLinkByHref('/admin/structure/paragraphs_type/grid'); + + // Check the tabs. + $this->assertLink('Layouts'); + $this->clickLink('Styles'); + + // Check the styles layouts overview. + $this->assertUrl('/admin/reports/paragraphs_collection/styles'); + $this->assertTitle('Available styles | Drupal'); + $this->assertText('Group'); + $this->assertText('Style label or ID'); + $this->assertText('Details'); + $this->assertText('Used in'); + + // Check that a concrete style is displayed. + $this->assertText('Blue'); + $this->assertText('paragraphs-blue'); + $this->assertText('General Group'); + $this->assertLink('Container'); + $this->assertLinkByHref('/admin/structure/paragraphs_type/paragraphs_container'); + + // Check the tabs. + $this->assertLink('Layouts'); + $this->assertLink('Styles'); + } + +}