![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00002 /*------------------------------------------------------------------------------- 00003 * Xataface Web Application Framework 00004 * Copyright (C) 2005-2008 Web Lite Solutions Corp (shannah@sfu.ca) 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 *------------------------------------------------------------------------------- 00020 */ 00021 00022 00023 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 ¤t(){ 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 ¤t(){ 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