Bugfix: Invalid call to viewObj (Thanks to Tobias Liebig)
authorThomas Hempel <thomas.hempel@typo3.org>
Wed, 12 Dec 2007 15:24:24 +0000 (15:24 +0000)
committerThomas Hempel <thomas.hempel@typo3.org>
Wed, 12 Dec 2007 15:24:24 +0000 (15:24 +0000)
Added support for fieldsets in renderMethod "form"
Added ability to send forms via AJAX
Improved DB compare code (Thanks to Francois Suter)

git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2823 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/install/mod/class.tx_install.php
typo3/sysext/install/mod/class.tx_install_basics.php
typo3/sysext/install/mod/class.tx_install_view.php
typo3/sysext/install/mod/scripts.js
typo3/sysext/install/modules/database/class.tx_install_module_database.php
typo3/sysext/install/modules/database/locallang.xml
typo3/sysext/install/modules/setup/res/styles.css

index 66d04fd..ef6968a 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2007-12-12     Thomas Hempel  <thomas@typo3-unleashed.net>
+
+       * Bugfix: Invalid call to viewObj
+       * Added support for fieldsets in renderMethod "form"
+       * Added ability to send forms via AJAX
+       * improved DB compare code (Thanks to Francois Suter)
+
+2007-12-11     Thomas Hempel  <thomas@typo3-unleashed.net>
+
+       * Added support for listing and calling methods in new installer
+
 2007-12-10  Ingmar Schlecht  <ingmar@typo3.org>
 
         * (security) Fixed a low-severity SQL injection in the modfunc2 of indexed_search (only exploitable by BE users, and severity limited because addslashes() was already applied to the value - yet not within a quoted string) (Thanks to Henning Pingel for findind the issue and Andreas Otto for the fix)
        * Fixed bug #5347: Flexforms dosen't resolve sheets
        * Fixed bug #3969: Missing sheets inclusion in flexforms?
 
-2007-10-28  Kasper Skårhøj  <kasperYYYY@typo3.com>
+2007-10-28  Kasper Sk�rh�j  <kasperYYYY@typo3.com>
 
        * - Reverting IRRE related changes in t3lib_BEfunc done for workspaces by Dmitry. They were faulty.
        * - Modified rendering of FlexForms in t3lib_TCEforms and also processing in t3lib_tcemain so that flexforms are now fully dynamic in their nature; This is particularly the case when flexforms have sections and containers within (see the original movie-list example for instance). DHTML is used to reorganize flexform elements, delete and add new. No ajax though (not necessary). It means we finally have a permanent implementation for what was before "_DELETE_FLEX_FORM" etc buttons... Used scriptaculous and prototype for the work.
