[!!!][TASK] Always store <p> tags in DB from RTE 21/47721/10
authorBenni Mack <benni@typo3.org>
Fri, 15 Apr 2016 18:57:17 +0000 (20:57 +0200)
committerBenni Mack <benni@typo3.org>
Wed, 20 Apr 2016 08:55:16 +0000 (10:55 +0200)
Twelve years ago, when the RTE was not working in
every browser, TYPO3 always stored as little
html code in the database as possible.

Now it's time to really store HTML in the database
so the custom transformations from RTE to DB
(and vice versa) and from DB to the frontend
are getting less.

This introduces less overhead and also makes
it easier to work with the content that
is stored in the database.

An upgrade wizard (coming separately) will ensure
that all existing fields will be migrated.

Resolves: #75708
Releases: master
Change-Id: I47ffb394129e6a6e5a2916616931c050f7b9b064
Reviewed-on: https://review.typo3.org/47721
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Michiel Roos <michiel@maxserv.com>
Tested-by: Michiel Roos <michiel@maxserv.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/core/Classes/Html/RteHtmlParser.php
typo3/sysext/core/Documentation/Changelog/master/Breaking-75708-AlwaysStorePTagsInDBFromRTE.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Html/RteHtmlParserTest.php

index e2316f8..ca7a146 100644 (file)
@@ -962,7 +962,7 @@ class RteHtmlParser extends HtmlParser
         if (count($divSplit) <= 1 || $count <= 0) {
             // Wrap hr tags with LF's
             $newValue = preg_replace('/<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>/i', LF . '<$1$2/>' . LF, $value);
-            $newValue = preg_replace('/' . LF . LF . '/i', LF, $newValue);
+            $newValue = str_replace(LF . LF, LF, $newValue);
             $newValue = preg_replace('/(^' . LF . ')|(' . LF . '$)/i', '', $newValue);
             return $newValue;
         }
@@ -1021,11 +1021,8 @@ class RteHtmlParser extends HtmlParser
                             }
                         }
                         // Remove any line break char (10 or 13)
-                        $subLines[$sk] = preg_replace('/' . LF . '|' . CR . '/', '', $subLines[$sk]);
-                        // If there are any attributes, then do so:
-                        if (!empty($newAttribs)) {
-                            $subLines[$sk] = '<' . trim('p ' . $this->compileTagAttribs($newAttribs)) . '>' . $subLines[$sk] . '</p>';
-                        }
+                        $subLines[$sk] = str_replace([LF, CR], '', $subLines[$sk]);
+                        $subLines[$sk] = '<' . rtrim('p ' . $this->compileTagAttribs($newAttribs)) . '>' . $subLines[$sk] . '</p>';
                     }
                 }
                 // Add the processed line(s)
@@ -1042,10 +1039,13 @@ class RteHtmlParser extends HtmlParser
                 $divSplit[$k] = trim(strip_tags($divSplit[$k], '<' . implode('><', $allowTagsOutside) . '>'));
                 // Wrap hr tags with LF's
                 $divSplit[$k] = preg_replace('/<(hr)(\\s[^>\\/]*)?[[:space:]]*\\/?>/i', LF . '<$1$2/>' . LF, $divSplit[$k]);
