|
TYPO3 API
SVNRelease
|
00001 <?php 00002 /*************************************************************** 00003 * Copyright notice 00004 * 00005 * (c) 2010 Xavier Perseguers <typo3@perseguers.ch> 00006 * All rights reserved 00007 * 00008 * This script is part of the TYPO3 project. The TYPO3 project is 00009 * free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * The GNU General Public License can be found at 00015 * http://www.gnu.org/copyleft/gpl.html. 00016 * A copy is found in the textfile GPL.txt and important notices to the license 00017 * from the author is found in LICENSE.txt distributed with these scripts. 00018 * 00019 * 00020 * This script is distributed in the hope that it will be useful, 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00023 * GNU General Public License for more details. 00024 * 00025 * This copyright notice MUST APPEAR in all copies of the script! 00026 ***************************************************************/ 00027 00028 /** 00029 * Hooks for TYPO3 Extension Manager. 00030 * 00031 * $Id: class.tx_dbal_em.php 40828 2010-12-05 14:55:53Z xperseguers $ 00032 * 00033 * @author Xavier Perseguers <typo3@perseguers.ch> 00034 * 00035 * @package TYPO3 00036 * @subpackage dbal 00037 */ 00038 class tx_dbal_em implements tx_em_Index_CheckDatabaseUpdatesHook { 00039 00040 /** 00041 * Maximal length for an identifier in Oracle. 00042 * 00043 * @var integer 00044 */ 00045 protected $maxIdentifierLength = 30; 00046 00047 /** 00048 * Table names should be short enough in order to let ADOdb generates 00049 * the corresponding sequence for the auto-increment field 'uid'. 00050 * That is, a sequence of the form {table}_uid 00051 * 00052 * @var integer 00053 */ 00054 protected $tableNameCharacterReservation = 4; 00055 00056 /** 00057 * Mapping of table and field names. 00058 * 00059 * @var array 00060 */ 00061 protected $mapping; 00062 00063 /** 00064 * Initializes internal variables. 00065 * 00066 * @return void 00067 */ 00068 protected function init() { 00069 $mapping = @$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping']; 00070 if (!$mapping) { 00071 $mapping = array(); 00072 } 00073 $this->mapping = $mapping; 00074 } 00075 00076 /** 00077 * Hook that allows pre-processing of database structure modifications. 00078 * This returns a user form that will temporarily replace the standard 00079 * database update form to let user configure mapping. 00080 * 00081 * @param string $extKey: Extension key 00082 * @param array $extInfo: Extension information array 00083 * @param array $diff: Database differences 00084 * @param t3lib_install $instObj: Instance of the installer 00085 * @param SC_mod_tools_em_index $parent: The calling parent object 00086 * @return string Either empty string or a pre-processing user form 00087 */ 00088 public function preProcessDatabaseUpdates($extKey, array $extInfo, array $diff, t3lib_install $instObj, SC_mod_tools_em_index $parent) { 00089 $content = ''; 00090 00091 // Remapping is only mandatory for Oracle: 00092 if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['type'] !== 'adodb' 00093 && $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driver'] !== 'oci8') { 00094 00095 // Not using Oracle 00096 return ''; 00097 } 00098 00099 $this->init(); 00100 00101 if (t3lib_div::GPvar('dbal')) { 00102 $this->updateMapping(t3lib_div::GPvar('dbal'), $instObj); 00103 } 00104 00105 // Search all table and field names which should be remapped 00106 $tableCandidates = array(); 00107 $fieldsCandidates = array(); 00108 foreach ($diff['extra'] as $table => $config) { 00109 if ($this->needsMapping($table)) { 00110 $tableCandidates[] = $table; 00111 } 00112 foreach ($config['fields'] as $field => $type) { 00113 if ($this->needsMapping($table, $field)) { 00114 if (!isset($fieldsCandidates[$table])) { 00115 $fieldsCandidates[$table] = array(); 00116 } 00117 $fieldsCandidates[$table][$field] = array( 00118 'fullName' => $field, 00119 ); 00120 } 00121 00122 } 00123 00124 /* 00125 if (!isset($config['keys'])) { 00126 continue; // Process next table 00127 } 00128 00129 foreach ($config['keys'] as $field => $def) { 00130 if ($field !== 'PRIMARY' && $this->needsMapping($table, $field, TRUE)) { 00131 if (!t3lib_div::inArray($tableCandidates, $table)) { 00132 $tableCandidates[] = $table; 00133 } 00134 if (!isset($fieldsCandidates[$table])) { 00135 $fieldsCandidates[$table] = array(); 00136 } 00137 $fieldsCandidates[$table][$field] = array( 00138 'fullName' => $table . '_' . $field, 00139 ); 00140 } 00141 } 00142 */ 00143 } 00144 00145 if ($tableCandidates || $fieldsCandidates) { 00146 $mappingSuggestions = $this->getMappingSuggestions($extKey, $extInfo, $tableCandidates, $fieldsCandidates); 00147 $content .= $this->generateMappingForm($tableCandidates, $fieldsCandidates, $mappingSuggestions); 00148 } 00149 00150 return $content; 00151 } 00152 00153 /** 00154 * Returns TRUE if either the table or the field name should be remapped. 00155 * 00156 * @param string $table 00157 * @param string $field 00158 * @param boolean $isKeyField 00159 * @return boolean TRUE if mapping is needed, otherwise FALSE 00160 */ 00161 protected function needsMapping($table, $field = '', $isKeyField = FALSE) { 00162 $needsRemapping = FALSE; 00163 00164 // Take existing DBAL mapping into account 00165 $origTable = $table; 00166 if (isset($this->mapping[$origTable])) { 00167 if (isset($this->mapping[$origTable]['mapTableName'])) { 00168 $table = $this->mapping[$origTable]['mapTableName']; 00169 } 00170 if ($field !== '' && isset($this->mapping[$origTable]['mapFieldNames'])) { 00171 if (isset($this->mapping[$origTable]['mapFieldNames'][$field])) { 00172 $field = $this->mapping[$origTable]['mapFieldNames'][$field]; 00173 } 00174 } 00175 } 00176 00177 if ($field === '') { 00178 if (substr($table, -3) === '_mm') { 00179 $needsRemapping = strlen($table) > $this->maxIdentifierLength; 00180 } else { 00181 $needsRemapping = strlen($table) > $this->maxIdentifierLength - $this->tableNameCharacterReservation; 00182 } 00183 } elseif (!$isKeyField) { 00184 $needsRemapping = strlen($field) > $this->maxIdentifierLength; 00185 } else { 00186 $needsRemapping = strlen($table . '_' . $field) > $this->maxIdentifierLength; 00187 } 00188 00189 return $needsRemapping; 00190 } 00191 00192 /** 00193 * Returns suggestions for the mapping of table/field names. 00194 * 00195 * @param string $extKey 00196 * @param array $extInfo 00197 * @param array $tables 00198 * @param array $fields 00199 * @return array 00200 * @api 00201 */ 00202 public function getMappingSuggestions($extKey, array $extInfo, array $tables, array $fields) { 00203 $suggestions = array(); 00204 switch ($extKey) { 00205 case 'direct_mail': 00206 $suggestions['sys_dmail_ttaddress_category_mm'] = array( 00207 'mapTableName' => 'sys_dmail_ttaddress_cat_mm', 00208 ); 00209 $suggestions['sys_dmail_ttcontent_category_mm'] = array( 00210 'mapTableName' => 'sys_dmail_ttcontent_cat_mm', 00211 ); 00212 break; 00213 case 'extbase': 00214 $suggestions['tx_extbase_cache_reflection_tags'] = array( 00215 'mapTableName' => 'tx_extbase_cache_reflect_tags', 00216 ); 00217 break; 00218 case 'templavoila': 00219 $suggestions['tx_templavoila_datastructure'] = array( 00220 'mapTableName' => 'tx_templavoila_ds', 00221 ); 00222 $suggestions['tx_templavoila_tmplobj'] = array( 00223 'mapTableName' => 'tx_templavoila_tmpl', 00224 ); 00225 break; 00226 default: 00227 $dependencies = array_keys($extInfo['EM_CONF']['constraints']['depends']); 00228 if (t3lib_div::inArray($dependencies, 'extbase')) { 00229 $this->storeExtbaseMappingSuggestions($suggestions, $extKey, $extInfo, $tables, $fields); 00230 } 00231 } 00232 00233 // Existing mapping take precedence over suggestions 00234 $suggestions = t3lib_div::array_merge_recursive_overrule($suggestions, $this->mapping); 00235 00236 return $suggestions; 00237 } 00238 00239 /** 00240 * Stores suggestions for the mapping of table/field names for an Extbase-based extension. 00241 * 00242 * @param array &$suggestions 00243 * @param string $extKey 00244 * @param array $extInfo 00245 * @param array $tables 00246 * @param array $fields 00247 * @return void 00248 */ 00249 protected function storeExtbaseMappingSuggestions(array &$suggestions, $extKey, array $extInfo, array $tables, array $fields) { 00250 foreach ($tables as $table) { 00251 // Remove the "domain_model" part of the table name 00252 $suggestions[$table] = array( 00253 'mapTableName' => str_replace('domain_model_', '', $table), 00254 ); 00255 } 00256 } 00257 00258 /** 00259 * Generates a mapping form. 00260 * 00261 * @param array $tables 00262 * @param array $fields 00263 * @param array $suggestions 00264 * @return string 00265 */ 00266 protected function generateMappingForm(array $tables, array $fields, array $suggestions) { 00267 $out = array(); 00268 $tableId = uniqid('table'); 00269 $label = 'DBAL Mapping'; 00270 $description = sprintf('Some table names are longer than %s characters and/or some field names are longer than %s characters.' 00271 . ' This is incompatible with your database:' 00272 . ' <ul style="list-style: square; margin: 3px 1em; padding: 3px 1em;">' 00273 . ' <li>Table names should be short enough to let ADOdb generates a sequence of the form {table}_uid for the' 00274 . ' auto-increment "uid" field within %s characters;</li>' 00275 . ' <li>Field names may not contain more than %s characters.</li>' 00276 . ' </ul>', 00277 $this->maxIdentifierLength - $this->tableNameCharacterReservation, 00278 $this->maxIdentifierLength, 00279 $this->maxIdentifierLength, 00280 $this->maxIdentifierLength 00281 ); 00282 00283 $tables = array_unique(array_merge($tables, array_keys($fields))); 00284 foreach ($tables as $table) { 00285 $newTableName = $table; 00286 if (isset($suggestions[$table]) && isset($suggestions[$table]['mapTableName'])) { 00287 $newTableName = $suggestions[$table]['mapTableName']; 00288 } 00289 $out[] = ' 00290 <tr> 00291 <td style="padding-top: 1em;"><label for="table-' . $table . '">' . $table . '</label></td> 00292 <td style="padding-top: 1em;">=></td> 00293 <td style="padding-top: 1em;"><input type="text" size="35" id="table-' . $table . '" name="dbal[tables][' . $table . ']" value="' . $newTableName . '" /> ' 00294 . strlen($newTableName) . ' characters' 00295 . '</td> 00296 </tr>'; 00297 00298 if (isset($fields[$table])) { 00299 foreach ($fields[$table] as $field => $info) { 00300 $newFieldName = $field; 00301 if (isset($suggestions[$table]) && isset($suggestions[$table]['mapFieldNames'])) { 00302 if (isset($suggestions[$table]['mapFieldNames'][$field])) { 00303 $newFieldName = $suggestions[$table]['mapFieldNames'][$field]; 00304 } 00305 } 00306 $newFieldFullName = preg_replace('/^' . $table . '/', $newTableName, $info['fullName']); 00307 $newFieldFullName = preg_replace('/' . $field . '$/', $newFieldName, $newFieldFullName); 00308 $out[] = ' 00309 <tr> 00310 <td> <label for="field-' . $table . '_' . $field . '">' . $field . '</label></td> 00311 <td>=></td> 00312 <td><input type="text" size="35" id="field-' . $table . '_' . $field . '" name="dbal[fields][' . $table . '][' . $field . ']" value="' . $newFieldName . '" /> ' 00313 . ($info['fullname'] !== $field ? strlen($newFieldFullName) . ' characters: ' . $newFieldFullName : '') 00314 . '</td> 00315 </tr>'; 00316 } 00317 } 00318 } 00319 00320 // Compile rows: 00321 $content = ' 00322 <!-- Remapping database fields / tables --> 00323 <h3>' . $label . '</h3> 00324 <p>' . $description . '</p> 00325 <table border="0" cellpadding="2" cellspacing="2" id="' . $tableId . '" class="remap-db-table-fields">' . implode('', $out) . ' 00326 </table>'; 00327 00328 return $content; 00329 } 00330 00331 /** 00332 * Updates the mapping in localconf.php according to form input values. 00333 * 00334 * @param array $data 00335 * @param t3lib_install $instObj 00336 * @return void 00337 * @api 00338 */ 00339 public function updateMapping(array $data, t3lib_install $instObj) { 00340 $newMapping = $this->mapping; 00341 00342 foreach ($data['tables'] as $table => $newName) { 00343 $newName = trim($newName); 00344 if ($newName && $newName !== $table) { 00345 if (!isset($newMapping[$table])) { 00346 $newMapping[$table] = array(); 00347 } 00348 $newMapping[$table]['mapTableName'] = $newName; 00349 } 00350 if (isset($data['fields'][$table])) { 00351 foreach ($data['fields'][$table] as $field => $newName) { 00352 $newName = trim($newName); 00353 if ($newName && $newName !== $field) { 00354 if (!isset($newMapping[$table])) { 00355 $newMapping[$table] = array(); 00356 } 00357 if (!isset($newMapping[$table]['mapFieldNames'])) { 00358 $newMapping[$table]['mapFieldNames'] = array(); 00359 } 00360 $newMapping[$table]['mapFieldNames'][$field] = $newName; 00361 } 00362 } 00363 } 00364 } 00365 00366 // Sort table and field names 00367 foreach ($newMapping as $table => &$config) { 00368 if (isset($config['mapFieldNames'])) { 00369 ksort($config['mapFieldNames']); 00370 } 00371 } 00372 ksort($newMapping); 00373 00374 // Write new mapping to localconf.php 00375 $key = '$TYPO3_CONF_VARS[\'EXTCONF\'][\'dbal\'][\'mapping\']'; 00376 $instObj->allowUpdateLocalConf = 1; 00377 $instObj->updateIdentity = 'TYPO3 Extension Manager'; 00378 $lines = $instObj->writeToLocalconf_control(); 00379 $instObj->setArrayValueInLocalconfFile($lines, $key, $newMapping); 00380 00381 if ($instObj->writeToLocalconf($lines)) { 00382 $this->mapping = $newMapping; 00383 } 00384 } 00385 00386 } 00387 00388 00389 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.tx_dbal_em.php'])) { 00390 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.tx_dbal_em.php']); 00391 } 00392 ?>
1.8.0