index 5449c39..2cfa462 100644 (file)
@@ -212,6 +212,12 @@ class tx_install {
                }
                
                if($this->passwordOK) {
+                       
+                               // Try to connect to the database
+                       if ($GLOBALS['TYPO3_DB']->link === false)       {
+                               $moduleContent = $this->basicsObj->executeMethod(array('database', 'checkDatabaseConnect'));
+                       }
+                       
                                // load module and execute main method
                        $method = 'main';
                        if ($this->env['method'])       {
@@ -219,8 +225,9 @@ class tx_install {
                        }
                        
                                // execute given method and save the result in a local variable
+                               // This method is only be executed if we have database connection
                        $moduleContent = $this->basicsObj->executeMethod(array($this->env['module'], $method));
-               
+                       
                                // check if we have to handle the module content with AJAX
                        if ($this->env['ajax'] == 1)    {
                                header('X-JSON: (true)');
index 5501b9b..e5ec312 100644 (file)
@@ -636,13 +636,12 @@ class tx_install_basics   {
                        }
                        
                        if($hasNoErrors && !@is_writable($file)) {
-                               $this->viewObj->addError(sprintf($this->getLabel('msg_filenotwriteable'), $file), FATAL);
+                               $viewObj->addError(sprintf($this->getLabel('msg_filenotwriteable'), $file), FATAL);
                                $hasNoErrors = false;
                        }
        
                                // write localconf!
                        if ($hasNoErrors)       {
-                               
                                if (!t3lib_div::writeFile($tmpFile,$fileContents))      {
                                        $viewObj->addError(sprintf($this->getLabel('msg_filenotwriteable'), $tmpFile), FATAL);
                                        $hasNoErrors = false;
index d011afe..e3b1e81 100644 (file)
@@ -74,7 +74,7 @@ class tx_install_view {
         * @var string
         */
        private $lastMessage = '';
-       
+
        /**
         * parent tx_install object
         *
@@ -83,6 +83,13 @@ class tx_install_view {
        private $pObj    = NULL;
 
        /**
+        * Last openend fieldset
+        *
+        * @var string
+        */
+       private $lastFieldset = NULL;
+       
+       /**
         * Constructor
         * 
         * @return      void
@@ -598,7 +605,7 @@ class tx_install_view {
                        $this->getAttributeString('id', $data['options']['id']).
                        $this->getAttributeString('method', $data['options']['method'], 'post');
                        
-               if(isset($data['options']['action'])) {
+               if(isset($data['options']['action']) && $data['options']['ajax'] == false) {
                        $content .= $this->getAttributeString('action', $data['options']['action']);
                }
                $content .= '>'."\n";
@@ -624,7 +631,18 @@ class tx_install_view {
                                }
                        }
                }
-               $content .= '<br /><input type="submit" class="submit" value="'.$data['options']['submit'].'" /></form>';
+               
+               if (!is_null($this->lastFieldset))      {
+                       $content .= '</fieldset>';
+               }
+               
+               if ($data['options']['ajax'] == true)   {
+                       $content .= '<br /><button class="submit" onclick="return '.$data['options']['action'].'">'.$data['options']['submit'].'</button>';
+               } else {
+                       $content .= '<br /><input type="submit" class="submit" value="'.$data['options']['submit'].'" />';
+               }
+               
+               $content .= '</form>';
                
                return $content;
        }
@@ -650,47 +668,55 @@ class tx_install_view {
         * @return      string          HTML output
         */
        public function renderFormelement($data) {
-               // var_dump(array('formelement', $data));
-               // debug($data, 'renderFormelement');
                $content   = '';
                $viewObj   = $this->pObj->getViewObject();
                $basicsObj = $this->pObj->getBasicsObject();
 
-               $elementRenderMethod = 'renderFormelement'.ucfirst($data['elementType']);
-               if(method_exists($this, $elementRenderMethod)) {
-                               // set the value of the field from the environment if no error is recognized for it
-                               // also set an error string if error was found
-                       $errors = $viewObj->getErrors();
-                       if(!isset($errors['fields'][$data['options']['name']])) {
-                               $environment = $this->pObj->getEnvironment();
-                               if(!empty($environment[$data['options']['name']])) {
-                                       $data['options']['value'] = $environment[$data['options']['name']];
-                               }
-                               $errorStr = '';
-                       } else {
-                               $errorStr = $viewObj->renderErrors(true, 'fields', $data['options']['name']);
+               if ($data['elementType'] == 'fieldset') {
+                       if (!is_null($this->lastFieldset) && $this->lastFieldset != $data['label'])     {
+                               $content = '</fieldset>';
                        }
                        
-                               // render the form element
-                       $formElementCode = $this->$elementRenderMethod($data['options']);
-                       
-                               // create a label if set in option
-                       if(isset($data['label'])) {
-                               $label = '<label for="'.$data['options']['id'].'">'.$basicsObj->getLabel($data['label'], $data['label']).'</label>';
+                       $content .= '<fieldset><legend>'.$data['label'].'</legend>';
+                       $this->lastFieldset = $data['label'];   
+               } else {
+               
+                       $elementRenderMethod = 'renderFormelement'.ucfirst($data['elementType']);
+                       if(method_exists($this, $elementRenderMethod)) {
+                                       // set the value of the field from the environment if no error is recognized for it
+                                       // also set an error string if error was found
+                               $errors = $viewObj->getErrors();
+                               if(!isset($errors['fields'][$data['options']['name']])) {
+                                       $environment = $this->pObj->getEnvironment();
+                                       if(!empty($environment[$data['options']['name']])) {
+                                               $data['options']['value'] = $environment[$data['options']['name']];
+                                       }
+                                       $errorStr = '';
+                               } else {
+                                       $errorStr = $viewObj->renderErrors(true, 'fields', $data['options']['name']);
+                               }
                                
-                                       // align the label (default is left)
-                               switch ($data['label_align']) {
-                                       case 'right':
-                                               $formElementCode = $errorStr.$formElementCode.$label;
-                                               break;
-                                       case 'left':
-                                       default:
-                                               $formElementCode = $label.$errorStr.$formElementCode;
+                                       // render the form element
+                               $formElementCode = $this->$elementRenderMethod($data['options']);
+                               
+                                       // create a label if set in option
+                               if(isset($data['label'])) {
+                                       $label = '<label for="'.$data['options']['id'].'">'.$basicsObj->getLabel($data['label'], $data['label']).'</label>';
+                                       
+                                               // align the label (default is left)
+                                       switch ($data['label_align']) {
+                                               case 'right':
+                                                       $formElementCode = $errorStr.$formElementCode.$label;
+                                                       break;
+                                               case 'left':
+                                               default:
+                                                       $formElementCode = $label.$errorStr.$formElementCode;
+                                       }
                                }
+                               
+                                       // return the element wrapped in a div
+                               $content = '<div class="formElement formElement'.ucfirst($data['elementType']).'">'.$formElementCode.'</div>';
                        }
-                       
-                               // return the element wrapped in a div
-                       $content = '<div class="formElement formElement'.ucfirst($data['elementType']).'">'.$formElementCode.'</div>';
                }
                
                return $content;
index beccc6b..f5b0975 100644 (file)
@@ -74,6 +74,26 @@ function sendForm(formId)    {
        loadModuleContent(elements.categoryMain.value, elements.categorySub.value, ajaxParameters);
 }
 
+function sendMethodForm(formId, module, method, callBack)      {
+       var elements = $(formId).elements;
+       var ajaxParameters = {};
+       for (var i = 0; i < elements.length; i++)       {
+               var el = elements.item(i);
+               switch (el.type)        {
+                       case 'checkbox':
+                               ajaxParameters[el.name] = (el.checked == true) ? 1 : 0;
+                               break;
+                       case 'text':
+                       default:
+                               ajaxParameters[el.name] = el.value;
+                               break;
+               }
+       };
+       
+       executeMethod(module, method, ajaxParameters, callBack);
+       return false;
+}
+
 function doSearch()    {
        searchString = $('treeFilter').value;
        $$('.tree_item').each(function(item, index)     { item.setStyle({'fontWeight': 'normal', backgroundColor: '#fff'}) });
@@ -166,7 +186,7 @@ function displayMethodResult(data)  {
        if (data.request.parameters.target)     {
                $(data.request.parameters.target).innerHTML = data.responseText;
        } else {
-               alert(data.responseText);
+               // console.debug(data.responseText);
        }
 }
 
index 9ba578f..0fa3caa 100755 (executable)
@@ -442,10 +442,10 @@ class tx_install_module_database extends tx_install_module_base   {
         * @return      HTML-Code or false if an error occured
         */
        public function analyzeCompareFile($sqlFile = NULL)     {
+                       // Load default SQL file if none is given
                if (is_null($sqlFile))  {
                        $sqlFile = PATH_t3lib.'stddb/tables.sql';
                }
-               
                $tblFileContent = t3lib_div::getUrl($sqlFile);
                
                        // return an error if the given file was not found
@@ -454,38 +454,45 @@ class tx_install_module_database extends tx_install_module_base   {
                        return false;
                }
 
-               /*
+                       // Add all SQL statements from all loaded extensions
                reset($GLOBALS['TYPO3_LOADED_EXT']);
                foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $loadedExtConf)        {
                        if (is_array($loadedExtConf) && $loadedExtConf['ext_tables.sql'])       {
-                               $tblFileContent.= chr(10).chr(10).chr(10).chr(10).t3lib_div::getUrl($loadedExtConf['ext_tables.sql']);
+                               $tblFileContent .= chr(10).chr(10).chr(10).chr(10).t3lib_div::getUrl($loadedExtConf['ext_tables.sql']);
                        }
                }
-               
+
+                       // Get an instance of the t3lib_install class
                $t3lib_install = t3lib_div::makeInstance('t3lib_install');
-               $statements = $t3lib_install->getStatementArray($tblFileContent, 1);
                
+                       // Transform string of SQL statements into an array
+               $statements = $t3lib_install->getStatementArray($tblFileContent, 1);
+
+                       // Get all the statements indexed for each table
                list($statements_table, $insertCount) = $t3lib_install->getCreateTables($statements, 1);
-               
-               $tblFileContent = t3lib_div::getUrl(PATH_t3lib.'stddb/tables.sql');
-               reset($GLOBALS['TYPO3_LOADED_EXT']);
-               
-               
-               
-               $fileContent = implode(
-                       $t3lib_install->getStatementArray($tblFileContent,1,'^CREATE TABLE '),
-                       chr(10)
-               );
+
+                       // Load default SQL file as a basis for comparison
+               // $tblFileContent = t3lib_div::getUrl(PATH_t3lib.'stddb/tables.sql');
+//             reset($GLOBALS['TYPO3_LOADED_EXT']);
+
+                       // Get all create table statements
+               $fileContent = implode($t3lib_install->getStatementArray($tblFileContent, 1, '^CREATE TABLE '), chr(10));
+                       // Get field definitions for each table and make sure they are clean
                $FDfile = $t3lib_install->getFieldDefinitions_sqlContent($fileContent);
                
                if (!count($FDfile))    {
-                       $this->addError(sprintf('There were no "CREATE TABLE" definitions in the provided file: %s', PATH_t3lib.'stddb/tables.sql'), FATAL);
+                       $this->addError(sprintf($this->get_LL('msg_analyze_error_nocreatedefinitions'), PATH_t3lib.'stddb/tables.sql'), FATAL);
                        return false;
                }
                
                        // Updating database...
-               /*
-               if (is_array($this->INSTALL['database_update']))        {
+               if ($this->env['action'] == 'performUpdate')    {
+                       // debug($this->env);
+                       /*
+                        * Here the script has to perform the update of the database. The code is pasted from old install class.
+                        */
+                       
+                       /*
                        $FDdb = $this->getFieldDefinitions_database();
                        $diff = $this->getDatabaseExtra($FDfile, $FDdb);
                        $update_statements = $this->getUpdateSuggestions($diff);
@@ -500,66 +507,119 @@ class tx_install_module_database extends tx_install_module_base  {
                        $this->performUpdateQueries($update_statements['create_table'],$this->INSTALL['database_update']);
                        $this->performUpdateQueries($remove_statements['change_table'],$this->INSTALL['database_update']);
                        $this->performUpdateQueries($remove_statements['drop_table'],$this->INSTALL['database_update']);
+                       */
                }
-               */
 
-               /*
+               
                        // Init again / first time depending...
                $FDdb = $t3lib_install->getFieldDefinitions_database();
-
                $diff = $t3lib_install->getDatabaseExtra($FDfile, $FDdb);
                $update_statements = $t3lib_install->getUpdateSuggestions($diff);
-
-               $diff = $t3lib_install->getDatabaseExtra($FDdb, $FDfile);
-               $remove_statements = $t3lib_install->getUpdateSuggestions($diff,'remove');
-
-               $tLabel = 'Update database tables and fields';
+                       
 
                if ($remove_statements || $update_statements)   {
-                       $formContent = $this->generateUpdateDatabaseForm('get_form',$update_statements,$remove_statements,$action_type);
+                       $formContent = $this->generateUpdateDatabaseForm($update_statements, $remove_statements);
+                       /*
                        $this->message($tLabel,'Table and field definitions should be updated',"
                        There seems to be a number of differencies between the database and the selected SQL-file.
                        Please select which statements you want to execute in order to update your database:<br /><br />
                        ".$formContent."
                        ",2);
+                       */
                } else {
-                       $formContent = $this->generateUpdateDatabaseForm('get_form',$update_statements,$remove_statements,$action_type);
+                       $formContent = $this->generateUpdateDatabaseForm($update_statements, $remove_statements);
+                       /*
                        $this->message($tLabel,'Table and field definitions are OK.',"
                        The tables and fields in the current database corresponds perfectly to the database in the selected SQL-file.
                        ",-1);
+                       */
                }
                
                return $formContent;
-               */
-               
-               return 'Here comes the result from the database analyzer';
        }
        
+       /**
+        * Generates the form for selecting actions that can be performed after a comparison. 
+        *
+        * @param       array   $arr_update: All actions concerning database updates
+        * @param       array   $arr_remove: All actions concerning database removales
+        * @return      HTML with complete formcode
+        */
+       private function generateUpdateDatabaseForm($arr_update, $arr_remove)   {
+               $content = '';
+               
+                       // get elements for various states
+               $elements = array();    
+               
+                       // Fields
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_update['add'], 'Add fields'));
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_update['change'], 'Changing fields', (t3lib_extMgm::isLoaded('dbal') ? false : true), $arr_update['change_currentValue']));
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_remove['change'], 'Remove unused fields (rename with prefix)'));
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_remove['drop'], 'Drop fields (really!)'));
+
+                       // Tables
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_update['create_table'], 'Add tables'));
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_remove['change_table'], 'Removing tables (rename with prefix)', $this->setAllCheckBoxesByDefault));
+               $elements = array_merge($elements, $this->generateUpdateDatabaseForm_checkboxes($arr_remove['drop_table'], 'Drop tables (really!)', $this->setAllCheckBoxesByDefault));
+
+                       // prepare config for rendering
+               $formConfig = array (
+                       'type' => 'form',
+                       'value' => array (
+                               'options' => array (
+                                       'name' => 'form_analyzeCompareFile',
+                                       'id' => 'form_analyzeCompareFile',
+                                       'submit' => $this->get_LL('label_writechanges'),
+                                       'ajax' => true,
+                                       'action' => 'sendMethodForm(\'form_analyzeCompareFile\', \'database\', \'analyzeCompareFile\', displayMethodResult)',
+                               ),
+                               'hidden' => array (
+                                       'action' => 'performUpdate',
+                                       'target' => $this->env['target']
+                               ),
+                               'elements' => $elements
+                       )
+               );
+               
+                       // render the form in viewObj
+               $content = $this->pObj->getViewObject()->render($formConfig);
+                       
+               return $content;
+       }
        
