TYPO3 API  SVNRelease
class.tx_dbal_handler_xmldb.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2004-2009 Kasper Skårhøj (kasper@typo3.com)
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  * Contains an example DBAL handler class
00029  *
00030  * $Id: class.tx_dbal_handler_xmldb.php 40828 2010-12-05 14:55:53Z xperseguers $
00031  *
00032  * @author  Kasper Skårhøj <kasper@typo3.com>
00033  */
00034 /**
00035  * [CLASS/FUNCTION INDEX of SCRIPT]
00036  *
00037  *
00038  *
00039  *   74: class tx_dbal_handler_xmldb extends tx_dbal_sqlengine
00040  *   91:     function init($config, &$pObj)
00041  *  128:     function readDataSource($table)
00042  *  157:     function saveDataSource($table)
00043  *  184:     function xmlDB_writeStructure()
00044  *  193:     function xmlDB_readStructure()
00045  *
00046  *              SECTION: SQL admin functions
00047  *  217:     function admin_get_tables()
00048  *  242:     function admin_get_fields($tableName)
00049  *  276:     function admin_get_keys($tableName)
00050  *  314:     function admin_query($query)
00051  *
00052  * TOTAL FUNCTIONS: 9
00053  * (This index is automatically created/updated by the extension "extdeveval")
00054  *
00055  */
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 /**
00067  * Example DBAL handler class
00068  * Stores data in XML, not a database.
00069  *
00070  * @author  Kasper Skårhøj <kasper@typo3.com>
00071  * @package TYPO3
00072  * @subpackage tx_dbal
00073  */
00074 class tx_dbal_handler_xmldb extends tx_dbal_sqlengine {
00075 
00076     var $config = array();
00077     var $pObj;  // Set from DBAL class.
00078 
00079     // Database Storage directory:
00080     var $DBdir = '';
00081     var $DBstructure = array(
00082         'tables' => array()
00083     );
00084 
00085     /**
00086      * Initialize handler
00087      *
00088      * @param   array       Configuration from DBAL
00089      * @param   object      Parent object
00090      * @return  void
00091      */
00092     function init($config, $pObj) {
00093         $this->config = $config['config'];
00094 
00095         $dbStorage = t3lib_div::getFileAbsFileName($this->config['DBstorageDir']);
00096         if ($dbStorage && @is_dir($dbStorage) && ($dbStorage{strlen($dbStorage)-1} == '/')) {
00097             $this->DBdir = $dbStorage;
00098 
00099                 // Read structure file:
00100             if (@is_file($this->DBdir.'_STRUCTURE.xml'))    {
00101                 $this->xmlDB_readStructure();
00102                 if (is_array($this->DBstructure))   {
00103                     return TRUE;
00104                 } else {
00105                     $this->errorStatus = 'The database structure array could not be loaded correctly. "_STRUCTURE.xml" may be corrupt';
00106                 }
00107             } else {
00108                 $this->xmlDB_writeStructure();
00109                 if (@is_file($this->DBdir.'_STRUCTURE.xml'))    {
00110                     return TRUE;
00111                 } else {
00112                     $this->errorStatus = 'The database structure file could not be created in dir "'.$dbStorage.'"';
00113                 }
00114             }
00115 
00116 
00117         } else $this->errorStatus = 'The database storage dir "'.$dbStorage.'" did not exist!';
00118 
00119 debug($this->errorStatus,'XMLDB connect ERROR:');
00120         return FALSE;
00121     }
00122 
00123     /**
00124      * Setting table data (overriding function)
00125      *
00126      * @param   string      Table name
00127      * @return  void
00128      */
00129     function readDataSource($table) {
00130 
00131         if (!$this->DBdir)  {
00132             $this->errorStatus = 'XMLdatabase not connected';
00133             return FALSE;
00134         }
00135 
00136             // Reading table:
00137         if (is_array($this->DBstructure['tables'][$table])) {
00138             if (!isset($this->data[$table]))    {   // Checking if it has already been read
00139                 $newTableFile = 'TABLE_'.$table.'.xml';
00140                 if (@is_file($this->DBdir.$newTableFile))   {
00141                     $this->data[$table] = t3lib_div::xml2array(t3lib_div::getUrl($this->DBdir.$newTableFile));
00142                     if (!is_array($this->data[$table]))     $this->data[$table] = array();
00143                     return TRUE;
00144                 } else {
00145                     $this->data[$table] = array();
00146                     $this->errorStatus = 'Tablefile for "'.$table.'" not found';
00147                 }
00148             }
00149         } else $this->errorStatus = 'Table "'.$table.'" not found';
00150     }
00151 
00152     /**
00153      * Saving data source
00154      *
00155      * @param   string      Table name
00156      * @return  boolean     True on success
00157      */
00158     function saveDataSource($table) {
00159 
00160         if (!$this->DBdir)  {
00161             $this->errorStatus = 'XMLdatabase not connected';
00162             return FALSE;
00163         }
00164 
00165             // Writing table:
00166         if (is_array($this->DBstructure['tables'][$table])) {
00167             $newTableFile = 'TABLE_'.$table.'.xml';
00168             if (t3lib_div::getFileAbsFileName($this->DBdir.$newTableFile) && @is_file($this->DBdir.$newTableFile))  {
00169 
00170                 $storeInCharset = $GLOBALS['LANG']->charSet;
00171                 $xmlValue = t3lib_div::array2xml($this->data[$table],'',0,'T3xmlDB',0,array('useIndexTagForNum'=>'rec'));
00172                 $content = '<?xml version="1.0" encoding="'.$storeInCharset.'" standalone="yes" ?>'.chr(10).$xmlValue;
00173                 t3lib_div::writeFile($this->DBdir.$newTableFile,$content);
00174 
00175                 return TRUE;
00176             } else $this->errorStatus = 'Tablefile for "'.$table.'" not found';
00177         } else $this->errorStatus = 'Table "'.$table.'" not found';
00178     }
00179 
00180     /**
00181      * Writing database structure
00182      *
00183      * @return  void
00184      */
00185     function xmlDB_writeStructure() {
00186         t3lib_div::writeFile($this->DBdir.'_STRUCTURE.xml', t3lib_div::array2xml($this->DBstructure,'',0,'T3xmlDBStructure',0,array('useIndexTagForNum'=>'item')));
00187     }
00188 
00189     /**
00190      * Reading database structure
00191      *
00192      * @return  void
00193      */
00194     function xmlDB_readStructure()  {
00195         $this->DBstructure = t3lib_div::xml2array(t3lib_div::getUrl($this->DBdir.'_STRUCTURE.xml'));
00196     }
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206     /**************************************
00207      *
00208      * SQL admin functions
00209      * (For use in the Install Tool and Extension Manager)
00210      *
00211      **************************************/
00212 
00213     /**
00214      * Returns the list of tables from the database
00215      *
00216      * @return  array       Tables in an array (tablename is in both key and value)
00217      * @todo    Should return table details in value! see t3lib_db::admin_get_tables()
00218      */
00219     function admin_get_tables() {
00220 
00221         if (!$this->DBdir)  {
00222             $this->errorStatus = 'XMLdatabase not connected';
00223             return FALSE;
00224         }
00225 
00226         $whichTables = array();
00227 
00228             // Traverse tables:
00229         if (is_array($this->DBstructure['tables'])) {
00230             foreach($this->DBstructure['tables'] as $tableName => $tableInfo)   {
00231                 $whichTables[$tableName] = $tableName;
00232             }
00233         }
00234 
00235         return $whichTables;
00236     }
00237 
00238     /**
00239      * Returns information about each field in the $table
00240      *
00241      * @param   string      Table name
00242      * @return  array       Field information in an associative array with fieldname => field row
00243      */
00244     function admin_get_fields($tableName)   {
00245 
00246         if (!$this->DBdir)  {
00247             $this->errorStatus = 'XMLdatabase not connected';
00248             return FALSE;
00249         }
00250 
00251         $output = array();
00252 
00253             // Traverse fields in table:
00254         if (is_array($this->DBstructure['tables'][$tableName]) && is_array($this->DBstructure['tables'][$tableName]['FIELDS'])) {
00255             foreach($this->DBstructure['tables'][$tableName]['FIELDS'] as $fieldName => $fieldInfo) {
00256                 $output[$fieldName] = array(
00257                     'Field' => $fieldName,
00258                     'Type' => $fieldInfo['definition']['fieldType'].
00259                                     ($fieldInfo['definition']['value']?'('.$fieldInfo['definition']['value'].')':'').
00260                                     (isset($fieldInfo['definition']['featureIndex']['UNSIGNED']) ? ' '.$fieldInfo['definition']['featureIndex']['UNSIGNED']['keyword'] : ''),
00261                     'Null' => isset($fieldInfo['definition']['featureIndex']['NOTNULL']) ? '' : 'Yes',
00262                     'Key' => '',
00263                     'Default' => $fieldInfo['definition']['featureIndex']['DEFAULT']['value'][0],
00264                     'Extra' => isset($fieldInfo['definition']['featureIndex']['AUTO_INCREMENT']) ? 'auto_increment' : '',
00265                 );
00266             }
00267         }
00268 
00269         return $output;
00270     }
00271 
00272     /**
00273      * Returns information about each index key in the $table
00274      *
00275      * @param   string      Table name
00276      * @return  array       Key information in a numeric array
00277      */
00278     function admin_get_keys($tableName) {
00279 
00280         if (!$this->DBdir)  {
00281             $this->errorStatus = 'XMLdatabase not connected';
00282             return FALSE;
00283         }
00284 
00285         $output = array();
00286 
00287             // Traverse fields in table:
00288         if (is_array($this->DBstructure['tables'][$tableName]) && is_array($this->DBstructure['tables'][$tableName]['KEYS']))   {
00289             foreach($this->DBstructure['tables'][$tableName]['KEYS'] as $keyName => $keyInfo)   {
00290                 foreach($keyInfo as $seq => $keyField)  {
00291                     $output[] = array(
00292                         'Table' => $tableName,
00293                         'Non_unique' => ($keyName=='PRIMARYKEY' ? 0 : 1),
00294                         'Key_name' => ($keyName=='PRIMARYKEY' ? 'PRIMARY' : $keyName),
00295                         'Seq_in_index' => $seq+1,
00296                         'Column_name' => $keyField,
00297                         'Collation' => 'A',
00298                         'Cardinality' => '',
00299                         'Sub_part' => '',
00300                         'Packed' => '',
00301                         'Comment' => '',
00302                     );
00303                 }
00304             }
00305         }
00306 
00307         return $output;
00308     }
00309 
00310     /**
00311      * mysql() wrapper function, used by the Install Tool and EM for all queries regarding management of the database!
00312      *
00313      * @param   string      Query to execute
00314      * @return  pointer     Result pointer
00315      */
00316     function admin_query($query)    {
00317 
00318         if (!$this->DBdir)  {
00319             $this->errorStatus = 'XMLdatabase not connected';
00320             return FALSE;
00321         }
00322 
00323         $parsedQuery = $this->parseSQL($query);
00324         $table = $parsedQuery['TABLE'];
00325 
00326         if (is_array($parsedQuery)) {
00327                 // Process query based on type:
00328             switch($parsedQuery['type'])    {
00329                 case 'CREATETABLE':
00330                     if (!is_array($this->DBstructure['tables'][$table]))    {
00331                         $newTableFile = 'TABLE_'.$table.'.xml';
00332                         if (!@is_file($this->DBdir.$newTableFile))  {
00333 
00334                                 // Write table file:
00335                             t3lib_div::writeFile($this->DBdir.$newTableFile, '');   // Create file
00336                             if (@is_file($this->DBdir.$newTableFile))   {
00337 
00338                                     // Set and write structure
00339                                 if (!is_array($this->DBstructure['tables']))    $this->DBstructure['tables']=array();
00340                                 $this->DBstructure['tables'][(string)$table] = $parsedQuery;    // I have some STRANGE behaviours with this variable - had to do this trick to make it work!
00341 
00342                                 $this->xmlDB_writeStructure();
00343                                 return TRUE;
00344                             } else $this->errorStatus = 'Table file "'.$this->DBdir.$newTableFile.'" could not be created! Cannot create table!';
00345                         } else $this->errorStatus = 'Table file "'.$this->DBdir.$newTableFile.'" already exists! Cannot create table!';
00346                     } else $this->errorStatus = 'Table "'.$table.'" already exists!';
00347                 break;
00348                 case 'ALTERTABLE':
00349                     if (is_array($this->DBstructure['tables'][$table])) {
00350                         switch($parsedQuery['action'])  {
00351                             case 'ADD':
00352                                 if (!is_array($this->DBstructure['tables'][$table]['FIELDS'][$parsedQuery['FIELD']]))   {
00353                                     $this->DBstructure['tables'][$table]['FIELDS'][$parsedQuery['FIELD']]['definition'] = $parsedQuery['definition'];   // Adding field in the end of list.
00354                                     $this->xmlDB_writeStructure();
00355                                     return TRUE;
00356 
00357                                     // TODO: Should traverse all data an add that field in arrays!
00358                                 } else $this->errorStatus = 'Field "'.$parsedQuery['FIELD'].'" already exists!';
00359                             break;
00360                             case 'CHANGE':
00361                                 if (is_array($this->DBstructure['tables'][$table]['FIELDS']))   {
00362                                     if (is_array($this->DBstructure['tables'][$table]['FIELDS'][$parsedQuery['FIELD']]))    {
00363                                         $newFieldInfo = array();
00364                                         foreach($this->DBstructure['tables'][$table]['FIELDS'] as $fieldName => $fieldDefinition)   {
00365                                             if (!strcmp($fieldName,$parsedQuery['FIELD']))  {
00366 
00367                                                     // New fieldname?
00368                                                 if ($parsedQuery['newField'])   {
00369                                                     if (!is_array($this->DBstructure['tables'][$table]['FIELDS'][$parsedQuery['newField']]))    {
00370                                                         $fieldName = $parsedQuery['newField'];
00371                                                     } else {
00372                                                         $this->errorStatus = 'A field in the table was already named "'.$parsedQuery['newField'].'"';
00373                                                         return FALSE;
00374                                                     }
00375                                                 }
00376                                                     // Set new field definition:
00377                                                 $fieldDefinition['definition'] = $parsedQuery['definition'];
00378                                             }
00379 
00380                                                 // Set the whole thing in new var:
00381                                             $newFieldInfo[$fieldName] = $fieldDefinition;
00382                                         }
00383                                         $this->DBstructure['tables'][$table]['FIELDS'] = $newFieldInfo;
00384                                         $this->xmlDB_writeStructure();
00385                                         return TRUE;
00386 
00387                                         // TODO: Should traverse all data an remove that field in arrays!
00388                                     } else $this->errorStatus = 'Field "'.$parsedQuery['FIELD'].'" does not exist!';
00389                                 } else $this->errorStatus = 'There are not fields in the table - strange!';
00390                             break;
00391                             case 'DROP':
00392                                 if (is_array($this->DBstructure['tables'][$table]['FIELDS'][$parsedQuery['FIELD']]))    {
00393                                     unset($this->DBstructure['tables'][$table]['FIELDS'][$parsedQuery['FIELD']]);   // Removing it...
00394                                     $this->xmlDB_writeStructure();
00395                                     return TRUE;
00396 
00397                                     // TODO: Should traverse all data an remove that field in arrays!
00398                                 } else $this->errorStatus = 'Field "'.$parsedQuery['FIELD'].'" does not exist!';
00399                             break;
00400                         }
00401                     } else $this->errorStatus = 'Table "'.$table.'" does not exist!';
00402                 break;
00403                 case 'DROPTABLE':
00404 
00405                         // TODO:
00406                     debug($parsedQuery);
00407 
00408 
00409                 break;
00410                 default:
00411                     $this->errorStatus = 'Query type "'.$parsedQuery['type'].'" was not supported!';
00412                 break;
00413             }
00414 
00415         } else $this->errorStatus = 'SQL parse error: '.$parsedQuery;
00416 
00417         return FALSE;
00418     }
00419 }
00420 
00421 
00422 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/handlers/class.tx_dbal_handler_xmldb.php'])) {
00423     include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/dbal/handlers/class.tx_dbal_handler_xmldb.php']);
00424 }
00425 ?>