-                $divSplit[$k] = preg_replace('/' . LF . LF . '/i', LF, $divSplit[$k]);
+                $divSplit[$k] = str_replace(LF . LF, LF, $divSplit[$k]);
                 $divSplit[$k] = preg_replace('/(^' . LF . ')|(' . LF . '$)/i', '', $divSplit[$k]);
                 if ((string)$divSplit[$k] === '') {
                     unset($divSplit[$k]);
+                } else {
+                    // add <p> tags around the content
+                    $divSplit[$k] = str_replace(strip_tags($divSplit[$k]), '<p>' . strip_tags($divSplit[$k]) . '</p>', $divSplit[$k]);
                 }
             }
         }
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-75708-AlwaysStorePTagsInDBFromRTE.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-75708-AlwaysStorePTagsInDBFromRTE.rst
new file mode 100644 (file)
index 0000000..0a8f553
--- /dev/null
@@ -0,0 +1,31 @@
+=======================================================
+Breaking: #75708 - Always store <p> tags in DB from RTE
+=======================================================
+
+Description
+===========
+
+When transforming HTML data from the Rich Text Editor to the database, the RteHtmlParser removed <p> tags from
+lines where there were no attributes for the <p> tags, otherwise they were kept as <p> tags with
+their attributes.
+
+The transformation now always keeps <p> tags within the content in order to minimize the transformation overhead
+between the RTE and the database.
+
+
+Impact
+======
+
+Every time an RTE field is edited, the <p> are now stored inside the database when saving the content.
+
+
+Affected Installations
+======================
+
+All installations using RTE fields or RteHtmlParser transformations.
+
+
+Migration
+=========
+
+An upgrade wizard inside the Install Tool (coming until 8.1) will make sure that any database RTE field is converted.
\ No newline at end of file
index d018fee..5e56163 100644 (file)
@@ -87,7 +87,11 @@ class RteHtmlParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             ),
             'Paragraph followed by linebreak and hr' => array(
                 '<p>Some text</p>' . CRLF . '<hr />',
-                'Some text' . CRLF . '<hr />',
+                '<p>Some text</p>' . CRLF . '<hr />',
+            ),
+            'Some text without HTML tags' => array(
+                'Some text',
+                'Some text',
             ),
             'Some text followed by hr' => array(
                 'Some text<hr />',
@@ -256,79 +260,79 @@ class RteHtmlParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             ),
             'Paragraph' => array(
                 '<p>paragraph</p>',
-                'paragraph',
+                '<p>paragraph</p>',
             ),
             'Paragraph followed by paragraph' => array(
                 '<p>paragraph1</p>' . '<p>paragraph2</p>',
-                'paragraph1' . CRLF . 'paragraph2',
+                '<p>paragraph1</p>' . CRLF . '<p>paragraph2</p>',
             ),
             'Paragraph followed by paragraph, linebreak-separated' => array(
                 '<p>paragraph1</p>' . CRLF . '<p>paragraph2</p>',
-                'paragraph1' . CRLF . 'paragraph2',
+                '<p>paragraph1</p>' . CRLF . '<p>paragraph2</p>',
             ),
             'Double spacing paragraph with text' => array(
                 '<p>&nbsp;</p><p>&nbsp;</p><p>paragraph1</p>',
-                CRLF . CRLF . 'paragraph1',
+                CRLF . CRLF . '<p>paragraph1</p>',
             ),
             'Paragraph followed by linebreak' => array(
                 '<p>paragraph</p>' . CRLF,
-                'paragraph',
+                '<p>paragraph</p>',
             ),
             'Paragraph followed by spacing paragraph' => array(
                 '<p>paragraph</p>' . '<p>&nbsp;</p>',
-                'paragraph' . CRLF . CRLF,
+                '<p>paragraph</p>' . CRLF . CRLF,
             ),
             'Paragraph followed by spacing paragraph, linebreak-separated' => array(
                 '<p>paragraph</p>' . CRLF . '<p>&nbsp;</p>',
-                'paragraph' . CRLF . CRLF,
+                '<p>paragraph</p>' . CRLF . CRLF,
             ),
             'Paragraph followed by double spacing paragraph' => array(
                 '<p>paragraph</p>' . '<p>&nbsp;</p>' . '<p>&nbsp;</p>',
-                'paragraph' . CRLF . CRLF . CRLF,
+                '<p>paragraph</p>' . CRLF . CRLF . CRLF,
             ),
             'Paragraph followed by double spacing paragraph, linebreak-separated' => array(
                 '<p>paragraph</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<p>&nbsp;</p>',
-                'paragraph' . CRLF . CRLF . CRLF,
+                '<p>paragraph</p>' . CRLF . CRLF . CRLF,
             ),
             'Paragraph followed by spacing paragraph and by paragraph' => array(
                 '<p>paragraph1</p>' . '<p>&nbsp;</p>' . '<p>paragraph2</p>',
-                'paragraph1' . CRLF . CRLF . 'paragraph2',
+                '<p>paragraph1</p>' . CRLF . CRLF . '<p>paragraph2</p>',
             ),
             'Paragraph followed by spacing paragraph and by paragraph, linebreak-separated' => array(
                 '<p>paragraph1</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<p>paragraph2</p>',
-                'paragraph1' . CRLF . CRLF . 'paragraph2',
+                '<p>paragraph1</p>' . CRLF . CRLF . '<p>paragraph2</p>',
             ),
             'Paragraph followed by double spacing paragraph and by paragraph' => array(
                 '<p>paragraph1</p>' . '<p>&nbsp;</p>' . '<p>&nbsp;</p>' . '<p>paragraph2</p>',
-                'paragraph1' . CRLF . CRLF . CRLF . 'paragraph2',
+                '<p>paragraph1</p>' . CRLF . CRLF . CRLF . '<p>paragraph2</p>',
             ),
             'Paragraph followed by double spacing paragraph and by paragraph, linebreak-separated' => array(
                 '<p>paragraph1</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<p>paragraph2</p>',
-                'paragraph1' . CRLF . CRLF . CRLF . 'paragraph2',
+                '<p>paragraph1</p>' . CRLF . CRLF . CRLF . '<p>paragraph2</p>',
             ),
             'Paragraph followed by block' => array(
                 '<p>paragraph</p>' . '<h1>block</h1>',
-                'paragraph' . CRLF . '<h1>block</h1>',
+                '<p>paragraph</p>' . CRLF . '<h1>block</h1>',
             ),
             'Paragraph followed by block, linebreak-separated' => array(
                 '<p>paragraph</p>' . CRLF . '<h1>block</h1>',
-                'paragraph' . CRLF . '<h1>block</h1>',
+                '<p>paragraph</p>' . CRLF . '<h1>block</h1>',
             ),
             'Paragraph followed by spacing paragraph and block' => array(
                 '<p>paragraph</p>' . '<p>&nbsp;</p>' . '<h1>block</h1>',
-                'paragraph' . CRLF . CRLF . '<h1>block</h1>',
+                '<p>paragraph</p>' . CRLF . CRLF . '<h1>block</h1>',
             ),
             'Paragraph followed by spacing paragraph and block, linebreak-separated' => array(
                 '<p>paragraph</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<h1>block</h1>',
-                'paragraph' . CRLF . CRLF . '<h1>block</h1>',
+                '<p>paragraph</p>' . CRLF . CRLF . '<h1>block</h1>',
             ),
             'Paragraph followed by double spacing paragraph and block' => array(
                 '<p>paragraph</p>' . '<p>&nbsp;</p>' . '<p>&nbsp;</p>' . '<h1>block</h1>',
-                'paragraph' . CRLF . CRLF . CRLF . '<h1>block</h1>',
+                '<p>paragraph</p>' . CRLF . CRLF . CRLF . '<h1>block</h1>',
             ),
             'Paragraph followed by double spacing paragraph and block, linebreak-separated' => array(
                 '<p>paragraph</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<h1>block</h1>',
-                'paragraph' . CRLF . CRLF . CRLF . '<h1>block</h1>',
+                '<p>paragraph</p>' . CRLF . CRLF . CRLF . '<h1>block</h1>',
             ),
             'Block followed by block' => array(
                 '<h1>block1</h1>' . '<h1>block2</h1>',
@@ -372,19 +376,19 @@ class RteHtmlParserTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
             ),
             'Block followed by paragraph and block' => array(
                 '<h1>block1</h1>' . '<p>paragraph</p>' . '<h1>block2</h1>',
-                '<h1>block1</h1>' . CRLF . 'paragraph' . CRLF . '<h1>block2</h1>',
+                '<h1>block1</h1>' . CRLF . '<p>paragraph</p>' . CRLF . '<h1>block2</h1>',
             ),
             'Block followed by paragraph and block, linebreak-separated' => array(
                 '<h1>block1</h1>' . CRLF . '<p>paragraph</p>' . CRLF . '<h1>block2</h1>',
-                '<h1>block1</h1>' . CRLF . 'paragraph' . CRLF . '<h1>block2</h1>',
+                '<h1>block1</h1>' . CRLF . '<p>paragraph</p>' . CRLF . '<h1>block2</h1>',
             ),
             'Block followed by paragraph, spacing paragraph and block' => array(
                 '<h1>block1</h1>' . '<p>paragraph</p>' . '<p>&nbsp;</p>' . '<h1>block2</h1>',
-                '<h1>block1</h1>' . CRLF . 'paragraph' . CRLF . CRLF . '<h1>block2</h1>',
+                '<h1>block1</h1>' . CRLF . '<p>paragraph</p>' . CRLF . CRLF . '<h1>block2</h1>',
             ),
             'Block followed by paragraph, spacing paragraph and block, linebreak-separated' => array(
                 '<h1>block1</h1>' . CRLF . '<p>paragraph</p>' . CRLF . '<p>&nbsp;</p>' . CRLF . '<h1>block2</h1>',
-                '<h1>block1</h1>' . CRLF . 'paragraph' . CRLF . CRLF . '<h1>block2</h1>',
+                '<h1>block1</h1>' . CRLF . '<p>paragraph</p>' . CRLF . CRLF . '<h1>block2</h1>',
             ),
         );
     }