[FEATURE] Fallback options for slug fields 67/59167/14
authorGuido Schmechel <guido.schmechel@brandung.de>
Sun, 16 Dec 2018 11:39:38 +0000 (12:39 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Fri, 1 Mar 2019 15:10:27 +0000 (16:10 +0100)
Now it is possible to define several fields with fallback function for
the generatorOptions fields.

Releases: master, 9.5
Resolves: #87085
Change-Id: I985f35267955dc43baaad2263ed8947c2c87b7c6
Reviewed-on: https://review.typo3.org/c/59167
Reviewed-by: Martin Kutschker <martin.kutschker@ymail.com>
Reviewed-by: André Schließer <andy.schliesser@gmail.com>
Reviewed-by: Sebastian Rosskopf <sebastian.rosskopf@gmx.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: André Schließer <andy.schliesser@gmail.com>
Tested-by: Sebastian Rosskopf <sebastian.rosskopf@gmx.de>
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/backend/Classes/Form/Element/InputSlugElement.php
typo3/sysext/core/Classes/DataHandling/SlugHelper.php
typo3/sysext/core/Documentation/Changelog/9.5.x/Feature-87085-FallbackOptionsForSlugFields.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/DataHandling/SlugHelperTest.php

index 6151dce..5cf0930 100644 (file)
@@ -166,8 +166,13 @@ class InputSlugElement extends AbstractFormElement
 
         [$commonElementPrefix] = GeneralUtility::revExplode('[', $parameterArray['itemFormElName'], 2);
         $validInputNamesToListenTo = [];
-        foreach ($config['generatorOptions']['fields'] ?? [] as $listenerFieldName) {
-            $validInputNamesToListenTo[$listenerFieldName] = $commonElementPrefix . '[' . htmlspecialchars($listenerFieldName) . ']';
+        foreach ($config['generatorOptions']['fields'] ?? [] as $fieldNameParts) {
+            if (is_string($fieldNameParts)) {
+                $fieldNameParts = GeneralUtility::trimExplode(',', $fieldNameParts);
+            }
+            foreach ($fieldNameParts as $listenerFieldName) {
+                $validInputNamesToListenTo[$listenerFieldName] = $commonElementPrefix . '[' . htmlspecialchars($listenerFieldName) . ']';
+            }
         }
         $parentPageId = $this->data['parentPageRow']['uid'] ?? 0;
         $signature = GeneralUtility::hmac(
index 2a3c37b..ed4c603 100644 (file)
@@ -182,11 +182,21 @@ class SlugHelper
         $slugParts = [];
 
         $replaceConfiguration = $this->configuration['generatorOptions']['replacements'] ?? [];
-        foreach ($this->configuration['generatorOptions']['fields'] ?? [] as $fieldName) {
-            if (!empty($recordData[$fieldName])) {
-                $pieceOfSlug = $recordData[$fieldName];
-                $pieceOfSlug = str_replace(array_keys($replaceConfiguration), array_values($replaceConfiguration), $pieceOfSlug);
-                $slugParts[] = $pieceOfSlug;
+        foreach ($this->configuration['generatorOptions']['fields'] ?? [] as $fieldNameParts) {
+            if (is_string($fieldNameParts)) {
+                $fieldNameParts = GeneralUtility::trimExplode(',', $fieldNameParts);
+            }
+            foreach ($fieldNameParts as $fieldName) {
+                if (!empty($recordData[$fieldName])) {
+                    $pieceOfSlug = $recordData[$fieldName];
+                    $pieceOfSlug = str_replace(
+                        array_keys($replaceConfiguration),
+                        array_values($replaceConfiguration),
+                        $pieceOfSlug
+                    );
+                    $slugParts[] = $pieceOfSlug;
+                    break;
+                }
             }
         }
         $slug = implode($fieldSeparator, $slugParts);
diff --git a/typo3/sysext/core/Documentation/Changelog/9.5.x/Feature-87085-FallbackOptionsForSlugFields.rst b/typo3/sysext/core/Documentation/Changelog/9.5.x/Feature-87085-FallbackOptionsForSlugFields.rst
new file mode 100644 (file)
index 0000000..0526db2
--- /dev/null
@@ -0,0 +1,57 @@
+.. include:: ../../Includes.txt
+
+==================================================
+Feature: #87085 - Fallback options for slug fields
+==================================================
+
+See :issue:`87085`
+
+Description
+===========
+
+In case of SEO optimizations and the daily work of an editor, now it is possible to define a list of fields in the slug
+configuration as nested array:
+
+
+.. code-block:: php
+   'columns' => [
+      'slug' => [
+         'config' => [
+            'generatorOptions' => [
+               'fields' => ['nav_title', 'title']
+            ]
+         ]
+      ],
+   ]
+
+The fallback field can also be combined with other fields:
+
+.. code-block:: php
+   'columns' => [
+      'slug' => [
+         'config' => [
+            'generatorOptions' => [
+               'fields' => [['nav_title', 'title'], 'other_field']
+            ]
+         ]
+      ],
+   ]
+
+Examples
+--------
+
++---------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+
+| Configuration value                                     | Values of an example page record                                                                                                     | Resulting slug                    |
++=========================================================+======================================================================================================================================+===================================+
+|:php:`['nav_title', 'title']`                            | :php:`['title' => 'Products', 'nav_title' => '', 'subtitle' => '']`                                                                  | `/products`                       |
++---------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+
+|:php:`['nav_title', 'title']`                            | :php:`['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => '']`                                                     | `/best-products`                  |
++---------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+
+|:php:`['subtitle', 'nav_title', 'title']`                | :php:`['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle']`                                     | `/product-subtitle`               |
++---------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+
+|:php:`['nav_title', 'title'], 'subtitle'`                | :php:`['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle']`                                     | `/best-products/product-subtitle` |
++---------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+
+|:php:`['seo_title', 'title'], ['nav_title', 'subtitle']` | :php:`['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle', 'seo_title' => 'SEO product title']` | `/seo-product-title/products`     |
++---------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+
+
+.. index:: TCA
index fc364ed..53d1569 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 declare(strict_types = 1);
+
 namespace TYPO3\CMS\Core\Tests\Unit\DataHandling;
 
 /*
@@ -483,4 +484,135 @@ class SlugHelperTest extends UnitTestCase
             $subject->generate(['title' => $input, 'uid' => 13], 13)
         );
     }
+
+    /**
+     * @return array
+     */
+    public function generateSlugWithNavTitleAndFallbackForPagesDataProvider(): array
+    {
+        return [
+            'title and empty nav_title' => [
+                ['title' => 'Products', 'nav_title' => '', 'subtitle' => ''],
+                '/products',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            ['nav_title', 'title']
+                        ],
+                    ],
+                ]
+            ],
+            'title and nav_title' => [
+                ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => ''],
+                '/best-products',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            ['nav_title', 'title']
+                        ],
+                    ],
+                ]
+            ],
+            'title and nav_title and subtitle' => [
+                ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
+                '/product-subtitle',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            ['subtitle', 'nav_title', 'title']
+                        ],
+                    ],
+                ]
+            ],
+            'definition with a non existing field (misconfiguration)' => [
+                ['title' => 'Products', 'nav_title' => '', 'subtitle' => ''],
+                '/products',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            ['custom_field', 'title']
+                        ],
+                    ],
+                ]
+            ],
+            'empty fields deliver default slug' => [
+                ['title' => '', 'nav_title' => '', 'subtitle' => ''],
+                '/default-b4dac929c2',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            ['nav_title', 'title']
+                        ],
+                    ],
+                ]
+            ],
+            'fallback combined with a second field' => [
+                ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
+                '/best-products/product-subtitle',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            ['nav_title', 'title'], 'subtitle'
+                        ],
+                    ],
+                ]
+            ],
+            'empty config array deliver default slug' => [
+                ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
+                '/default-e13d142b36',
+                [
+                    'generatorOptions' => [
+                        'fields' => [
+                            []
+                        ],
+                    ],
+                ]
+            ],
+            'empty config deliver default slug' => [
+                ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle'],
+                '/default-e13d142b36',
+                [
+                    'generatorOptions' => [
+                        'fields' => [],
+                    ],
+                ]
+            ],
+            'combine two fallbacks' => [
+                ['title' => 'Products', 'nav_title' => 'Best products', 'subtitle' => 'Product subtitle', 'seo_title' => 'SEO product title'],
+                '/seo-product-title/products',
+                [
+                    'generatorOptions' => [
+                        'fields' => ['seo_title', 'title'], ['nav_title', 'subtitle'],
+                    ],
+                ]
+            ],
+        ];
+    }
+
+    /**
+     * @dataProvider generateSlugWithNavTitleAndFallbackForPagesDataProvider
+     * @param array $input
+     * @param string $expected
+     * @param array $options
+     * @test
+     */
+    public function generateSlugWithNavTitleAndFallbackForPages(array $input, string $expected, array $options)
+    {
+        $GLOBALS['dummyTable']['ctrl'] = [];
+        $subject = new SlugHelper(
+            'pages',
+            'slug',
+            ['generatorOptions' => $options['generatorOptions']]
+        );
+        static::assertEquals(
+            $expected,
+            $subject->generate([
+                'title' => $input['title'],
+                'nav_title' => $input['nav_title'],
+                'subtitle' => $input['subtitle'],
+                'seo_title' => $input['seo_title'] ?? '',
+                'uid' => 13
+            ], 13)
+        );
+    }
 }