Xataface 2.0
Xataface Application Framework
Dataface/Record.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 import( 'Dataface/Table.php');
00024 import( 'Dataface/RelatedRecord.php');
00025 import('Dataface/LinkTool.php');
00026 
00027 
00033 define('DATAFACE_RECORD_RELATED_RECORD_BLOCKSIZE', 30);
00034 
00035 
00100 class Dataface_Record {
00101 
00109         var $secureDisplay = true;
00110 
00111 
00117         var $_id;
00118         
00125         static function _nextId(){
00126                 static $id = 0;
00127                 return $id++;
00128         }
00129 
00138         var $_parentRecord;
00139         
00140         
00146         var $propertyChangeListeners=array();
00147         
00153         var $_values;
00154         
00155         
00161         var $_table;
00162         
00163         
00169         var $_tablename;
00170         
00171         
00181         var $_relatedValues = array();
00182         
00188         var $_relatedValuesLoaded = array();
00189         
00193         var $_numRelatedRecords = array();
00197         var $_lastRelatedRecordStart = 0;
00198         
00202         var $_lastRelatedRecordLimit = 30;
00203         
00207         var $_relationshipRanges;
00208         
00209         
00214         var $_title;
00215         
00216         
00223         var $_oldValues;
00224         
00228         var $_transientValues=array();
00229         
00230         
00235         var $useMetaData = true;
00236         
00237         
00244         var $_dirtyFlags = array();
00245         
00251         var $_relatedDirtyFlags = array();
00252         
00256         var $_isLoaded = array();
00257         
00261         var $_metaDataValues=array();
00262         
00263         
00269         var $loadBlobs = false;
00270         
00275         var $_relatedMetaValues=array();
00276         
00277         
00282         var $_delegate = null;
00283         
00287         var $cache=array();
00288         
00300         var $vetoSecurity = false;
00301         
00308         var $vetoFields = array();
00309         
00310         
00315         var $pouch = array();
00316         
00317         
00324         var $lang = null;
00325         
00326         //--------------------------------------------------------------------------------
00327         // @{
00336         function Dataface_Record($tablename, $values=null){
00337                 $app =& Dataface_Application::getInstance();
00338                 $this->_id = Dataface_Record::_nextId();
00339                 $this->_tablename = $tablename;
00340                 $this->_table =& Dataface_Table::loadTable($tablename);
00341                 $this->_delegate =& $this->_table->getDelegate();
00342                 $this->lang = $app->_conf['lang'];
00343                 
00344                 if ( $values !== null ){
00345                         foreach ($values as $k=>$v){
00346                                 $this->setValue($k, $v);
00347                         }
00348                         //$this->setValues($values);
00349                         $this->setSnapshot();
00350                 }
00351         }
00352         
00353         // @}
00354         // END Initialization 
00355         //---------------------------------------------------------------------------------
00356         
00366         function __destruct(){
00367                 unset($this->propertyChangeListeners);
00368                 unset($this->cache);
00369                 unset($this->pouch);
00370                 unset($this->vetoFields);
00371                 unset($this->_delegate);
00372                 unset($this->_metaDataValues);
00373                 unset($this->_transientValues);
00374                 unset($this->_oldValues);
00375         
00376                 if ( isset($this->_parentRecord) ){
00377                         $this->_parentRecord->__destruct();
00378                         unset($this->_parentRecord);
00379                 }
00380                 
00381                 
00382         }
00383         
00384         //------------------------------------------------------------------------------------
00385         // @{
00403         function callDelegateFunction($function, $fallback=null){
00404                 $del =& $this->_table->getDelegate();
00405                 $parent =& $this->getParentRecord();
00406                 if ( isset($del) && method_exists($del, $function) ){
00407                         return $del->$function($this);
00408                         //return call_user_func(array(&$del, $function), $this);
00409                 } else if ( isset($parent) ){
00410                 
00411                         return $parent->callDelegateFunction($function, $fallback);
00412                 } else {
00413                         return $fallback;
00414                 }
00415         
00416         }
00417         
00418         
00419 
00420         
00421         
00435         function getActions($params=array()){
00436                 $params['record'] =& $this;
00437                 $actions = $this->_table->getActions($params);
00438                 
00439                 $parent =& $this->getParentRecord();
00440                 if ( isset($parent) ){
00441                         $actions = array_merge_recursive_unique($parent->getActions($params), $actions);
00442                 }
00443                 return $actions;
00444         }
00445         
00446         
00452         function &table(){
00453                 return $this->_table;
00454         }
00455         
00456         
00465         function clearCache(){
00466                 
00467                 unset($this->cache);
00468                 
00469                 $this->cache=array();
00470                 
00471                 $this->_relatedValuesLoaded = array();
00472                 
00473                 $this->_relatedValues = array();
00474                 $this->_relatedMetaValues = array();
00475                 
00476                 
00477         }
00478         
00479         
00480         
00481         
00482                 
00507         function parseString( $str){
00508                 if ( !is_string($str) ) return $str;
00509                 $matches = array();
00510                 $blackString = $str;
00511                 while ( preg_match( '/(?<!\\\)\$([0-9a-zA-Z\._\-]+)/', $blackString, $matches ) ){
00512                         if ( $this->_table->hasField($matches[1]) ){
00513                                 $replacement = $this->strval($matches[1]);
00514                                 
00515                                 
00516                         } else {
00517                                 $replacement = $matches[1];
00518                         }
00519                         $str = preg_replace( '/(?<!\\\)\$'.$matches[1].'/', $replacement, $str);
00520                         $blackString = preg_replace( '/(?<!\\\)\$'.$matches[1].'/', "", $blackString);
00521                         
00522                 }
00523                 return $str;
00524         }
00525         
00526         // @}
00527         // END Utility Methods
00528         //-------------------------------------------------------------------------------
00529         
00530         
00531         //---------------------------------------------------------------------------------
00532         //{@
00533         
00554         function getRelationshipRange($relationshipName){
00555                 if ( isset( $this->_relationshipRanges[$relationshipName] ) ){
00556                         return $this->_relationshipRanges[$relationshipName];
00557                 } else {
00558                         return $this->_table->getRelationshipRange($relationshipName);
00559                 }
00560         }
00561         
00574         function setRelationshipRange($relationshipName, $lower, $upper){
00575                 if ( !isset( $this->_relationshipRanges ) ) $this->_relationshipRanges = array();
00576                 $this->_relationshipRanges[$relationshipName] = array($lower, $upper);
00577                 
00578         }
00579 
00580         
00581         
00582         
00583         
00584         
00585         
00586         
00600         function _relatedRecordLoaded($relname, $index, $where=0, $sort=0){
00601         
00602                 $blockNumber = floor($index / DATAFACE_RECORD_RELATED_RECORD_BLOCKSIZE);
00603                 return ( isset( $this->_relatedValuesLoaded[$relname][$where][$sort][$blockNumber] ) and $this->_relatedValuesLoaded[$relname][$where][$sort][$blockNumber] );
00604         }
00605         
00606         
00619         function _translateRangeToBlocks($lower, $upper){
00620         
00621                 $lowerBlock = floor($lower / DATAFACE_RECORD_RELATED_RECORD_BLOCKSIZE);
00622                 $upperBlock = floor($upper / DATAFACE_RECORD_RELATED_RECORD_BLOCKSIZE);
00623                 return array(intval($lowerBlock), intval($upperBlock));
00624         }
00625         
00641         function _relatedRecordBlockLoaded($relname, $block, $where=0, $sort=0){
00642                 return ( isset( $this->_relatedValuesLoaded[$relname][$where][$sort][$block] ) and $this->_relatedValuesLoaded[$relname][$where][$sort][$block] );
00643         }
00644         
00663         function _loadRelatedRecordBlock($relname, $block, $where=0, $sort=0){
00664                 if ( $this->_relatedRecordBlockLoaded($relname, $block, $where, $sort) ) return true;
00665 
00666                 $relationship =& $this->_table->getRelationship($relname);
00667                 if ( !is_object($relationship) ){
00668                         throw new Exception(
00669                                 df_translate(
00670                                         'scripts.Dataface.Record._loadRelatedRecordBlock.ERROR_GETTING_RELATIONSHIP',
00671                                         "Error getting relationship '$relname'.  The value returned by getRelationship() was '$relationship'.",
00672                                         array('relationship'=>$relname, 'retval'=>$relationship)
00673                                         ), E_USER_ERROR);
00674                 }
00675                 
00676                 $start = $block * DATAFACE_RECORD_RELATED_RECORD_BLOCKSIZE;
00677                 $limit = DATAFACE_RECORD_RELATED_RECORD_BLOCKSIZE;
00678                 
00679                 if ( $start >= $this->numRelatedRecords($relname, $where) ){
00680 
00681 
00682                         return false;
00683                 }
00684                 
00685                 //$sql = $this->parseString($relationship->_schema['sql']);
00686                 $sql = $this->parseString($relationship->getSQL($this->loadBlobs, $where, $sort));
00687 
00688                 // TODO We need to change this so that it is compatible with relationships that already specify a limit.
00689                 $sql .= " LIMIT ".addslashes($start).",".addslashes($limit);
00690                 
00691 
00692                 //$res = mysql_query($sql, $this->_table->db);
00693                 $db =& Dataface_DB::getInstance();
00694                 $res = $db->query($sql, $this->_table->db, null, true);
00695                 if ( !$res and !is_array($res) ){
00696                         
00697                         throw new Exception( mysql_error($this->_table->db).
00698                                 df_translate(
00699                                         'scripts.Dataface.Record._loadRelatedRecordBlock.ERROR_LOADING_RELATED_RECORDS',
00700                                         "Error loading related records for relationship '$relname' in table '".$this->_table->tablename."'.  There was a problem performing the sql query '$sql'. The Mysql error returned was '".mysql_error($this->_table->db),
00701                                         array('relationship'=>$relname,'table'=>$this->_table->tablename, 'mysql_error'=>mysql_error($this->_table->db), 'sql'=>$sql)
00702                                         )
00703                                 ,E_USER_ERROR);
00704                 }
00705                 $index = $start;
00706                 //while ( $row = mysql_fetch_assoc($res) ){
00707                 foreach ($res as $row){
00708                         $record_row = array();
00709                         $meta_row = array();
00710                         foreach ($row as $key=>$value){
00711                                 
00712                                 if (  strpos($key, '__') === 0  ){
00713                                         $meta_row[$key] = $value;
00714                                 } else {
00715                                         $record_row[$key] = $this->_table->parse($relname.'.'.$key, $value);
00716                                 }
00717                                 unset($value);
00718                         }
00719                         $this->_relatedValues[$relname][$where][$sort][$index++] =& $record_row;
00720                         $this->_relatedMetaValues[$relname][$where][$sort][$index-1] =& $meta_row;
00721                         unset($record_row);
00722                         unset($meta_row);
00723                         
00724                 }
00725 
00726                 $this->_relatedValuesLoaded[$relname][$where][$sort][$block] = true;
00727                 
00728                 return true;
00729         }
00730         
00731         
00764         function numRelatedRecords($relname, $where=0){
00765         
00766                 if ( !isset( $this->_numRelatedRecords[$relname][$where]) ){
00767                         $relationship =& $this->_table->getRelationship($relname);
00768                         
00769                         //if ( $where !== 0 ){
00770                                 $sql = $this->parseString($relationship->getSQL($this->loadBlobs, $where));
00771                         //} else {
00772                         //      $sql = $this->parseString($relationship->_schema['sql']);
00773                         //}
00774                         $sql = stristr($sql, ' FROM ');
00775                         $sql = "SELECT COUNT(*) as num".$sql;
00776                         //$dbObj = 
00777                         //$res = mysql_query($sql, $this->_table->db);
00778                         //$res = mysql_query($sql, $this->_table->db);
00779                         $db =& Dataface_DB::getInstance();
00780                         $res = $db->query($sql, $this->_table->db, null, true);
00781                         if ( !$res and !is_array($res) ){
00782                         //if ( !$res ){
00783                                 throw new Exception(
00784                                         df_translate(
00785                                                 'scripts.Dataface.Record.numRelatedRecords.ERROR_CALCULATING_NUM_RELATED_RECORDS',
00786                                                 "Error calculating the number of related records there are for the relationship '$relname' in the table '".$this->_table->tablename."'.  There was a problem performing the sql query '$sql'.  The MYSQL error returned was '".mysql_error($this->_table->db)."'.\n<br>",
00787                                                 array('relationship'=>$relname,'table'=>$this->_table->tablename,'mysql_error'=>mysql_error($this->_table->db),'sql'=>$sql)
00788                                                 ), E_USER_ERROR);
00789                         }
00790                         
00791                         $this->_numRelatedRecords[$relname][$where] = $res[0]['num'];
00792                 }
00793                 return $this->_numRelatedRecords[$relname][$where];
00794                 
00795         }
00796         
00859         function &getRelatedRecords( $relname, $multipleRows=true , $start = null, $limit=null, $where=0, $sort=0){
00860                 if ( !is_bool($multipleRows) and intval($multipleRows) > 0  ){
00861                         /*
00862                          * Give caller the option of omitting the "MultipleRows" option.
00863                          */
00864                         $sort = $where;
00865                         $where = $limit;
00866                         $limit = $start;
00867                         $start = $multipleRows;
00868                         $multipleRows = true;
00869                 } else if ( $multipleRows === 'all'){
00870                         // the second argument is the 'all' specifier - meaning that all records should be returned.
00871                         $where = ($start === null ? 0:$start);
00872                         $sort = $limit;
00873                         $start = 0;
00874                         $limit = $this->numRelatedRecords($relname, $where) + 1;
00875                         $multipleRows = true;
00876 
00877                 
00878                 
00879                 } else if ( is_string($multipleRows) and intval($multipleRows) === 0 and $multipleRows !== "0"){
00880 
00881                         if ( is_string($start) and intval($start) === 0 and $start !== "0" ){
00882                                 // $start actually contains the sort parameter
00883                                 $sort = $start;
00884                                 $start = $limit;
00885                                 $limit = $where;
00886                         } else {
00887                                 $sort = $where;
00888                         
00889                         }
00890                         $where = $multipleRows;
00891                         $multipleRows = 'all';
00892                         return $this->getRelatedRecords($relname, $multipleRows, $where, $sort);
00893                 }
00894                         
00895                 
00896                 if ( $where === null ) $where = 0;
00897                 if ( $sort === null ) $sort = 0;
00898                 list($defaultStart, $defaultEnd) = $this->getRelationshipRange($relname);
00899                 if ( $start === null){
00900                         //$start = $this->_lastRelatedRecordStart;
00901                         $start = $defaultStart;
00902                 } else {
00903                         $this->_lastRelatedRecordStart = $start;
00904                 }
00905                 
00906                 if ( $limit === null ){
00907                         //$limit = $this->_lastRelatedRecordLimit;
00908                         $limit = $defaultEnd-$defaultStart;
00909                 } else {
00910                         $this->_lastRelatedRecordLimit = $limit;
00911                 }
00912                 
00913                 
00914                 $range = $this->_translateRangeToBlocks($start,$start+$limit-1);
00915                 if ( $where === null ) $where = 0;
00916                 if ( $sort === null ) $sort = 0;
00917                 if ( !$sort ){
00918                         $relationship =& $this->_table->getRelationship($relname);
00919                         $order_column = $relationship->getOrderColumn();
00920                         if ( !PEAR::isError($order_column) and $order_column){
00921                                 $sort = $order_column;
00922                         }
00923                 }
00924                 // [0]->startblock as int , [1]->endblock as int
00925                 for ( $i=$range[0]; $i<=$range[1]; $i++){
00926                         $res = $this->_loadRelatedRecordBlock($relname, $i, $where, $sort);
00927                         
00928                         // If the above returned false, that means that we have reached the end of the result set.
00929                         if (!$res ) break;
00930                 }
00931                 
00932                 
00933                 if ( $multipleRows === true ){
00934                 
00935                 
00936                         $out = array();
00937                         for ( $i=$start; $i<$start+$limit; $i++){
00938                                 if ( !isset( $this->_relatedValues[$relname][$where][$sort][$i] ) ) continue;
00939                                 $out[$i] =& $this->_relatedValues[$relname][$where][$sort][$i];
00940                         }
00941                         //return $this->_relatedValues[$relname][$where][$sort];
00942                         return $out;
00943                 } else if (is_array($multipleRows) ){
00944                         throw new Exception("Unsupported feature: using array query for multiple rows in getRelatedRecords", E_USER_ERROR);
00945                         // we are searching using a query
00946                         foreach ( array_keys($this->_relatedValues[$relname][$where][$sort]) as $rowIndex ){
00947                                 $row =& $this->_relatedValues[$relname][$where][$sort][$rowIndex];
00948                                 $match = true;
00949                                 foreach ( $multipleRows as $key=>$value ){
00950                                         if ( strpos($key,'.')!== false ){
00951                                                 // if the query specifies an absolute path, just parse it
00952                                                 list($dummy, $key) = explode('.', $key);
00953                                                 if ( trim($dummy) != trim($relname) ){
00954                                                         // make sure that this query is for this relationship
00955                                                         continue;
00956                                                 }
00957                                         }
00958                                         $fullpath = $relname.'.'.$key;
00959                                         $nvalue = $this->_table->normalize($fullpath, $value);
00960                                         if ( $nvalue != $this->_table->normalize($fullpath, $rowIndex) ){
00961                                                 // see if this column matches
00962                                                 $match = false;
00963                                         }
00964                                 }
00965                                 if ( $match ) return $row;
00966                                 unset($row);
00967                         }
00968                         
00969                 
00970                 } else {
00971                         if (count($this->_relatedValues[$relname][$where][$sort])>0){
00972                                 if ( is_int( $start ) ){
00973                                         return $this->_relatedValues[$relname][$where][$sort][$start];
00974                                 } else {
00975                                         return reset($this->_relatedValues[$relname][$where][$sort]);
00976                                 }
00977                                 //$first =& array_shift($this->_relatedValues[$relname]);
00978                                 //array_unshift($this->_relatedValues[$relname], $first);
00979                                 //return $first;
00980                         } else {
00981                                 return null;
00982                         }
00983                 }
00984                                 
00985         }
00986         
01029         function getChildren($start=null, $limit=null){
01030                 $delegate =& $this->_table->getDelegate();
01031                 if ( isset($delegate) and method_exists($delegate, 'getChildren')){
01032                         $children =& $delegate->getChildren($this);
01033                         return $children;
01034                 } else if ( ( $rel =& $this->_table->getChildrenRelationship() ) !== null ){
01035                         $it = $this->getRelationshipIterator($rel->getName(), $start, $limit);
01036                         $out = array();
01037                         while ( $it->hasNext() ){
01038                                 $child = $it->next();
01039                                 $out[] = $child->toRecord();
01040                         }
01041                         return $out;
01042                 } else {
01043                         
01044                         return null;
01045                 }
01046         }
01047         
01048         
01066         function getChild($index){
01067                 $children =& $this->getChildren($index,1);
01068                 if ( !isset($children) || count($children) == 0 ) return null;
01069                 return $children[0];
01070         }
01071         
01102         function &getParent(){
01103                 $delegate =& $this->_table->getDelegate();
01104                 if ( isset($delegate) and method_exists($delegate, 'getParent')){
01105                         $parent =  $delegate->getParent($this);
01106                         return $parent;
01107                 } else if ( ( $rel =& $this->_table->getParentRelationship() ) !== null ){
01108                         $it = $this->getRelationshipIterator($rel->getName());
01109                         
01110                         if ( $it->hasNext() ){
01111                                 $parent = $it->next();
01112                                 $out = $parent->toRecord();
01113                                 return $out;
01114                         }
01115                         return null;
01116                 } else {
01117                         return null;
01118                 }
01119         }
01120         
01121         
01122         
01123         
01124         
01125         
01146         function getRelationshipIterator($relationshipName, $start=null, $limit=null,$where=0, $sort=0){
01147                 if ( !$sort ){
01148                         $relationship =& $this->_table->getRelationship($relationshipName);
01149                         $order_column = $relationship->getOrderColumn();
01150                         if ( !PEAR::isError($order_column) and $order_column){
01151                                 $sort = $order_column;
01152                         }
01153                 }
01154                 return new Dataface_RelationshipIterator($this, $relationshipName, $start, $limit, $where, $sort);
01155         }
01156         
01181         function &getRelatedRecordObjects($relationshipName, $start=null, $end=null,$where=0, $sort=0){
01182                 $out = array();
01183                         
01184                 $it = $this->getRelationshipIterator($relationshipName, $start, $end,$where,$sort);
01185                 while ($it->hasNext() ){
01186                         $out[] =& $it->next();
01187                 }
01188                 return $out;
01189         }
01190         
01191         
01210         function &getRelatedRecord($relationshipName, $index=0, $where=0, $sort=0){
01211                 if ( isset($this->cache[__FUNCTION__][$relationshipName][$index][$where][$sort]) ){
01212                         return $this->cache[__FUNCTION__][$relationshipName][$index][$where][$sort];
01213                 }
01214                 $it = $this->getRelationshipIterator($relationshipName, $index, 1, $where, $sort);
01215                 if ( $it->hasNext() ){
01216                         $rec =& $it->next();
01217                         $this->cache[__FUNCTION__][$relationshipName][$index][$where][$sort] =& $rec;
01218                         return $rec;
01219                 } else {
01220                         $null = null;   // stupid hack because literal 'null' can't be returned by ref.
01221                         return $null;
01222                 }
01223         }
01224         
01225         
01226         
01227         
01247         function moveUp($relationship, $index){
01248                 
01249                 $r =& $this->_table->getRelationship($relationship);
01250                 $order_col = $r->getOrderColumn();
01251                 if ( PEAR::isError($order_col) ) return $order_col;
01252                 $order_table =& $r->getTable($order_col);
01253                 if ( PEAR::isError($order_table) ) return $order_table;
01254                 
01255                 if ( $index == 0 ) return PEAR::raiseError("Cannot move up index 0");
01256                 $it =& $this->getRelationshipIterator($relationship, $index-1, 2);
01257                 if ( PEAR::isError($it) ) return $it;
01258                 if ( $it->hasNext() ){
01259                         $prev_record =& $it->next();
01260                         if ( $it->hasNext() ){
01261                                 $curr_record =& $it->next();
01262                         }
01263                 }
01264                 
01265                 if ( !isset($prev_record) || !isset($curr_record) ){
01266                         return PEAR::raiseError('Attempt to move record up in "'.$relationship.'" but the index "'.$index.'" did not exist.');
01267                 }
01268                 
01269                 if ( intval($prev_record->val($order_col)) == intval($curr_record->val($order_col)) ){
01270                         // The relationship's records are not ordered yet (consecutive records should have distinct order values.
01271                         $res = $this->sortRelationship($relationship);
01272                         if ( PEAR::isError($res) ) return $res;
01273                         return $this->moveUp($relationship, $index);
01274                 }
01275                 
01276                 
01277                 $prev = $prev_record->toRecord($order_table->tablename);
01278                 $curr = $curr_record->toRecord($order_table->tablename);
01279                 $temp = $prev->val($order_col);
01280                 $res = $prev->setValue($order_col, $curr->val($order_col));
01281                 if (PEAR::isError($res) ) return $res;
01282                 $res = $prev->save();
01283                 if ( PEAR::isError($res) ) return $res;
01284                 $res = $curr->setValue($order_col, $temp);
01285                 if ( PEAR::isError($res) ) return $res;
01286                 $res = $curr->save();
01287                 if ( PEAR::isError($res) ) return $res;
01288                 
01289                 return true;
01290                 
01291                 
01292         }
01293         
01312         function moveDown($relationship, $index){
01313                 return $this->moveUp($relationship, $index+1);
01314         }
01315         
01316         
01317         
01325         function sortRelationship($relationship, $start=null, $subset=null){
01326                 $r =& $this->_table->getRelationship($relationship);
01327                 $order_col = $r->getOrderColumn();
01328                 if ( PEAR::isError($order_col) ) return $order_col;
01329                 $order_table =& $r->getTable($order_col);
01330                 if ( PEAR::isError($order_table) ) return $order_table;
01331                 
01332                 // Our strategy for sorting only a subset.
01333                 // Let R be the list of records in the relationship ordered
01334                 // using the default order.
01335                 //
01336                 // Let A be the list of records in our subset of R using the 
01337                 // default order.
01338                 // 
01339                 // Let b = A[0]
01340                 // Let a be the predecessor of b.
01341                 // Let c be the last record in A.
01342                 // Let d be the successor of c.
01343                 // Let B = A union {a,d}
01344                 // For any record x in R, let ord(x) be the value of the order column
01345                 // in x.
01346                 //
01347                 //
01348                 //  The algorithm we will use to sort our subset is as follows:
01349                 //      if ( !exists(a) or ord(a) < ord(b) )
01350                 //              and 
01351                 //      ( !exists(d) or ord(c) < ord(d) )
01352                 //              and
01353                 //      ( ord(c) - ord(b) >= count(A) ){
01354                 //              sort(A)
01355                 //  } else {
01356                 //              sort(R)
01357                 //      }
01358                 
01359                 
01360                 if ( isset($start) ){
01361                         // We are dealing with a subset, so let's go through our algorithm
01362                         // to see if we can get away with only sorting the subset
01363                         //$countR = $this->numRelatedRecords($relationship);
01364                         $aExists = ($start > 0);
01365                         $countA = count($subset);
01366                         $B =& $this->getRelatedRecordObjects($relationship, max($start-1,0), $countA+2);
01367                         $countB = count($B);
01368                 
01369                         
01370                         if ( $aExists ){
01371                                 $dExists = ( $countB-$countA >=2 );
01372                         } else {
01373                                 $dExists = ($countB-$countA >= 1);
01374                         }
01375                         
01376                         
01377                         $AOffset = 0;
01378                         if ( $aExists ) $AOffset++; 
01379                         
01380                         
01381                         if ( (!$aExists or $B[0 + $AOffset]->val($order_col) > $B[0]->val($order_col) )
01382                                         and
01383                                  (!$dExists or $B[$countA-1+$AOffset]->val($order_col) < $B[$countB-1]->val($order_col) )
01384                                         and
01385                                  ( ($B[$countA-1+$AOffset]->val($order_col) - $B[0+$AOffset]->val($order_col)) >= ($countA - 1) ) ){
01386                                  
01387                                 
01388                                  $sortIndex = array();
01389                                  $i = $B[0+$AOffset]->val($order_col);
01390                                  foreach ($subset as $record){
01391                                         $sortIndex[$record->getId()] = $i++;
01392                                  }
01393                                  
01394                                  
01395                                  $i0 = $AOffset;
01396                                  $i1 = $countA+$AOffset;
01397                                  for ( $i = $i0; $i<$i1; $i++ ){
01398                                         $B[$i]->setValue($order_col, $sortIndex[ $B[$i]->getId() ] );
01399                                         $res = $B[$i]->save();
01400                                         if ( PEAR::isError($res) ) echo $res->getMessage();
01401                                  }
01402                                  $this->clearCache();
01403                                  return true;
01404                         }
01405                         
01406                         
01407                         
01408                 }
01409                 
01410                 $it =& $this->getRelationshipIterator($relationship, 'all');
01411                 $i = 1;
01412                 
01413                 while ( $it->hasNext() ){
01414                         $rec =& $it->next();
01415                         //$rec->setValue($order_col, $i++);
01416                         $orderRecord =& $rec->toRecord($order_table->tablename);
01417                         $orderRecord->setValue($order_col, $i++);
01418                         $res = $orderRecord->save();
01419                         if ( PEAR::isError($res) ) return $res;
01420                         unset($rec);
01421                         unset($orderRecord);
01422                         
01423                 }
01424                 $this->clearCache();
01425                 
01426         }
01427         
01428         // @}
01429         // End Relationships
01430         //--------------------------------------------------------------------------------------
01431         
01432         // @{
01433         
01473         function setValue($key, $value, $index=0){
01474                 
01475                 $oldValue = $this->getValue($key, $index);
01476                 
01477                 
01478                 if ( strpos($key, '.')!== false ){
01479                         throw new Exception("Unsupported operation: setting value on related record.", E_USER_ERROR);
01480                 
01481                 }
01482                         
01483                 // This is a local field
01484                 else {
01485                         if ( strpos($key, "__") === 0 && $this->useMetaData ){
01486                                 /*
01487                                  * This is a meta value..
01488                                  */
01489                                 return $this->setMetaDataValue($key, $value);
01490                         }
01491                         
01492                         $add=true;
01493                         
01494                          
01495                         if ( !array_key_exists($key, $this->_table->fields() ) ){
01496                                 
01497                                 if ( array_key_exists($key, $this->_table->transientFields()) ){
01498                                         
01499                                         $this->_transientValues[$key] = $value;
01500                                         $add=false;
01501                                         //return;
01502                                 }
01503                         
01504                                 else if ( !array_key_exists($key, $this->_table->graftedFields(false)) ){
01505                                         $parent =& $this->getParentRecord();
01506                                         
01507                                         if ( isset($parent) and $parent->_table->hasField($key) ){
01508                                                 
01509                                                 $parent->setValue($key, $value, $index);
01510                                 
01511                                         }
01512                                         $add=false;
01513                                 } else {
01514                                         
01515                                         
01516                                         
01517                                         $add=true;
01518                                 }
01519                                 
01520                         } 
01521                         if ( $add ){
01522                                 $this->_values[$key] = $this->_table->parse($key, $value);
01523                                 
01524                                 $this->_isLoaded[$key] = true;
01525                         }
01526                 }
01527                 
01528                 
01529                 // now set the flag to indicate that the value has been changed.
01530                 
01531                 $this->clearCache();
01532                 
01533                 if ($oldValue != $this->getValue($key, $index) ){
01534                         
01535                         $this->setFlag($key, $index);
01536                         if ( $this->vetoSecurity ){
01537                                 $this->vetoFields[$key] = true;
01538                         }
01539                         $this->clearCache();
01540                         
01541                         $this->firePropertyChangeEvent($key, $oldValue, $this->getValue($key,$index));
01542                         
01543                         // Now we should notify the parent record if this was a key field
01544                         if ( array_key_exists($key, $this->_table->keys() ) ){
01545                                 if ( !isset($parent) ) $parent =& $this->getParentRecord();
01546                                 if ( isset($parent) ){
01547                                         $keys = array_keys($this->_table->keys());
01548                                         $pkeys = array_keys($parent->_table->keys());
01549                                         $key_index = array_search($key, $keys);
01550                                         
01551                                         $parent->setValue($pkeys[$key_index], $this->getValue($key, $index));
01552                                 }
01553                         }
01554                 }
01555                 
01556                 
01557         }
01558         
01559         
01560         
01561         
01562         
01579         function setValues($values){
01580                 $fields = $this->_table->fields(false, true);
01581                 foreach ($values as $key=>$value){
01582                         if ( isset( $fields[$key] ) ){
01583                                 $this->setValue($key, $value);
01584                         } else if ( strpos($key,'__')===0){
01585                                 $this->setMetaDataValue($key,$value);
01586                         }
01587                 }
01588         }
01589         
01590         
01774         function &getValue($fieldname, $index=0, $where=0, $sort=0, $debug=false){
01775                 static $callcount=0;
01776                 $callcount++;
01777                 if ( $debug ) echo "Num calls to getValue(): $callcount";
01778                 if ( isset($this->cache[__FUNCTION__][$fieldname][$index][$where][$sort]) ){
01779                         return $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort];
01780                 }
01781                 
01782                 
01783                 
01784                 if ( is_array($index) ){
01785                         throw new Exception(
01786                                 df_translate(
01787                                         'scripts.Dataface.Record.getValue.ERROR_PARAMETER_2',
01788                                         "In Dataface_Record.getValue() expected 2nd parameter to be integer but received array."
01789                                         ), E_USER_ERROR);
01790                 }
01791                 if ( is_array($where) ){
01792                         throw new Exception(
01793                                 df_translate(
01794                                         'scripts.Dataface.Record.getValue.ERROR_PARAMETER_3',
01795                                         "In Dataface_Record.getValue() expected 3rd parameter to be a string, but received array."
01796                                         ), E_USER_ERROR);
01797                 }
01798                 if ( is_array($sort) ){
01799                         throw new Exception(
01800                                 df_translate(
01801                                         'scripts.Dataface.Record.getValue.ERROR_PARAMETER_4',
01802                                         "In Dataface_Record.getValue() expected 4th parameter to be a string but received array."
01803                                         ), E_USER_ERROR);
01804                 }
01805                 
01806                 $out = null;
01807                 if ( strpos($fieldname,'.') === false ){
01808                         $delegate =& $this->_delegate;
01809                         
01810                         if ( !isset( $this->_values[$fieldname] ) ) {
01811                                 // The field is not set... check if there is a calculated field we can use.
01812                                 if ( $delegate !== null and method_exists($delegate, "field__$fieldname")){
01813                                         $methodname = "field__$fieldname";
01814                                         $out =& $delegate->$methodname($this,$index);
01815                                         //$out =& call_user_func( array(&$delegate, "field__$fieldname"), $this, $index);
01816                                 //} else if ( array_key_exists($fieldname, $this->_transientValues) ){
01817                                 } else if ( array_key_exists($fieldname, $this->_table->transientFields()) ){
01818                                         $transientFields =& $this->_table->transientFields();
01819                                         if ( array_key_exists( $fieldname, $this->_transientValues) ){
01820                                                 $out = $this->_transientValues[$fieldname];
01821                                         } else if ( isset($transientFields[$fieldname]['relationship']) and $transientFields[$fieldname]['widget']['type'] == 'grid'){
01822                                                 $out= array();
01823                                                 $rrecords =& $this->getRelatedRecordObjects($transientFields[$fieldname]['relationship'], 'all');
01824                                                 $currRelationship =& $this->_table->getRelationship($transientFields[$fieldname]['relationship']);
01825                                                 $relKeys =& $currRelationship->keys();
01826                                                 //print_r(array_keys($currRelationship->keys()));
01827                                                 foreach ($rrecords as $rrecord){
01828                                                         $row = $rrecord->strvals();
01829                                                         
01830                                                         foreach ( array_keys($row) as $row_field ){
01831                                                                 $ptable =& $rrecord->_relationship->getTable($row_field);
01832                                                                 $precord =& $rrecord->toRecord($ptable->tablename);
01833                                                                 if ( !$precord or PEAR::isError($precord) ) continue;
01834                                                                 $row['__permissions__'][$row_field] = $precord->getPermissions(array('field'=>$row_field));
01835                                                                 if ( isset($relKeys[$row_field]) ) unset($row['__permissions__'][$row_field]['edit']);
01836                                                                 unset($precord);
01837                                                                 unset($ptable);
01838                                                         }
01839                                                         $row['__id__'] = $rrecord->getId();
01840                                                         
01841                                                         $out[] = $row;
01842                                                         unset($rrecord);
01843                                                         unset($row);
01844                                                 }
01845                                                 unset($relKeys);
01846                                                 unset($currRelationship);
01847                                                 unset($rrecords);
01848                                                 $this->_transientValues[$fieldname] = $out;
01849                                         } else if ( isset($transientFields[$fieldname]['relationship']) and $transientFields[$fieldname]['widget']['type'] == 'checkbox'){
01850                                                 $out= array();
01851                                                 $rrecords =& $this->getRelatedRecordObjects($transientFields[$fieldname]['relationship'], 'all');
01852                                                 $currRelationship =& $this->_table->getRelationship($transientFields[$fieldname]['relationship']);
01853                                                 foreach ($rrecords as $rrecord){
01854                                                         $row = $rrecord->strvals();
01855                                                         $domRec = $rrecord->toRecord();
01856                                                         
01857                                                         $rowstr = array();
01858                                                         foreach (array_keys($domRec->_table->keys()) as $relKey){
01859                                                                 $rowStr[] = urlencode($relKey).'='.urlencode($row[$relKey]);
01860                                                         }
01861                                                         $out[] = implode('&',$rowStr);
01862                                                         
01863                                                         unset($rowStr, $domRec);
01864                                                         unset($rrecord);
01865                                                         unset($row);
01866                                                 }
01867                                                 unset($relKeys);
01868                                                 unset($currRelationship);
01869                                                 unset($rrecords);
01870                                                 $this->_transientValues[$fieldname] = $out;
01871                                         } else {
01872                                                 
01873                                                 if ( isset($delegate) and  method_exists($delegate, $fieldname.'__init') ){
01874                                                         $methodname = $fieldname.'__init';
01875                                                         $out = $delegate->$methodname($this);
01876                                                         if ( isset($out) ){
01877                                                                 $this->_transientValues[$fieldname] = $out;
01878                                                         }
01879                                                 }
01880                                                 
01881                                                 if ( !isset($out) ){
01882                                                         $methodname = 'initTransientField';
01883                                                         $app = Dataface_Application::getInstance();
01884                                                         $appdel = $app->getDelegate();
01885                                                         if ( isset($appdel) and method_exists($appdel, $methodname) ){
01886                                                                 $out = $appdel->$methodname($this, $transientFields[$fieldname]);
01887                                                                 if ( isset($out) ){
01888                                                                         $this->_transientValues[$fieldname] = $out;
01889                                                                 }
01890                                                         }
01891                                                         
01892                                                 
01893                                                 }
01894                                                 
01895                                                 if ( !isset($out) ){
01896                                                         $event = new StdClass;
01897                                                         $event->record = $this;
01898                                                         $event->field = $transientFields[$fieldname];
01899                                                         $out = null;
01900                                                         
01901                                                         
01902                                                         $app = Dataface_Application::getInstance();
01903                                                         $app->fireEvent('initTransientField', $event);
01904                                                         
01905                                                         
01906                                                         $out = $event->out;
01907                                                         if ( isset($out) ){
01908                                                                 $this->_transientValues[$fieldname] = $out;
01909                                                         }
01910                                                 }
01911                                                         
01912                                                 
01913                                                 
01914                                                 $out = null;
01915                                         }
01916                                         
01917                                 } else if ( ( $parent =& $this->getParentRecord() ) and $parent->_table->hasField($fieldname) ){
01918                                 
01919                                         return $parent->getValue($fieldname,$index,$where,$sort,$debug);
01920                                 } else {
01921                                         $this->_values[$fieldname] = null;
01922                                         $out = null;
01923                                 }
01924                         } else {
01925                                 $out = $this->_values[$fieldname];
01926                         }
01927                         if ( isset($out) ){
01928                                 // We only store non-null values in cache.  We were having problems 
01929                                 // with segfaulting in PHP5 when groups are used.
01930                                 // This seems to fix the issue, but let's revisit it later.
01931                                 $this->cache[strval(__FUNCTION__)][strval($fieldname)][$index][$where][$sort] = $out;
01932                         }
01933                         return $out;
01934                 } else {
01935                         list($relationship, $fieldname) = explode('.', $fieldname);
01936                         
01937                         $rec =& $this->getRelatedRecords($relationship, false, $index, 1, $where, $sort);
01938                         $this->cache[__FUNCTION__][$relationship.'.'.$fieldname][$index][$where][$sort] =& $rec[$fieldname];
01939                         return $rec[$fieldname];
01940                         
01941                         
01942                 }
01943         }
01944         
01945         
01946         
01947         
01953         function &value($fieldname, $index=0, $where=0, $sort=0){
01954                 $val =& $this->getValue($fieldname, $index,$where, $sort);
01955                 return $val;
01956         }
01957         
01962         function &val($fieldname, $index=0, $where=0, $sort=0){
01963                 $val =& $this->getValue($fieldname, $index, $where, $sort);
01964                 return $val;
01965         }
01966         
02035         function &getValues($fields = null, $index=0, $where=0, $sort=0){
02036                 if ( !isset( $this->_values ) ) $this->_values = array();
02037                 $values = array();
02038                 $fields = ( $fields === null ) ? array_keys($this->_table->fields(false,true)) : $fields;
02039                 foreach ($fields as $field){
02040                         $values[$field] =& $this->getValue($field, $index, $where, $sort);
02041                 }
02042                         
02043                 return $values;
02044         }
02045         
02051         function &values($fields = null, $index=0, $where=0, $sort=0){
02052                 $vals =& $this->getValues($fields, $index, $where, $sort);
02053                 return $vals;
02054         }
02055         
02060         function &vals($fields = null, $index=0, $where=0, $sort=0){
02061                 $vals =& $this->getValues($fields, $index, $where, $sort);
02062                 return $vals;
02063         }
02064         
02151         function getValueAsString($fieldname, $index=0, $where=0, $sort=0){
02152                 //return $this->_table->getValueAsString($fieldname, $this->getValue($fieldname), $index);
02153                 
02154                 $value = $this->getValue($fieldname, $index, $where, $sort);
02155                 
02156                 
02157                 $table =& $this->_table->getTableTableForField($fieldname);
02158                 $delegate =& $table->getDelegate();
02159                 $rel_fieldname = $table->relativeFieldName($fieldname);
02160                 if ( $delegate !== null and method_exists( $delegate, $rel_fieldname.'__toString') ){
02161                         $methodname = $rel_fieldname.'__toString';
02162                         $value = $delegate->$methodname($value); //call_user_func( array(&$delegate, $rel_fieldname.'__toString'), $value);
02163                 } else 
02164                 
02165                 
02166                 if ( !is_scalar($value) ){
02167                         $methodname = $this->_table->getType($fieldname)."_to_string";
02168                         if ( method_exists( $this->_table, $methodname) ){
02169                                 
02170                                 $value = $this->_table->$methodname($value); //call_user_func( array( &$this->_table, $this->_table->getType($fieldname)."_to_string"), $value );
02171                         } else {
02172                                 $value = $this->array2string($value);
02173                                 
02174                         }
02175                 }
02176                 
02177                 else if ( ( $parent =& $this->getParentRecord() ) and $parent->_table->hasField($fieldname) ){
02178                         return $parent->getValueAsString($fieldname, $index, $where, $sort);
02179                 }
02180                 
02181                 $evt = new stdClass;
02182                 $evt->table = $table;
02183                 $evt->field =& $table->getField($rel_fieldname);
02184                 $evt->value = $value;
02185                 $evt->type = $table->getType($rel_fieldname);
02186                 $table->app->fireEvent('after_getValueAsString', $evt);
02187                 $value = $evt->value;
02188                 
02189                 return $value;
02190         }
02191         
02195         function array2string($value){
02196                 if ( is_string($value) ) return $value;
02197                 if ( is_array($value) ){
02198                         if ( count($value) > 0 and is_array($value[0]) ){
02199                                 $delim = "\n";
02200                         } else {
02201                                 $delim = ', ';
02202                         }
02203                         return implode($delim, array_map(array(&$this,'array2string'), $value));
02204                 }
02205                 return '';
02206         }
02207         
02208         
02236         function getValuesAsStrings($fields='', $index=0, $where=0, $sort=0){
02237                 $keys = is_array($fields) ? $fields : array_keys($this->_table->fields(false,true));
02238                 $values = array();
02239                 foreach ($keys as $key){
02240                         $values[$key] = $this->getValueAsString($key, $index, $where, $sort);
02241                 }
02242                 return $values;
02243         }
02244         
02248         function strvals($fields='', $index=0, $where=0, $sort=0){
02249                 return $this->getValuesAsStrings($fields, $index, $where, $sort);
02250         }
02251         
02252         
02256         function strval($fieldname, $index=0, $where=0, $sort=0){
02257                 return $this->getValueAsString($fieldname, $index, $where, $sort);
02258         }
02259         
02260         
02264         function stringValue($fieldname, $index=0, $where=0, $sort=0){
02265                 return $this->getValueAsString($fieldname, $index, $where, $sort);
02266         }
02267         
02268         
02283         function getSerializedValue($fieldname, $index=0, $where=0, $sort=0){
02284                 $s = $this->_table->getSerializer();
02285                 return $s->serialize($fieldname, $this->getValue($fieldname, 0, $where, $sort));
02286         
02287         }
02288         
02289         
02459         function display($fieldname, $index=0, $where=0, $sort=0, $urlencode=false){
02460                 if ( isset($this->cache[__FUNCTION__][$fieldname][$index][$where][$sort]) ){
02461                         return $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort];
02462                 }
02463                 if ( strpos($fieldname,'.') === false ){
02464                         // this is not a related field.
02465                         if ( $this->secureDisplay and !Dataface_PermissionsTool::view($this, array('field'=>$fieldname)) ){
02466                                 $del =& $this->_table->getDelegate();
02467                                 if ( $del and method_exists($del, 'no_access_text') ){
02468                                         return $del->no_access_text($this, array('field'=>$fieldname));
02469                                 } else {
02470                                         return 'NO ACCESS';
02471                                 }
02472                         }
02473                 } else {
02474                         list($relationship,$fieldname) = explode('.',$fieldname);
02475                         $rrecord =& $this->getRelatedRecord($relationship,$index,$where,$sort);
02476                         if ( !$rrecord ) return null;
02477                         $out = $rrecord->display($fieldname);
02478                         $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02479                         return $out;
02480                 }
02481                 
02482                 
02483         
02484                 $table =&  $this->_table->getTableTableForField($fieldname);
02485                 
02486                 
02487                 $delegate =& $this->_table->getDelegate();
02488                 if ( $delegate !== null and method_exists( $delegate, $fieldname."__display") ){
02489                         $methodname = $fieldname."__display";
02490                         $out = $delegate->$methodname($this);
02491                         //$out = call_user_func(array(&$delegate, $fieldname."__display"), $this);
02492                         $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02493                         return $out;
02494                         
02495                 }
02496                 
02497                 $field =& $this->_table->getField($fieldname);
02498                 if ( $this->_table->isBlob($fieldname) or ($this->_table->isContainer($fieldname) and @$field['secure'])  ){
02499                         
02500                         unset($table);
02501                         $table =& Dataface_Table::loadTable($field['tablename']);
02502                         $keys = array_keys($table->keys());
02503                         $qstr = '';
02504                         foreach ($keys as $key){
02505                                 $qstr .= "&$key"."=".$this->strval($key,$index,$where,$sort);
02506                         }
02507                         $out = DATAFACE_SITE_HREF."?-action=getBlob&-table=".$field['tablename']."&-field=$fieldname&-index=$index$qstr";
02508                         $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02509                         return $out;
02510                 }
02511                 
02512                 else if ( $this->_table->isContainer($fieldname) ){
02513                         $field =& $this->_table->getField($fieldname);
02514                         $strvl=$this->strval($fieldname,$index,$where,$sort);
02515                         if ($urlencode)
02516                         {
02517                             $strvl=rawurlencode($strvl);
02518                         }
02519                         $out = $field['url'].'/'.$strvl;
02520                         if ( strlen($out) > 1 and $out{0} == '/' and $out{1} == '/' ){
02521                                 $out = substr($out,1);
02522                         }
02523                         $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02524                         return $out;
02525                 }
02526                 
02527                 else { //if ( !$this->_table->isBlob($fieldname) ){
02528                 
02529                         $field =& $this->_table->getField($fieldname);
02530                         
02531                         
02532                         if ( PEAR::isError($field) ){
02533                                 $field->addUserInfo("Failed to get field '$fieldname' while trying to display its value in Record::display()");
02534                                 return $field;
02535                                 
02536                                 
02537                         }
02538                         $vocab = $field['vocabulary'];
02539                         if ( $vocab ){
02540                                 $valuelist =& $table->getValuelist($vocab);
02541                         }
02542                         $value = $this->getValue($fieldname, $index, $where, $sort);
02543                         if ( PEAR::isError($value) ) return '';
02544                         if ( isset($valuelist) && !PEAR::isError($valuelist) ){
02545                                 if ( $field['repeat'] and is_array($value) ){
02546                                         $out = "";
02547                                         foreach ($value as $value_item){
02548                                                 if ( isset( $valuelist[$value_item] ) ){
02549                                                         $out .= $valuelist[$value_item].', ';
02550                                                 } else {
02551                                                         $out .= $value_item.', ';
02552                                                 }
02553                                         }
02554                                         if ( strlen($out) > 0 ) $out = substr($out, 0, strlen($out)-2);
02555                                         $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02556                                         return $out;
02557                                 }
02558                                 
02559                                 //else if ( isset( $valuelist[$value]) ){
02560                                 else {
02561                                         if ( is_array($value) ) $value = $this->strval($fieldname, $index, $where, $sort);
02562                                         if ( isset($valuelist[$value]) ){
02563                                                 $out = $valuelist[$value];
02564                                                 $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02565                                                 return $out;
02566                                         } else {
02567                                                 return $value;
02568                                         }
02569                                 } 
02570                         } else {
02571                                 $parent =& $this->getParentRecord();
02572                                 
02573                                 
02574                                 
02575                                 if ( isset($parent) and $parent->_table->hasField($fieldname) ){
02576                                         
02577                                         return $parent->display($fieldname, $index, $where, $sort);
02578                                 }
02579                                 $out = $this->getValueAsString($fieldname, $index, $where, $sort);
02580                                 
02581                                 
02582                                 $out = $table->format($fieldname, $out);
02583                                 
02584                                 
02585                                 // Let's pass the value through an event filter to give modules
02586                                 // a crack at the final output.
02587                                 $evt = new stdClass;
02588                                 $evt->record = $this;
02589                                 $evt->field =& $field;
02590                                 $evt->value = $out;
02591                                 $table->app->fireEvent('Record::display', $evt);
02592                                 $out = $evt->value;
02593                                 
02594                                 
02595                                 
02596                                 $this->cache[__FUNCTION__][$fieldname][$index][$where][$sort] = $out;
02597                                 return $out;
02598                         }
02599                 
02600                 
02601                         //return $this->_table->display($fieldname, $this->getValue($fieldname, $index));
02602                 } 
02603                                 
02604                                 
02605         }
02606         
02607         
02608         
02609         
02640         function htmlValue($fieldname, $index=0, $where=0, $sort=0,$params=array()){
02641                 $recid = $this->getId();
02642                 $uri = $recid.'#'.$fieldname;
02643                 $domid = $uri.'-'.rand();
02644                 
02645                 
02646                 
02647                 $delegate =& $this->_table->getDelegate();
02648                 if ( isset($delegate) && method_exists($delegate, $fieldname.'__htmlValue') ){
02649                         $methodname = $fieldname.'__htmlValue';
02650                         $res = $delegate->$methodname($this);
02651                         //$res = call_user_func(array(&$delegate, $fieldname.'__htmlValue'), $this);
02652                         if ( is_string($res) and DATAFACE_USAGE_MODE == 'edit' and $this->checkPermission('edit', array('field'=>$fieldname)) and !$this->_table->isMetaField($fieldname) ){
02653                                 $res = '<span id="'.$domid.'" df:id="'.$uri.'" class="df__editable">'.$res.'</span>';
02654                         }
02655                         return $res;
02656                 }
02657                 $parent =& $this->getParentRecord();
02658                 if ( isset($parent) and $parent->_table->hasField($fieldname) ){
02659                         return $parent->htmlValue($fieldname, $index, $where, $sort, $params);
02660                 }       
02661                 $val = $this->display($fieldname, $index, $where, $sort);
02662                 
02663                 if ( $this->secureDisplay and !Dataface_PermissionsTool::view($this, array('field'=>$fieldname)) ){
02664                         $del =& $this->_table->getDelegate();
02665                         if ( $del and method_exists($del, 'no_access_link') ){
02666                                 $link = $del->no_access_link($this, array('field'=>$fieldname));
02667                                 return '<a href="'.htmlspecialchars($link).'">'.$val.'</a>';
02668                         }
02669                 }
02670                 
02671                 $field = $this->_table->getField($fieldname);
02672                 //if ( $field['widget']['type'] != 'htmlarea' ) $val = htmlentities($val,ENT_COMPAT, 'UTF-8');
02673                 if ( $this->_table->isText($fieldname) and $field['widget']['type'] != 'htmlarea' and $field['contenttype'] != 'text/html' ) $val = nl2br($val);
02674                 
02675                 if ( $this->_table->isBlob($fieldname) or $this->_table->isContainer($fieldname) ){
02676                         if ( $this->getLength($fieldname, $index,$where,$sort) > 0 ){
02677                                 if ( $this->isImage($fieldname, $index, $where, $sort) ){
02678                                         $val = '<img src="'.$val.'"';
02679                                         if ( !isset($params['width']) and isset($field['width']) ){
02680                                                 $params['width'] = $field['width'];
02681                                         }
02682                                         foreach ($params as $pkey=>$pval){
02683                                                 $val .= ' '.$pkey.'="'.$pval.'"';
02684                                         }
02685                                         $val .= '/>';
02686                                 } else {
02687                                         $file_icon = df_translate(
02688                                                 $this->getMimetype($fieldname,$index,$where,$sort).' file icon',
02689                                                 df_absolute_url(DATAFACE_URL).'/images/document_icon.gif'
02690                                                 );
02691                                         $val = '<img src="'.$file_icon.'"/><a href="'.$val.'" target="_blank"';
02692                                         foreach ($params as $pkey=>$pval){
02693                                                 $val .= ' '.$pkey.'="'.$pval.'"';
02694                                         }
02695                                         $val .= '>View Field Content In New Window ('.$this->getMimetype($fieldname, $index,$where,$sort).')</a>';
02696                                 }
02697                         } else {
02698                                 $val = "(Empty)";
02699                         }
02700                 }
02701                 if ( is_string($val) and DATAFACE_USAGE_MODE == 'edit' and $this->checkPermission('edit', array('field'=>$fieldname))  and !$this->_table->isMetaField($fieldname)){
02702                         $val = '<span id="'.$domid.'" df:id="'.$uri.'" class="df__editable">'.$val.'</span>';
02703                 }
02704                 return $val;
02705                 
02706         
02707         
02708         }
02709         
02710         
02729         function preview($fieldname, $index=0, $maxlength=255, $where=0, $sort=0){
02730         
02731                 $strval = strip_tags($this->display($fieldname,$index, $where, $sort));
02732                 $out = substr($strval, 0, $maxlength);
02733                 if ( strlen($strval)>$maxlength) {
02734                         $out .= '...';
02735                 }        
02736                 return $out;
02737                 
02738         }
02739         
02745         function printValue($fieldname, $index=0, $where=0, $sort=0 ){
02746                 return $this->display($fieldname, $index, $where, $sort);
02747         }
02748         
02754         function printval($fieldname, $index=0, $where=0, $sort=0){
02755                 return $this->display($fieldname, $index, $where, $sort);
02756         }
02757         
02763         function q($fieldname, $index=0, $where=0, $sort=0){
02764                 return $this->display($fieldname, $index, $where, $sort);
02765         }
02766         
02773         function qq($fieldname, $index=0, $where=0, $sort=0){
02774                 return $this->htmlValue($fieldname, $index, $where, $sort);
02775         }
02776         
02792         function hasValue($fieldname){
02793                 return (isset( $this->_values) and array_key_exists($fieldname, $this->_values) );
02794         }
02795         
02796         
02827         function getAbsoluteValues(){
02828                 $values = $this->getValues();
02829                 $absValues = array();
02830                 foreach ( $values as $key=>$value){
02831                         $absValues[$this->_table->tablename.".".$key] = $value;
02832                 }
02833                 return $absValues;
02834         }
02835         
02836         
02837         
02861         function getContainerSource($fieldname){
02862                 $filename =& $this->strval($fieldname);
02863                 if ( strlen($filename)===0 ){
02864                         return null;
02865                 }
02866                 $field =& $this->_table->getField($fieldname);
02867                 return $field['savepath'].'/'.$filename;
02868         
02869         }
02870 
02871         
02888         function setMetaDataValue($key, $value){
02889                 if ( !isset( $this->_metaDataValues ) ) $this->_metaDataValues = array();
02890                 $this->_metaDataValues[$key] = $value;
02891                 $parent =& $this->getParentRecord();
02892                 if ( isset($parent) ){
02893                         $parent->setMetaDataValue($key, $value);
02894                 }
02895         }
02896         
02897         
02898         
02899         
02900         
02901         
02902         
02908         function clearValues(){
02909                 $this->_values = array();
02910                 $this->_relatedValues = array();
02911                 $this->_valCache = array();
02912                 
02913                 $this->clearFlags();
02914                 
02915                 $parent =& $this->getParentRecord();
02916                 if ( isset($parent) ){
02917                         $parent->clearValues();
02918                 }
02919         
02920         }
02921         
02929         function clearValue($field){
02930                 
02931                 unset($this->_values[$field]);
02932                 $this->clearFlag($field);
02933                 
02934                 $parent =& $this->getParentRecord();
02935                 if ( isset($parent) ){
02936                         $parent->clearValue();
02937                 }
02938         }
02939         
02940         
02941         
02942         // @}
02943         // End Field Values Methods
02944         //-------------------------------------------------------------------------------
02945         
02946         
02947         // @{
02981         function addPropertyChangeListener($key, &$listener){
02982                 $this->propertyChangeListeners[$key][] = &$listener;
02983         }
02984         
02999         function removePropertyChangeListener($key, &$listener){
03000                 if ( !isset($key) ) $key = '*';
03001                 if ( !isset($callback) ) unset($this->propertyChangeListeners[$key]);
03002                 else if ( isset($this->propertyChangeListeners[$key]) ){
03003                         if ( ($index = array_search($listener,$this->propertyChangeListeners[$key])) !== false){
03004                                 unset($this->propertyChangeListeners[$key][$index]);
03005                         }
03006                 }
03007         }
03008         
03023         function firePropertyChangeEvent($key, $oldValue, $newValue){
03024                 $origKey = $key;
03025                 $keys = array('*');
03026                 if ( isset($key) ) $keys[] = $key;
03027                 foreach ($keys as $key){
03028                         if ( !isset($this->propertyChangeListeners[$key] ) ) continue;
03029                         foreach ( array_keys($this->propertyChangeListeners[$key]) as $lkey){
03030                                 $this->propertyChangeListeners[$key][$lkey]->propertyChanged($this,$origKey, $oldValue, $newValue);
03031                                 
03032                         }
03033                 }
03034                 
03035                 
03036         }
03037         
03055         function propertyChanged(&$source, $key, $oldValue, $newValue){
03056                 $parentRecord =& $this->getParentRecord();
03057                 if ( is_a($source, 'Dataface_Record') and is_a($parentRecord, 'Dataface_Record') and $source->_id === $parentRecord->_id ){
03058                         $pkeys = $source->_table->keys();
03059                         $pkey_names = array_keys($pkeys);
03060                         $okeys = $this->_table->keys();
03061                         $okey_names = array_keys($okeys);
03062                         
03063                         if ( !array_key_exists($key, $pkeys) ) return false;
03064                                 // The field that was changed was not a key so we don't care
03065                                 
03066                         $key_index = array_search($key, $pkey_names);
03067                         if ( $key_index === false ) throw new Exception("An error occurred trying to find the index of the parent's key.  This is a code error that should be fixded by the developer.", E_USER_ERROR);
03068                         
03069                         
03070                         if ( !isset($okey_names[$key_index]) )
03071                                 throw new Exception("Attempt to keep the current record in sync with its parent but they seem to have a different number of primary keys.  To use Dataface inheritance, tables must have a corresponding primary key.", E_USER_ERROR);
03072                         
03073                         
03074                         $this->setValue( $okey_names[$key_index], $newValue);
03075                 }
03076         }
03077         
03078         
03079         
03080         
03081         // @}
03082         // END Property Change Events
03083         //-------------------------------------------------------------------------------------
03084         
03085         // @{
03117         function getJoinRecord($tablename, $nullIfNotFound=false){
03118                 $table =& Dataface_Table::loadTable($tablename);
03119                 $query = $this->getJoinKeys($tablename);
03120                 foreach ( $query as $key=>$val ){
03121                         $query[$key] = '='.$val;
03122                 }
03123                 
03124                 $record = df_get_record($tablename, $query);
03125                 if ( !$record ){
03126                         if ( $nullIfNotFound ) return null;
03127                         // No record was found, so we create a new one.
03128                         $record = new Dataface_Record($tablename, array());
03129                         foreach ( $query as $key=>$value){
03130                                 $record->setValue($key, substr($value,1));
03131                         }
03132                 }
03133                 return $record;
03134                 
03135         }
03136         
03137         
03162         function getJoinKeys($tablename){
03163                 $table =& Dataface_Table::loadTable($tablename);
03164                 $query = array();
03165                 
03166                 $pkeys1 = array_keys($this->_table->keys());
03167                 $pkeys2 = array_keys($table->keys());
03168                 
03169                 if ( count($pkeys1) != count($pkeys2) ){
03170                         return PEAR::raiseError("Attempt to get join record [".$this->_table->tablename."] -> [".$table->tablename."] but they have a different number of columns as primary key.");
03171                 }
03172                 
03173                 for ($i =0; $i<count($pkeys1); $i++ ){
03174                         $query[$pkeys2[$i]] = $this->strval($pkeys1[$i]);
03175                 }
03176                 
03177                 return $query;
03178         
03179         }
03180         
03189         function tabs(){
03190                 return $this->_table->tabs($this);
03191         }
03192         
03193         // @}
03194         // END TAB Management
03195         
03196         
03197         //---------------------------------------------------------------------------
03198         // @{
03223         function getRoles($params=array()){
03224                 return $this->_table->getRoles($this, $params);
03225                 
03226         }
03227         
03234         function getRolePermissions($params=array()){
03235                 return $this->_table->getRolePermissions($this, $params);
03236         }
03237         
03238         
03324         function getPermissions($params=array()){
03325                 $params['record'] =& $this;
03326                 return $this->_table->getPermissions($params);
03327         }
03328         
03338         function checkPermission($perm, $params=array()){
03339                 $perms = $this->getPermissions($params);
03340                 return ( isset($perms[$perm]) and $perms[$perm] );
03341         }
03342         
03343         
03344         
03345         // @}
03346         // END Permissions
03347         //----------------------------------------------------------------------------------
03348         
03374         function validate( $fieldname, $value, &$params){
03375                 //if ( func_num_args() > 2 ){
03376                 //      $params =& func_get_arg(2);
03377                 //}
03378                 //else {
03379                 //      $params = array();
03380                 //}
03381                 
03382                 if ( !is_array($params) ){
03383                         $params = array('message'=> &$params);
03384                 }
03385                 $res = $this->_table->validate($fieldname, $value, $params);
03386                 
03387                 $field =& $this->_table->getField($fieldname);
03388                 
03389                 if ( $field['widget']['type'] == 'file' and @$field['validators']['required'] and is_array($value) and $this->getLength($fieldname) == 0 and !is_uploaded_file(@$value['tmp_name'])){
03390                                 // This bit of validation operates on the upload values assuming the file was just uploaded as a form.  It assumes
03391                                 // that $value is of the form
03393                                 $params['message'] = "$fieldname is a required field.";
03394                                 $params['message_i18n_id'] = "Field is a required field";
03395                                 $params['message_i18n_params'] = array('field'=>$fieldname);
03396                                 return false;
03397                 }
03398                 if ( $res ){
03399                         $delegate =& $this->_table->getDelegate();
03400                         if ( $delegate !== null and method_exists($delegate, $fieldname."__validate") ){
03401                                 /*
03402                                  *
03403                                  * The delegate defines a custom validation method for this field.  Use it.
03404                                  *
03405                                  */
03406                                 $methodname = $fieldname."__validate";
03407                                 $res = $delegate->$methodname($this,$value,$params);
03408                                 //$res = call_user_func(array(&$delegate, $fieldname."__validate"), $this, $value, $params);
03409                         }
03410                         
03411                         
03412                 }
03413                 
03414                 if ($res){
03415                         $parent =& $this->getParentRecord();
03416                         if ( isset($parent) and $parent->_table->hasField($fieldname) ){
03417                                 $res = $parent->validate($fieldname, $value, $params);
03418                         }
03419                 }
03420                 
03421                 return $res;
03422                 
03423                 
03424         }
03425         
03426 
03438         function &getParentRecord(){
03439                 if ( !isset($this->_parentRecord) ){
03440                         $parent =& $this->_table->getParent();
03441                         if ( isset($parent) ){
03442                                 $this->_parentRecord = new Dataface_Record($parent->tablename, array());
03443                                 foreach ( array_keys($parent->keys()) as $key ){
03444                                         $this->_parentRecord->addPropertyChangeListener( $key, $this);
03445                                 }
03446                         }       
03447                 }
03448                 return $this->_parentRecord;
03449         
03450         }
03451         
03452         
03453         //------------------------------------------------------------------------------------
03454         // @{ 
03468         function setSnapshot(){
03469                  
03470                 $this->clearFlags();
03471                 if ( isset($this->_values) ){
03472                         // If there are no values, then we don't need to set the snapshot
03473                         $this->_oldValues = $this->getValues();
03474                 }
03475                 $parent =& $this->getParentRecord();
03476                 if ( isset($parent) ){
03477                         $parent->setSnapshot();
03478                 }
03479                 
03480                 return $this;
03481                 
03482         }
03483         
03492         function snapshotExists(){
03493                 return (is_array($this->_oldValues) and count($this->_oldValues) > 0);
03494         }
03495         
03504         function clearSnapshot(){
03505                 $this->_oldValues = null;
03506                 $parent =& $this->getParentRecord();
03507                 if ( isset($parent) ){
03508                         $parent->clearSnapshot();
03509                 }
03510                 return $this;
03511         }
03512         
03522         function &getSnapshot($fields=''){
03523                 if ( is_array($fields) ){
03524                         $out = array();
03525                         foreach ($fields as $field){
03526                                 if ( isset( $this->_oldValues[$field] ) ){
03527                                         $out[$field] = $this->_oldValues[$field];
03528                                 }
03529                         }
03530                         
03531                         return $out;
03532                 } else {
03533                         return $this->_oldValues;
03534                 }
03535         }
03536         
03545         function snapshotKeys(){
03546                 return $this->getSnapshot(array_keys($this->_table->keys()));
03547         }
03548         
03560         function valueChanged($fieldname, $index=0, $checkParent=false){
03561                 if ( strpos($fieldname, '.') !== false ){
03562                         // This is a related field, so we have to check the relationship for dirty flags
03563                         $path = explode('.', $fieldname);
03564                         
03565                         if ( is_array($index) ){
03566                                 $index = $this->getRelatedIndex($index);
03567                         }
03568                         
03569                         return (isset( $this->_relatedDirtyFlags[$path[0]]) and 
03570                                         isset( $this->_relatedDirtyFlags[$path[0]][$path[1]]) and 
03571                                         $this->_relatedDirtyFlags[$path[0]][$path[1]] === true );
03572                 } else {
03573                         // this is a local related field... just check the local dirty flags array.
03574                         if ( $checkParent ){
03575                                 $parent =& $this->getParentRecord();
03576                                 if ( isset($parent) and $parent->_table->hasField($fieldname) ){
03577                                         return $parent->valueChanged($fieldname, $index);
03578                                 }
03579                         }
03580                         return (@$this->_dirtyFlags[$fieldname]);
03581                 }
03582         }
03583         
03584         
03593         function recordChanged($checkParent=false){
03594                 if ($checkParent){
03595                         $parent =& $this->getParentRecord();
03596                         if ( isset($parent) ){
03597                                 $res = $parent->recordChanged();
03598                                 if ( $res ) return true;
03599                         }
03600                 }
03601                 
03602                 $fields =& $this->_table->fields();
03603                 foreach ( array_keys( $fields) as $fieldname){
03604                         if ( $this->valueChanged($fieldname) ) return true;
03605                 }
03606                 return false;
03607         }
03608         
03609         
03610         
03618         function clearFlags(){
03619                 $keys = array_keys($this->_dirtyFlags);
03620                 foreach ( $keys as $i) {
03621                         $this->_dirtyFlags[$i] = false;
03622                         $this->vetoFields[$i] = false;
03623                 }
03624                 foreach (array_keys($this->_relatedDirtyFlags) as $rel_name){
03625                         foreach ( array_keys($this->_relatedDirtyFlags[$rel_name]) as $field_name){
03626                                 $this->_relatedDirtyFlags[$rel_name][$field_name] = false;
03627                         }
03628                 }
03629                 
03630                 // Clear the snapshot of old values.
03631                 $this->clearSnapshot();
03632                 
03633                 $parent =& $this->getParentRecord();
03634                 if ( isset($parent) ){
03635                         $parent->clearFlags();
03636                 }
03637                 return $this;
03638                 
03639         }
03640         
03652         function clearFlag($name){
03653                 if ( strpos($name, '.') !== false ){
03654                         // This is a related field.  We store dirty flags in the relationship array.
03655                         $path = explode('.', $name);
03656                         
03657                         if ( !isset($this->_relatedDirtyFlags[$path[0]]) ){
03658                                 return;
03659                         }
03660                         if ( !isset($this->_relatedDirtyFlags[$path[0]][$path[1]]) ){
03661                                 return;
03662                         }
03663                         $this->_relatedDirtyFlags[$path[0]][$path[1]] = false;
03664                 } else {
03665                         
03666                         $this->_dirtyFlags[$name] = false;
03667                         $this->vetoFields[$name] = false;
03668                         $parent =& $this->getParentRecord();
03669                         if ( isset($parent) and $parent->_table->hasField($name) ){
03670                                 $parent->clearFlag($name);
03671                         }
03672                 }
03673                 
03674                 return $this;
03675         }
03676                 
03677         
03689         function setFlag($fieldname, $index=0){
03690                 if ( strpos($fieldname, '.') !== false ){
03691                         // This is a related field.  We store dirty flags in the relationship array.
03692                         $path = explode('.', $fieldname);
03693                         
03694                         
03695                         if ( !isset($this->_relatedDirtyFlags[$path[0]]) ){
03696                                 $this->_relatedDirtyFlags[$path[0]] = array();
03697                         }
03698                         $this->_relatedDirtyFlags[$path[0]][$path[1]] = true;
03699                 } else {
03700                         // This is a local field
03701                         $this->_dirtyFlags[$fieldname] = true;
03702                         $parent =& $this->getParentRecord();
03703                         if ( isset($parent) and $parent->_table->hasField($fieldname)){
03704                                 $parent->setFlag($fieldname, $index);
03705                         }
03706                 }
03707         }
03708         
03709         
03717         function isLoaded($fieldname){
03718                 $parent =& $this->getParentRecord();
03719                 if ( isset($parent) and $parent->_table->hasField($fieldname) ){
03720                         return $parent->isLoaded($fieldname);
03721                 }
03722                 return ( isset( $this->_isLoaded[$fieldname] ) and $this->_isLoaded[$fieldname]);
03723         }
03724         
03725         
03726         // @}
03727         // END OF TRANSACTIONS 
03728         //-----------------------------------------------------------------------------------------
03729                 
03738         function getLink($fieldname){
03739                 
03740                 $field =& $this->_table->getField($fieldname);
03741                 if ( PEAR::isError($field) ){
03742                         return null;
03743                 }
03744                 $table =& Dataface_Table::loadTable($field['tablename']);
03745                 $delegate =& $table->getDelegate();
03746                 if ( !$table->hasField($fieldname) ) return null;
03747                 
03748                 
03749                 
03750                 // Case 1: Delegate is defined -- we use the delegate's link
03751                 if ( method_exists($delegate, $fieldname."__link") ){
03752                         $methodname = $fieldname."__link";
03753                         $link = $delegate->$methodname($this);
03754                         //$link = call_user_func(array(&$delegate, $fieldname."__link"), $this);
03755                         
03756                 
03757                 // Case 2: The link was specified in an ini file.
03758                 } else if ( isset($field['link']) ){
03759                         
03760                         $link = $field['link'];
03761                         
03762                 // Case 3: The link was not specified
03763                 } else {
03764                         
03765                         $link = null;
03766                 }
03767                 
03768                 
03769                 if ( is_array($link) ){
03770                         foreach ( array_keys($link) as $key){
03771                                 $link[$key] = $this->parseString($link[$key]);
03772                         }
03773                         
03774                         
03775                         return $link;
03776                         
03777                 } else if ( $link  ){
03778                         return $this->parseString($link);
03779                 } else {
03780                         
03781                         return null;
03782                 }
03783         
03784         }
03785         
03786         //-----------------------------------------------------------------------------------
03787         // @{
03798         function _getSubfield(&$fieldval, $path){
03799                 if ( !is_array($fieldval) ){
03800                         return PEAR::raiseError("_getSubfield() expects its first parameter to be an array.");
03801                 }
03802                 $path = explode(":",$path);
03803                 $temp1 =& $fieldval[array_shift($path)];
03804                 $temp2 =& $temp1;
03805                 while ( sizeof($path) > 0 ){
03806                         unset($temp1);
03807                         $temp1 =& $temp2[array_shift($path)];
03808                         unset($temp2);
03809                         $temp2 =& $temp1;
03810                 }
03811                 return $temp2;
03812         }
03813         
03898         function getTitle($dontGuess=false){
03899                 if ( !isset($this->_title) ){
03900                         $delegate =& $this->_table->getDelegate();
03901                         $title = null;
03902                         if ( $delegate !== null and method_exists($delegate, 'getTitle') ){
03903                                 
03904                                 $title = $delegate->getTitle($this);
03905                         } else {
03906                         
03907                                 $parent =& $this->getParentRecord();
03908                                 if ( isset($parent) ){
03909                                         $title = $parent->getTitle(true);
03910                                 }
03911                         }
03912                         
03913                         if ( $dontGuess ){
03914                                 if ( isset($title) ) $this->_title = $title;
03915                                 return $title;
03916                         }
03917                         
03918                         if ( !isset($title) ){  
03919                                 $fields =& $this->_table->fields();
03920                                 $found_title = false; // flag to specify that a specific title field has been found
03921                                                                           // declared by the 'title' flag in the fields.ini file.
03922                                                                           
03923                                 foreach (array_keys($fields) as $field_name){
03924                                         if ( isset($fields[$field_name]['title']) ){
03925                                                 $title = $this->display($field_name);
03926                                                 $found_title = true;
03927                                         }
03928                                         else if ( !isset($title) and $this->_table->isChar($field_name) ){
03929                                                 $title = $this->display($field_name );
03930                                         }
03931                                         if ( $found_title) break;
03932                                 }
03933                                 
03934                                 if ( !isset( $title) ){
03935                                         $title = "Untitled ".$this->_table->getLabel()." Record";
03936                                 }
03937                                 
03938                         }
03939                         $this->_title = $title;
03940                 }
03941                 
03942                 return $this->_title;
03943                 
03944         
03945         }
03946         
03947         
03948         
03972         function getDescription(){
03973                 if ( ($res = $this->callDelegateFunction('getDescription')) !== null ){
03974                         return $res;
03975                 } else if ( $descriptionField = $this->_table->getDescriptionField() ){
03976                         return $this->htmlValue($descriptionField);
03977                 } else {
03978                         return '';
03979                 }
03980         
03981         }
03982         
04005         function getCreated(){
04006                 if ( $res = $this->callDelegateFunction('getCreated') ){
04007                         return $res;
04008                 } else if ( $createdField = $this->_table->getCreatedField() ){
04009                         if ( strcasecmp($this->_table->getType($createdField),'timestamp') === 0 ){
04010                                 $date = $this->val($createdField);
04011                                 return strtotime($date['year'].'-'.$date['month'].'-'.$date['day'].' '.$date['hours'].':'.$date['minutes'].':'.$date['seconds']);
04012                                 
04013                         }
04014                         return strtotime($this->display($createdField));
04015                 } else {
04016                         return '';
04017                 }
04018         }
04019         
04041         function getCreator(){
04042                 if ( ($res = $this->callDelegateFunction('getCreator',-1)) !== -1 ){
04043                         return $res;
04044                 } else if ( $creatorField = $this->_table->getCreatorField() ){
04045                         return $this->display($creatorField);
04046                 } else {
04047                         return '';
04048                 }
04049         }
04050         
04051         
04073         function getLastModified(){
04074                 if ( $res = $this->callDelegateFunction('getLastModified') ){
04075                         return $res;
04076                 } else if ( $lastModifiedField = $this->_table->getLastUpdatedField() ){
04077                         if ( strcasecmp($this->_table->getType($lastModifiedField),'timestamp') === 0 ){
04078                                 $date = $this->val($lastModifiedField);
04079                                 return strtotime($date['year'].'-'.$date['month'].'-'.$date['day'].' '.$date['hours'].':'.$date['minutes'].':'.$date['seconds']);
04080                                 
04081                         }
04082                         $strtime = $this->strval($lastModifiedField);
04083                         if ( $strtime){
04084                                 return strtotime($strtime);
04085                         } else {
04086                                 return 0;
04087                         }
04088                 } else {
04089                         return 0;
04090                 }
04091         }
04092         
04116         function getBody(){
04117                 if ( $res = $this->callDelegateFunction('getBody') ){
04118                         return $res;
04119                 } else if ( $bodyField = $this->_table->getBodyField() ){
04120                         return $this->htmlValue($bodyField);
04121                 } else {
04122                         return '';
04123                 }
04124         }
04125         
04182         function getPublicLink($params=null){
04183                 if ( $res = $this->callDelegateFunction('getPublicLink') ){
04184                         return $res;
04185                 } else {
04186                         return $this->getURL($params);
04187                 }
04188         
04189         }
04190         
04191         
04227         function getBreadCrumbs(){
04228                 $delegate =& $this->_table->getDelegate();
04229                 if ( $delegate !== null and method_exists($delegate, 'getBreadCrumbs') ){
04230                         return $delegate->getBreadCrumbs($this);
04231                 }
04232                 
04233                 
04234                 if ( ( $parent = $this->getParent() ) !== null ){
04235                         $bc = $parent->getBreadCrumbs();
04236                         $bc[$this->getTitle()] = $this->getURL( array('-action'=>'browse'));
04237                         return $bc;
04238                 }
04239                 
04240                 
04241                 return array(
04242                         $this->_table->getLabel() => Dataface_LinkTool::buildLink(array('-action'=>'list', '-table'=>$this->_table->tablename)), 
04243                         $this->getTitle() => $this->getURL(array('-action'=>'browse'))
04244                         );
04245         }
04246         
04318         function getURL($params=array()){
04319                 if ( is_string($params) ){
04320                         $pairs = explode('&',$params);
04321                         $params = array();
04322                         foreach ( $pairs as $pair ){
04323                                 list($key,$value) = explode('=', $pair);
04324                                 $params[$key] = $value;
04325                         }
04326                 }
04327                 if ( $this->secureDisplay and !$this->checkPermission('link') ){
04328                         $del =& $this->_table->getDelegate();
04329                         if ( $del and method_exists($del, 'no_access_link')){
04330                                 return $del->no_access_link($this, $params);
04331                         } 
04332                 }
04333                 
04334                 $params['-table'] = $this->_table->tablename;
04335                 if ( !isset($params['-action']) ) $params['-action'] = 'browse';
04336                 foreach (array_keys($this->_table->keys()) as $key){
04337                         $params[$key] = '='.$this->strval($key);
04338                 }
04339                 
04340                 $delegate =& $this->_table->getDelegate();
04341                 if ( isset($delegate) and method_exists($delegate, 'getURL') ){
04342                         $res = $delegate->getURL($this, $params);
04343                         if ( $res and is_string($res) ) return $res;
04344                 }
04345                 
04346                 import('Dataface/LinkTool.php');
04347                 //$linkTool =& Dataface_LinkTool::getInstance();
04348         
04349                 return Dataface_LinkTool::buildLink($params ,false);
04350         }
04351         
04352         
04358         function getId(){
04359                 $keys = array_keys($this->_table->keys());
04360                 $params=array();
04361                 foreach ($keys as $key){
04362                         $params[] = urlencode($key).'='.urlencode($this->strval($key));
04363                 }
04364                 return $this->_table->tablename.'?'.implode('&',$params);
04365         }
04366         
04367         
04368         // @}
04369         // END Record Metadata
04370         //--------------------------------------------------------------------------------------
04371         
04372         
04373         // @{
04389         function getMimetype($fieldname,$index=0,$where=0,$sort=0){
04390                 $field =& $this->_table->getField($fieldname);
04391                 if ( isset($field['mimetype'])  and strlen($field['mimetype']) > 0 ){
04392                         return $this->getValue($field['mimetype'], $index,$where,$sort);
04393                 }
04394                 
04395                 if ( $this->_table->isContainer($fieldname) ){
04396                         $filename = $this->strval($fieldname,$index,$where,$sort);
04397                         if ( strlen($filename) > 0 ){
04398                                 $path = $field['savepath'].'/'.$filename;
04399                                 $mimetype='';
04400                                 //if(!extension_loaded('fileinfo')) {
04401                                 //      @dl('fileinfo.' . PHP_SHLIB_SUFFIX);
04402                                 //}
04403                                 if(extension_loaded('fileinfo')) {
04404                                         $res = finfo_open(FILEINFO_MIME); /* return mime type ala mimetype extension */
04405                                         $mimetype = finfo_file($res, $path);
04406                                 } else if (function_exists('mime_content_type')) {
04407                                         
04408                                 
04409                                         $mimetype = mime_content_type($path);
04410                                         
04411                                 }
04412                                 
04413                                 
04414                                 return $mimetype;
04415                         }
04416                 }
04417                 return '';
04418                 
04419         }
04420          
04434         function isImage($fieldname, $index=0, $where=0, $sort=0){
04435                 return preg_match('/^image/', $this->getMimetype($fieldname,$index,$where,$sort));
04436         
04437         }
04438          
04439          
04454         function getLength($fieldname, $index=0, $where=0, $sort=0){
04455                 if ( strpos($fieldname, '.') !== false ){
04456                         
04457                         list($relname, $localfieldname) = explode('.',$fieldname);
04458                         $record =& $this->getRelatedRecords($relname, false, $index, null, $where, $sort);
04459                         $relatedRecord = new Dataface_RelatedRecord($this, $relname,$record);
04460                         $relatedRecord->setValues($this->_relatedMetaValues[$relname][0][0][$index]);
04461                         return $relatedRecord->getLength($localfieldname);
04462                         //$key = '__'.$localfieldname.'_length';
04463                         //if ( isset($record[$key]) ){
04464                         //      return $record[$key];
04465                         //} else {
04466                         //      return null;
04467                         //}
04468                 } else {
04469                         $key = '__'.$fieldname.'_length';
04470                         if ( isset($this->_metaDataValues[$key] ) ){
04471                                 return $this->_metaDataValues[$key];
04472                         } else {
04473                                 return strlen($this->getValueAsString($fieldname));
04474                         }
04475                 }
04476                 
04477         }
04478          
04479          
04480          
04481          // @}
04482          // END Field Metadata
04483          //--------------------------------------------------------------------------------------
04484         
04485         
04486         
04487         
04488         //-------------------------------------------------------------------------------------
04489         // @{
04506         function save($lang=null, $secure=false){
04507                 if ( !isset($lang) ) $lang = $this->lang;
04508                 return df_save_record($this, $this->strvals(array_keys($this->_table->keys())), $lang, $secure);
04509         }
04510         
04518         function delete($secure=false){
04519                 import('Dataface/IO.php');
04520                 $io = new Dataface_IO($this->_table->tablename);
04521                 return $io->delete($this, $secure);
04522                 
04523         }
04524         
04525         
04526         // @}
04527         // END IO Methods
04528         //---------------------------------------------------------------------------------------
04529         
04530         function toJS($fields=null){
04531                 $strvals = $this->strvals($fields);
04532                 $out = array();
04533                 foreach ( $strvals as $key=>$val){
04534                         if ( $this->checkPermission('view', array('field'=>$key)) ){
04535                                 $out[$key] = $val;
04536                                 
04537                         }
04538                 }
04539                 $out['__title__'] = $this->getTitle();
04540                 //$out[] = "'__title__': '".addslashes($this->getTitle())."'";
04541                 $out['__url__'] = $this->getURL();
04542                 //$out[] = "'__url__': '".addslashes($this->getURL())."'";
04543                 $out['__expandable'] = ($this->checkPermission('expandable')?1:0);
04544                 //$out[] = "'__expandable__': ".($this->checkPermission('expandable')?1:0);
04545                 
04546                 return json_encode($out);
04547                 //return '{'.implode(',',$out).'}';
04548                 
04549         }
04550 
04551         
04552         
04553         
04554         
04555         
04556 }
04557 
04561 class Dataface_RecordIterator {
04562 
04563         var $_records;
04564         var $_keys;
04565         var $_tablename;
04566         function Dataface_RecordIterator($tablename, &$records){
04567                 $this->_records =& $records;
04568                 $this->_keys = array_keys($records);
04569                 $this->_tablename = $tablename;
04570                 $this->reset();
04571         }
04572         
04573         function &next(){
04574                 $out = new Dataface_Record($this->_tablename, $this->_records[current($this->_keys)]);
04575                 next($this->_keys);
04576                 return $out;
04577         }
04578         
04579         function &current(){
04580                 return new Dataface_Record($this->_tablename, $this->_records[current($this->_keys)]);
04581         }
04582         
04583         function reset(){
04584                 return reset($this->_keys);
04585         }
04586         
04587         function hasNext(){
04588                 
04589                 return (current($this->_keys) !== false);
04590         }
04591         
04592 }
04593 
04594 
04598 class Dataface_RelationshipIterator{
04599         var $_record;
04600         var $_relationshipName;
04601         var $_records;
04602         var $_keys;
04603         var $_where;
04604         var $_sort;
04605         function Dataface_RelationshipIterator(&$record, $relationshipName, $start=null, $limit=null, $where=0, $sort=0){
04606                 $this->_record =& $record;
04607                 $this->_relationshipName = $relationshipName;
04608                 $this->_where = $where;
04609                 $this->_sort = $sort;
04610                 if ( $start !== 'all' ){
04611                 
04612                         $this->_records =& $record->getRelatedRecords($relationshipName, true, $start, $limit, $where, $sort);
04613                 } else {
04614                         $this->_records =& $record->getRelatedRecords($relationshipName, 'all',$where, $sort);
04615                 }
04616                 if ( is_array($this->_records) ){
04617                         $this->_keys = array_keys($this->_records);
04618                 } else {
04619                         $this->_keys = array();
04620                 }
04621         }
04622         
04623         function &next(){
04624                 $out =& $this->current();
04625                 next($this->_keys);
04626                 return $out;
04627         }
04628         
04629         function &current(){
04630                 $rec = new Dataface_RelatedRecord($this->_record, $this->_relationshipName, $this->_records[current($this->_keys)]);
04631                 $rec->setValues($this->_record->_relatedMetaValues[$this->_relationshipName][$this->_where][$this->_sort][current($this->_keys)]);
04632                 return $rec;
04633         }
04634         
04635         function reset(){
04636                 return reset($this->_keys);
04637         }
04638         
04639         function hasNext(){
04640                 return (current($this->_keys) !== false);
04641         }
04642 }
04643 
 All Data Structures Namespaces Files Functions Variables Enumerations