class.t3lib_flexformtools.php

Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2006 Kasper Skaarhoj (kasperYYYY@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 functions for manipulating flex form data
00029  *
00030  * $Id: class.t3lib_flexformtools.php 3489 2008-03-31 13:13:04Z ohader $
00031  *
00032  * @author  Kasper Skaarhoj <kasperYYYY@typo3.com>
00033  */
00034 /**
00035  * [CLASS/FUNCTION INDEX of SCRIPT]
00036  *
00037  *
00038  *
00039  *   71: class t3lib_flexformtools
00040  *  105:     function traverseFlexFormXMLData($table,$field,$row,&$callBackObj,$callBackMethod_value)
00041  *  203:     function traverseFlexFormXMLData_recurse($dataStruct,$editData,&$PA,$path='')
00042  *  274:     function getAvailableLanguages()
00043  *
00044  *              SECTION: Processing functions
00045  *  323:     function cleanFlexFormXML($table,$field,$row)
00046  *  347:     function cleanFlexFormXML_callBackFunction($dsArr, $data, $PA, $path, &$pObj)
00047  *
00048  *              SECTION: Multi purpose functions
00049  *  374:     function &getArrayValueByPath($pathArray,&$array)
00050  *  403:     function setArrayValueByPath($pathArray,&$array,$value)
00051  *  433:     function flexArray2Xml($array, $addPrologue=FALSE)
00052  *
00053  * TOTAL FUNCTIONS: 8
00054  * (This index is automatically created/updated by the extension "extdeveval")
00055  *
00056  */
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 /**
00065  * Contains functions for manipulating flex form data
00066  *
00067  * @author  Kasper Skaarhoj <kasperYYYY@typo3.com>
00068  * @package TYPO3
00069  * @subpackage t3lib
00070  */
00071 class t3lib_flexformtools {
00072 
00073     var $convertCharset = FALSE;        // If set, the charset of data XML is converted to system charset.
00074     var $reNumberIndexesOfSectionData = FALSE;  // If set, section indexes are re-numbered before processing
00075 
00076     var $traverseFlexFormXMLData_DS = array();  // Contains data structure when traversing flexform
00077     var $traverseFlexFormXMLData_Data = array();    // Contains data array when traversing flexform
00078 
00079         // Options for array2xml() for flexform. This will map the weird keys from the internal array to tags that could potentially be checked with a DTD/schema
00080     var $flexArray2Xml_options = array(
00081             'parentTagMap' => array(
00082                 'data' => 'sheet',
00083                 'sheet' => 'language',
00084                 'language' => 'field',
00085                 'el' => 'field',
00086                 'field' => 'value',
00087                 'field:el' => 'el',
00088                 'el:_IS_NUM' => 'section',
00089                 'section' => 'itemType'
00090             ),
00091             'disableTypeAttrib' => 2
00092         );
00093 
00094         // Internal:
00095     /**
00096      * Reference to object called
00097      */
00098     var $callBackObj = NULL;
00099     var $cleanFlexFormXML = array();        // Used for accumulation of clean XML
00100 
00101     /**
00102      * Handler for Flex Forms
00103      *
00104      * @param   string      The table name of the record
00105      * @param   string      The field name of the flexform field to work on
00106      * @param   array       The record data array
00107      * @param   object      Object (passed by reference) in which the call back function is located
00108      * @param   string      Method name of call back function in object for values
00109      * @return  boolean     If true, error happened (error string returned)
00110      */
00111     function traverseFlexFormXMLData($table,$field,$row,&$callBackObj,$callBackMethod_value)    {
00112 
00113         if (!is_array($GLOBALS['TCA'][$table]) || !is_array($GLOBALS['TCA'][$table]['columns'][$field]))    {
00114             return 'TCA table/field was not defined.';
00115         }
00116 
00117         $this->callBackObj = &$callBackObj;
00118 
00119             // Get Data Structure:
00120         $dataStructArray = t3lib_BEfunc::getFlexFormDS($GLOBALS['TCA'][$table]['columns'][$field]['config'],$row,$table);
00121 
00122             // If data structure was ok, proceed:
00123         if (is_array($dataStructArray)) {
00124 
00125                 // Get flexform XML data:
00126             $xmlData = $row[$field];
00127 
00128                 // Convert charset:
00129             if ($this->convertCharset)  {
00130                 $xmlHeaderAttributes = t3lib_div::xmlGetHeaderAttribs($xmlData);
00131                 $storeInCharset = strtolower($xmlHeaderAttributes['encoding']);
00132                 if ($storeInCharset)    {
00133                     $currentCharset = $GLOBALS['LANG']->charSet;
00134                     $xmlData = $GLOBALS['LANG']->csConvObj->conv($xmlData,$storeInCharset,$currentCharset,1);
00135                 }
00136             }
00137 
00138             $editData = t3lib_div::xml2array($xmlData);
00139             if (!is_array($editData))   {
00140                 return 'Parsing error: '.$editData;
00141             }
00142 
00143                 // Language settings:
00144             $langChildren = $dataStructArray['meta']['langChildren'] ? 1 : 0;
00145             $langDisabled = $dataStructArray['meta']['langDisable'] ? 1 : 0;
00146 
00147                 // empty or invalid <meta>
00148             if (!is_array($editData['meta']))   {
00149                 $editData['meta'] = array();
00150             }
00151             $editData['meta']['currentLangId'] = array();
00152             $languages = $this->getAvailableLanguages();
00153 
00154             foreach ($languages as $lInfo)  {
00155                 $editData['meta']['currentLangId'][] = $lInfo['ISOcode'];
00156             }
00157             if (!count($editData['meta']['currentLangId'])) {
00158                 $editData['meta']['currentLangId'] = array('DEF');
00159             }
00160             $editData['meta']['currentLangId'] = array_unique($editData['meta']['currentLangId']);
00161 
00162             if ($langChildren || $langDisabled) {
00163                 $lKeys = array('DEF');
00164             } else {
00165                 $lKeys = $editData['meta']['currentLangId'];
00166             }
00167 
00168                 // Tabs sheets
00169             if (is_array($dataStructArray['sheets']))   {
00170                 $sKeys = array_keys($dataStructArray['sheets']);
00171             } else {
00172                 $sKeys = array('sDEF');
00173             }
00174 
00175                 // Traverse languages:
00176             foreach($lKeys as $lKey)    {
00177                 foreach($sKeys as $sheet)   {
00178                     $sheetCfg = $dataStructArray['sheets'][$sheet];
00179                     list ($dataStruct, $sheet) = t3lib_div::resolveSheetDefInDS($dataStructArray,$sheet);
00180 
00181                         // Render sheet:
00182                     if (is_array($dataStruct['ROOT']) && is_array($dataStruct['ROOT']['el']))       {
00183                         $lang = 'l'.$lKey;  // Separate language key
00184                         $PA['vKeys'] = $langChildren && !$langDisabled ? $editData['meta']['currentLangId'] : array('DEF');
00185                         $PA['lKey'] = $lang;
00186                         $PA['callBackMethod_value'] = $callBackMethod_value;
00187                         $PA['table'] = $table;
00188                         $PA['field'] = $field;
00189                         $PA['uid'] = $row['uid'];
00190 
00191                         $this->traverseFlexFormXMLData_DS = &$dataStruct;
00192                         $this->traverseFlexFormXMLData_Data = &$editData;
00193 
00194                             // Render flexform:
00195                         $this->traverseFlexFormXMLData_recurse(
00196                             $dataStruct['ROOT']['el'],
00197                             $editData['data'][$sheet][$lang],
00198                             $PA,
00199                             'data/'.$sheet.'/'.$lang
00200                         );
00201                     } else return 'Data Structure ERROR: No ROOT element found for sheet "'.$sheet.'".';
00202                 }
00203             }
00204         } else return 'Data Structure ERROR: '.$dataStructArray;
00205     }
00206 
00207     /**
00208      * Recursively traversing flexform data according to data structure and element data
00209      *
00210      * @param   array       (Part of) data structure array that applies to the sub section of the flexform data we are processing
00211      * @param   array       (Part of) edit data array, reflecting current part of data structure
00212      * @param   array       Additional parameters passed.
00213      * @param   string      Telling the "path" to the element in the flexform XML
00214      * @return  array
00215      */
00216     function traverseFlexFormXMLData_recurse($dataStruct,$editData,&$PA,$path='')   {
00217 
00218         if (is_array($dataStruct))  {
00219             foreach($dataStruct as $key => $value)  {
00220                 if (is_array($value))   {   // The value of each entry must be an array.
00221 
00222                     if ($value['type']=='array')    {
00223                         if ($value['section'])  {       // Array (Section) traversal:
00224 
00225                             $cc = 0;
00226                             if (is_array($editData[$key]['el']))    {
00227 
00228                                 if ($this->reNumberIndexesOfSectionData)    {
00229                                     $temp = array();
00230                                     $c3=0;
00231                                     foreach($editData[$key]['el'] as $v3)   {
00232                                         $temp[++$c3] = $v3;
00233                                     }
00234                                     $editData[$key]['el'] = $temp;
00235                                 }
00236 
00237                                 foreach($editData[$key]['el'] as $k3 => $v3)    {
00238                                     if (is_array($v3))  {
00239                                         $cc=$k3;
00240                                         $theType = key($v3);
00241                                         $theDat = $v3[$theType];
00242                                         $newSectionEl = $value['el'][$theType];
00243                                         if (is_array($newSectionEl))    {
00244                                             $this->traverseFlexFormXMLData_recurse(
00245                                                 array($theType => $newSectionEl),
00246                                                 array($theType => $theDat),
00247                                                 $PA,
00248                                                 $path.'/'.$key.'/el/'.$cc
00249                                             );
00250                                         }
00251                                     }
00252                                 }
00253                             }
00254                         } else {    // Array traversal:
00255                             $this->traverseFlexFormXMLData_recurse(
00256                                 $value['el'],
00257                                 $editData[$key]['el'],
00258                                 $PA,
00259                                 $path.'/'.$key.'/el'
00260                             );
00261                         }
00262                     } elseif (is_array($value['TCEforms']['config'])) { // Processing a field value:
00263 
00264                         foreach($PA['vKeys'] as $vKey)  {
00265                             $vKey = 'v'.$vKey;
00266 
00267                                 // Call back:
00268                             if ($PA['callBackMethod_value'])    {
00269                                 $this->callBackObj->$PA['callBackMethod_value'](
00270                                     $value,
00271                                     $editData[$key][$vKey],
00272                                     $PA,
00273                                     $path.'/'.$key.'/'.$vKey,
00274                                     $this
00275                                 );
00276                             }
00277                         }
00278                     }
00279                 }
00280             }
00281         }
00282     }
00283 
00284     /**
00285      * Returns an array of available languages to use for FlexForm operations
00286      *
00287      * @return  array
00288      */
00289     function getAvailableLanguages()    {
00290         $isL = t3lib_extMgm::isLoaded('static_info_tables');
00291 
00292             // Find all language records in the system:
00293         $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('static_lang_isocode,title,uid', 'sys_language', 'pid=0'.t3lib_BEfunc::deleteClause('sys_language'), '', 'title');
00294 
00295             // Traverse them:
00296         $output = array();
00297         $output[0]=array(
00298             'uid' => 0,
00299             'title' => 'Default language',
00300             'ISOcode' => 'DEF'
00301         );
00302 
00303         while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))   {
00304             $output[$row['uid']] = $row;
00305 
00306             if ($isL && $row['static_lang_isocode'])    {
00307                 $rr = t3lib_BEfunc::getRecord('static_languages',$row['static_lang_isocode'],'lg_iso_2');
00308                 if ($rr['lg_iso_2'])    $output[$row['uid']]['ISOcode']=$rr['lg_iso_2'];
00309             }
00310 
00311             if (!$output[$row['uid']]['ISOcode'])   unset($output[$row['uid']]);
00312         }
00313         return $output;
00314     }
00315 
00316 
00317 
00318 
00319 
00320 
00321 
00322 
00323 
00324     /***********************************
00325      *
00326      * Processing functions
00327      *
00328      ***********************************/
00329 
00330     /**
00331      * Cleaning up FlexForm XML to hold only the values it may according to its Data Structure. Also the order of tags will follow that of the data structure.
00332      * BE CAREFUL: DO not clean records in workspaces unless IN the workspace! The Data Structure might resolve falsely on a workspace record when cleaned from Live workspace.
00333      *
00334      * @param   string      Table name
00335      * @param   string      Field name of the flex form field in which the XML is found that should be cleaned.
00336      * @param   array       The record
00337      * @return  string      Clean XML from FlexForm field
00338      */
00339     function cleanFlexFormXML($table,$field,$row)   {
00340 
00341             // New structure:
00342         $this->cleanFlexFormXML = array();
00343 
00344             // Create and call iterator object:
00345         $flexObj = t3lib_div::makeInstance('t3lib_flexformtools');
00346         $flexObj->reNumberIndexesOfSectionData = TRUE;
00347         $flexObj->traverseFlexFormXMLData($table,$field,$row,$this,'cleanFlexFormXML_callBackFunction');
00348 
00349         return $this->flexArray2Xml($this->cleanFlexFormXML, TRUE);
00350     }
00351 
00352     /**
00353      * Call back function for t3lib_flexformtools class
00354      * Basically just setting the value in a new array (thus cleaning because only values that are valid are visited!)
00355      *
00356      * @param   array       Data structure for the current value
00357      * @param   mixed       Current value
00358      * @param   array       Additional configuration used in calling function
00359      * @param   string      Path of value in DS structure
00360      * @param   object      Object reference to caller
00361      * @return  void
00362      */
00363     function cleanFlexFormXML_callBackFunction($dsArr, $data, $PA, $path, &$pObj)   {
00364         #debug(array($dsArr, $data, $PA),$path);
00365             // Just setting value in our own result array, basically replicating the structure:
00366         $pObj->setArrayValueByPath($path,$this->cleanFlexFormXML,$data);
00367 
00368             // Looking if an "extension" called ".vDEFbase" is found and if so, accept that too:
00369         if ($GLOBALS['TYPO3_CONF_VARS']['BE']['flexFormXMLincludeDiffBase'])    {
00370             $vDEFbase = $pObj->getArrayValueByPath($path.'.vDEFbase',$pObj->traverseFlexFormXMLData_Data);
00371             if (isset($vDEFbase))   {
00372                 $pObj->setArrayValueByPath($path.'.vDEFbase',$this->cleanFlexFormXML,$vDEFbase);
00373             }
00374         }
00375     }
00376 
00377 
00378 
00379 
00380 
00381 
00382 
00383 
00384 
00385     /***********************************
00386      *
00387      * Multi purpose functions
00388      *
00389      ***********************************/
00390 
00391     /**
00392      * Get a value from a multi-dimensional array by giving a path "../../.." pointing to the element
00393      *
00394      * @param   string      The path pointing to the value field, eg. test/2/title to access $array['test'][2]['title']
00395      * @param   array       Array to get value from. Passed by reference so the value returned can be used to change the value in the array!
00396      * @return  mixed       Value returned
00397      */
00398     function &getArrayValueByPath($pathArray,&$array)   {
00399         if (!is_array($pathArray))  {
00400             $pathArray = explode('/',$pathArray);
00401         }
00402         if (is_array($array))   {
00403             if (count($pathArray))  {
00404                 $key = array_shift($pathArray);
00405 
00406                 if (isset($array[$key]))    {
00407                     if (!count($pathArray)) {
00408                         return $array[$key];
00409                     } else {
00410                         return $this->getArrayValueByPath($pathArray,$array[$key]);
00411                     }
00412                 } else {
00413                     return NULL;
00414                 }
00415             }
00416         }
00417     }
00418 
00419     /**
00420      * Set a value in a multi-dimensional array by giving a path "../../.." pointing to the element
00421      *
00422      * @param   string      The path pointing to the value field, eg. test/2/title to access $array['test'][2]['title']
00423      * @param   array       Array to set value in. Passed by reference so the value returned can be used to change the value in the array!
00424      * @param   mixed       Value to set
00425      * @return  mixed       Value returned
00426      */
00427     function setArrayValueByPath($pathArray,&$array,$value) {
00428         if (isset($value))   {
00429             if (!is_array($pathArray))  {
00430                 $pathArray = explode('/',$pathArray);
00431             }
00432             if (is_array($array))   {
00433                 if (count($pathArray))  {
00434                     $key = array_shift($pathArray);
00435 
00436                     if (!count($pathArray)) {
00437                         $array[$key] = $value;
00438                         return TRUE;
00439                     } else {
00440                         if (!isset($array[$key]))   {
00441                             $array[$key] = array();
00442                         }
00443                         return $this->setArrayValueByPath($pathArray,$array[$key],$value);
00444                     }
00445                 }
00446             }
00447         }
00448     }
00449 
00450     /**
00451      * Convert FlexForm data array to XML
00452      *
00453      * @param   array       Array to output in <T3FlexForms> XML
00454      * @param   boolean     If set, the XML prologue is returned as well.
00455      * @return  string      XML content.
00456      */
00457     function flexArray2Xml($array, $addPrologue=FALSE)  {
00458 
00459         $options = $GLOBALS['TYPO3_CONF_VARS']['BE']['niceFlexFormXMLtags'] ? $this->flexArray2Xml_options : array();
00460         $spaceInd = ($GLOBALS['TYPO3_CONF_VARS']['BE']['compactFlexFormXML'] ? -1 : 4);
00461         $output = t3lib_div::array2xml($array,'',0,'T3FlexForms', $spaceInd, $options);
00462 
00463         if ($addPrologue)   {
00464             $output = '<?xml version="1.0" encoding="'.$GLOBALS['LANG']->charSet.'" standalone="yes" ?>'.chr(10).$output;
00465         }
00466 
00467         return $output;
00468     }
00469 }
00470 
00471 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_flexformtools.php']) {
00472     include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_flexformtools.php']);
00473 }
00474 ?>

Generated on Sat Jan 3 04:23:26 2009 for TYPO3 API by  doxygen 1.4.7