Xataface 2.0
Xataface Application Framework
Dataface/Table.php
Go to the documentation of this file.
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 &quot;$blockName&quot;</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 }
 All Data Structures Namespaces Files Functions Variables Enumerations