-       
-       private function displaySuggestions($arr, $excludeList='')      {
-               $out='';
-               $out.='<tr><td bgcolor="#9BA1A8" align="center"><strong>'.$this->fw('Field name:').'</strong></td><td bgcolor="#9BA1A8" align="center"><strong>'.$this->fw('Info / Suggestion for the field:').'</strong></td></tr>';
-               $fC=0;
-               if (is_array($arr))     {
-                       reset($arr);
-                       while(list($fieldname, $fieldContent)=each($arr))       {
-                               if (!t3lib_div::inList($excludeList,$fieldname) && substr($fieldname,0,strlen($this->deletedPrefixKey))!=$this->deletedPrefixKey && substr($fieldname,-1)!='.') {
-                                       $fieldContent = $this->fw($fieldContent);
-                                       if ($arr[$fieldname.'.'])       {
-                                               $fieldContent.= '<hr />';
-                                               $fieldContent.= '<pre>'.trim($arr[$fieldname.'.']).'</pre>';
-                                       }
-                                       $out.='<tr><td bgcolor="#ABBBB4">'.$this->fw($fieldname).'</td><td bgcolor="#ABBBB4">'.$fieldContent.'</td></tr>';
-                                       $fC++;
-                               }
+       private function generateUpdateDatabaseForm_checkboxes($data, $label, $checked = true, $currentValue = array()) {
+               $result = array();
+               
+               if (is_array($data))    {
+                       $result[] = array(
+                               'type' => 'formelement',
+                               'value' => array (
+                                       'elementType' => 'fieldset',
+                                       'label' => $label
+                               )
+                       );
+                       
+                       foreach ($data as $key => $statement)   {
+                               $result[] = array(
+                                       'type' => 'formelement',
+                                       
+                                       'value' => array (
+                                               'elementType' => 'checkbox',
+                                               'label' => htmlspecialchars($statement).'<br />'.((empty($currentValue[$key]) ? '' : '<em>Current value: '.$currentValue[$key].'</em>')),
+                                               'label_align' => 'right',
+                                               'options' => array (
+                                                       'name' => $key,
+                                                       'default' => $checked,
+                                                       'id' => $key
+                                               )
+                                       )
+                               );
                        }
                }
-               $out= '<table border="0" cellpadding="2" cellspacing="2">'.$out.'</table>';
-               return array($out,$fC);
+               
+               return $result;
        }
 
-
 }
 
 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/install/modules/database/class.tx_install_database.php'])     {
index 070e052..891ae68 100755 (executable)
                        <label index="label_database_defaulttables">Create default database tables</label>
                        <label index="label_selectdump">Please select a database dump</label>
                        <label index="label_execute">Execute</label>
+                       <label index="label_writechanges">Write selected changes to database</label>
 
                        <label index="msg_database_error_cantconnect">FATAL: Can't connect to database-server!</label>
                        <label index="msg_database_error_cantselectdb">FATAL: Can't select database "%s"</label>
                        <label index="msg_database_error_couldnotcreate">Could not create database with name "%s"</label>
                        <label index="msg_database_error_filenotfound">The compare-file "%s" was not found!</label>
+                       <label index="msg_analyze_error_nocreatedefinitions">There were no "CREATE TABLE" definitions in the provided file: %s</label>
 
                        <label index="msg_database_warning_selectdb">Please select a database or fill in a name for a new database.</label>
                        <label index="msg_database_warning_invalidname">The NEW database name "%s" was not alphanumeric, a-zA-Z0-9_-</label>
index b3170d1..c0cdf6a 100644 (file)
@@ -17,13 +17,23 @@ h3  {
        border-bottom: 1px #c0c0c0 dashed;
 }
 
-input, select  {
+fieldset       {
+       font-weight: bold;
+}
+
+input, select, button  {
        background: #fff url(../../../imgs/icons/bg_input.gif) no-repeat scroll left top;
        border: 1px solid #aaa;
        margin-top: 2px;
        padding:3px;
 }
 
+label em       {
+       font-style: italic;
+       display: block;
+       margin: 0px 0px 7px 20px;
+}
+
 .categoryTreeContainer {
        position: fixed;
        top: 5px;