0byt3m1n1
Path:
/
data
/
applications
/
aps
/
typo3
/
4.5.5-0
/
standard
/
htdocs
/
typo3
/
sysext
/
dbal
/
[
Home
]
File: class.tx_dbal_em.php
<?php /*************************************************************** * Copyright notice * * (c) 2010-2011 Xavier Perseguers <xavier@typo3.org> * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * A copy is found in the textfile GPL.txt and important notices to the license * from the author is found in LICENSE.txt distributed with these scripts. * * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ /** * Hooks for TYPO3 Extension Manager. * * @author Xavier Perseguers <xavier@typo3.org> * * @package TYPO3 * @subpackage dbal */ class tx_dbal_em implements tx_em_Index_CheckDatabaseUpdatesHook { /** * Maximal length for an identifier in Oracle. * * @var integer */ protected $maxIdentifierLength = 30; /** * Table names should be short enough in order to let ADOdb generates * the corresponding sequence for the auto-increment field 'uid'. * That is, a sequence of the form {table}_uid * * @var integer */ protected $tableNameCharacterReservation = 4; /** * Mapping of table and field names. * * @var array */ protected $mapping; /** * Initializes internal variables. * * @return void */ protected function init() { $mapping = @$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['mapping']; if (!$mapping) { $mapping = array(); } $this->mapping = $mapping; } /** * Hook that allows pre-processing of database structure modifications. * This returns a user form that will temporarily replace the standard * database update form to let user configure mapping. * * @param string $extKey: Extension key * @param array $extInfo: Extension information array * @param array $diff: Database differences * @param t3lib_install $instObj: Instance of the installer * @param SC_mod_tools_em_index $parent: The calling parent object * @return string Either empty string or a pre-processing user form */ public function preProcessDatabaseUpdates($extKey, array $extInfo, array $diff, t3lib_install $instObj, SC_mod_tools_em_index $parent) { $content = ''; // Remapping is only mandatory for Oracle: if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['type'] !== 'adodb' || $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['dbal']['handlerCfg']['_DEFAULT']['config']['driver'] !== 'oci8') { // Not using Oracle return ''; } $this->init(); if (t3lib_div::_GP('dbal')) { $this->updateMapping(t3lib_div::_GP('dbal'), $instObj); } // Search all table and field names which should be remapped $tableCandidates = array(); $fieldsCandidates = array(); foreach ($diff['extra'] as $table => $config) { if ($this->needsMapping($table)) { $tableCandidates[] = $table; } foreach ($config['fields'] as $field => $type) { if ($this->needsMapping($table, $field)) { if (!isset($fieldsCandidates[$table])) { $fieldsCandidates[$table] = array(); } $fieldsCandidates[$table][$field] = array( 'fullName' => $field, ); } } /* if (!isset($config['keys'])) { continue; // Process next table } foreach ($config['keys'] as $field => $def) { if ($field !== 'PRIMARY' && $this->needsMapping($table, $field, TRUE)) { if (!t3lib_div::inArray($tableCandidates, $table)) { $tableCandidates[] = $table; } if (!isset($fieldsCandidates[$table])) { $fieldsCandidates[$table] = array(); } $fieldsCandidates[$table][$field] = array( 'fullName' => $table . '_' . $field, ); } } */ } if ($tableCandidates || $fieldsCandidates) { $mappingSuggestions = $this->getMappingSuggestions($extKey, $extInfo, $tableCandidates, $fieldsCandidates); $content .= $this->generateMappingForm($tableCandidates, $fieldsCandidates, $mappingSuggestions); } return $content; } /** * Returns TRUE if either the table or the field name should be remapped. * * @param string $table * @param string $field * @param boolean $isKeyField * @return boolean TRUE if mapping is needed, otherwise FALSE */ protected function needsMapping($table, $field = '', $isKeyField = FALSE) { $needsRemapping = FALSE; // Take existing DBAL mapping into account $origTable = $table; if (isset($this->mapping[$origTable])) { if (isset($this->mapping[$origTable]['mapTableName'])) { $table = $this->mapping[$origTable]['mapTableName']; } if ($field !== '' && isset($this->mapping[$origTable]['mapFieldNames'])) { if (isset($this->mapping[$origTable]['mapFieldNames'][$field])) { $field = $this->mapping[$origTable]['mapFieldNames'][$field]; } } } if ($field === '') { if (substr($table, -3) === '_mm') { $needsRemapping = strlen($table) > $this->maxIdentifierLength; } else { $needsRemapping = strlen($table) > $this->maxIdentifierLength - $this->tableNameCharacterReservation; } } elseif (!$isKeyField) { $needsRemapping = strlen($field) > $this->maxIdentifierLength; } else { $needsRemapping = strlen($table . '_' . $field) > $this->maxIdentifierLength; } return $needsRemapping; } /** * Returns suggestions for the mapping of table/field names. * * @param string $extKey * @param array $extInfo * @param array $tables * @param array $fields * @return array * @api */ public function getMappingSuggestions($extKey, array $extInfo, array $tables, array $fields) { $suggestions = array(); switch ($extKey) { case 'direct_mail': $suggestions['sys_dmail_ttaddress_category_mm'] = array( 'mapTableName' => 'sys_dmail_ttaddress_cat_mm', ); $suggestions['sys_dmail_ttcontent_category_mm'] = array( 'mapTableName' => 'sys_dmail_ttcontent_cat_mm', ); break; case 'extbase': $suggestions['tx_extbase_cache_reflection_tags'] = array( 'mapTableName' => 'tx_extbase_cache_reflect_tags', ); break; case 'templavoila': $suggestions['tx_templavoila_datastructure'] = array( 'mapTableName' => 'tx_templavoila_ds', ); $suggestions['tx_templavoila_tmplobj'] = array( 'mapTableName' => 'tx_templavoila_tmpl', ); break; default: $dependencies = array_keys($extInfo['EM_CONF']['constraints']['depends']); if (t3lib_div::inArray($dependencies, 'extbase')) { $this->storeExtbaseMappingSuggestions($suggestions, $extKey, $extInfo, $tables, $fields); } } // Existing mapping take precedence over suggestions $suggestions = t3lib_div::array_merge_recursive_overrule($suggestions, $this->mapping); return $suggestions; } /** * Stores suggestions for the mapping of table/field names for an Extbase-based extension. * * @param array &$suggestions * @param string $extKey * @param array $extInfo * @param array $tables * @param array $fields * @return void */ protected function storeExtbaseMappingSuggestions(array &$suggestions, $extKey, array $extInfo, array $tables, array $fields) { foreach ($tables as $table) { // Remove the "domain_model" part of the table name $suggestions[$table] = array( 'mapTableName' => str_replace('domain_model_', '', $table), ); } } /** * Generates a mapping form. * * @param array $tables * @param array $fields * @param array $suggestions * @return string */ protected function generateMappingForm(array $tables, array $fields, array $suggestions) { $out = array(); $tableId = uniqid('table'); $label = 'DBAL Mapping'; $description = sprintf('Some table names are longer than %s characters and/or some field names are longer than %s characters.' . ' This is incompatible with your database:' . ' <ul style="list-style: square; margin: 3px 1em; padding: 3px 1em;">' . ' <li>Table names should be short enough to let ADOdb generates a sequence of the form {table}_uid for the' . ' auto-increment "uid" field within %s characters;</li>' . ' <li>Field names may not contain more than %s characters.</li>' . ' </ul>', $this->maxIdentifierLength - $this->tableNameCharacterReservation, $this->maxIdentifierLength, $this->maxIdentifierLength, $this->maxIdentifierLength ); $tables = array_unique(array_merge($tables, array_keys($fields))); foreach ($tables as $table) { $newTableName = $table; if (isset($suggestions[$table]) && isset($suggestions[$table]['mapTableName'])) { $newTableName = $suggestions[$table]['mapTableName']; } $out[] = ' <tr> <td style="padding-top: 1em;"><label for="table-' . $table . '">' . $table . '</label></td> <td style="padding-top: 1em;">=></td> <td style="padding-top: 1em;"><input type="text" size="35" id="table-' . $table . '" name="dbal[tables][' . $table . ']" value="' . $newTableName . '" /> ' . strlen($newTableName) . ' characters' . '</td> </tr>'; if (isset($fields[$table])) { foreach ($fields[$table] as $field => $info) { $newFieldName = $field; if (isset($suggestions[$table]) && isset($suggestions[$table]['mapFieldNames'])) { if (isset($suggestions[$table]['mapFieldNames'][$field])) { $newFieldName = $suggestions[$table]['mapFieldNames'][$field]; } } $newFieldFullName = preg_replace('/^' . $table . '/', $newTableName, $info['fullName']); $newFieldFullName = preg_replace('/' . $field . '$/', $newFieldName, $newFieldFullName); $out[] = ' <tr> <td> <label for="field-' . $table . '_' . $field . '">' . $field . '</label></td> <td>=></td> <td><input type="text" size="35" id="field-' . $table . '_' . $field . '" name="dbal[fields][' . $table . '][' . $field . ']" value="' . $newFieldName . '" /> ' . ($info['fullname'] !== $field ? strlen($newFieldFullName) . ' characters: ' . $newFieldFullName : '') . '</td> </tr>'; } } } // Compile rows: $content = ' <!-- Remapping database fields / tables --> <h3>' . $label . '</h3> <p>' . $description . '</p> <table border="0" cellpadding="2" cellspacing="2" id="' . $tableId . '" class="remap-db-table-fields">' . implode('', $out) . ' </table>'; return $content; } /** * Updates the mapping in localconf.php according to form input values. * * @param array $data * @param t3lib_install $instObj * @return void * @api */ public function updateMapping(array $data, t3lib_install $instObj) { $newMapping = $this->mapping; foreach ($data['tables'] as $table => $newName) { $newName = trim($newName); if ($newName && $newName !== $table) { if (!isset($newMapping[$table])) { $newMapping[$table] = array(); } $newMapping[$table]['mapTableName'] = $newName; } if (isset($data['fields'][$table])) { foreach ($data['fields'][$table] as $field => $newName) { $newName = trim($newName); if ($newName && $newName !== $field) { if (!isset($newMapping[$table])) { $newMapping[$table] = array(); } if (!isset($newMapping[$table]['mapFieldNames'])) { $newMapping[$table]['mapFieldNames'] = array(); } $newMapping[$table]['mapFieldNames'][$field] = $newName; } } } } // Sort table and field names foreach ($newMapping as $table => &$config) { if (isset($config['mapFieldNames'])) { ksort($config['mapFieldNames']); } } ksort($newMapping); // Write new mapping to localconf.php $key = '$TYPO3_CONF_VARS[\'EXTCONF\'][\'dbal\'][\'mapping\']'; $instObj->allowUpdateLocalConf = 1; $instObj->updateIdentity = 'TYPO3 Extension Manager'; $lines = $instObj->writeToLocalconf_control(); $instObj->setArrayValueInLocalconfFile($lines, $key, $newMapping); if ($instObj->writeToLocalconf($lines)) { $this->mapping = $newMapping; } } } if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.tx_dbal_em.php'])) { include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/class.tx_dbal_em.php']); } ?>