diff --git a/modules/base/src/Plugin/Action/ListSort.php b/modules/base/src/Plugin/Action/ListSort.php new file mode 100644 index 0000000000000000000000000000000000000000..a2ff9a13a8e0ddfbd365e3525bde0054f1debaab --- /dev/null +++ b/modules/base/src/Plugin/Action/ListSort.php @@ -0,0 +1,124 @@ +<?php + +namespace Drupal\eca_base\Plugin\Action; + +use Drupal\Core\Form\FormStateInterface; +use Drupal\eca\Plugin\Action\ListOperationBase; +use Drupal\eca\Plugin\DataType\DataTransferObject; +use Drupal\eca\Plugin\ECA\PluginFormTrait; + +/** + * Sorts a list. + * + * @Action( + * id = "eca_list_sort", + * label = @Translation("List: sort items"), + * description = @Translation("Sorts a list."), + * eca_version_introduced = "2.2.0" + * ) + */ +class ListSort extends ListOperationBase { + + use PluginFormTrait; + + /** + * Gets the supported sorting methods. + * + * @return array + * The supported sorting methods. + */ + public function getSupportedSortMethods() { + return [ + 'asort' => $this->t('Ascending by value'), + 'arsort' => $this->t('Descending by value'), + 'ksort' => $this->t('Ascending by key'), + 'krsort' => $this->t('Descending by key'), + 'natsort' => $this->t('Natural'), + 'natcasesort' => $this->t('Natural (case insensitive)'), + ]; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration(): array { + return [ + 'sort_method' => 'sort', + 'token_name' => '', + ] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { + $form['sort_method'] = [ + '#type' => 'select', + '#title' => $this->t('Sort method'), + '#options' => $this->getSupportedSortMethods(), + '#default_value' => $this->configuration['sort_method'], + '#weight' => 0, + ]; + + $form['token_name'] = [ + '#type' => 'textfield', + '#title' => $this->t('Name of token'), + '#description' => $this->t('The sorted list will be loaded into this specified token. If this is not provided, the list will be sorted in-place.'), + '#default_value' => $this->configuration['token_name'], + '#weight' => 4, + ]; + + return parent::buildConfigurationForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void { + parent::submitConfigurationForm($form, $form_state); + $this->configuration['sort_method'] = $form_state->getValue('sort_method'); + $this->configuration['token_name'] = $form_state->getValue('token_name'); + } + + /** + * {@inheritdoc} + */ + public function execute(): void { + $list = $this->getItemList(); + $items = ($list instanceof DataTransferObject) ? $list->toArray() : \iterator_to_array($list); + + // Note - verbosity is intended to aid in static analysis. + switch ($this->configuration['sort_method']) { + case 'asort': + \asort($items); + break; + + case 'arsort': + \arsort($items); + break; + + case 'ksort': + \ksort($items); + break; + + case 'krsort': + \krsort($items); + break; + + case 'natsort': + \natsort($items); + break; + + case 'natcasesort': + \natcasesort($items); + break; + } + + $dest_token = trim((string) $this->configuration['token_name']); + if (!$dest_token) { + $dest_token = trim((string) $this->configuration['list_token']); + } + $this->tokenService->addTokenData($dest_token, DataTransferObject::create($items)); + } + +} diff --git a/modules/base/tests/src/Kernel/ListOperationTest.php b/modules/base/tests/src/Kernel/ListOperationTest.php index 07ddc06b9b57a6f2fae5b8bf339b94beda4e6c78..1ab1cf51c55a25756264048f526854a6e321713d 100644 --- a/modules/base/tests/src/Kernel/ListOperationTest.php +++ b/modules/base/tests/src/Kernel/ListOperationTest.php @@ -379,4 +379,75 @@ class ListOperationTest extends KernelTestBase { $this->assertNull(User::load(2)); } + /** + * Data provider for the list sort test case. + * + * @return array[] + * Test case data for in-place and copy based sorting. + */ + public function listSortProvider(): array { + return [ + 'without dest token' => [''], + 'with dest token' => ['dest_token'], + ]; + } + + /** + * Tests the "eca_list_sort" action plugin. + * + * @dataProvider listSortProvider + */ + public function testListSortDestToken(string $dest_token): void { + + $chaos = [ + 'Img12.png' => 'Img12.png', + 'img1.png' => 'img1.png', + 'img10.png' => 'img10.png', + 'Img10.png' => 'Img10.png', + 'Img2.png' => 'Img2.png', + 'img12.png' => 'img12.png', + 'img2.png' => 'img2.png', + 'Img1.png' => 'Img1.png', + ]; + + /** @var \Drupal\Core\Action\ActionManager $action_manager */ + $action_manager = \Drupal::service('plugin.manager.action'); + /** @var \Drupal\eca\Token\TokenInterface $token_services */ + $token_services = \Drupal::service('eca.token_services'); + + /** @var \Drupal\eca\Plugin\Action\ListSortBase $action */ + $action = $action_manager->createInstance('eca_list_sort', []); + + foreach (array_keys($action->getSupportedSortMethods()) as $method) { + + $action->setConfiguration([ + 'list_token' => 'list', + 'sort_method' => $method, + 'token_name' => $dest_token, + ]); + $token_services->addTokenData( + $action->getConfiguration()['list_token'], + DataTransferObject::create($chaos) + ); + + // Copy the unsorted list into a new variable, then sort it. + $expected = $chaos; + $method($expected); + + $action->execute(); + + $dest_token = trim((string) $action->getConfiguration()['token_name']); + if (!$dest_token) { + $dest_token = trim((string) $action->getConfiguration()['list_token']); + } + + $list = $token_services->getTokenData($dest_token); + + $this->assertSame($expected, $list->toArray()); + + // Reset the input token data. + $token_services->clearTokenData(); + } + } + }