![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00002 /*------------------------------------------------------------------------------- 00003 * Xataface Web Application Framework 00004 * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 *------------------------------------------------------------------------------- 00020 */ 00021 00022 00023 00024 /******************************************************************************* 00025 * File: Table.php 00026 * Author: Steve Hannah <shannah@sfu.ca> 00027 * Description: 00028 * Encapsulates a table of a data driven data type. 00029 * 00030 ******************************************************************************/ 00031 00032 if ( !defined('DATAFACE_EXTENSION_LOADED_APC') ){ 00033 00034 define('DATAFACE_EXTENSION_LOADED_APC',extension_loaded('apc')); 00035 00036 } 00037 00038 import( 'PEAR.php'); 00039 import( 'Dataface/Error.php'); 00040 import( 'Dataface/Globals.php'); 00041 import( 'Dataface/Relationship.php'); 00042 import( 'Dataface/converters/date.php'); 00043 import( 'Dataface/Application.php'); 00044 //require_once dirname(__FILE__).'/../config.inc.php'; 00045 import( 'SQL/Parser.php'); 00046 import( 'SQL/Parser/wrapper.php'); 00047 import( 'Dataface/Serializer.php'); 00048 import( 'Dataface/ConfigTool.php'); 00049 00050 define('Dataface_Table_UseCache', false); 00051 00056 $GLOBALS['Dataface_Table_DefaultFieldPermissions'] = array( 00057 "view"=>'View', 00058 "edit"=>'Edit' 00059 ); 00060 00061 $GLOBALS['Dataface_Table_DefaultTablePermissions'] = array( 00062 "view"=>"View", 00063 "edit"=>"Edit", 00064 "delete"=>"Delete" 00065 ); 00066 00067 define( 'SCHEMA_INVALID_ADDRESS_ERROR', 1); 00068 define( 'SCHEMA_NO_SUCH_FIELD_ERROR',2); 00069 define( 'SCHEMA_AMBIGUOUS_FIELD_ERROR',3); 00070 define( 'Dataface_SCHEMA_NO_VALUE_ASSIGNED', 4); 00071 define( 'Dataface_SCHEMA_INDEX_OUT_OF_BOUNDS_ERROR', 5); 00072 define( 'Dataface_SCHEMA_SQL_ERROR', 6); 00073 define( 'Dataface_SCHEMA_NO_SUCH_RELATIONSHIP_ERROR',7); 00074 define( 'Dataface_SCHEMA_INVALID_VALUE_ERROR',8); 00075 define( 'DATAFACE_TABLE_SQL_PARSE_ERROR', 9); 00076 define( 'DATAFACE_TABLE_RELATED_RECORD_CREATION_ERROR', 10); 00077 define( 'DATAFACE_TABLE_RELATED_RECORD_REQUIRED_FIELD_MISSING_ERROR',12); 00078 define( 'DATAFACE_TABLE_RECORD_RELATED_RECORD_BLOCKSIZE', 30); 00079 define( 'DATAFACE_TABLE_SQL_ERROR',11); 00080 define( 'SCHEMA_TABLE_NOT_FOUND', 12); 00081 00098 class Dataface_Table { 00104 var $tablename; 00105 00110 var $db; 00111 00116 var $_fields = array(); 00117 00123 var $_grafted_fields = null; 00124 00125 00133 var $_transient_fields = null; 00134 00141 var $_parentTable = null; 00142 00147 var $_cookedValuelists=array(); 00148 00149 00172 var $_joinTables = null; 00173 00180 var $_sql; 00181 00190 var $_proxyViews = array(); 00191 00198 var $_fieldsByTab = null; 00199 00200 00205 var $_relatedFields = array(); 00206 00211 var $_fieldgroups = array(); 00212 00217 var $_tabs = array(); 00218 00225 var $_keys = array(); 00226 00232 var $_iniFile = ''; 00233 00238 var $_atts; 00239 00244 var $_relationships = array(); 00245 00253 var $_relationshipRanges; 00254 00259 var $_defaultRelationshipRange = array(0, DATAFACE_TABLE_RECORD_RELATED_RECORD_BLOCKSIZE); 00260 00265 var $_valuelists; 00266 00271 var $_delegate; 00272 00277 var $status; 00278 00279 00286 var $_relationshipsLoaded = false; 00287 00288 00292 var $errors = array(); 00293 00298 var $_permissions; 00299 00304 var $_serializer; 00305 00312 var $_filters = array(); 00313 00314 00320 var $_importFilters = null; 00321 00329 var $_fieldsConfig; 00330 00334 var $_relationshipsConfig; 00335 00339 var $_valuelistsConfig; 00340 00344 var $_actionsLoaded = false; 00345 00349 var $_actionsConfig = null; 00350 00351 // reference to application object 00355 var $app = null; 00356 00357 00362 var $_permissionsLoaded = false; 00363 00367 var $translations = null; 00368 00369 00373 var $_cache = array(); 00374 00379 var $metadataColumns = null; 00380 00385 var $_securityFilter = array(); 00386 00390 var $_securityFilterLoaded = false; 00391 00392 00401 var $descriptionField; 00402 00406 var $createdField; 00407 00411 var $creatorField; 00412 00416 var $lastUpdatedField; 00417 00421 var $publicLinkTemplate; 00422 00426 var $bodyField; 00427 00431 var $_global_field_properties; 00432 //---------------------------------------------------------------------------------------------- 00433 // @{ 00454 public static function &loadTable($name, $db=null, $getAll=false, $quiet=false){ 00455 if ( !is_string($name) ){ 00456 throw new Exception("In Dataface_Table::loadTable() expected first argument to be a string but received '".get_class($name)."'", E_USER_ERROR); 00457 } 00458 00459 if ( $db === null and defined('DATAFACE_DB_HANDLE')) $db = DATAFACE_DB_HANDLE; 00460 if ( !isset( $_tables ) ){ 00461 static $_tables = array(); 00462 00463 static $_db = ''; 00464 } 00465 if ( $getAll ){ 00466 return $_tables; 00467 00468 } 00469 if ( $db ) $_db = $db; 00470 if ( !isset( $_tables[$name] ) ){ 00471 $app =& Dataface_Application::getInstance(); 00472 $_tables[$name] = new Dataface_Table($name, $_db, $quiet); 00473 00474 00475 $_tables[$name]->postInit(); 00476 } 00477 00478 return $_tables[$name]; 00479 00480 } 00481 00482 00490 function Dataface_Table($tablename, $db=null, $quiet=false){ 00491 if ( !$tablename || !is_string($tablename) ){ 00492 throw new Exception("Invalid tablename specified: $tablename", E_USER_ERROR); 00493 } 00494 if ( strpos($tablename,'`') !== false ){ 00495 throw new Exception("Invalid character found in table '$tablename'.", E_USER_ERROR); 00496 00497 } 00498 import('Dataface/Record.php'); 00499 $this->app =& Dataface_Application::getInstance(); 00500 // register this table name with the application object so we can keep 00501 // track of which tables are used on each request. This helps with 00502 // caching. 00503 $this->app->tableNamesUsed[] = $tablename; 00504 $this->tablename = $tablename; 00505 if ( $db === null and defined('DATAFACE_DB_HANDLE') ) $db = DATAFACE_DB_HANDLE; 00506 $this->db = $db; 00507 $this->_permissions = Dataface_PermissionsTool::getRolePermissions($this->app->_conf['default_table_role']); 00508 00509 00510 $this->tablename = str_replace(' ', '', $this->tablename); 00511 // prevent malicious SQL injection 00512 00513 $this->_atts = array(); 00514 $this->_atts['name'] = $this->tablename; 00515 00516 $this->_atts['label'] = (isset( $this->app->_tables[$this->tablename] ) ? $this->app->_tables[$this->tablename] : $this->tablename); 00517 00518 $mod_times =& self::getTableModificationTimes(); 00519 00520 $apc_key = DATAFACE_SITE_PATH.'-Table.php-'.$this->tablename.'-columns'; 00521 $apc_key_fields = $apc_key.'-fields'; 00522 $apc_key_keys = $apc_key.'-keys'; 00523 $apc_key_mtime = $apc_key.'__mtime'; 00524 if ( DATAFACE_EXTENSION_LOADED_APC 00525 and 00526 ( !@$_GET['--refresh-apc'] ) 00527 and 00528 ( @$mod_times[$this->tablename] < apc_fetch($apc_key_mtime) ) 00529 and 00530 ( $this->_fields = apc_fetch($apc_key_fields) ) 00531 and 00532 ( $this->_keys = apc_fetch($apc_key_keys) ) 00533 ){ 00534 // no need to refresh the cache 00535 $fieldnames = array_keys($this->_fields); 00536 00537 } else { 00538 00539 00540 00541 00542 $res = mysql_query("SHOW COLUMNS FROM `".$this->tablename."`", $this->db); 00543 if ( !$res ){ 00544 if ( $quiet ){ 00545 return PEAR::raiseError("Error performing mysql query to get column information from table '".$this->tablename."'. The mysql error returned was : '".mysql_error($this->db)); 00546 } else { 00547 throw new Exception("Error performing mysql query to get column information from table '".$this->tablename."'. The mysql error returned was : '".mysql_error($this->db), E_USER_ERROR); 00548 } 00549 00550 } 00551 00552 if ( mysql_num_rows($res) > 0 ){ 00553 while ( $row = mysql_fetch_assoc($res) ){ 00554 /* 00555 Example row as follows: 00556 Array 00557 ( 00558 [Field] => id 00559 [Type] => int(7) 00560 [Null] => 00561 [Key] => PRI 00562 [Default] => 00563 [Extra] => auto_increment 00564 ) 00565 */ 00566 00567 00568 00569 $widget = array(); 00570 $widget['label'] = ucfirst(str_replace('_',' ',$row['Field'])); 00571 $widget['description'] = ''; 00572 $widget['label_i18n'] = $this->tablename.'.'.$row['Field'].'.label'; 00573 $widget['description_i18n'] = $this->tablename.'.'.$row['Field'].'.description'; 00574 $widget['macro'] = ''; 00575 $widget['helper_css'] = ''; 00576 $widget['helper_js'] = ''; 00577 $widget['type'] = 'text'; 00578 $widget['class'] = ''; 00579 $widget['atts'] = array(); 00580 if ( preg_match( '/text/', $row['Type']) ){ 00581 $widget['type'] = 'textarea'; 00582 } else if ( preg_match( '/blob/', $row['Type']) ){ 00583 $widget['type'] = 'file'; 00584 } 00585 00586 00587 00588 $widget['class'] = 'default'; 00589 00590 $row['tablename'] = $this->tablename; 00591 $row['widget'] =& $widget; 00592 $row['tableta'] = 'default'; 00593 $row['vocabulary'] = ''; 00594 $row['enforceVocabulary'] = false; 00595 $row['validators'] = array(); 00596 $row['name'] = $row['Field']; 00597 $row['permissions'] = Dataface_PermissionsTool::getRolePermissions($this->app->_conf['default_field_role']); 00598 $row['repeat'] = false; 00599 $row['visibility'] = array('list'=>'visible', 'browse'=>'visible', 'find'=>'visible'); 00600 00601 00602 00603 00604 00605 00606 00607 00608 00609 00610 00611 $this->_fields[ $row['Field'] ] = $row; 00612 if ( strtolower($row['Key']) == strtolower('PRI') ){ 00613 $this->_keys[ $row['Field'] ] =& $this->_fields[ $row['Field'] ]; 00614 } 00615 00616 unset($widget); 00617 } 00618 } 00619 00620 mysql_free_result($res); 00621 00622 00623 00624 00625 00626 // check for obvious field types 00627 $fieldnames = array_keys($this->_fields); 00628 foreach ($fieldnames as $key){ 00629 $matches = array(); 00630 00631 if ( preg_match( '/^(.*)_mimetype$/', $key, $matches) and 00632 isset( $this->_fields[$matches[1]] ) /*and 00633 ($this->isBlob($matches[1]) or $this->isContainer($matches[1]))*/ ){ 00634 00635 $this->_fields[$key]['widget']['type'] = 'hidden'; 00636 $this->_fields[$matches[1]]['mimetype'] = $key; 00637 $this->_fields[$key]['metafield'] = true; 00638 } else if ( preg_match( '/^(.*)_filename$/', $key, $matches) and 00639 isset( $this->_fields[$matches[1]] ) and 00640 $this->isBlob($matches[1]) ){ 00641 $this->_fields[$key]['widget']['type'] = 'hidden'; 00642 $this->_fields[$matches[1]]['filename'] = $key; 00643 $this->_fields[$key]['metafield'] = true; 00644 } else if ( preg_match('/password/', strtolower($key) ) ){ 00645 $this->_fields[$key]['widget']['type'] = 'password'; 00646 } else if ( $this->_fields[$key]['Extra'] == 'auto_increment'){ 00647 $this->_fields[$key]['widget']['type'] = 'hidden'; 00648 } else if ( preg_match('/^date/', strtolower($this->_fields[$key]['Type']) ) ){ 00649 $this->_fields[$key]['widget']['type'] = 'calendar'; 00650 00651 if ( !preg_match('/time/', strtolower($this->_fields[$key]['Type']) ) ){ 00652 $this->_fields[$key]['widget']['showsTime'] = false; 00653 $this->_fields[$key]['widget']['ifFormat'] = '%Y-%m-%d'; 00654 } 00655 } else if ( preg_match('/timestamp/', strtolower($this->_fields[$key]['Type']) ) ){ 00656 $this->_fields[$key]['widget']['type'] = 'static'; 00657 } else if ( strtolower(substr($this->_fields[$key]['Type'],0, 4)) == 'time'){ 00658 $this->_fields[$key]['widget']['type'] = 'time'; 00659 } else if ( substr($this->_fields[$key]['Type'], 0,4) == 'enum' ){ 00660 $this->_fields[$key]['widget']['type'] = 'select'; 00661 } 00662 } 00663 if ( DATAFACE_EXTENSION_LOADED_APC ){ 00664 apc_store($apc_key_fields, $this->_fields); 00665 apc_store($apc_key_keys, $this->_keys); 00666 apc_store($apc_key_mtime, time()); 00667 } 00668 } 00669 00670 $this->_loadFieldsIniFile(); 00671 00672 $parent =& $this->getParent(); 00673 if ( isset($parent) ){ 00674 foreach ( array_keys($this->keys()) as $currkey ){ 00675 $this->_fields[$currkey]['widget']['type'] = 'hidden'; 00676 } 00677 } 00678 00679 $curr_order = 0; 00680 $needs_sort = false; // flag to indicate if any "order" attributes were set in the fields.ini file 00681 00682 foreach (array_keys($this->_fields) as $field_name ){ 00683 if ( isset($this->_fields[$field_name]['order']) ) { 00684 $needs_sort = true; 00685 $curr_order++; 00686 } 00687 else $this->_fields[$field_name]['order'] = $curr_order++; 00688 } 00689 00690 //$this->_loadValuelistsIniFile(); 00691 // lazily created now in valuelists() and getValuelist() 00692 //$this->_loadRelationshipsIniFile(); 00693 // had to be removed to prevent possibility of infinite loops. This is now called lazily as relationships 00694 // are needed. 00695 00696 //$GLOBALS['DATAFACE_QUERYBUILDER_SECURITY_CONSTRAINTS'][$this->tablename] = $this->_filters; 00697 00698 00699 // get some validation information to start with 00700 foreach ($fieldnames as $key){ 00701 $row =& $this->_fields[$key]; 00702 00703 00704 // handle case where this is an enumerated field 00705 $matches = array(); 00706 if ( preg_match('/^(enum|set)\(([^\)]+)\)$/', $row['Type'], $matches )){ 00707 00708 $valuelists =& $this->valuelists(); 00709 $options = explode(',', $matches[2]); 00710 00711 $vocab = array(); 00712 foreach ( $options as $val){ 00713 $val = substr($val,1,strlen($val)-2); // strip off the quotes 00714 $vocab[$val] = $val; 00715 } 00716 00717 $valuelists[$row['name']."_values"] =& $vocab; 00718 if ( !@$row['vocabulary'] ) $row['vocabulary'] = $row['name']."_values"; 00719 00720 00721 if ( strtolower($matches[1]) == 'set'){ 00722 $row['repeat'] = true; 00723 } else { 00724 $row['repeat'] = false; 00725 } 00726 00727 $row['widget']['type'] = 'select'; 00728 00729 $opt_keys = array_keys($vocab); 00730 00731 $dummy = ''; 00732 if ( $this->isYesNoValuelist($row['name']."_values", $dummy, $dummy) ){ 00733 $widget['type'] = 'checkbox'; 00734 } 00735 00736 unset( $valuelists); 00737 unset( $vocab); 00738 00739 } 00740 00741 00742 00743 00744 00745 if ( !$this->isBlob($row['name']) and 00746 !$this->isText($row['name']) and 00747 !$this->isDate($row['name']) and 00748 !$this->isPassword($row['name']) and 00749 $row['Null'] != 'YES' and 00750 strlen($row['Default']) == 0 and 00751 $row['Extra'] != 'auto_increment' and 00752 @$row['validators']['required'] !== 0){ 00753 $row['validators'][ 'required' ] = array('message' => $row['widget']['label'] ." is a required field.", 00754 'arg' => '' ); 00755 } 00756 00757 00758 // check for signs that this is a repeated field 00759 if ( $row['widget']['type'] == 'checkbox' and isset( $row['vocabulary'] ) and ( $this->isText($key) or $this->isChar($key) ) ){ 00760 if ( isset( $row['repeat'] ) and !$row['repeat'] ){ 00761 //do nothing 00762 } else { 00763 $row['repeat'] = true; 00764 } 00765 } 00766 if ( !isset($row['repeat']) ) $row['repeat'] = false; 00767 if ( $row['repeat'] and !isset( $row['separator'] )){ 00768 $row['separator'] = "\n"; 00769 } 00770 00771 if ( !isset($row['display']) and $this->isText($row['name']) ) $row['display'] = 'block'; 00772 else if ( !isset($row['display']) ) $row['display'] = 'inline'; 00773 00774 unset($row); 00775 } 00776 00777 // check for obvious signs that this is a repeating field 00778 00779 // sort the fields now based on their order attribute 00780 if ($needs_sort){ 00781 uasort($this->_fields, array(&$this, '_compareFields')); 00782 } 00783 00784 00785 } 00786 00791 function postInit(){ 00792 // call init method of delegate 00793 $delegate =& $this->getDelegate(); 00794 00795 00796 $parent =& $this->getParent(); 00797 if ( isset($parent) ){ 00798 $pdelegate =& $parent->getDelegate(); 00799 if ( isset($pdelegate) and method_exists($pdelegate, 'init') ){ 00800 $res = $pdelegate->init($this); 00801 } 00802 } 00803 00804 if ( $delegate !== null and method_exists($delegate, 'init') ){ 00805 $res = $delegate->init($this); 00806 } 00807 00808 foreach ( array_keys($this->_fields) as $key){ 00809 $this->_fields[$key]['widget']['description'] = $this->getFieldProperty('widget:description', $key); 00810 $this->_fields[$key]['widget']['label'] = $this->getFieldProperty('widget:label', $key); 00811 $this->_fields[$key]['vocabulary'] = $this->getFieldProperty('vocabulary', $key); 00812 $this->_fields[$key]['widget']['type'] = $this->getFieldProperty('widget:type', $key); 00813 $this->_fields[$key]['widget'] = array_merge($this->_fields[$key]['widget'], $this->getFieldProperty('widget', $key)); 00814 } 00815 00816 if ( count($this->_securityFilter) == 0 ){ 00817 $this->setSecurityFilter(); 00818 } 00819 00820 } 00821 00822 00823 // @} 00824 // END Initialization 00825 //---------------------------------------------------------------------------------------------- 00826 00827 00828 //---------------------------------------------------------------------------------------------- 00829 // @{ 00837 // Some static utility methods 00838 00847 public static function &getTableField($address, $db=''){ 00848 $addr = array_map('trim', explode('.', $address) ); 00849 if ( sizeof($addr) != 2 ) { 00850 return PEAR::raiseError(SCHEMA_NO_SUCH_FIELD_ERROR, null,null,null, "Call to getTableField with invalid address: '$address'. Address must be absolute in the form 'table_name.column_name'."); 00851 } 00852 00853 $table =& self::loadTable($addr[0], $db); 00854 if ( PEAR::isError($table) ){ 00855 return $table; 00856 } 00857 00858 $fields =& $table->fields(false,true,true); 00859 if ( !isset( $fields[ $addr[1] ] ) ){ 00860 return PEAR::raiseError(SCHEMA_NO_SUCH_FIELD_ERROR, null,null,null, "Call to getTableField with invalid address: '$address'. Column $addr[1] does not exists in table $addr[0]."); 00861 } 00862 00863 return $fields[$addr[1]]; 00864 } 00865 00866 00867 00868 00869 00877 public static function fieldExists($address, $db=''){ 00878 00879 $res = self::getTableField($address, $db); 00880 return !PEAR::isError($res); 00881 00882 } 00883 00891 public static function tableExists($tablename, $usecache=true){ 00892 $app =& Dataface_Application::getInstance(); 00893 static $index = 0; 00894 if ($index === 0 ) $index = array(); 00895 if ( !isset($index[$tablename]) or !$usecache ) { 00896 $index[$tablename] = mysql_num_rows(mysql_query("show tables like '".addslashes($tablename)."'", $app->db())); 00897 } 00898 return $index[$tablename]; 00899 } 00900 00909 function exists($fieldname, $checkParent=true){ 00910 return $this->hasField($fieldname, $checkParent); 00911 } 00912 00919 function hasField($fieldname, $checkParent=true){ 00920 if ( strpos($fieldname,'.') > 0 ){ 00921 list($rel_name, $fieldname) = explode('.', $fieldname); 00922 if ( !$this->hasRelationship($rel_name) ) return false; 00923 $relationship =& $this->getRelationship($rel_name); 00924 if ( $relationship->hasField($fieldname, true, true) ) return true; 00925 return false; 00926 } else { 00927 if ( array_key_exists($fieldname, $this->fields(false,true)) ) return true; 00928 //if ( isset( $this->_fields[$fieldname] ) ) return true; 00929 //if ( isset( $this->_graftedFields[$fieldname]) ) return true; 00930 $delegate =& $this->getDelegate(); 00931 if ( $delegate !== null and method_exists($delegate, 'field__'.$fieldname) ) return true; 00932 $transient =& $this->transientFields(); 00933 if ( isset($transient[$fieldname]) ) return true; 00934 00935 if ( $checkParent ){ 00936 $parent =& $this->getParent(); 00937 if ( isset($parent) and $parent->hasField($fieldname, $checkParent) ) return true; 00938 } 00939 } 00940 return false; 00941 00942 } 00943 00960 public static function absoluteFieldName($field, $tablenames, $db='', $columnList=null){ 00961 if ( self::fieldExists($field, $db) ){ 00962 return $field; 00963 } else if ( strpos($field, '.') > 0 ){ 00964 return self::getTableField($field, $db); 00965 } else { 00966 $found = 0; 00967 $name = ''; 00968 00969 if ( is_array($columnList) ){ 00970 foreach ( $columnList as $column ){ 00971 if ( preg_match('/^(\w+)\.'.$field.'$/', $column) ){ 00972 $name = $column; 00973 $found++; 00974 } 00975 } 00976 } else { 00977 foreach ($tablenames as $table){ 00978 if ( self::fieldExists($table.'.'.$field, $db) ){ 00979 $name = $table.'.'.$field; 00980 $found++; 00981 } 00982 } 00983 } 00984 } 00985 00986 if ( $found == 0 ){ 00987 $err = PEAR::raiseError(SCHEMA_NO_SUCH_FIELD_ERROR,null,null,null, "Field $field does not exist in tables ".implode(',', $tablenames)."."); 00988 00989 throw new Exception($err->toString(), E_USER_WARNING); 00990 } 00991 00992 00993 return $name; 00994 00995 } 00996 01002 function relativeFieldName($fieldname){ 01003 if ( strpos($fieldname,'.') !== false ){ 01004 $path = explode('.', $fieldname); 01005 return $path[1]; 01006 } 01007 return $fieldname; 01008 01009 } 01010 01011 01016 function _fieldsIniFilePath(){ 01017 return $this->basePath().'/tables/'.basename($this->tablename).'/fields.ini'; 01018 } 01019 01046 function guessField($types, $patterns, $forcePattern=false){ 01047 $candidates = array(); 01048 $max = null; 01049 foreach ($this->fields(false,true) as $field){ 01050 $type = strtolower($this->getType($field['name'])); 01051 if ( !isset($types[$type]) ){ 01052 continue; 01053 } 01054 01055 $score = $types[$type]; 01056 $found=false; 01057 foreach ($patterns as $pattern=>$value){ 01058 if ( preg_match($pattern, $field['name']) ){ 01059 $score *= $value; 01060 $found=true; 01061 } 01062 } 01063 if ( $forcePattern and !$found ){ 01064 $score = 0; 01065 } 01066 $candidates[$field['name']] = $score; 01067 if ( !isset($max) ) $max = $field['name']; 01068 else if ( $candidates[$max] < $score ){ 01069 $max = $field['name']; 01070 } 01071 } 01072 return $max; 01073 01074 } 01075 01076 01085 function getDescriptionField(){ 01086 if ( !isset($this->descriptionField) ){ 01087 01088 $this->descriptionField = $this->guessField( 01089 array('text'=>10, 'mediumtext'=>10, 'shorttext'=>10, 'longtext'=>2, 01090 'varchar'=>1, 'char'=>1), 01091 array('/description|summary|overview/'=>10, '/desc/'=>2) 01092 ); 01093 01094 } 01095 return $this->descriptionField; 01096 01097 } 01098 01099 01107 function getCreatedField(){ 01108 if ( !isset($this->createdField) ){ 01109 01110 $this->createdField = $this->guessField( 01111 array('datetime'=>10, 'timestamp'=>10, 'date'=>1), 01112 array('/created|inserted|added|posted|creation|insertion/i'=>10, '/timestamp/i'=>5) 01113 ); 01114 01115 } 01116 return $this->createdField; 01117 } 01118 01126 function getCreatorField(){ 01127 if ( !isset($this->creatorField) ){ 01128 01129 $this->creatorField = $this->guessField( 01130 array('varchar'=>10,'char'=>10,'int'=>5), 01131 array('/(created.*by)|(owner)|(posted*by)|(author)|(creator)/i'=>10), 01132 true 01133 ); 01134 01135 } 01136 return $this->creatorField; 01137 } 01138 01146 function getLastUpdatedField(){ 01147 if ( !isset($this->lastUpdatedField) ){ 01148 $this->lastUpdatedField = $this->guessField( 01149 array('datetime'=>10,'timestamp'=>12), 01150 array('/updated|modified|change|modification|update/i'=>10,'/timestamp/i'=>5) 01151 ) ; 01152 } 01153 return $this->lastUpdatedField; 01154 } 01155 01164 function getBodyField(){ 01165 if ( !isset($this->bodyField) ){ 01166 $this->bodyField = $this->guessField( 01167 array('text'=>10,'longtext'=>10,'mediumtext'=>10), 01168 array('/main|body|content|profile|writeup|bio/i'=>10) 01169 ); 01170 } 01171 } 01172 01173 01174 01181 function _compareFields($a,$b){ 01182 if ( @$a['order'] == @$b['order'] ) return 0; 01183 return ( @$a['order'] < @$b['order'] ) ? -1 : 1; 01184 } 01185 01186 01205 function &getIndexes(){ 01206 if ( !isset( $this->_indexes) ){ 01207 $this->_indexes = array(); 01208 $res = mysql_query("SHOW index FROM `".$this->tablename."`", $this->db); 01209 if ( !$res ){ 01210 throw new Exception("Failed to get index list due to a mysql error: ".mysql_error($this->db), E_USER_ERROR); 01211 } 01212 01213 while ( $row = mysql_fetch_array($res) ){ 01214 if ( !isset( $this->_indexes[ $row['Key_name'] ] ) ) 01215 $this->_indexes[ $row['Key_name'] ] = array(); 01216 $index =& $this->_indexes[$row['Key_name']]; 01217 $index['name'] = $row['Key_name']; 01218 if ( !isset( $index['columns'] ) ) 01219 $index['columns'] = array(); 01220 $index['columns'][] = $row['Column_name']; 01221 $index['unique'] = ( $row['Non_unique'] ? false : true ); 01222 $index['type'] = $row['Index_type']; 01223 $index['comment'] = $row['Comment']; 01224 unset($index); 01225 } 01226 mysql_free_result($res); 01227 01228 } 01229 01230 return $this->_indexes; 01231 01232 01233 } 01234 01245 function getFullTextIndexedFields(){ 01246 01247 $indexes =& $this->getIndexes(); 01248 $fields = array(); 01249 foreach ( array_keys($indexes) as $indexName ){ 01250 if ( strtolower($indexes[$indexName]['type']) === 'fulltext' ){ 01251 foreach ( $indexes[$indexName]['columns'] as $col ){ 01252 $fields[] = $col; 01253 } 01254 } 01255 } 01256 01257 return $fields; 01258 } 01259 01270 function getCharFields($includeGraftedFields=false, $excludeUnsearchable=false){ 01271 if ( !isset($this->_cache[__FUNCTION__]) ){ 01272 $out = array(); 01273 foreach ( array_keys($this->fields(false, $includeGraftedFields)) as $field){ 01274 if ( $this->isChar($field) or $this->isText($field) or (strtolower($this->getType($field)) == 'enum') ){ 01275 if ( $excludeUnsearchable and !$this->isSearchable($field) ) continue; 01276 $out[] = $field; 01277 } 01278 } 01279 $this->_cache[__FUNCTION__] = $out; 01280 } 01281 return $this->_cache[__FUNCTION__]; 01282 01283 } 01284 01292 function isSearchable($field){ 01293 $fld =& $this->getField($field); 01294 return !@$fld['not_searchable']; 01295 } 01296 01306 function isMetaField($fieldname){ 01307 01308 $field =& $this->getField($fieldname); 01309 if ( !isset($field['metafield']) ){ 01310 $fields =& $this->fields(); 01311 $field_names = array_keys($fields); 01312 foreach ( $field_names as $fn){ 01313 if ( ( isset($fields[$fn]['mimetype']) and $fields[$fn]['mimetype'] == $fieldname ) or 01314 ( isset($fields[$fn]['filename']) and $fields[$fn]['filename'] == $fieldname ) ) { 01315 $field['metafield'] = true; 01316 break; 01317 } 01318 } 01319 if ( !isset($field['metafield']) ){ 01320 $field['metafield'] = false; 01321 } 01322 } 01323 return $field['metafield']; 01324 01325 01326 } 01327 01328 01339 function getMetadataColumns(){ 01340 if ( !isset($this->metadataColumns) ){ 01341 $metatablename = $this->tablename.'__metadata'; 01342 $sql = "SHOW COLUMNS FROM `{$metatablename}`"; 01343 $res = mysql_query($sql, $this->db); 01344 if ( !$res || mysql_num_rows($res) == 0){ 01345 Dataface_MetadataTool::refreshMetadataTable($this->tablename); 01346 $res = mysql_query($sql, $this->db); 01347 } 01348 if ( !$res ) throw new Exception(mysql_error($this->db), E_USER_ERROR); 01349 if ( mysql_num_rows($res) == 0 ) throw new Exception("No metadata table set up for table '{$this->tablename}'", E_USER_ERROR); 01350 $this->metadataColumns = array(); 01351 while ($row = mysql_fetch_assoc($res) ){ 01352 if ( substr($row['Field'],0,2) == '__' ){ 01353 $this->metadataColumns[] = $row['Field']; 01354 } 01355 } 01356 01357 } 01358 return $this->metadataColumns; 01359 } 01360 01361 01372 function &formFields($byTab=false, $includeTransient=false){ 01373 if ( !isset($this->_cache[__FUNCTION__][intval($byTab)][intval($includeTransient)]) ){ 01374 $fields = $this->fields($byTab,false,$includeTransient); 01375 $parent =& $this->getParent(); 01376 if ( isset($parent) ){ 01377 01378 $fields = array_merge_recursive_unique($parent->fields($byTab,false,$includeTransient), $fields); 01379 uasort($fields, array(&$this, '_compareFields')); 01380 } 01381 01382 $this->_cache[__FUNCTION__][intval($byTab)][intval($includeTransient)] =& $fields; 01383 } 01384 return $this->_cache[__FUNCTION__][intval($byTab)][intval($includeTransient)]; 01385 } 01386 01397 function &fields($byTab=false, $includeGrafted=false, $includeTransient=false){ 01398 if ( !$byTab) { 01399 //if ( $includeGrafted or $includeTransient){ 01400 if ( !isset($this->_cache[__FUNCTION__][intval($includeGrafted)][intval($includeTransient)]) ){ 01401 //return $this->_cache[intval($includeGrafted)][intval($includeTransient)]; 01402 01403 $fields = array(); 01404 01405 if ( $includeGrafted ){ 01406 $grafted_fields =& $this->graftedFields(); 01407 foreach (array_keys($grafted_fields) as $fname){ 01408 $fields[$fname] =& $grafted_fields[$fname]; 01409 } 01410 } 01411 01412 if ( $includeTransient ){ 01413 $transient_fields =& $this->transientFields(); 01414 foreach ( array_keys($transient_fields) as $fname){ 01415 if ( !isset($fields[$fname]) ) $fields[$fname] =& $transient_fields[$fname]; 01416 01417 } 01418 } 01419 01420 if ( count($fields) > 0 ){ 01421 $fields = array_merge_recursive_unique($this->_fields, $fields); 01422 uasort($fields, array(&$this, '_compareFields')); 01423 $this->_cache[__FUNCTION__][intval($includeGrafted)][intval($includeTransient)] =& $fields; 01424 01425 } else { 01426 $this->_cache[__FUNCTION__][intval($includeGrafted)][intval($includeTransient)] =& $this->_fields; 01427 } 01428 } 01429 01430 return $this->_cache[__FUNCTION__][intval($includeGrafted)][intval($includeTransient)]; 01431 01432 } 01433 else { 01434 if ( !isset( $this->_fieldsByTab ) ){ 01435 $this->_fieldsByTab = array(); 01436 01437 foreach ( $this->fields(false,$includeGrafted, $includeTransient) as $field){ 01438 01439 $tab = ( isset( $field['tab'] ) ? $field['tab'] : '__default__'); 01440 01441 if ( !isset( $this->_fieldsByTab[ $tab] ) ){ 01442 $this->_fieldsByTab[ $tab ] = array(); 01443 } 01444 $this->_fieldsByTab[ $tab ][$field['name']] = $field; 01445 01446 } 01447 } 01448 return $this->_fieldsByTab; 01449 01450 } 01451 } 01452 01478 function &graftedFields($includeParent=true){ 01479 $tsql = $this->sql(); 01480 if ( $includeParent ) $includeParent = 1; 01481 else $includeParent = 0; 01482 01483 if ( !isset($this->_cache[__FUNCTION__][intval($includeParent)]) ){ 01484 //if ( !isset($this->_grafted_fields) ){ 01485 01486 $this->_grafted_fields = array(); 01487 if (isset($tsql)){ 01488 01489 $this->_grafted_fields = array(); 01490 import('SQL/Parser.php'); 01491 $parser = new SQL_Parser(null,'MySQL'); 01492 $data = $parser->parse($tsql); 01493 foreach ( $data['columns'] as $col ){ 01494 if ( $col['type'] != 'glob' ){ 01495 $alias = ( @$col['alias'] ? $col['alias'] : $col['value']); 01496 if ( isset($this->_fields[$alias]) ) continue; 01497 $this->_grafted_fields[$alias] = $this->_newSchema('varchar(32)', $alias); 01498 $this->_grafted_fields[$alias]['grafted']=1; 01499 if ( isset($this->_atts[$alias]) and is_array($this->_atts[$alias]) ){ 01500 01501 $this->_parseINISection($this->_atts[$alias], $this->_grafted_fields[$alias]); 01502 } 01503 //array('Field'=>$alias, 'name'=>$alias, 'Type'=>'varchar(32)', 'widget'=>array('label'=>$alias, 'description'=>'')); 01504 01505 } 01506 } 01507 } 01508 if ( $includeParent ){ 01509 // We now want to load the parent table columns as well. 01510 $parent =& $this->getParent(); 01511 if ( isset($parent) ){ 01512 $this->_grafted_fields = array_merge( $parent->fields(false,true), $this->_grafted_fields); 01513 } 01514 } 01515 $this->_cache[__FUNCTION__][intval($includeParent)] = $this->_grafted_fields; 01516 01517 } 01518 01519 return $this->_cache[__FUNCTION__][intval($includeParent)]; 01520 } 01521 01532 function &transientFields($includeParent=false){ 01533 if ( !isset($this->_cache[__FUNCTION__][intval($includeParent)]) ){ 01534 if ( !isset($this->_transient_fields) ){ 01535 $this->_transient_fields = array(); 01536 foreach ( $this->_atts as $fieldname=>$field ){ 01537 if ( !is_array($field) ) continue; 01538 if ( @$field['transient'] ){ 01539 $curr = array(); 01540 $this->_parseINISection($field, $curr); 01541 if ( @$curr['relationship'] ) $curr['repeat'] = 1; 01542 01543 $curr = array_merge_recursive_unique($this->_global_field_properties, $curr); 01544 $schema = $this->_newSchema('text',$fieldname); 01545 01546 $curr = array_merge_recursive_unique($schema, $curr); 01547 $this->_transient_fields[$fieldname] = $curr; 01548 } 01549 } 01550 if ( $includeParent){ 01551 $parent =& $this->getParent(); 01552 if ( isset($parent) ){ 01553 $this->_transient_fields = array_merge( $parent->transientFields(), $this->_transient_fields); 01554 } 01555 } 01556 } 01557 $this->_cache[__FUNCTION__][intval($includeParent)] =& $this->_transient_fields; 01558 01559 01560 } 01561 //return $this->_transient_fields; 01562 return $this->_cache[__FUNCTION__][intval($includeParent)]; 01563 } 01564 01569 function _hasFieldsIniFile(){ 01570 01571 return file_exists( $this->_fieldsIniFilePath() ); 01572 01573 } 01574 01584 function &delegateFields($includeParent=false){ 01585 if ( !isset($this->_cache[__FUNCTION__][intval($includeParent)]) ){ 01586 //if ( !isset($this->_transient_fields) ){ 01587 $fields = array(); 01588 01589 $del =& $this->getDelegate(); 01590 if ( isset($del) ){ 01591 $delegate_methods = get_class_methods(get_class($del)); 01592 01593 $delegate_fields = preg_grep('/^field__/', $delegate_methods); 01594 01595 foreach ($delegate_fields as $dfield){ 01596 $dfieldname = substr($dfield,7); 01597 $fields[$dfieldname] = $this->_newSchema('varchar(32)', $dfieldname); 01598 $fields[$dfieldname]['visibility']['browse'] = 'hidden'; 01599 if ( isset($this->_atts[$dfieldname]) and 01600 is_array($this->_atts[$dfieldname]) ){ 01601 $this->_parseINISection($this->_atts[$dfieldname], $fields[$dfieldname]); 01602 01603 } 01604 01605 01606 } 01607 01608 01609 if ( $includeParent){ 01610 $parent =& $this->getParent(); 01611 if ( isset($parent) ){ 01612 $fields = array_merge( $parent->delegateFields(), $fields); 01613 } 01614 } 01615 } 01616 $this->_cache[__FUNCTION__][intval($includeParent)] = $fields; 01617 01618 01619 } 01620 //return $this->_transient_fields; 01621 return $this->_cache[__FUNCTION__][intval($includeParent)]; 01622 01623 } 01624 01635 function sql(){ 01636 $del =& $this->getDelegate(); 01637 if ( isset($del) and method_exists($del,'__sql__') ){ 01638 return $del->__sql__(); 01639 } else if ( isset($this->_sql) ){ 01640 return $this->_sql; 01641 } else { 01642 return null; 01643 } 01644 01645 } 01646 01647 01662 function getProxyView(){ 01663 if ( defined('XATAFACE_DISABLE_PROXY_VIEWS') and XATAFACE_DISABLE_PROXY_VIEWS ){ 01664 return null; 01665 } 01666 $sql = $this->sql(); 01667 01668 // If there is no custom SQL then there is no point using a view at all 01669 if ( !$sql ){ 01670 return null; 01671 } 01672 $sqlKey = md5($sql); 01673 $viewName = 'dataface__view_'.$this->tablename.'_'.$sqlKey; 01674 if ( isset($this->_proxyViews[$viewName]) and $this->_proxyViews[$viewName]) return $viewName; 01675 else if ( isset($this->_proxyViews[$viewName]) and !$this->_proxyViews[$viewName]) return null; 01676 01677 01678 if ( Dataface_Application::getInstance()->getMySQLMajorVersion() < 5 ){ 01679 $this->_proxyViews[$viewName] = false; 01680 return null; 01681 } 01682 01683 if ( @$this->app->_conf['multilingual_content'] and $this->getTranslations() ){ 01684 $this->_proxyViews[$viewName] = false; 01685 return null; 01686 } 01687 01688 // Check if view already exists 01689 $res = mysql_query("show table status like '".addslashes($viewName)."'", df_db()); 01690 if ( !$res ) throw new Exception(mysql_error(df_db())); 01691 if ( mysql_num_rows($res) < 1 ){ 01692 @mysql_free_result($res); 01693 // The view doesn't exist yet 01694 $res = mysql_query("create view `".str_replace('`','', $viewName)."` as ".$sql, df_db()); 01695 if ( !$res ){ 01696 error_log(mysql_error(df_db())); 01697 $this->_proxyViews[$viewName] = false; 01698 return null; 01699 } 01700 01701 01702 } else { 01703 @mysql_free_result($res); 01704 } 01705 $this->_proxyViews[$viewName] = true; 01706 01707 return $viewName; 01708 01709 } 01710 01711 01725 function &keys(){ 01726 return $this->_keys; 01727 } 01728 01729 01736 function hasKey($name){ 01737 if ( !isset( $this->_fields[$name] ) ) return false; 01738 if ( isset( $this->_fields[$name]['Key'] ) && strtolower($this->_fields[$name]['Key']) == strtolower('PRI') ){ 01739 return true; 01740 } 01741 return false; 01742 01743 } 01744 01758 function &mandatoryFields(){ 01759 $fields = array(); 01760 foreach ( array_keys($this->keys()) as $key){ 01761 if ( $this->_fields[$key]['Extra'] == 'auto_increment') continue; 01762 $fields[ $key ] =& $this->_fields[$key]; 01763 } 01764 01765 return $fields; 01766 01767 01768 } 01769 01770 01771 01772 01779 public function getDefaultValue($fieldname){ 01780 $field =& $this->getField($fieldname); 01781 if ( @$field['tablename'] and $field['tablename'] != $this->tablename ){ 01782 // Some fields may have been taken from another table. 01783 $table =& self::loadTable($field['tablename']); 01784 return $table->getDefaultValue($fieldname); 01785 } 01786 $delegate =& $this->getDelegate(); 01787 if ( isset($delegate) and method_exists($delegate, $fieldname.'__default') ){ 01788 return call_user_func(array(&$delegate, $fieldname.'__default')); 01789 } else if ( $field['Default'] ){ 01790 return $field['Default']; 01791 } else { 01792 return null; 01793 } 01794 } 01795 01796 01797 01803 function &getFieldsConfig(){ 01804 return $this->_fieldsConfig; 01805 } 01806 01807 01813 function _newSchema($type, $fieldname, $tablename=null, $permissions = null){ 01814 /* 01815 Example row as follows: 01816 Array 01817 ( 01818 [Field] => id 01819 [Type] => int(7) 01820 [Null] => 01821 [Key] => PRI 01822 [Default] => 01823 [Extra] => auto_increment 01824 ) 01825 */ 01826 if ( !isset($tablename) ) $tablename = $this->tablename; 01827 if ( !isset($permissions) and is_a($this, 'Dataface_Table') ){ 01828 $permissions = Dataface_PermissionsTool::getRolePermissions($this->app->_conf['default_field_role']); 01829 } else if ( !isset($permissions) ){ 01830 $permissions = Dataface_PermissionsTool::READ_ONLY(); 01831 } 01832 01833 $schema = array("Field"=>$fieldname, "Type"=>$type, "Null"=>'', "Key"=>'', "Default"=>'', "Extra"=>''); 01834 $schema = array_merge_recursive_unique($this->_global_field_properties, $schema); 01835 $widget = array(); 01836 $widget['label'] = ucfirst($schema['Field']); 01837 $widget['description'] = ''; 01838 $widget['label_i18n'] = $tablename.'.'.$fieldname.'.label'; 01839 $widget['description_i18n'] = $tablename.'.'.$fieldname.'.description'; 01840 $widget['macro'] = ''; 01841 $widget['helper_css'] = ''; 01842 $widget['helper_js'] = ''; 01843 $widget['class'] = ''; 01844 $widget['type'] = 'text'; 01845 $widget['atts'] = array(); //html attributes 01846 if ( preg_match( '/text/', $schema['Type']) ){ 01847 $widget['type'] = 'textarea'; 01848 } else if ( preg_match( '/blob/', $schema['Type']) ){ 01849 $widget['type'] = 'file'; 01850 } 01851 $schema['widget'] =& $widget; 01852 $schema['tab'] = '__main__'; 01853 01854 $schema['tablename'] = $tablename; 01855 $schema['tableta'] = 'default'; 01856 $schema['vocabulary'] = ''; 01857 $schema['enforceVocabulary'] = false; 01858 $schema['validators'] = array(); 01859 $schema['name'] = $schema['Field']; 01860 $schema['permissions'] = $permissions; 01861 $schema['repeat'] = false; 01862 $schema['visibility'] = array('list'=>'visible', 'browse'=>'visible', 'find'=>'visible'); 01863 $schema = array_merge_recursive_unique($schema, $this->_global_field_properties); 01864 01865 return $schema; 01866 } 01867 01868 01869 01904 function titleColumn(){ 01905 if (!isset( $this->_atts['title'] ) ){ 01906 $delegate =& $this->getDelegate(); 01907 if ( $delegate !== null and method_exists($delegate, 'titleColumn') ){ 01908 $this->_atts['title'] = $delegate->titleColumn(); 01909 } else { 01910 $bestCandidate = null; 01911 $this->fields(); 01912 $fieldnames = array_keys($this->_fields); 01913 foreach ($fieldnames as $fieldname){ 01914 $field =& $this->_fields[$fieldname]; 01915 if ( $bestCandidate === null and $this->isChar($fieldname) ){ 01916 $bestCandidate = '`'.$fieldname.'`'; 01917 } 01918 //if ( strpos(strtolower($fieldname),'title') !== false ){ 01919 // $bestCandidate = $fieldname; 01920 //} 01921 } 01922 if ( $bestCandidate === null ){ 01923 $keynames = array_keys($this->keys()); 01924 $bestCandidate = "CONCAT(".implode(",", $keynames).")"; 01925 } 01926 $this->_atts['title'] = $bestCandidate; 01927 } 01928 } 01929 return $this->_atts['title']; 01930 01931 } 01932 01933 01934 01945 function &getField($fieldname){ 01946 $path = explode('.', $fieldname); 01947 if ( count($path)==1){ 01948 if ( !isset( $this->_fields[$fieldname]) ){ 01949 $delegate =& $this->getDelegate(); 01950 01951 if ( $delegate !== null and method_exists($delegate, "field__$fieldname")){ 01952 if ( isset($this->_atts[$fieldname]) ){ 01953 $schema = array_merge_recursive_unique($this->_newSchema('calculated',$fieldname), $this->_atts[$fieldname]); 01954 } else { 01955 $schema = $this->_newSchema('calculated', $fieldname); 01956 } 01957 return $schema; 01958 } 01959 $grafted =& $this->graftedFields(); 01960 if ( isset($grafted[$fieldname]) ) return $grafted[$fieldname]; 01961 01962 $transient =& $this->transientFields(); 01963 if ( isset($transient[$fieldname]) ) return $transient[$fieldname]; 01964 01965 $parent =& $this->getParent(); 01966 if ( isset($parent) and ( $field =& $parent->getField($fieldname) ) ){ 01967 if ( !PEAR::isError($field) ) return $field; 01968 } 01969 01970 $err = PEAR::raiseError(SCHEMA_NO_SUCH_FIELD_ERROR,null,null,null, "Field $fieldname does not exist in table ".$this->tablename); 01971 01972 return $err; 01973 } 01974 return $this->_fields[$fieldname]; 01975 } else { 01976 // this field is from a relationship. 01977 01978 // first check the cache 01979 if ( !isset( $this->_relatedFields[$path[0]] ) ) $this->_relatedFields[$path[0]] = array(); 01980 if ( !isset( $this->_relatedFields[$path[0]][$path[1]] ) ) { 01981 01982 $relationship =& $this->getRelationship($path[0]); 01983 01984 if ( PEAR::isError($relationship) ){ 01985 $err = PEAR::raiseError(SCHEMA_NO_SUCH_FIELD_ERROR,null,null,null, "Field $fieldname does not exist in table ".$this->tablename); 01986 return $err; 01987 } 01988 01989 $this->_relatedFields[$path[0]][$path[1]] =& $relationship->getField($path[1]); //Dataface_Table::getTableField($absolute_name); 01990 } 01991 01992 return $this->_relatedFields[$path[0]][$path[1]]; 01993 01994 } 01995 01996 } 01997 02018 function getFieldProperty($propertyName, $fieldname, $params=array()){ 02019 $field =& $this->getField($fieldname); 02020 02021 if ( $field['tablename'] != $this->tablename ){ 02022 $table =& self::loadTable($field['tablename']); 02023 return $table->getFieldProperty($propertyName, $fieldname, $params); 02024 } 02025 02026 $table =& $this->getTableTableForField($fieldname); 02027 if ( $this->tablename !== $table->tablename ){ 02028 // THis is a related field so we will have to check the delegate 02029 // class for that table. 02030 list($tablename, $fieldname) = explode('.', $fieldname); 02031 return $table->getFieldProperty($propertyName,$fieldname, $params); 02032 } 02033 02034 02035 // First we will see if the delegate class defines as custom description. 02036 $delegate =& $this->getDelegate(); 02037 $delegate_property_name = str_replace(':', '_', $propertyName); 02038 if ( method_exists($delegate, $fieldname.'__'.$delegate_property_name) ){ 02039 02040 if ( !isset( $params['record'] ) ) $params['record'] = null; 02041 $methodname = $fieldname.'__'.$delegate_property_name; 02042 $res =& $delegate->$methodname($params['record'], $params); 02043 //$res =& call_user_func(array(&$delegate, $fieldname.'__'.$delegate_property_name), $params['record'], $params); 02044 02045 if ( !PEAR::isError($res) || $res->getCode() !== DATAFACE_E_REQUEST_NOT_HANDLED ){ 02046 return $res; 02047 } 02048 } 02049 // The delegate class doesn't define a custom description 02050 // we will just pull the property from the schema 02051 02052 $path = explode(':', $propertyName); 02053 $arr =& $field; 02054 while ( count($path)> 0 ){ 02055 $temp =& $arr[array_shift($path)]; 02056 unset($arr); 02057 $arr =& $temp; 02058 unset($temp); 02059 } 02060 return $arr; 02061 } 02062 02063 02064 02065 02072 function getAutoIncrementField(){ 02073 foreach (array_keys($this->keys()) as $field){ 02074 if (strtolower($this->_fields[$field]['Extra']) == 'auto_increment'){ 02075 return $field; 02076 } 02077 } 02078 return null; 02079 } 02080 02081 private static $globalFieldsConfig = null; 02082 public static function &getGlobalFieldsConfig(){ 02083 if ( !isset(self::$globalFieldsConfig) ){ 02084 //self::$globalFieldsConfig = array(); 02085 import( 'Dataface/ConfigTool.php'); 02086 $configTool =& Dataface_ConfigTool::getInstance(); 02087 self::$globalFieldsConfig =& $configTool->loadConfig('fields', null); 02088 02089 } 02090 //print_r(self::$globalFieldsConfig); 02091 return self::$globalFieldsConfig; 02092 02093 } 02094 02095 02100 function _loadFieldsIniFile(){ 02101 02102 02103 import( 'Dataface/ConfigTool.php'); 02104 $configTool =& Dataface_ConfigTool::getInstance(); 02105 $conf =& $configTool->loadConfig('fields', $this->tablename); //$temp['root']; 02106 $gConf =& self::getGlobalFieldsConfig(); 02107 $conf = array_merge($gConf, $conf); 02108 $app =& Dataface_Application::getInstance(); 02109 $appDel =& $app->getDelegate(); 02110 if ( method_exists($appDel,'decorateFieldsINI') ){ 02111 $appDel->decorateFieldsINI($conf, $this); 02112 } 02113 02114 $this->_global_field_properties = array(); 02115 if ( isset($conf['__global__']) ) $this->_parseINISection($conf['__global__'], $this->_global_field_properties); 02116 else $this->_global_field_properties = array(); 02117 //print_r($this->_fields); 02118 foreach ($this->_fields as $key=>$val){ 02119 if ( isset($conf[$key]) ){ 02120 $conf[$key] = array_merge_recursive_unique($this->_global_field_properties, $conf[$key]); 02121 } else { 02122 $conf[$key] = $this->_global_field_properties; 02123 } 02124 //$conf[$key] = array_merge_recursive_unique($this->_global_field_properties, $conf[$key]); 02125 } 02126 foreach ($conf as $key=>$value ){ 02127 if ( $key == '__sql__' and !is_array($value) ){ 02128 $this->_sql = $value; 02129 continue; 02130 } 02131 02132 if ( is_array($value) and @$value['decorator'] ){ 02133 $event = new StdClass; 02134 $event->key = $key; 02135 $event->conf =& $value; 02136 $event->table = $this; 02137 02138 $app->fireEvent($value['decorator'].'__decorateConf', $event); 02139 02140 } 02141 02142 if ( is_array($value) ){ 02143 02144 02145 if ( isset($value['extends']) and isset($conf[$value['extends']]) ){ 02146 $conf[$key] = array_merge($conf[$value['extends']], $value); 02147 $value = $conf[$key]; 02148 } 02149 02150 if ( isset($value['Type']) ){ 02151 02152 $ftype = strtolower(preg_replace('/\(.*$/','',$value['Type'])); 02153 //echo $ftype; 02154 if ( isset($conf['/'.$ftype]) ){ 02155 $conf[$key] = $value = array_merge($conf['/'.$ftype], $value); 02156 //print_r($value); 02157 } 02158 02159 } 02160 } 02161 02162 /* 02163 * Iterate through all of the fields. 02164 */ 02165 $matches = array(); // temp holder for preg matches 02166 if ( preg_match('/fieldgroup:(.+)/', $key, $matches) ){ 02167 // This is a group description - not a field description 02168 $this->_fieldgroups[trim($matches[1])] = $value; 02169 $this->_fieldgroups[trim($matches[1])]['name'] = $matches[1]; 02170 02171 $grp =& $this->_fieldgroups[trim($matches[1])]; 02172 foreach ($grp as $grpkey=>$grpval){ 02173 $tmp = explode(':',$grpkey); 02174 switch (count($tmp)){ 02175 case 2: $grp[$tmp[0]][$tmp[1]] =& $grp[$grpkey]; break; 02176 case 3: $grp[$tmp[0]][$tmp[1]][$tmp[2]] =& $grp[$grpkey]; break; 02177 case 4: $grp[$tmp[0]][$tmp[1]][$tmp[2]][$tmp[3]] =& $grp[$grpkey]; break; 02178 case 5: $grp[$tmp[0]][$tmp[1]][$tmp[2]][$tmp[3]][$tmp[4]] =& $grp[$grpkey]; break; 02179 02180 } 02181 } 02182 02183 if ( !isset( $grp['label'] ) ) $grp['label'] = ucfirst($grp['name']); 02184 if ( !isset( $grp['description']) ) $grp['description'] = ''; 02185 if ( !isset( $grp['display']) ) $grp['display'] = "inline"; 02186 if ( !isset( $grp['element_label_visible'])) { 02187 $grp['element_label_visible'] = true; 02188 } 02189 if ( !isset($grp['element_description_visible'])){ 02190 $grp['element_description_visible'] = 02191 ($grp['display'] == 'inline' ? false : true); 02192 02193 } 02194 02195 // Now do the translation stuff 02196 $grp['label'] = df_translate('tables.'.$this->tablename.'.fieldgroups.'.$grp['name'].'.label', $grp['label']); 02197 $grp['description'] = df_translate('tables.'.$this->tablename.'.fieldgroups.'.$grp['name'].'.description', $grp['description']); 02198 if ( !isset($grp['order']) ) $grp['order'] = 0; 02199 unset($grp); 02200 } 02201 02202 else if ( preg_match('/tab:(.+)/', $key, $matches) ){ 02203 // This is a tab description 02204 $tabname = trim($matches[1]); 02205 $this->_parseINISection($value, $this->_tabs[$tabname]); 02206 $tabarr =& $this->_tabs[$tabname]; 02207 $tabarr['name'] = $tabname; 02208 02209 if ( !isset($tabarr['label']) ) $tabarr['label'] = ucfirst($tabname); 02210 if ( !isset($tabarr['description']) ) $tabarr['description'] = ''; 02211 02212 unset($tabarr); 02213 02214 02215 } 02216 02217 else if ( $key == "__filters__"){ 02218 // THis is a filter to be added to queries of this table. 02219 $this->_filters=$value; 02220 02221 } 02222 02223 else if ($key == "__title__"){ 02224 $this->_atts['title'] = $value; 02225 } 02226 02227 else if ( $key == '__join__' ){ 02228 $this->_joinTables = $value; 02229 02230 } 02231 02232 else if ( strpos($key, ':') > 0 ){ 02233 // This is the definition of a subfield (ie: a field within a 02234 // table. 02235 list($parent, $child) = explode(':', $key); 02236 if ( !isset( $this->_fields[$parent] ) ){ 02237 throw new Exception("Error while loading definition for subfield '$key' from the fields.ini file for the table '".$this->tablename."'. The field '$parent' does not exist.", E_USER_ERROR); 02238 } 02239 02240 $field =& $this->_fields[$parent]; 02241 if ( !isset($field['fields']) ) $field['fields'] = array(); 02242 $curr = $this->_newSchema('varchar(255)', $child); 02243 02244 $this->_parseINISection($value, $curr); 02245 $field['fields'][$child] =& $curr; 02246 unset($curr); 02247 unset($field); 02248 02249 02250 } 02251 02252 else if ( isset( $this->_fields[ $key ] ) ){ 02253 02254 $field =& $this->_fields[$key]; 02255 $widget =& $field['widget']; 02256 $permissions =& $field['permissions']; 02257 $validators =& $field['validators']; 02258 $ftype = $field['Type']; 02259 if ( isset($value['Type']) ) $ftype = $value['Type']; 02260 $ftype = strtolower(preg_replace('/\(.*$/','',$ftype)); 02261 //echo $ftype; 02262 if ( isset($conf['/'.$ftype]) ){ 02263 $conf[$key] = $value = array_merge($conf['/'.$ftype], $value); 02264 //print_r($value); 02265 } 02266 02267 02268 // get the attributes defined in the ini file 02269 foreach ( $value as $att => $attval ){ 02270 // some of the attributes will be prefixed to indicate 02271 // widget, vocabulary, etc... 02272 $attpath = explode( ":", $att ); 02273 02274 if ( count( $attpath ) == 1 ){ 02275 // there was no prefix ... attribute goes straight into table 02276 if ( is_array($attval) ){ 02277 $field[ $att ] = $attval; 02278 } else { 02279 $field[ $att ] = trim( $attval ); 02280 if ( strcasecmp($att, 'key') === 0 and strcasecmp($attval, 'pri')===0 and !isset($this->_keys[$field['name']])){ 02281 // This field is a surrogate primary key 02282 $this->_keys[$field['name']] =& $field; 02283 02284 } 02285 } 02286 // todo handle validators which can be in the form of a list 02287 // ** ** ** 02288 } else { 02289 // There was a prefix 02290 02291 switch ( $attpath[0] ){ 02292 case "widget": 02293 if ( count($attpath) > 2 ){ 02294 $widget[ $attpath[1] ][ $attpath[2] ] = trim($attval); 02295 } else { 02296 $widget[ $attpath[1] ] = trim($attval); 02297 } 02298 02299 break; 02300 case "permissions": 02301 $permissions[ $attpath[1] ] = trim($attval); 02302 break; 02303 case "validators": 02304 if ( !$attval || $attval == 'false' ) { 02305 $validators[ $attpath[1] ] = 0; 02306 02307 continue; 02308 } 02309 if ( !isset( $validators[ $attpath[1] ] ) ){ 02310 $validators[ $attpath[1] ] = array(); 02311 } 02312 if ( count( $attpath ) <= 2 ){ 02313 $validators[ $attpath[1] ]['arg'] = trim($attval); 02314 } else { 02315 $validators[ $attpath[1] ][ $attpath[2] ] = trim($attval); 02316 } 02317 if ( !isset( $validators[ $attpath[1] ]['message'] )){ 02318 $validators[ $attpath[1] ]['message'] = "Illegal input for field ".$field['name']; 02319 } 02320 break; 02321 02322 case "visibility": 02323 if ( !isset($field['visibility'] ) ) $field['visibility'] = array('list'=>'visible', 02324 'browse'=>'visible', 02325 'find'=>'visible'); 02326 $field['visibility'][ $attpath[1] ] = trim($attval); 02327 02328 break; 02329 02330 default: 02331 $field[$attpath[0]][$attpath[1]] = trim($attval); 02332 break; 02333 02334 } 02335 02336 02337 } 02338 02339 02340 } 02341 02342 // prevent ourselves from doing damage 02343 unset($field); 02344 unset($widget); 02345 unset($permissions); 02346 unset($validators); 02347 } else { 02348 $this->_atts[$key] = $value; 02349 } 02350 } 02351 02352 // Create missing fieldgroups 02353 // Explanation: It is possible that fields reference 02354 // groups that don't have an explicit definition in the ini files. 02355 // This step creates those implicit groups. 02356 foreach (array_keys($this->_fields) as $key){ 02357 if ( isset($this->_fields[$key]['group']) ){ 02358 $grpname = $this->_fields[$key]['group']; 02359 if ( !isset( $this->_fieldgroups[$grpname] ) ){ 02360 $this->_fieldgroups[$grpname] = array( 02361 "name"=>$grpname, 02362 "label"=>df_translate('tables.'.$this->tablename.'.fieldgroups.'.$grpname.'.label', ucfirst($grpname)), 02363 "description"=>'', 02364 "display"=>'inline', 02365 "element_label_visible"=>true, 02366 "element_description_visible"=>false, 02367 'order'=>0 02368 ); 02369 } 02370 } 02371 if ( strcasecmp($this->_fields[$key]['Type'], 'container') === 0){ 02372 /* 02373 * This field is a Container field. We will need to set up the save path. 02374 * If no save path is specified we will create a directory by the name 02375 * of this field inside the table's directory. 02376 */ 02377 if ( $this->_fields[$key]['widget']['type'] == 'text' ) $this->_fields[$key]['widget']['type'] = 'file'; 02378 if ( !isset( $this->_fields[$key]['savepath'] ) ){ 02379 $this->_fields[$key]['savepath'] = $this->basePath().'/tables/'.$this->tablename.'/'.$key; 02380 } else if ( strpos($this->_fields[$key]['savepath'], '/') !== 0 and !preg_match('/^[a-z0-9]{1,5}:\/\//', $this->_fields[$key]['savepath']) ) { 02381 $this->_fields[$key]['savepath'] = DATAFACE_SITE_PATH.'/'.$this->_fields[$key]['savepath']; 02382 } 02383 02384 if ( !isset($this->_fields[$key]['url']) ){ 02385 $this->_fields[$key]['url'] = str_replace(DATAFACE_SITE_PATH, DATAFACE_SITE_URL, $this->_fields[$key]['savepath']); 02386 02387 } else if ( strpos( $this->_fields[$key]['url'], '/') !== 0 and strpos($this->_fields[$key]['url'], 'http://') !== 0 ){ 02388 $this->_fields[$key]['url'] = DATAFACE_SITE_URL.'/'.$this->_fields[$key]['url']; 02389 } 02390 } 02391 02392 02393 if ( !isset($this->_fields[$key]['tab']) ) $this->_fields[$key]['tab'] = '__main__'; 02394 $tab = $this->_fields[$key]['tab']; 02395 if ( !isset($this->_tabs[$tab]) ){ 02396 02397 $this->_tabs[$tab] = array('name'=>$tab, 'label'=>ucfirst(str_replace('_',' ',$tab)), 'description'=>''); 02398 02399 } 02400 02401 02402 if ( $this->_fields[$key]['widget']['type'] == 'checkbox' and ($this->isText($key) || $this->isChar($key)) and @$this->_fields[$key]['vocabulary'] ){ 02403 // This is a checkbox field with a vocabulary. It should be a repeating field 02404 $this->_fields[$key]['repeat'] = true; 02405 } 02406 02407 $widget =& $this->_fields[$key]['widget']; 02408 switch ($widget['type']){ 02409 case 'text': 02410 if ( !isset($widget['atts']['size']) ){ 02411 if ( $this->isInt($key) or $this->isFloat($key) ){ 02412 $widget['atts']['size'] = 10; 02413 } else { 02414 $widget['atts']['size'] = 30; 02415 } 02416 } 02417 break; 02418 case 'textarea': 02419 if (!isset($widget['atts']['rows']) ){ 02420 $widget['atts']['rows'] = 6; 02421 } 02422 if ( !isset($widget['atts']['cols']) ){ 02423 $widget['atts']['cols'] = 60; 02424 } 02425 break; 02426 } 02427 02428 // Now we do the translation stuff 02429 $widget['label'] = df_translate('tables.'.$this->tablename.'.fields.'.$key.'.widget.label',$widget['label']); 02430 $widget['description'] = df_translate('tables.'.$this->tablename.'.fields.'.$key.'.widget.description',$widget['description']); 02431 if ( isset($widget['question']) ){ 02432 $widget['question'] = df_translate('tables.'.$this->tablename.'.fields.'.$key.'.widget.question',$widget['question']); 02433 02434 } 02435 //$this->_fields[ $key ] = 02436 02437 unset($widget); 02438 } 02439 02440 } 02441 02442 02443 02444 02445 02446 02447 02448 02449 // @} 02450 // END Fields methods 02451 //---------------------------------------------------------------------------------------------- 02452 02453 //---------------------------------------------------------------------------------------------- 02454 // @{ 02467 function readOnly(){ 02468 return false; 02469 } 02470 02471 02499 function setSecurityFilter($filter=null){ 02500 02501 if ( !isset($filter)){ 02502 $filter = array(); 02503 $app =& Dataface_Application::getInstance(); 02504 $query =& $app->getQuery(); 02505 if ( class_exists('Dataface_AuthenticationTool') ){ 02506 $auth =& Dataface_AuthenticationTool::getInstance(); 02507 $user =& $auth->getLoggedInUser(); 02508 } else { 02509 $auth = null; 02510 $user = null; 02511 } 02512 02513 foreach ($this->_filters as $key=>$value){ 02514 if ( isset($this->_securityFilter[$key]) ) continue; 02515 if ( $value{0} == '$' ){ 02516 if ( !$user and strpos($value, '$user') !== false ) continue; 02517 eval('$filter[$key] = "=".'.$value.';'); 02518 } else if ( substr($value,0,4) == 'php:' ){ 02519 if ( !$user and strpos($value, '$user') !== false ) continue; 02520 eval('$filter[$key] = "=".'.substr($value,4).';'); 02521 } else { 02522 $filter[$key] = "=".$value; 02523 } 02524 } 02525 02526 } 02527 02528 $this->_securityFilter = $filter; 02529 } 02530 02538 function getSecurityFilter($filter=array()){ 02539 return array_merge($this->_securityFilter, $filter); 02540 } 02541 02542 02543 02573 function getRelationshipPermissions($relationshipName, $params=array()){ 02574 02575 $params['relationship'] = $relationshipName; 02576 return $this->getPermissions($params); 02577 } 02578 02602 function getPermissions($params=array()){ 02603 02604 // First let's try to load permissions from the cache 02605 $pt =& Dataface_PermissionsTool::getInstance(); 02606 $params['table'] = $this->tablename; 02607 if ( isset($params['record']) ) $record =& $params['record']; 02608 else $record = null; 02609 $cachedPermissions = $pt->getCachedPermissions($record, $params); 02610 if ( isset($cachedPermissions) ) return $cachedPermissions; 02611 02612 02613 $delegate =& $this->getDelegate(); 02614 $app =& Dataface_Application::getInstance(); 02615 $appDelegate =& $app->getDelegate(); 02616 $parent =& $this->getParent(); 02617 $recordmask = @$params['recordmask']; 02618 $methods = array(); 02619 if ( isset($params['relationship']) ){ 02620 if ( isset($params['relationshipmask']) ) $rmask =& $params['relationshipmask']; 02621 else $rmask = array(); 02622 02623 if ( isset($params['field']) ){ 02624 $relprefix = 'rel_'.$params['relationship'].'__'; 02625 $methods[] = array('object'=>&$delegate, 'name'=>$relprefix.$params['field'].'__permissions', 'type'=>'permissions', 'partial'=>1); 02626 $methods[] = array('object'=>&$delegate, 'name'=>$relprefix.$params['field'].'__roles', 'type'=>'roles', 'partial'=>1); 02627 $methods[] = array('object'=>&$delegate, 'name'=>$relprefix.'__field__permissions', 'type'=>'permissions', 'partial'=>1); 02628 $methods[] = array('object'=>&$delegate, 'name'=>$relprefix.'__field__roles', 'type'=>'roles', 'partial'=>1); 02629 02630 //if ( @$params['recordmask'] ) $methods[] = 'recordmask'; 02631 if ( @$params['nobubble'] ) $methods[] = 'break'; 02632 02633 } 02634 02635 02636 $methods[] = array('object'=>&$delegate, 'name'=>'rel_'.$params['relationship'].'__permissions', 'type'=>'permissions', 'mask'=>&$rmask, 'partial'=>1); 02637 $methods[] = array('object'=>&$delegate, 'name'=>'rel_'.$params['relationship'].'__roles', 'type'=>'roles', 'mask'=>&$rmask, 'partial'=>1); 02638 if ( isset($parent) ) $methods[] = array('object'=>&$parent, 'name'=>'getPermissions', 'type'=>'Dataface_Table', 'partial'=>1); 02639 if ( @$params['nobubble'] ) $methods[] = 'break'; 02640 } 02641 else if ( isset($params['field']) ){ 02642 $methods[] = array('object'=>&$delegate, 'name'=>$params['field'].'__permissions', 'type'=>'permissions', 'partial'=>1); 02643 $methods[] = array('object'=>&$delegate, 'name'=>$params['field'].'__roles', 'type'=>'roles', 'partial'=>1); 02644 $methods[] = array('object'=>&$delegate, 'name'=>'__field__permissions', 'type'=>'permissions', 'partial'=>1); 02645 $methods[] = array('object'=>&$delegate, 'name'=>'__field__roles', 'type'=>'roles', 'partial'=>1); 02646 if ( isset($parent) ) $methods[] = array('object'=>&$parent, 'name'=>'getPermissions', 'type'=>'Dataface_Table', 'partial'=>1); 02647 if ( @$params['recordmask'] ) $methods[] = 'recordmask'; 02648 if ( @$params['nobubble'] ) $methods[] = 'break'; 02649 02650 02651 } 02652 //if ( isset($params['recordmask']) ) $mask =& $params['recordmask']; 02653 //else $mask = array(); 02654 $methods[] = array('object'=>&$delegate, 'name'=>'getPermissions', 'type'=>'permissions'); 02655 $methods[] = array('object'=>&$delegate, 'name'=>'getRoles', 'type'=>'roles'); 02656 $methods[] = array('object'=>&$appDelegate, 'name'=>'getPermissions', 'type'=>'permissions'); 02657 $methods[] = array('object'=>&$appDelegate, 'name'=>'getRoles', 'type'=>'roles'); 02658 if ( isset($parent) ) $methods[] = array('object'=>&$parent, 'name'=>'getPermissions', 'type'=>'Dataface_Table'); 02659 02660 $perms = array(); 02661 foreach ($methods as $method){ 02662 if ( $method == 'break' ) { 02663 if ( !$perms ) return null; 02664 else return $perms; 02665 } 02666 if ( $method == 'recordmask' and is_array($recordmask) ){ 02667 // If a record mask has been supplied we apply that here 02668 // so that unspecified permissions in a field request will 02669 // be augmented with a specified recordmask 02670 $perms = array_merge($recordmask, $perms); 02671 continue; 02672 } 02673 if ( isset($method['object']) and method_exists($method['object'], $method['name']) ){ 02674 $name = $method['name']; 02675 if ( $method['type'] == 'Dataface_Table'){ 02676 $res = $method['object']->$name(array_merge($params, array('nobubble'=>1))); 02677 } else { 02678 $res = $method['object']->$name($record, $params); 02679 } 02680 if ( $method['type'] == 'roles' ){ 02681 $res = $this->convertRolesToPermissions($res); 02682 } 02683 if ( is_array($res) ){ 02684 if ( @$method['mask'] and is_array(@$method['mask']) ) $res = array_merge($method['mask'], $res); 02685 $perms = array_merge($res, $perms); 02686 if ( !@$method['partial'] ){ 02687 $pt->filterPermissions($record, $perms, $params); 02688 $pt->cachePermissions($record, $params, $perms); 02689 return $perms; 02690 } 02691 } 02692 } 02693 } 02694 $res = array_merge(Dataface_PermissionsTool::ALL(), $perms); 02695 $pt->filterPermissions($record, $res, $params); 02696 $pt->cachePermissions($record,$params,$res); 02697 return $res; 02698 } 02699 02700 02710 function convertRolesToPermissions($roles){ 02711 if ( is_array($roles) ){ 02712 $perms = array(); 02713 foreach ($roles as $role){ 02714 if ( is_string($role) ){ 02715 $perms = array_merge($perms, Dataface_PermissionsTool::getRolePermissions($role)); 02716 } 02717 } 02718 return $perms; 02719 } else if ( is_string($roles) ){ 02720 return Dataface_PermissionsTool::getRolePermissions($roles); 02721 } 02722 02723 return $roles; 02724 } 02725 02726 02732 function loadPermissions(){ 02733 $this->_permissionsLoaded = true; 02734 $configTool =& Dataface_ConfigTool::getInstance(); 02735 $conf =& $configTool->loadConfig('permissions', $this->tablename); 02736 $permissionsTool =& Dataface_PermissionsTool::getInstance(); 02737 $permissionsTool->addPermissions($conf); 02738 02739 } 02740 02741 // @} 02742 // END Permissions 02743 //---------------------------------------------------------------------------------------------- 02744 02745 //---------------------------------------------------------------------------------------------- 02746 // @{ 02761 function &getTranslations(){ 02762 if ( $this->translations === null ){ 02763 $this->translations = array(); 02764 $res = mysql_query("SHOW TABLES LIKE '".addslashes($this->tablename)."%'", $this->db); 02765 if ( !$res ){ 02766 02767 throw new Exception( 02768 Dataface_LanguageTool::translate( 02769 'MySQL query error loading translation tables', 02770 'MySQL query error while trying to find translation tables for table "'.addslashes($this->tablename).'". '.mysql_error($this->db).'. ', 02771 array('sql_error'=>mysql_error($this->db), 'stack_trace'=>'', 'table'=>$this->tablename) 02772 ), 02773 E_USER_ERROR 02774 02775 ); 02776 } 02777 if (mysql_num_rows($res) <= 0 ){ 02778 // there should at least be the current table returned.. there is a problem 02779 // if nothing was returned. 02780 throw new Exception( 02781 Dataface_LanguageTool::translate( 02782 'Not enough results returned loading translation tables', 02783 'No tables were returned when trying to load translation tables for table "'.$this->tablename.'". This query should have at least returned one record (the current table) so there must be a problem with the query.', 02784 array('table'=>$this->tablename) 02785 ), 02786 E_USER_ERROR 02787 ); 02788 } 02789 02790 while ( $row = mysql_fetch_array($res ) ){ 02791 $tablename = $row[0]; 02792 if ( $tablename == $this->tablename ){ 02793 continue; 02794 } 02795 02796 $matches = array(); 02797 if ( preg_match( '/^'.$this->tablename.'_([a-zA-Z]{2})$/', $tablename, $matches) ){ 02798 $this->translations[$matches[1]] = 0; 02799 } 02800 02801 } 02802 mysql_free_result($res); 02803 02804 02805 } 02806 return $this->translations; 02807 02808 } 02809 02816 function &getTranslation($name){ 02817 $translations =& $this->getTranslations(); 02818 if ( isset( $translations[$name] )){ 02819 // the translation exists 02820 if ( !$translations[$name] ){ 02821 // the columns are not loaded yet, we need to load them. 02822 $res = mysql_query("SHOW COLUMNS FROM `".addslashes($this->tablename)."_".addslashes($name)."`", $this->db); 02823 if ( !$res ){ 02824 throw new Exception( 02825 Dataface_LanguageTool::translate( 02826 'Problem loading columns from translation table', 02827 'Problem loading columns from translation table for table "'.$this->tablename.'" in language "'.$name.'". ', 02828 array('table'=>$this->tablename,'langauge'=>$name,'stack_trace'=>'','sql_error'=>mysql_error($this->db)) 02829 ), 02830 E_USER_ERROR 02831 ); 02832 } 02833 $translations[$name] = array(); 02834 while ( $row = mysql_fetch_assoc($res) ){ 02835 $translations[$name][] = $row['Field']; 02836 } 02837 mysql_free_result($res); 02838 } 02839 02840 return $translations[$name]; 02841 } 02842 $null = null; 02843 return $null; 02844 } 02845 02851 function getTranslationStates(){ 02852 return array( 02853 'o-a-c'=>'Original translation', 02854 'm-u-c'=>'Machine translation - unapproved', 02855 'm-a-c'=>'Machine translation - approved', 02856 'm-u-o'=>'Machine translation - unapproved - out of date', 02857 'm-a-o'=>'Machine translation - approved - out of date', 02858 'h-u-c'=>'Human translation - unapproved', 02859 'h-a-c'=>'Human translation - approved', 02860 'h-u-o'=>'Human translation - unapproved - out of date', 02861 'h-a-o'=>'Human translation - approved - out of date' 02862 ); 02863 02864 } 02865 02866 02867 // @} 02868 // END Internationalization 02869 //---------------------------------------------------------------------------------------------- 02870 02871 //---------------------------------------------------------------------------------------------- 02872 // @{ 02883 function getLabel(){ 02884 return (@$this->_atts['label'] ? $this->_atts['label'] : $this->tablename); 02885 } 02886 02887 02899 function getSingularLabel(){ 02900 if ( !isset($this->_atts['singular_label']) ){ 02901 $this->_atts['singular_label'] = df_singularize($this->getLabel()); 02902 } 02903 return $this->_atts['singular_label']; 02904 02905 } 02906 02911 function tableInfo(){ 02912 02913 $info = array(); 02914 foreach ( array_keys($this->fields()) as $fieldname){ 02915 $field =& $this->getField($fieldname); 02916 $info['fields'][$fieldname]['Type'] = $field['Type']; 02917 $info['fields'][$fieldname]['Extra'] = $field['Extra']; 02918 $info['fields'][$fieldname]['Key'] = $field['Key']; 02919 $info['fields'][$fieldname]['widget'] = $field['widget']; 02920 unset($field); 02921 } 02922 return $info; 02923 } 02924 02928 function databaseInfo(){ 02929 $tables =& self::loadTable('',null,true); 02930 $info = array(); 02931 foreach ( array_keys($tables) as $tablename ){ 02932 $info[$tablename] =& $tables[$tablename]->tableInfo(); 02933 } 02934 return $info; 02935 } 02936 02941 function &attributes(){ 02942 if ( !isset($this->_cache[__FUNCTION__]) ){ 02943 $atts =& $this->_atts; 02944 $parent =& $this->getParent(); 02945 if ( isset($parent) ){ 02946 $atts = array_merge($parent->attributes(), $atts); 02947 } 02948 $this->_cache[__FUNCTION__] =& $atts; 02949 } 02950 return $this->_cache[__FUNCTION__]; 02951 } 02952 02953 02954 02962 function &getParent(){ 02963 if ( !isset($this->_parentTable) ){ 02964 if ( isset($this->_atts['__isa__']) ){ 02965 $this->_parentTable =& self::loadTable($this->_atts['__isa__']); 02966 } 02967 } 02968 return $this->_parentTable; 02969 } 02970 02983 function implementsOntology($ontologyName){ 02984 return (isset($this->_atts['__implements__']) and isset($this->_atts['__implements__'][$ontologyName])); 02985 } 02986 02987 02988 02989 02990 02995 function &getStatus(){ 02996 if ( !isset( $this->status ) ){ 02997 /* 02998 * Get the table status - when was it last updated, etc... 02999 */ 03000 $res = mysql_query("SHOW TABLE STATUS LIKE '".addslashes($this->tablename)."'",$this->db); 03001 if ( !$res ){ 03002 throw new Exception("Error performing mysql query to obtain status for table '".$this->tablename."': ".mysql_error($this->db), E_USER_ERROR); 03003 } 03004 03005 $this->status = mysql_fetch_array($res); 03006 mysql_free_result($res); 03007 } 03008 03009 return $this->status; 03010 03011 03012 } 03013 03014 03037 public static function &getBackupModificationTimes($refresh=false){ 03038 static $backup_times = 0; 03039 if ( $backup_times === 0 or $refresh ){ 03040 $res = mysql_query("select * from dataface__mtimes", df_db()); 03041 if ( !$res ){ 03042 import('Dataface/IO.php'); 03043 Dataface_IO::createModificationTimesTable(); 03044 $res = mysql_query("select * from dataface__mtimes", df_db()); 03045 if ( !$res ) throw new Exception(mysql_error(df_db())); 03046 03047 } 03048 $backup_times = array(); 03049 while ( $row = mysql_fetch_assoc($res) ){ 03050 $backup_times[$row['name']] = $row['mtime']; 03051 } 03052 @mysql_free_result($res); 03053 } 03054 return $backup_times; 03055 03056 03057 } 03058 03059 03074 public static function &getTableModificationTimes($refresh=false){ 03075 static $mod_times = 0; 03076 if ( $mod_times === 0 or $refresh ){ 03077 $mod_times = array(); 03078 03079 03080 $res = mysql_query("show table status", df_db()); 03081 if ( !$res ){ 03082 throw new Exception(mysql_error(df_db())); 03083 } 03084 03085 while ( $row = mysql_fetch_assoc($res) ){ 03086 if ( @$row['Update_time'] ){ 03087 $mod_times[$row['Name']] = @strtotime($row['Update_time']); 03088 } else { 03089 $backup_times =& self::getBackupModificationTimes($refresh); 03090 if ( isset($backup_times[$row['Name']]) and $backup_times[$row['Name']] ){ 03091 $mod_times[$row['Name']] = $backup_times[$row['Name']]; 03092 } else { 03093 $mod_times[$row['Name']] = time(); 03094 } 03095 } 03096 } 03097 } 03098 return $mod_times; 03099 } 03100 03106 function getUpdateTime(){ 03107 $status =& $this->getStatus(); 03108 return $status['Update_time']; 03109 } 03110 03117 function getCreateTime(){ 03118 $status =& $this->getStatus(); 03119 return $status['Create_time']; 03120 } 03121 03122 // @} 03123 // END Table Info 03124 //---------------------------------------------------------------------------------------------- 03125 03126 //---------------------------------------------------------------------------------------------- 03127 // @{ 03143 function isYesNoValuelist($valuelist_name, &$yes, &$no){ 03144 03145 $options =& $this->getValuelist($valuelist_name); 03146 if ( !$options ) return false; 03147 03148 if (count($options) != 2) return false; 03149 $opt_keys = array_keys($options); 03150 $yes_val = false; 03151 $no_val = false; 03152 foreach ($opt_keys as $opt_key){ 03153 if ( stristr($opt_key,'n') == $opt_key ) $no_val = $opt_key; 03154 else if ( stristr($opt_key,'y') == $opt_key) $yes_val = $opt_key; 03155 else if ( $opt_key == "0" ) $no_val = $opt_key; 03156 else if ( $opt_key == "1" ) $yes_val = $opt_key; 03157 else if ( in_array(strtolower($opt_key), array('on','active','true','t') ) ){ 03158 $yes_val = $opt_key; 03159 } else if ( in_array(strtolower($opt_key), array('off','inactive','false','f') ) ){ 03160 $no_val = $opt_key; 03161 } 03162 } 03163 03164 if ( $yes_val and $no_val ){ 03165 $yes = $yes_val; 03166 $no = $no_val; 03167 return true; 03168 } 03169 return false; 03170 03171 } 03172 03173 03178 function _valuelistsIniFilePath(){ 03179 return $this->basePath().'/tables/'.$this->tablename.'/valuelists.ini'; 03180 } 03181 03186 function _hasValuelistsIniFile(){ 03187 return file_exists( $this->_valuelistsIniFilePath() ); 03188 } 03189 03190 03195 function _loadValuelistsIniFile(){ 03196 if ( !isset( $this->_valuelists ) ){ 03197 $this->_valuelists = array(); 03198 } 03199 $valuelists =& $this->_valuelists; 03200 03201 import( 'Dataface/ConfigTool.php'); 03202 $configTool =& Dataface_ConfigTool::getInstance(); 03203 $conf =& $configTool->loadConfig('valuelists', $this->tablename); 03204 03205 03206 foreach ( $conf as $vlname=>$vllist ){ 03207 $valuelists[$vlname] = array(); 03208 if ( is_array( $vllist ) ){ 03209 foreach ( $vllist as $key=>$value ){ 03210 if ( $key == '__import__' ){ 03211 // we import the values from another value list. The value of this 03212 // entry should be in the form tablename.valuelistname 03213 list( $ext_table, $ext_valuelist ) = explode('.', $value); 03214 if ( isset( $ext_table ) && isset( $ext_valuelist ) ){ 03215 $ext_table =& self::loadTable($ext_table, $this->db); 03216 } else if ( isset( $ext_table ) ){ 03217 $ext_valuelist = $ext_table; 03218 $ext_table =& $this; 03219 } 03220 03221 if ( isset( $ext_table ) ){ 03222 $ext_valuelist = $ext_table->getValuelist( $ext_valuelist ); 03223 foreach ( $ext_valuelist as $ext_key=>$ext_value ){ 03224 $valuelists[$vlname][$ext_key] = $ext_value; 03225 } 03226 } 03227 // clean up temp variables so they don't confuse us 03228 // in the next iteration. 03229 unset($ext_table); 03230 unset($ext_table); 03231 unset($ext_valuelist); 03232 } else if ( $key == '__sql__' ) { 03233 // we perform the sql query specified to produce our valuelist. 03234 // the sql query should return two columns only. If more are 03235 // returned, only the first two will be used. If one is returned 03236 // it will be used as both the key and value. 03237 $res = df_query($value, null, true, true); 03238 if ( is_array($res) ){ 03239 //while ($row = mysql_fetch_row($res) ){ 03240 foreach ($res as $row){ 03241 $valuekey = $row[0]; 03242 $valuevalue = count($row)>1 ? $row[1] : $row[0]; 03243 $valuelists[$vlname][$valuekey] = $valuevalue; 03244 03245 if ( count($row)>2 ){ 03246 $valuelists[$vlname.'__meta'][$valuekey] = $row[2]; 03247 } 03248 } 03249 //mysql_free_result($res); 03250 } else { 03251 throw new Exception("Valuelist query '".$value."' failed. ", E_USER_NOTICE); 03252 } 03253 03254 } else { 03255 $valuelists[$vlname][$key] = $value; 03256 } 03257 } 03258 } 03259 03260 03261 } 03262 03263 } 03264 03265 03271 function &getValuelistsConfig(){ 03272 return $this->_valuelistsConfig; 03273 } 03274 03275 03279 function clearValuelistCache(){ 03280 $this->_valuelists = null; 03281 } 03282 03292 function &getValuelist( $name ){ 03293 if ( !isset($this->_cookedValuelists[$name]) ){ 03294 $this->_cookedValuelists[$name] = null; 03295 $delegate =& $this->getDelegate(); 03296 if ( method_exists($delegate, 'valuelist__'.$name) ){ 03297 $res = call_user_func(array(&$delegate, 'valuelist__'.$name)); 03298 if ( is_array($res) ) $this->_cookedValuelists[$name] = $res; 03299 } 03300 03301 $parent =& $this->getParent(); 03302 if ( !isset($this->_cookedValuelists[$name]) and isset($parent) ){ 03303 $res = $parent->getValuelist($name); 03304 if ( is_array($res) ) $this->_cookedValuelists[$name] = $res; 03305 } 03306 03307 $app =& Dataface_Application::getInstance(); 03308 $appdel =& $app->getDelegate(); 03309 if ( !isset($this->_cookedValuelists[$name]) and isset($appdel) and method_exists($appdel, 'valuelist__'.$name) ){ 03310 $res = call_user_func(array(&$appdel, 'valuelist__'.$name)); 03311 if ( is_array($res) ) $this->_cookedValuelists[$name] = $res; 03312 } 03313 03314 if ( !isset($this->_cookedValuelists[$name]) and !isset( $this->_valuelists ) ){ 03315 $this->_loadValuelistsIniFile(); 03316 } 03317 if ( !isset($this->_cookedValuelists[$name]) and isset( $this->_valuelists[$name] ) ){ 03318 $this->_cookedValuelists[$name] = $this->_valuelists[$name]; 03319 03320 } 03321 import( 'Dataface/ValuelistTool.php'); 03322 if ( !isset($this->_cookedValuelists[$name]) and Dataface_ValuelistTool::getInstance()->hasValuelist($name) ){ 03323 03324 $this->_cookedValuelists[$name] = Dataface_ValuelistTool::getInstance()->getValuelist($name); 03325 } 03326 03327 if ( isset($this->_cookedValuelists[$name]) and isset($delegate) and method_exists($delegate, 'valuelist__'.$name.'__decorate') ){ 03328 03329 $methodname = 'valuelist__'.$name.'__decorate'; 03330 $this->_cookedValuelists[$name] = $delegate->$methodname($this->_cookedValuelists[$name]); 03331 } else if ( isset($this->_cookedValuelists[$name]) and isset($appdel) and method_exists($appdel, 'valuelist__'.$name.'__decorate') ){ 03332 $methodname = 'valuelist__'.$name.'__decorate'; 03333 $this->_cookedValuelists[$name] = $appdel->$methodname($this->_cookedValuelists[$name]); 03334 03335 } 03336 } 03337 return $this->_cookedValuelists[$name]; 03338 } 03339 03347 function &valuelists(){ 03348 03349 if ( !isset( $this->_valuelists ) ){ 03350 03351 $this->_loadValuelistsIniFile(); 03352 } 03353 return $this->_valuelists; 03354 } 03355 03356 03362 function getAvailableValuelistNames(){ 03363 $valuelists = array_keys($this->valuelists()); 03364 $delegate =& $this->getDelegate(); 03365 if ( isset($delegate) ){ 03366 $delegate_methods = get_class_methods(get_class($delegate)); 03367 $valuelist_methods = preg_grep('/^valuelist__/', $delegate_methods); 03368 foreach ( $valuelist_methods as $method ){ 03369 $valuelists[] = substr($method, 11); 03370 } 03371 } 03372 import( 'Dataface/ValuelistTool.php'); 03373 03374 $valuelists = array_merge($valuelists, array_keys(Dataface_ValuelistTool::getInstance()->valuelists())); 03375 return $valuelists; 03376 } 03377 03378 03379 // @} 03380 // END Valuelists 03381 //---------------------------------------------------------------------------------------------- 03382 03383 03384 //---------------------------------------------------------------------------------------------- 03385 // @{ 03396 function _relationshipsIniFilePath(){ 03397 return $this->basePath().'/tables/'.$this->tablename.'/relationships.ini'; 03398 } 03399 03404 function _hasRelationshipsIniFile(){ 03405 03406 return file_exists( $this->_relationshipsIniFilePath() ); 03407 } 03408 03409 03417 function _loadRelationshipsIniFile(){ 03418 03419 03420 import( 'Dataface/ConfigTool.php'); 03421 $configTool =& Dataface_ConfigTool::getInstance(); 03422 $conf =& $configTool->loadConfig('relationships', $this->tablename); 03423 03424 $r =& $this->_relationships; 03425 foreach ($conf as $rel_name => $rel_values){ 03426 // Case 1: The we have an array of values - meaning that this is the definition of a relationship. 03427 // Right now there is only one case, but we could have cases with single entries also. 03428 if ( is_array( $rel_values ) ){ 03429 03430 $r[$rel_name] = new Dataface_Relationship($this->tablename, $rel_name, $rel_values); 03431 03432 } 03433 } 03434 03435 $parent =& $this->getParent(); 03436 if ( isset($parent) ){ 03437 $this->_relationships = array_merge($parent->relationships(), $this->_relationships); 03438 } 03439 $this->_relationshipsLoaded = true; 03440 03441 } 03442 03443 03444 03451 function addRelationship($name, $relationship){ 03452 if ( !is_array($relationship) ){ 03453 throw new Exception("In Dataface_Table::addRelationship() 2nd argument expected to be an array, but received ", E_USER_ERROR); 03454 } 03455 $this->_relationships[$name] = new Dataface_Relationship($this->tablename, $name, $relationship); 03456 03457 } 03458 03465 function &getParentRelationship(){ 03466 $r =& $this->relationships(); 03467 if ( array_key_exists(__FUNCTION__,$this->_cache) ) return $this->_cache[__FUNCTION__]; 03468 foreach ( array_keys($r) as $name ){ 03469 if ( $this->_relationships[$name]->isParentRelationship() ){ 03470 $this->_cache[__FUNCTION__] =& $r[$name]; 03471 return $r[$name]; 03472 } 03473 } 03474 $null = null; 03475 return $null; 03476 } 03477 03483 function &getChildrenRelationship(){ 03484 $r =& $this->relationships(); 03485 if ( array_key_exists(__FUNCTION__,$this->_cache) ) return $this->_cache[__FUNCTION__]; 03486 foreach ( array_keys($r) as $name ){ 03487 if ( $r[$name]->isChildrenRelationship() ){ 03488 $this->_cache[__FUNCTION__] =& $r[$name]; 03489 return $r[$name]; 03490 } 03491 } 03492 $null = null; 03493 return $null; 03494 } 03495 03496 03507 function getRelationshipRange($relationshipName){ 03508 if ( isset( $this->_relationshipRanges[$relationshipName] ) ){ 03509 return $this->_relationshipRanges[$relationshipName]; 03510 } else { 03511 return $this->_defaultRelationshipRange; 03512 } 03513 } 03514 03527 function setRelationshipRange($relationshipName, $lower, $upper){ 03528 if ( !isset( $this->_relationshipRanges ) ) $this->_relationshipRanges = array(); 03529 $this->_relationshipRanges[$relationshipName] = array($lower, $upper); 03530 03531 } 03532 03540 function getDefaultRelationshipRange(){ 03541 return $this->_defaultRelationshipRange; 03542 } 03543 03550 function setDefaultRelationshipRange($lower, $upper){ 03551 $this->_defaultRelationshipRange = array($lower, $upper); 03552 } 03553 03559 function &getRelationshipsConfig(){ 03560 return $this->_relationshipsConfig; 03561 } 03562 03563 03564 03573 function &getRelationship($name){ 03574 $r =& $this->relationships(); 03575 if ( !is_string($name) ) throw new Exception("Relationship name is not a string"); 03576 if ( !isset($r[$name]) ){ 03577 $err = PEAR::raiseError("Attempt to get relationship nonexistent '$name' from table '".$this->tablename, E_USER_ERROR); 03578 return $err; 03579 } 03580 03581 return $r[$name]; 03582 } 03583 03591 function hasRelationship($name){ 03592 $r =& $this->relationships(); 03593 return isset($r[$name]); 03594 } 03595 03596 03597 03611 function getRelationshipsAsActions($params=array(), $relationshipName=null, $passthru=false){ 03612 03613 $relationships =& $this->relationships(); 03614 $rkeys = array_keys($relationships); 03615 03616 if ( isset( $this->_cache['getRelationshipsAsActions']) ){ 03617 $actions = $this->_cache['getRelationshipsAsActions']; 03618 } else { 03619 $actions = array(); 03620 foreach ( $rkeys as $key){ 03621 $srcTable =& $relationships[$key]->getSourceTable(); 03622 $actions[$key] = array( 03623 'name'=>$key, 03624 'id'=>$key, 03625 'label'=>ucwords(str_replace('_',' ',$key)), 03626 'url' =>'{$this->url(\'-action=related_records_list&-relationship='.$key.'\')}', 03627 'selected_condition' => '$query[\'-relationship\'] == \''.$key.'\'', 03628 //'label_i18n' => $srcTable->tablename.'::'.$key.'.label', 03629 //'description_i18n' => $srcTable->tablename.'::'.$key.'.description', 03630 'condition' => '$record and $record->checkPermission("view related records", array("relationship"=>"'.basename($key).'"))', 03631 'order' => 1, 03632 'visible'=>(!($relationships[$key]->isParentRelationship()) ? 1 : 0) 03633 ); 03634 if ( isset($relationships[$key]->_schema['action']) ){ 03635 $actions[$key] = array_merge($actions[$key], $relationships[$key]->_schema['action']); 03636 } 03637 $actions[$key]['label'] = df_translate('tables.'.$srcTable->tablename.'.relationships.'.$key.'.label', @$actions[$key]['label']); 03638 $actions[$key]['description'] = df_translate('tables.'.$srcTable->tablename.'.relationships.'.$key.'.description', @$actions[$key]['description']); 03639 unset($srcTable); 03640 } 03641 $this->_cache['getRelationshipsAsActions'] = $actions; 03642 } 03643 03644 import('Dataface/ActionTool.php'); 03645 $actionsTool =& Dataface_ActionTool::getInstance(); 03646 $out = $actionsTool->getActions($params, $actions); 03647 if ( isset($relationshipName) ) { 03648 if ( isset($out[$relationshipName]) ){ 03649 return @$out[$relationshipName]; 03650 } else { 03651 return $actionsTool->getAction($params, $actions[$relationshipName]); 03652 03653 } 03654 } 03655 return $out; 03656 } 03657 03664 function &relationships(){ 03665 if ( !$this->_relationshipsLoaded ){ 03666 $start = microtime_float(); 03667 $this->_loadRelationshipsIniFile(); 03668 $end = microtime_float()-$start; 03669 if ( DATAFACE_DEBUG ){ 03670 $this->app->addDebugInfo("Time to load relationships: $end"); 03671 } 03672 } 03673 03674 return $this->_relationships; 03675 } 03676 03677 03685 function &getTableTableForField($fieldname){ 03686 03687 if ( strpos($fieldname,'.') !== false ){ 03688 $path = explode('.', $fieldname); 03689 $relationship =& $this->getRelationship($path[0]); 03690 03691 $domainTable =& self::loadTable($relationship->getDomainTable()); 03692 if ( $domainTable->hasField($path[1]) ) return $domainTable; 03693 03694 //print_r($relationship->_schema['selected_tables']); 03695 foreach ($relationship->_schema['selected_tables'] as $table ){ 03696 if ( $table == $domainTable->tablename ) continue; 03697 $table =& self::loadTable($table, $this->db); 03698 //if ( in_array( $path[1], array_keys($table->fields()) ) ){ 03699 if ( $table->hasField($path[1]) ){ 03700 return $table; 03701 } 03702 unset($table); 03703 } 03704 03705 return PEAR::raiseError(SCHEMA_TABLE_NOT_FOUND,null,null,null,"Failed to find table table for field '$fieldname' in Dataface_Table::getTableTableForField() "); 03706 } else { 03707 return $this; 03708 } 03709 03710 } 03711 03712 // @} 03713 // End Relationships 03714 //---------------------------------------------------------------------------------------------- 03715 03716 //---------------------------------------------------------------------------------------------- 03717 // @{ 03731 function &getDelegate(){ 03732 $out = null; 03733 if ( !isset( $this->_delegate ) ){ 03734 if ( $this->_hasDelegateFile() ){ 03735 03736 $this->_loadDelegate(); 03737 03738 } else { 03739 03740 return $out; 03741 } 03742 } 03743 return $this->_delegate; 03744 03745 } 03746 03747 03748 03749 03750 03751 03752 03753 03754 03755 03760 function _delegateFilePath(){ 03761 $path =$this->basePath().'/tables/'.$this->tablename.'/'.$this->tablename.'.php'; 03762 03763 return $path; 03764 } 03765 03766 03767 03768 03769 03770 03771 03776 function _hasDelegateFile(){ 03777 return file_exists( $this->_delegateFilePath() ); 03778 } 03779 03780 03785 function _loadDelegate(){ 03786 03787 if ( $this->_hasDelegateFile() ){ 03788 03789 import( $this->_delegateFilePath() ); 03790 $delegate_name = "tables_".$this->tablename; 03791 $this->_delegate = new $delegate_name(); 03792 if ( isset($this->_delegate) and method_exists($this->_delegate, 'getDelegate') ){ 03793 $del = $this->_delegate->getDelegate(); 03794 if ( isset($del) ){ 03795 $this->_delegate = $del; 03796 } 03797 } 03798 03799 if ( method_exists($this->_delegate, 'tablePermissions') ){ 03800 // table permissions are now just done inside the getPermissions() method. 03801 // so the tablePermissions() method is no longer supported. Let the developer 03802 // know in case he has old code. 03803 throw new Exception( 03804 Dataface_LanguageTool::translate( 03805 'tablePermissions method no longer supported', 03806 'Dataface noticed that the delegate class for the table "'.$this->tablename.'" contains a tablePermissions() method. This method is no longer supported as of Dataface version 0.6. Please use the getPermissions() method instead with first parameter null to achieve the same results. 03807 For example: 03808 function getPermissions(&$record, $params){ 03809 if ( $record === null ){ 03810 // return generic table permissions 03811 } else { 03812 // return record-specific permissions 03813 } 03814 }', 03815 array('table'=>$this->tablename) 03816 ), E_USER_NOTICE 03817 ); 03818 } 03819 03820 return true; 03821 } else { 03822 return false; 03823 } 03824 } 03825 03826 03827 // @} 03828 // End Delegate Classes 03829 //---------------------------------------------------------------------------------------------- 03830 03831 03832 03833 //---------------------------------------------------------------------------------------------- 03834 // @{ 03853 function getTabs(){ 03854 return array_keys($this->tabs()); 03855 } 03856 03882 function &tabs($record=null){ 03883 03884 $del =& $this->getDelegate(); 03885 if ( isset($del) and method_exists($del, '__tabs__') ){ 03886 $tabs = $del->__tabs__($record); 03887 $i=0; 03888 foreach ($tabs as $tkey=>$tdata){ 03889 $tabs[$tkey]['order'] = $i++; 03890 } 03891 return $tabs; 03892 } else { 03893 03894 $tabs = $this->_tabs; 03895 if ( isset($record) ){ 03896 foreach ( $this->__join__($record) as $tablename=>$tablelabel ){ 03897 if ( !isset($tabs[$tablename]) ){ 03898 $tabs[$tablename] = array('name'=>$tablename, 'label'=>$tablelabel, 'description'=>''); 03899 } 03900 } 03901 } 03902 $i=0; 03903 foreach ($tabs as $tkey=>$tdata){ 03904 $tabs[$tkey]['order'] = $i++; 03905 } 03906 return $tabs; 03907 } 03908 } 03909 03917 function &getTab($tabname, $record=null){ 03918 $tabs =& $this->tabs($record); 03919 return $tabs[$tabname]; 03920 } 03921 03922 03939 function __join__(&$record){ 03940 $del =& $this->getDelegate(); 03941 if ( isset($del) and method_exists($del, '__join__') ){ 03942 return $del->__join__($record); 03943 } else if ( isset($this->_joinTables) ){ 03944 return $this->_joinTables; 03945 } else { 03946 return array(); 03947 } 03948 } 03949 03961 function hasJoinTable($tablename, &$record){ 03962 return array_key_exists($tablename,$this->__join__($record)); 03963 } 03964 03965 03966 03967 // @} 03968 // End Tabs 03969 //---------------------------------------------------------------------------------------------- 03970 03971 03972 //---------------------------------------------------------------------------------------------- 03973 // @{ 04004 function &getFieldgroup($fieldgroupname){ 04005 if ( !isset( $this->_fieldgroups[$fieldgroupname] ) ){ 04006 $parent =& $this->getParent(); 04007 if ( isset($parent) ){ 04008 $fg =& $parent->getFieldgroup($fieldgroupname); 04009 return $fg; 04010 } 04011 return PEAR::raiseError("Attempt to get nonexistent field group '$fieldgroupname' from table '".$this->tablename."'\n<br>", E_USER_ERROR); 04012 } 04013 return $this->_fieldgroups[$fieldgroupname]; 04014 } 04015 04016 04029 function &getFieldgroups(){ 04030 if ( !isset( $this->_cache[__FUNCTION__] ) ){ 04031 $fg =& $this->_fieldgroups; 04032 $parent =& $this->getParent(); 04033 if ( isset($parent) ){ 04034 $fg = array_merge_recursive_unique($parent->getFieldgroups(), $fg); 04035 uasort($fg, array(&$this, '_compareFields')); 04036 } 04037 $this->_cache[__FUNCTION__] =& $fg; 04038 } 04039 return $this->_cache[__FUNCTION__]; 04040 } 04041 04042 04043 // @} 04044 // End Field Groups 04045 //---------------------------------------------------------------------------------------------- 04046 04047 04048 //---------------------------------------------------------------------------------------------- 04049 // @{ 04065 function &getImportFilters(){ 04066 import( 'Dataface/ImportFilter.php'); 04067 if ( $this->_importFilters === null ){ 04068 $this->_importFilters = array(); 04069 /* 04070 * Filters have not been loaded yet.. let's load them. 04071 * 04072 * Any method in the delegate file with a name of the form __import__<string> 04073 * is considered to be an import filter. 04074 * 04075 */ 04076 $delegate =& $this->getDelegate(); 04077 if ( $delegate !== null ) { 04078 $methods = get_class_methods(get_class( $delegate ) ); 04079 foreach ( $methods as $method ){ 04080 $matches = array(); 04081 if ( preg_match( '/^__import__(.*)$/', $method, $matches) ){ 04082 $filter = new Dataface_ImportFilter($this->tablename, $matches[1], df_translate('import_filters:'.$matches[1].':label', ucwords(str_replace('_',' ',$matches[1])))); 04083 $this->_importFilters[$matches[1]] =& $filter; 04084 unset($filter); 04085 } 04086 } 04087 } 04088 04089 $parent =& $this->getParent(); 04090 if ( isset($parent) ){ 04091 $this->_importFilters = array_merge($parent->getImportFilters(), $this->_importFilters); 04092 } 04093 04094 } 04095 04096 return $this->_importFilters; 04097 } 04098 04099 04111 function registerImportFilter(&$filter){ 04112 if (!is_a( $filter, 'Dataface_ImportFilter') ){ 04113 throw new Exception("In Dataface_Table::registerImportFilter() 2nd argument expected to be of type 'Dataface_ImportFilter' but received '".get_class($filter)."'. ", E_USER_ERROR); 04114 } 04115 $filters =& $this->getImportFilters(); 04116 $filters[$filter->name] =& $filter; 04117 04118 } 04119 04120 04121 04131 function getImportTables(){ 04132 $res = mysql_query("SHOW TABLES LIKE '".$this->tablename."__import_%'", $this->db); 04133 if ( !$res ){ 04134 throw new Exception("Error getting import table list for table '".$this->tablename."'.", E_USER_ERROR); 04135 } 04136 04137 $tables = array(); 04138 while ( $row = mysql_fetch_row($res) ){ 04139 $tables[] = $row[0]; 04140 } 04141 mysql_free_result($res); 04142 return $tables; 04143 } 04144 04145 04154 function createImportTable(){ 04155 import('Dataface/QueryBuilder.php'); 04156 /* 04157 * It is a good idea to clean the import tables before we create them. 04158 * That way they don't get cluttered 04159 */ 04160 $this->cleanImportTables(); 04161 04162 $rand = rand(10000,999999); 04163 $name = $this->tablename.'__import_'.strval(time()).'_'.strval($rand); 04164 $qb = new Dataface_QueryBuilder($this->tablename); 04165 $res = mysql_query("CREATE TABLE `$name` SELECT * ".$qb->_from()." LIMIT 0", $this->db); 04166 if (!$res ){ 04167 throw new Exception("Failed to create import table `$name` because a mysql error occurred: ".mysql_error($this->db)."\n", E_USER_ERROR); 04168 } 04169 return $name; 04170 04171 } 04172 04181 function cleanImportTables(){ 04182 04183 $tables = $this->getImportTables(); 04184 $app =& Dataface_Application::getInstance(); 04185 $garbageLifetime = $app->_conf['garbage_collector_threshold']; 04186 foreach ($tables as $table){ 04187 $matches =array(); 04188 if ( preg_match('/^'.$this->tablename.'__import_(\d+)_(\d)$/', $table, $matches) ){ 04189 if ( time() - intval($matches[1]) > intval($garbageLifetime) ){ 04190 $res = mysql_query("DROP TABLE `$table`", $this->db); 04191 if ( !$res ){ 04192 throw new Exception("Problem occurred attemtping to clean up old import table '$table'. MySQL returned an error: ".mysql_error($this->db)."\n", E_USER_ERROR); 04193 } 04194 } 04195 } 04196 } 04197 } 04198 04199 04208 function isImportTable($tablename){ 04209 return preg_match('/^\w+__import_(\d{5,20})_(\d{4,10})$/', $tablename); 04210 04211 04212 } 04213 04214 04266 function parseImportData($data, $importFilter=null, $defaultValues=array()){ 04267 $filters =& $this->getImportFilters(); 04268 $delegate =& $this->getDelegate(); 04269 if ( $delegate === null ){ 04270 /* 04271 * Currently the only place that Import filters can be defined is in the 04272 * delegate file. If there is no delegate file, then there are no filters. 04273 * if there are no filters, then we can't possibly do any importing so we 04274 * return an error. 04275 */ 04276 return Dataface_Error::noImportFiltersFound(); 04277 } 04278 $errors = array(); 04279 if ( $importFilter === null ){ 04280 /* 04281 * The filter is not specified so we will try every filter until we find one 04282 * that works. 04283 */ 04284 foreach (array_keys($filters) as $filtername){ 04285 $parsed =& $filters[$filtername]->import($data, $defaultValues); 04286 if ( PEAR::isError($parsed) ){ 04287 /* 04288 * This filter encountered an error. 04289 * Record the error, and unset the $parsed variable. 04290 */ 04291 $errors[$filtername] =& $parsed; 04292 unset($parsed); 04293 continue; 04294 } 04295 04296 break; 04297 } 04298 04299 if ( isset($parsed) ){ 04300 /* 04301 * The only way that the $parsed variable should be 'set' is if 04302 * one of the filters successfully parsed the data. 04303 */ 04304 return $parsed; 04305 04306 } else { 04307 return Dataface_Error::noImportFiltersFound( 04308 "No suitable import filter was found to import data into table '".$this->tablename."'. The following filters were attempted: {".implode(',', array_keys($errors))."}." 04309 ); 04310 } 04311 } else { 04312 /* 04313 * A particular import filter was specified so we will try with that one. 04314 */ 04315 if ( !isset( $filters[$importFilter] ) ){ 04316 return Dataface_Error::noImportFiltersFound("The import filter '".$importFilter."' was not found while attempting to import data into the table '".$this->tablename."'. The following import filters are available: {".implode(',', array_keys($errors))."}." 04317 ); 04318 } 04319 04320 return $filters[$importFilter]->import($data, $defaultValues); 04321 } 04322 04323 } 04324 04325 04326 // @} 04327 // End Imports 04328 //---------------------------------------------------------------------------------------------- 04329 04330 04331 04332 04333 04334 04335 04336 04337 04338 04339 04340 04341 04342 04346 function _parseINISection($section, &$curr){ 04347 04348 foreach ($section as $valuekey=>$valuevalue){ 04349 if ( strpos($valuekey,':') > 0 ){ 04350 $path = explode(':', $valuekey); 04351 $temp =& $curr; 04352 for ( $i=0; $i<count($path); $i++){ 04353 if ( $i<count($path)-1){ 04354 if ( !isset($temp[$path[$i]])) $temp[$path[$i]] = array(); 04355 $temp2 =& $temp[$path[$i]]; 04356 unset($temp); 04357 $temp =& $temp2; 04358 unset($temp2); 04359 } else { 04360 $temp[$path[$i]] = $valuevalue; 04361 } 04362 } 04363 } else { 04364 $curr[$valuekey] = $valuevalue; 04365 } 04366 } 04367 04368 04369 } 04370 04371 04372 04373 04374 04375 04376 04377 04378 04379 //---------------------------------------------------------------------------------------------- 04380 // @{ 04393 function getType($fieldname){ 04394 if ( !isset($this->_cache[__FUNCTION__][$fieldname]) ){ 04395 $field =& $this->getField($fieldname); 04396 if ( PEAR::isError($field) ) return $field; 04397 04398 if ( isset( $field ) ){ 04399 04400 $type = $field['Type']; 04401 04402 $matches = array(); 04403 04404 if ( preg_match('/^([^\( ]+).*/', $type, $matches) ){ 04405 $type = $matches[1]; 04406 } 04407 04408 $type = trim($type); 04409 $this->_cache[__FUNCTION__][$fieldname] = strtolower($type); 04410 } 04411 } 04412 return $this->_cache[__FUNCTION__][$fieldname]; 04413 04414 04415 } 04416 04423 function isDate($fieldname){ 04424 $type = $this->getType($fieldname); 04425 if ( PEAR::isError($type) ){ 04426 return false; 04427 } 04428 return in_array( $type, array('date','datetime','time','timestamp') ); 04429 } 04430 04431 04438 function isBlob($fieldname){ 04439 return in_array( $this->getType($fieldname), array('blob', 'longblob','tinyblob','mediumblob') ); 04440 } 04441 04451 function isContainer($fieldname){ 04452 return strtolower($this->getType($fieldname)) == 'container'; 04453 04454 } 04455 04463 function isPassword($fieldname){ 04464 $field =& $this->getField($fieldname); 04465 //if ( !is_array($field) ) return false; 04466 return ($field['widget']['type'] == 'password'); 04467 } 04468 04474 function isText($fieldname){ 04475 return in_array( $this->getType($fieldname), array('text','longtext','tinytext','mediumtext') ); 04476 } 04477 04485 function isXML($fieldname){ 04486 $fld =& $this->getField($fieldname); 04487 return in_array( $fld['widget']['type'], array('table','group')); 04488 } 04489 04495 function isChar($fieldname){ 04496 return in_array( $this->getType($fieldname), array('varchar','char') ); 04497 } 04498 04504 function isInt($fieldname){ 04505 return in_array(strtolower($this->getType($fieldname)), array('int','tinyint','mediumint','smallint','bigint')); 04506 } 04507 04508 04514 function isFloat($fieldname){ 04515 return in_array(strtolower($this->getType($fieldname)), array('float','double','tinyfloat','mediumfloat','decimal')); 04516 } 04517 04518 04519 // @} 04520 // END Field Type Information 04521 //---------------------------------------------------------------------------------------------- 04522 04523 04524 //---------------------------------------------------------------------------------------------- 04525 // @{ 04546 function parse_datetime($value){ 04547 return $this->parse_datetype($value); 04548 04549 04550 } 04551 04556 function parse_date($value){ 04557 04558 return $this->parse_datetype($value); 04559 04560 } 04561 04574 function parse_timestamp($value){ 04575 if ( $value == 'CURRENT_TIMESTAMP' ){ 04576 $value = date('Y-m-d H:i:s'); 04577 } 04578 return $this->parse_datetype($value); 04579 04580 } 04581 04586 function parse_time($value){ 04587 return $this->parse_datetype($value); 04588 } 04589 04594 function isTimeStamp($value){ 04595 $converter = new Dataface_converters_date; 04596 return $converter->isTimestamp($value); 04597 } 04598 04603 function parse_datetype($value){ 04604 $converter = new Dataface_converters_date; 04605 return $converter->parseDate($value); 04606 04607 04608 } 04609 04610 04620 function normalize($fieldname, $value){ 04621 04622 return $this->getValueAsString($fieldname, $this->parse($fieldname, $value)); 04623 } 04624 04637 function getValueAsString($fieldname, $value){ 04638 $table =& $this->getTableTableForField($fieldname); 04639 $delegate =& $table->getDelegate(); 04640 $rel_fieldname = $table->relativeFieldName($fieldname); 04641 if ( $delegate !== null and method_exists( $delegate, $rel_fieldname.'__toString') ){ 04642 $value = call_user_func( array(&$delegate, $rel_fieldname.'__toString'), $value); 04643 } else 04644 04645 04646 if ( is_array($value) ){ 04647 if ( method_exists( $this, $this->getType($fieldname)."_to_string") ){ 04648 $value = call_user_func( array( &$this, $this->getType($fieldname)."_to_string"), $value ); 04649 } else { 04650 $value = implode(', ', $value); 04651 } 04652 } 04653 $evt = new stdClass; 04654 $evt->table = $table; 04655 $evt->field =& $table->getField($rel_fieldname); 04656 $evt->value = $value; 04657 $evt->type = $table->getType($rel_fieldname); 04658 $this->app->fireEvent('after_getValueAsString', $evt); 04659 $value = $evt->value; 04660 return $value; 04661 } 04662 04663 04684 public function format($fieldname, $value){ 04685 04686 $out = $value; 04687 $table = $this->getTableTableForField($fieldname); 04688 if ( strpos($fieldname, '.') !== false ){ 04689 list($rel, $fieldname) = explode('.', $fieldname); 04690 } 04691 $delegate = $table->getDelegate(); 04692 $field =& $table->getField($fieldname); 04693 if ( PEAR::isError($field) ){ 04694 throw new Exception('Could not load field '.$fieldname.': '.$field->getMessage(), $field->getCode()); 04695 } 04696 $method = $fieldname.'__format'; 04697 if ( isset($delegate) and method_exists($delegate, $method) ){ 04698 return $delegate->$method($value); 04699 } 04700 // If this is a number, let's format it!! 04701 if ( $table->isInt($fieldname) or $table->isFloat($fieldname) ){ 04702 if ( isset($field['number_format']) ){ 04703 $locale_data = localeconv(); 04704 $decimal = $locale_data['decimal_point']; 04705 $sep = $locale_data['thousands_sep']; 04706 $places = intval($field['number_format']); 04707 $out = number_format(floatval($out), $places, $decimal, $sep); 04708 } else if ( isset($field['money_format']) ){ 04709 04710 $fieldLocale = null; 04711 if ( method_exists($delegate, 'getFieldLocale') ){ 04712 $fieldLocale = $delegate->getFieldLocale($this, $fieldname); 04713 04714 } 04715 if ( !isset($fieldLocale) and @$field['locale'] ){ 04716 $fieldLocale = $field['locale']; 04717 } 04718 04719 if ( isset($fieldLocale) ){ 04720 $oldLocale = setlocale(LC_MONETARY, '0'); 04721 if ( $oldLocale != $fieldLocale ){ 04722 setlocale(LC_MONETARY, $fieldLocale); 04723 } 04724 } 04725 $out = money_format($field['money_format'], floatval($out)); 04726 if ( isset($fieldLocale) ){ 04727 setlocale(LC_MONETARY, $oldLocale); 04728 } 04729 04730 } 04731 } else if ( $table->isDate($fieldname) ){ 04732 04733 // If this is a date field, we will do some date formatting 04734 04735 $fmt = null; 04736 switch ( strtolower($table->getType($fieldname)) ){ 04737 04738 case 'date': 04739 $fmt = '%x';break; 04740 case 'time': 04741 $fmt = '%r';break; 04742 default: 04743 $fmt = '%c'; 04744 04745 } 04746 04747 04748 $fieldLocale = null; 04749 if ( method_exists($delegate, 'getFieldLocale') ){ 04750 $fieldLocale = $delegate->getFieldLocale($this, $fieldname); 04751 04752 } 04753 if ( !isset($fieldLocale) and @$field['locale'] ){ 04754 $fieldLocale = $field['locale']; 04755 } 04756 04757 if ( isset($fieldLocale) ){ 04758 $oldLocale = setlocale(LC_TIME, '0'); 04759 if ( $oldLocale != $fieldLocale ){ 04760 setlocale(LC_TIME, $fieldLocale); 04761 } 04762 } 04763 04764 if ( isset($field['date_format']) ){ 04765 $fmt = $field['date_format']; 04766 } 04767 04768 if ( !strtotime($out) ) return ''; 04769 $out = strftime($fmt, strtotime($out)); 04770 04771 if ( isset($fieldLocale) ){ 04772 setlocale(LC_TIME, $oldLocale); 04773 } 04774 04775 04776 04777 } 04778 04779 04780 // If A display format was set for this field, let's apply it 04781 if ( isset($field['display_format']) ){ 04782 if ( isset($field['display_format_i18n']) ){ 04783 $fmt = df_translate($field['display_format_18n'], $field['display_format']); 04784 } else { 04785 $fmt = $field['display_format']; 04786 } 04787 04788 $out = sprintf($fmt, $out); 04789 } 04790 return $out; 04791 } 04792 04793 04804 function parse($fieldname, $value, $parseRepeat=true){ 04805 if ( strpos($fieldname, '.') !== false ){ 04806 // If this is a related field, we allow the related table to do the 04807 // parsing 04808 $table =& $this->getTableTableForField($fieldname); 04809 if ( PEAR::isError($table) ){ 04810 throw new Exception( $table->toString(), E_USER_ERROR); 04811 } 04812 list($rel, $fieldname) = explode('.', $fieldname); 04813 return $table->parse($fieldname, $value, $parseRepeat); 04814 } 04815 $type = $this->getType($fieldname); 04816 04817 $field =& $this->getField($fieldname); 04818 04819 04820 $delegate =& $this->getDelegate(); 04821 if ( $delegate !== null and method_exists( $delegate, $fieldname.'__parse') ){ 04822 $value = call_user_func( array( &$delegate, $fieldname.'__parse'), $value); 04823 } 04824 04825 else if ( $parseRepeat and $field['repeat'] and ($this->isText($fieldname) or $this->isChar($fieldname) ) ){ 04826 04827 $value = $this->parse_repeated($fieldname, $value, $field['separator']); 04828 } 04829 04830 else if ( method_exists( $this, 'parse_'.strtolower($type) ) ){ 04831 04832 $value = call_user_func( array(&$this, 'parse_'.strtolower($type)), $value); 04833 } 04834 04835 else if ( in_array($field['widget']['type'], array('group','table') ) and is_string($value) ){ 04836 //error_log("\nAbout to parse $fieldname for value $value",3,'log.txt'); 04837 //if ( is_string($value) and strlen($value)> 10){ 04838 //error_log('About to serialize '.$fieldname, 3, 'log.txt'); 04839 import( 'XML/Unserializer.php'); 04840 $unserializer = new XML_Unserializer(); 04841 $parsed = $unserializer->unserialize($value); 04842 04843 if ( !PEAR::isError($parsed) ){ 04844 $value = $unserializer->getUnserializedData(); 04845 } 04846 04847 //} 04848 04849 04850 } else if ( $value === "" and ($this->isInt($fieldname) or $this->isFloat($fieldname)) ){ 04851 $value = null; 04852 } 04853 04854 $evt = new stdClass; 04855 $evt->table = $this; 04856 $evt->field =& $field; 04857 $evt->value = $value; 04858 $evt->type = $type; 04859 $evt->parseRepeat = $parseRepeat; 04860 $this->app->fireEvent('after_parse', $evt); 04861 $value = $evt->value; 04862 return $value; 04863 04864 } 04865 04866 04875 function parse_repeated($fieldname, $value, $separator="\n"){ 04876 if ( !$separator ) $separator = "\n"; 04877 if ( !is_array($value) ){ 04878 $value = explode($separator, $value); 04879 } 04880 foreach (array_keys($value) as $key) { 04881 $value[$key] = $this->parse($fieldname, $value[$key], false); 04882 } 04883 04884 return $value; 04885 } 04886 04887 04888 04895 function parseString( $str, $values ){ 04896 if ( !is_string($str) ) return $str; 04897 $matches = array(); 04898 $blackString = $str; 04899 while ( preg_match( '/(?<!\\\)\$([0-9a-zA-Z\._\-]+)/', $blackString, $matches ) ){ 04900 if ( $this->hasField($matches[1]) ){ 04901 $replacement = $this->normalize($matches[1], $values[$matches[1]]); 04902 04903 } else { 04904 $replacement = ""; 04905 } 04906 $str = preg_replace( '/(?<!\\\)\$'.$matches[1].'/', $replacement, $str); 04907 $blackString = preg_replace( '/(?<!\\\)\$'.$matches[1].'/', "", $blackString); 04908 04909 } 04910 return $str; 04911 } 04912 04913 04914 04926 function validate($fieldname, $value, &$params){ 04927 $field =& $this->getField($fieldname); 04928 if ( $field['widget']['type'] == 'file' and is_uploaded_file(@$value['tmp_name']) and is_array($value)){ 04929 // This bit of validation code is executed for files that have just been uploaded from the form. 04930 // It expects the value to be an array of the form: 04931 // eg: array('tmp_name'=>'/path/to/uploaded/file', 'name'=>'filename.txt', 'type'=>'image/gif'). 04932 04933 if ( !is_array(@$field['allowed_extensions']) and @$field['allowed_extensions']){ 04934 $field['allowed_extensions'] = explode(',',@$field['allowed_extensions']); 04935 } 04936 if ( !is_array(@$field['allowed_mimetypes']) and @$field['allowed_mimetypes'] ){ 04937 $field['allowed_mimetypes'] = explode(',',@$field['allowed_mimetypes']); 04938 } 04939 if ( !is_array(@$field['disallowed_extensions']) and @$field['disallowed_extensions'] ){ 04940 $field['disallowed_extensions'] = explode(',',@$field['disallowed_extensions']); 04941 } 04942 if ( !is_array(@$field['disallowed_mimetypes']) and @$field['disallowed_extensions']){ 04943 $field['disallowed_mimetypes'] = explode(',',@$field['disallowed_mimetypes']); 04944 } 04945 04946 $field['allowed_extensions'] = @array_map('strtolower', @$field['allowed_extensions']); 04947 $field['allowed_mimetypes'] = @array_map('strtolower', @$field['allowed_mimetypes']); 04948 $field['disallowed_extensions'] = @array_map('strtolower', @$field['disallowed_extensions']); 04949 $field['disallowed_mimetypes'] = @array_map('strtolower', @$field['disallowed_mimetypes']); 04950 // We do some special validation for file uploads 04951 // Validate -- make sure that it is the proper mimetype and extension. 04952 if ( is_array( @$field['allowed_mimetypes'] ) and count($field['allowed_mimetypes']) > 0 ){ 04953 if ( !in_array($value['type'], $field['allowed_mimetypes']) ){ 04954 $params['message'] = "The file submitted in field '".$field['name']."' is not the correct type. Received '".$value['type']."' but require one of (".implode(',', $field['allowed_mimetypes']).")."; 04955 04956 return false; 04957 } 04958 } 04959 04960 if ( @is_array(@$field['disallowed_mimetypes']) and in_array($value['type'], $field['disallowed_mimetypes']) ){ 04961 $params['message'] = "The file submitted in field '".$fieldname."' has a restricted mime type. The mime type received was '".$value['type']."'."; 04962 return false; 04963 } 04964 04965 $extension = ''; 04966 $matches = array(); 04967 if ( preg_match('/\.([^\.]+)$/', $value['name'], $matches) ){ 04968 $extension = $matches[1]; 04969 } 04970 $extension = strtolower($extension); 04971 04972 04973 if ( is_array( @$field['allowed_extensions'] ) and count($field['allowed_extensions']) > 0 ){ 04974 if ( !in_array($extension, $field['allowed_extensions']) ){ 04975 $params['message'] = "The file submitted does not have the correct extension. Received file has extension '".$extension."' but the field requires either ".implode(' or ', $field['allowed_extensions'])."."; 04976 04977 return false; 04978 } 04979 } 04980 04981 if ( @is_array( @$field['disallowed_extensions'] ) and in_array($extension, $field['disallowed_extensions']) ){ 04982 $params['message'] = "The file submitted in field '".$fieldname."' has a restricted extension. Its extension was '".$extension."' which is disallowed for this form."; 04983 return false; 04984 } 04985 04986 if ( @$field['max_size'] and intval($field['max_size']) < intval(@$value['size']) ){ 04987 $params['message'] = "The file submitted in field '".$fieldname."' is {$value['size']} bytes which exceeds the limit of {$field['max_size']} bytes for this field."; 04988 return false; 04989 } 04990 } 04991 04992 //$delegate =& $this->getDelegate(); 04993 //if ( $delegate !== null and method_exists($delegate, $fieldname."__validate") ){ 04994 // /* 04995 // * 04996 // * The delegate defines a custom validation method for this field. Use it. 04997 // * 04998 // */ 04999 // return call_user_func(array(&$delegate, $fieldname."__validate"), $this, $value, $params); 05000 //} 05001 return true; 05002 } 05003 05004 05005 // @} 05006 // End Field Data Manipulation 05007 //---------------------------------------------------------------------------------------------- 05008 05009 05010 05011 05012 //---------------------------------------------------------------------------------------------- 05013 // @{ 05028 function displayBlock($blockName, $params=array()){ 05029 if ( @$this->app->_conf['debug'] ) echo "<div class=\"debug_marker\">Block "$blockName"</div>"; 05030 $delegate =& $this->getDelegate(); 05031 //echo "Checking for block $blockName"; 05032 $res = false; 05033 05034 // Add the ability for Modules to define blocks without conflicting with 05035 // defined blocks in the application. 05036 // Added Feb. 28, 2007 by Steve Hannah for 0.6.14 release. 05037 $mres = false; 05038 if ( isset($this->app->_conf['_modules']) and count($this->app->_conf['_modules']) > 0){ 05039 $mtool =& Dataface_ModuleTool::getInstance(); 05040 $mres = $mtool->displayBlock($blockName, $params); 05041 } 05042 if ( isset($delegate) and method_exists($delegate, 'block__'.$blockName) ){ 05043 $methodname = 'block__'.$blockName; 05044 $fres = $delegate->$methodname($params); 05045 //$fres = call_user_func(array(&$delegate, 'block__'.$blockName), $params); 05046 if ( !PEAR::isError($fres) ) 05047 $res = true; 05048 } else { 05049 05050 $appDelegate =& $this->app->getDelegate(); 05051 if (isset($appDelegate) and method_exists($appDelegate, 'block__'.$blockName) ){ 05052 $methodname = 'block__'.$blockName; 05053 $fres = $appDelegate->$methodname($params); 05054 //$fres = call_user_func(array(&$appDelegate, 'block__'.$blockName), $params); 05055 if ( !PEAR::isError($fres) ) 05056 $res = true; 05057 } 05058 } 05059 return ($res or $mres); 05060 05061 } 05062 05069 function getBlockContent($blockName, $params=array()){ 05070 ob_start(); 05071 $res = $this->displayBlock($blockName, $params); 05072 $out = ob_get_contents(); 05073 ob_end_clean(); 05074 if ( !$res ) return null; 05075 return $out; 05076 } 05077 05078 05079 // @} 05080 // End Templates 05081 //---------------------------------------------------------------------------------------------- 05082 05083 05084 05085 05086 //---------------------------------------------------------------------------------------------- 05087 // @{ 05100 function newRecord($vals=null){ 05101 return new Dataface_Record($this->tablename, $vals); 05102 } 05103 05110 function &getRecord($query=null){ 05111 return df_get_record($this->tablename, $query); 05112 } 05113 05114 // @} 05115 // End Factory Methods 05116 //---------------------------------------------------------------------------------------------- 05117 05118 05119 //---------------------------------------------------------------------------------------------- 05120 // @{ 05135 function baseUrl(){ 05136 return DATAFACE_SITE_URL; 05137 //return $GLOBALS['Dataface_Globals_BaseUrl']; 05138 05139 } 05140 05141 05142 private static $basePaths = array(); 05143 public static function setBasePath($table, $path){ 05144 self::$basePaths[$table] = $path; 05145 } 05146 public static function getBasePath($table){ 05147 if ( isset(self::$basePaths[$table]) ){ 05148 return self::$basePaths[$table]; 05149 } else { 05150 return DATAFACE_SITE_PATH; 05151 } 05152 } 05153 05160 function basePath(){ 05161 05162 return self::getBasePath($this->tablename); 05163 //return realpath($GLOBALS['Dataface_Globals_BasePath']); 05164 } 05165 05166 05167 05168 05169 05170 05175 function getIniFile(){ 05176 return $this->_iniFile; 05177 } 05178 05183 function setIniFile($file){ 05184 $this->_iniFile = $file; 05185 } 05186 05187 05188 05189 05190 05195 function clearCache(){ 05196 $this->_cache = array(); 05197 } 05198 05199 05200 05201 05202 05203 05204 05205 05212 function date_to_string($value){ 05213 05214 return Dataface_converters_date::date_to_string($value); 05215 05216 05217 } 05218 05223 function getSerializer(){ 05224 if ( !isset( $this->_serializer ) ){ 05225 05226 $this->_serializer = new Dataface_Serializer($this->tablename); 05227 } 05228 return $this->_serializer; 05229 } 05230 05236 function datetime_to_string($value){ 05237 return Dataface_converters_date::datetime_to_string($value); 05238 } 05239 05245 function time_to_string($value){ return Dataface_converters_date::time_to_string($value); } 05246 05252 function timestamp_to_string($value){ return Dataface_converters_date::timestamp_to_string($value); } 05253 05254 05255 05256 05257 // @} 05258 // End Utility Methods 05259 //---------------------------------------------------------------------------------------------- 05260 05261 05262 //---------------------------------------------------------------------------------------------- 05263 // @{ 05284 function getActions(&$params,$noreturn=false){ 05285 import( 'Dataface/ActionTool.php'); 05286 $actionsTool =& Dataface_ActionTool::getInstance(); 05287 if ( !$this->_actionsLoaded ){ 05288 $this->_actionsLoaded = true; 05289 import( 'Dataface/ConfigTool.php'); 05290 $configTool =& Dataface_ConfigTool::getInstance(); 05291 $actions =& $configTool->loadConfig('actions',$this->tablename); 05292 //print_r($actions); 05293 foreach ($actions as $key=>$action){ 05294 $action['table'] = $this->tablename; 05295 $action['name'] = $key; 05296 if ( !isset($action['id']) ) $action['id'] = $action['name']; 05297 if ( !isset($action['label']) ) $action['label'] = str_replace('_',' ',ucfirst($action['name'])); 05298 if ( !isset($action['accessKey'])) $action['accessKey'] = substr($action['name'],0,1); 05299 if ( !isset($action['label_i18n']) ) $action['label_i18n'] = 'action:'.$action['name'].' label'; 05300 if ( !isset($action['description_i18n'])) $action['description_i18n'] = 'action:'.$action['name'].' description'; 05301 $actionsTool->addAction($key, $action); 05302 } 05303 05304 05305 } 05306 05307 $params['table'] = $this->tablename; 05308 if ( $noreturn ) return true; 05309 return $actionsTool->getActions($params); 05310 05311 } 05312 05313 05314 // @} 05315 // End Actions 05316 //---------------------------------------------------------------------------------------------- 05317 05318 }