f193df00875eb079dd5c07ee8a2de1ef56765d12
[Packages/TYPO3.CMS.git] / typo3 / sysext / rtehtmlarea / Classes / Hook / Install / DeprecatedRteProperties.php
1 <?php
2 namespace TYPO3\CMS\Rtehtmlarea\Hook\Install;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Install\Updates\AbstractUpdate;
18
19 /**
20 * Contains the update class for the replacement of deprecated RTE properties in Page TSconfig.
21 * Used by the upgrade wizard in the install tool.
22 *
23 * @author Stanislas Rolland <typo3@sjbr.ca>
24 */
25 class DeprecatedRteProperties extends AbstractUpdate {
26
27 /**
28 * @var string
29 */
30 protected $title = 'Deprecated RTE properties in Page TSconfig';
31
32 /**
33 * Properties that may be replaced automatically in Page TSconfig (except inludes from external files)
34 * Syntax: 'oldProperty' => 'newProperty'
35 *
36 * @var array
37 */
38 protected $replacementRteProperties = array(
39 'disableRightClick' => 'contextMenu.disable',
40 'disableContextMenu' => 'contextMenu.disable',
41 'hidePStyleItems' => 'buttons.formatblock.removeItems',
42 'hideFontFaces' => 'buttons.fontstyle.removeItems',
43 'fontFace' => 'buttons.fontstyle.addItems',
44 'hideFontSizes' => 'buttons.fontsize.removeItems',
45 'classesCharacter' => 'buttons.textstyle.tags.span.allowedClasses',
46 'classesParagraph' => 'buttons.blockstyle.tags.div.allowedClasses',
47 'classesTable' => 'buttons.blockstyle.tags.table.allowedClasses',
48 'classesTD' => 'buttons.blockstyle.tags.td.allowedClasses',
49 'classesImage' => 'buttons.image.properties.class.allowedClasses',
50 'classesLinks' => 'buttons.link.properties.class.allowedClasses',
51 'blindImageOptions' => 'buttons.image.options.removeItems',
52 'blindLinkOptions' => 'buttons.link.options.removeItems',
53 'defaultLinkTarget' => 'buttons.link.properties.target.default'
54 );
55
56 /**
57 * Properties that may be replaced automatically in Page TSconfig (except inludes from external files)
58 * Syntax: 'oldProperty' => [ 'newProperty', 'newProperty' ]
59 *
60 * @var array
61 */
62 protected $doubleReplacementRteProperties = array(
63 'disableTYPO3Browsers' => array(
64 'buttons.image.TYPO3Browser.disabled',
65 'buttons.link.TYPO3Browser.disabled'
66 ),
67 'showTagFreeClasses' => array(
68 'buttons.blockstyle.showTagFreeClasses',
69 'buttons.textstyle.showTagFreeClasses'
70 ),
71 'disablePCexamples' => array(
72 'buttons.blockstyle.disableStyleOnOptionLabel',
73 'buttons.textstyle.disableStyleOnOptionLabel'
74 )
75 );
76
77 /**
78 * Properties that may not be replaced automatically in Page TSconfig
79 * Syntax: 'oldProperty' => 'newProperty'
80 *
81 * @var array
82 */
83 protected $useInsteadRteProperties = array(
84 'fontSize' => 'buttons.fontsize.addItems',
85 'RTE.default.classesAnchor' => 'RTE.default.buttons.link.properties.class.allowedClasses',
86 'RTE.default.classesAnchor.default.[link-type]' => 'RTE.default.buttons.link.[link-type].properties.class.default',
87 'mainStyleOverride' => 'contentCSS',
88 'mainStyleOverride_add.[key]' => 'contentCSS',
89 'mainStyle_font' => 'contentCSS',
90 'mainStyle_size' => 'contentCSS',
91 'mainStyle_color' => 'contentCSS',
92 'mainStyle_bgcolor' => 'contentCSS',
93 'inlineStyle.[any-keystring]' => 'contentCSS',
94 'ignoreMainStyleOverride' => 'n.a.'
95 );
96
97 /**
98 * Function which checks if update is needed. Called in the beginning of an update process.
99 *
100 * @param string $description Pointer to description for the update
101 * @return bool TRUE if update is needs to be performed, FALSE otherwise.
102 */
103 public function checkForUpdate(&$description) {
104 $result = FALSE;
105
106 $pages = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
107 $pagesCount = count($pages);
108 $deprecatedProperties = '';
109 $deprecatedRteProperties = array_merge($this->replacementRteProperties, $this->useInsteadRteProperties);
110 foreach ($deprecatedRteProperties as $deprecatedProperty => $replacementProperty) {
111 $deprecatedProperties .= '<tr><td>' . $deprecatedProperty . '</td><td>' . $replacementProperty . '</td></tr>' . LF;
112 }
113 foreach ($this->doubleReplacementRteProperties as $deprecatedProperty => $replacementProperties) {
114 $deprecatedProperties .= '<tr><td>' . $deprecatedProperty . '</td><td>' . implode(' and ', $replacementProperties) . '</td></tr>' . LF;
115 }
116 $description = '<p>The following Page TSconfig RTE properties are deprecated since TYPO3 4.6 and have been removed in TYPO3 6.0.</p>' . LF . '<table><thead><tr><th>Deprecated property</th><th>Use instead</th></tr></thead>' . LF . '<tbody>' . $deprecatedProperties . '</tboby></table>' . LF . '<p>You are currently using some of these properties on <strong>' . strval($pagesCount) . '&nbsp;pages</strong> (including deleted and hidden pages).</p>' . LF;
117 if ($pagesCount) {
118 $pagesUids = array();
119 foreach ($pages as $page) {
120 $pagesUids[] = $page['uid'];
121 }
122 $description .= '<p>Pages id\'s: ' . implode(', ', $pagesUids) . '</p>';
123 }
124 $replacementProperties = '';
125 foreach ($this->useInsteadRteProperties as $deprecatedProperty => $replacementProperty) {
126 $replacementProperties .= '<tr><td>' . $deprecatedProperty . '</td><td>' . $replacementProperty . '</td></tr>' . LF;
127 }
128 if ($pagesCount) {
129 $updateablePages = $this->findUpdateablePagesWithDeprecatedRteProperties($pages);
130 if (count($updateablePages)) {
131 $replacementProperties = '';
132 foreach ($this->replacementRteProperties as $deprecatedProperty => $replacementProperty) {
133 $replacementProperties .= '<tr><td>' . $deprecatedProperty . '</td><td>' . $replacementProperty . '</td></tr>' . LF;
134 }
135 $description .= '<p>This wizard will perform automatic replacement of the following properties on <strong>' . strval(count($updateablePages)) . '&nbsp;pages</strong> (including deleted and hidden):</p>' . LF . '<table><thead><tr><th>Deprecated property</th><th>Will be replaced by</th></tr></thead><tbody>' . $replacementProperties . '</tboby></table>' . LF . '<p>The Page TSconfig column of the remaining pages will need to be updated manually.</p>' . LF;
136 } else {
137 $replacementProperties = '';
138 foreach ($this->useInsteadRteProperties as $deprecatedProperty => $_) {
139 $replacementProperties .= '<tr><td>' . $deprecatedProperty . '</td></tr>' . LF;
140 }
141 foreach ($this->doubleReplacementRteProperties as $deprecatedProperty => $_) {
142 $replacementProperties .= '<tr><td>' . $deprecatedProperty . '</td></tr>' . LF;
143 }
144 $description .= '<p>This wizard cannot update the following properties, some of which are present on those pages:</p>' . LF . '<table><thead><tr><th>Deprecated property</th></tr></thead><tbody>' . $replacementProperties . '</tboby></table>' . LF . '<p>Therefore, the Page TSconfig column of those pages will need to be updated manually.</p>' . LF;
145 }
146 $result = TRUE;
147 } else {
148 // if we found no occurrence of deprecated settings and wizard was already executed, then
149 // we do not show up anymore
150 if ($this->isWizardDone()) {
151 $result = FALSE;
152 }
153 }
154 $description .= '<p>Only page records are searched for deprecated properties. However, such properties can also be used in BE group and BE user records (prepended with page.). These are not searched nor updated by this wizard.</p>' . LF . '<p>Page TSconfig may also be included from external files. These are not updated by this wizard. If required, the update will need to be done manually.</p>' . LF . '<p>Note also that deprecated properties have been replaced in default configurations provided by htmlArea RTE';
155
156 return $result;
157 }
158
159 /**
160 * Performs the update itself
161 *
162 * @param array $dbQueries Pointer where to insert all DB queries made, so they can be shown to the user if wanted
163 * @param string $customMessages Pointer to output custom messages
164 * @return bool TRUE if update succeeded, FALSE otherwise
165 */
166 public function performUpdate(array &$dbQueries, &$customMessages) {
167 $customMessages = '';
168 $pages = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
169 if (empty($customMessages)) {
170 $pagesCount = count($pages);
171 if ($pagesCount) {
172 $updateablePages = $this->findUpdateablePagesWithDeprecatedRteProperties($pages);
173 if (count($updateablePages)) {
174 $this->updatePages($updateablePages, $dbQueries, $customMessages);
175 // If the update was successful
176 if (empty($customMessages)) {
177 // If all pages were updated, we query again to check if any deprecated properties are still present.
178 if (count($updateablePages) === $pagesCount) {
179 $pagesAfter = $this->getPagesWithDeprecatedRteProperties($dbQueries, $customMessages);
180 if (empty($customMessages)) {
181 if (count($pagesAfter)) {
182 $customMessages = 'Some deprecated Page TSconfig properties were found. However, the wizard was unable to automatically replace all the deprecated properties found. Some properties will have to be replaced manually.';
183 }
184 }
185 } else {
186 $customMessages = 'Some deprecated Page TSconfig properties were found. However, the wizard was unable to automatically replace all the deprecated properties found. Some properties will have to be replaced manually.';
187 }
188 }
189 } else {
190 $customMessages = 'Some deprecated Page TSconfig properties were found. However, the wizard was unable to automatically replace any of the deprecated properties found. These properties will have to be replaced manually.';
191 }
192 }
193 }
194 $this->markWizardAsDone();
195 return empty($customMessages);
196 }
197
198 /**
199 * Gets the pages with deprecated RTE properties in TSConfig column
200 *
201 * @param array $dbQueries Pointer where to insert all DB queries made, so they can be shown to the user if wanted
202 * @param string $customMessages Pointer to output custom messages
203 * @return array uid and inclusion string for the pages with deprecated RTE properties in TSConfig column
204 */
205 protected function getPagesWithDeprecatedRteProperties(&$dbQueries, &$customMessages) {
206 $fields = 'uid, TSconfig';
207 $table = 'pages';
208 $where = '';
209 $db = $this->getDatabaseConnection();
210 foreach (array_merge($this->replacementRteProperties, $this->useInsteadRteProperties, $this->doubleReplacementRteProperties) as $deprecatedRteProperty => $_) {
211 $where .= ($where ? ' OR ' : '') . '(TSConfig LIKE BINARY ' . $db->fullQuoteStr('%RTE.%' . $deprecatedRteProperty . '%', 'pages') . ' AND TSConfig NOT LIKE BINARY ' . $db->fullQuoteStr('%RTE.%' . $deprecatedRteProperty . 's%', 'pages') . ')' . LF;
212 }
213 $res = $db->exec_SELECTquery($fields, $table, $where);
214 $dbQueries[] = str_replace(LF, ' ', $db->debug_lastBuiltQuery);
215 if ($db->sql_error()) {
216 $customMessages = 'SQL-ERROR: ' . htmlspecialchars($db->sql_error());
217 }
218 $pages = array();
219 while ($row = $db->sql_fetch_assoc($res)) {
220 $pages[] = $row;
221 }
222 return $pages;
223 }
224
225 /**
226 * Gets the pages with updateable deprecated RTE properties in TSConfig column
227 *
228 * @param array $pages reference to pages with deprecated property
229 * @return array uid and inclusion string for the pages with deprecated RTE properties in TSConfig column
230 */
231 protected function findUpdateablePagesWithDeprecatedRteProperties(&$pages) {
232 foreach ($pages as $index => $page) {
233 $deprecatedProperties = explode(',', '/' . implode('/,/((RTE\\.(default\\.|config\\.[a-zA-Z0-9_\\-]*\\.[a-zA-Z0-9_\\-]*\\.))|\\s)', array_keys($this->replacementRteProperties)) . '/');
234 $replacementProperties = explode(',', '$1' . implode(',$1', array_values($this->replacementRteProperties)));
235 $updatedPageTSConfig = preg_replace($deprecatedProperties, $replacementProperties, $page['TSconfig']);
236 if ($updatedPageTSConfig == $page['TSconfig']) {
237 unset($pages[$index]);
238 } else {
239 $pages[$index]['TSconfig'] = $updatedPageTSConfig;
240 }
241 }
242 return $pages;
243 }
244
245 /**
246 * updates the pages records with updateable Page TSconfig properties
247 *
248 * @param array $pages Page records to update, fetched by getTemplates() and filtered by
249 * @param array $dbQueries Pointer where to insert all DB queries made, so they can be shown to the user if wanted
250 * @param string $customMessages Pointer to output custom messages
251 */
252 protected function updatePages($pages, &$dbQueries, &$customMessages) {
253 $db = $this->getDatabaseConnection();
254 foreach ($pages as $page) {
255 $table = 'pages';
256 $where = 'uid =' . $page['uid'];
257 $field_values = array(
258 'TSconfig' => $page['TSconfig']
259 );
260 $db->exec_UPDATEquery($table, $where, $field_values);
261 $dbQueries[] = str_replace(LF, ' ', $db->debug_lastBuiltQuery);
262 if ($db->sql_error()) {
263 $customMessages .= 'SQL-ERROR: ' . htmlspecialchars($db->sql_error()) . LF . LF;
264 }
265 }
266 }
267
268 }