41 import(
'Dataface/QueryBuilder.php');
42 import(
'Dataface/DB.php');
43 define(
'Dataface_IO_READ_ERROR', 1001);
44 define(
'Dataface_IO_WRITE_ERROR', 1002);
45 define(
'Dataface_IO_NOT_FOUND_ERROR', 1003);
46 define(
'Dataface_IO_TOO_MANY_ROWS', 1004);
47 define(
'Dataface_IO_NO_TABLES_SELECTED', 1005);
48 define(
'MYSQL_ER_DUP_KEY', 1022);
49 define(
'MYSQL_ER_DUP_ENTRY', 1062);
50 define(
'MYSQL_ER_ROW_IS_REFERENCED', 1217);
51 define(
'MYSQL_ER_ROW_IS_REFERENCED_2', 1451);
52 define(
'MYSQL_ER_NO_REFERENCED_ROW', 1216);
53 define(
'MYSQL_ER_NO_REFERENCED_ROW_2', 1452);
79 $this->lang =
$app->_conf[
'lang'];
82 $this->_altTablename = $altTablename;
89 unset($this->_serializer);
91 if ( isset($this->parentIO) and $this->parentIO != -1 ){
92 $this->parentIO->__destruct();
93 unset($this->parentIO);
98 if ( $this->parentIO == -1 ){
99 if ( isset($this->_altTablename) and $this->_altTablename != $this->_table->tablename) {
105 $parentTable =& $this->_table->getParent();
106 if ( isset($parentTable) ){
107 $this->parentIO =
new Dataface_IO($parentTable->tablename, null, null);
109 $this->parentIO->fireTriggers =
false;
111 $this->parentIO = null;
146 list($base,$qstr) = explode(
'?', $recordid);
147 if ( strpos($base,
'/') !==
false ){
148 list($query[
'-table'],$query[
'-relationship']) = explode(
'/',$base);
150 $query[
'-table'] = $base;
152 $params = explode(
'&', $qstr);
153 foreach ( $params as $param){
154 list($key,$value) = explode(
'=', $param);
155 $query[urldecode($key)] =
'='.urldecode($value);
178 if ( !is_a($record,
"Dataface_Record") ){
181 'scripts.Dataface.IO.read.ERROR_PARAMETER_2',
182 "Dataface_IO::read() requires second parameter to be of type 'Dataface_Record' but received '".get_class($record).
"\n<br>",
183 array(
'class'=>get_class($record))
187 if ( is_string($query) and !empty($query) ){
193 if (
$tablename === null and $this->_altTablename !== null ){
199 $qb->selectMetaData =
true;
200 $query[
'-limit'] = 1;
201 if ( @$query[
'-cursor']>0 ) $query[
'-skip'] = $query[
'-cursor'];
203 $res = $this->dbObj->query($sql, $this->_table->db, $this->lang,
true );
205 $app->refreshSchemas($this->_table->tablename);
206 $res = $this->dbObj->query($sql, $this->_table->db, $this->lang,
true );
212 "Error reading record",
214 "Error reading table '".
215 $this->_table->tablename.
216 "' from the database: ".
217 mysql_error($this->_table->db),
220 array(
'table'=>$this->_table->tablename,
221 'mysql_error'=>mysql_error(),
234 if ( count($res) == 0 ){
240 "Record for table '".
241 $this->_table->tablename.
242 "' could not be found.",
244 array(
'table'=>$this->_table->tablename,
'sql'=>$sql)
253 $record->setValues($row);
254 $record->setSnapshot();
270 function delete(&$record, $secure=
false){
271 if ( $secure && !$record->checkPermission(
'delete') ){
276 'scripts.Dataface.IO.delete.PERMISSION_DENIED',
277 'Could not delete record "'.$record->getTitle().
'" from table "'.$record->_table->tablename.
'" because you have insufficient permissions.',
278 array(
'title'=>$record->getTitle(),
'table'=>$record->_table->tablename)
286 if ( $this->fireTriggers ){
294 $keys =& $record->_table->keys();
298 'scripts.Dataface.IO.delete.ERROR_NO_PRIMARY_KEY',
299 'Could not delete record from table "'.$record->_table->tablename.
'" because no primary key was defined.',
300 array(
'tablename'=>$record->_table->tablename)
306 foreach ( array_keys(
$keys) as $key ){
307 if ( !$record->strval($key) ){
311 'Could not delete record because missing keys',
313 'Could not delete record '.
315 ' because not all of the keys were included.',
317 array(
'title'=>$record->getTitle(),
'key'=>$key)
322 $query[$key] =
'='.$record->strval($key);
325 $sql = $builder->delete($query);
329 $res = $this->dbObj->query($sql, null, $this->lang);
332 else $msg = mysql_error(df_db());
337 'Failed to delete record. SQL error',
339 'Failed to delete record '.
341 ' because of an sql error. '.mysql_error(df_db()),
343 array(
'title'=>$record->getTitle(),
'sql'=>$sql,
'mysql_error'=>$msg)
351 $parentRecord =& $record->getParentRecord();
352 if ( isset($parentRecord) ){
353 $res =
$parentIO->delete($parentRecord, $secure);
358 if ( $this->fireTriggers ){
372 foreach ( $record->_table->transientFields() as $tfield ){
373 if ( !isset($tfield[
'relationship']) )
continue;
374 if ( !$record->
valueChanged($tfield[
'name']) )
continue;
376 $trelationship =& $record->_table->getRelationship($tfield[
'relationship']);
381 return $trelationship;
384 $orderCol = $trelationship->getOrderColumn();
387 $tval = $record->
getValue($tfield[
'name']);
388 if ( $tfield[
'widget'][
'type'] ==
'grid' ){
390 $tval_existing = array();
392 $tval_new_existing = array();
394 foreach ($tval as $trow){
395 if ( !is_array($trow) )
continue;
396 $trow[
'__order__'] = $torder++;
397 if ( isset($trow[
'__id__']) and preg_match(
'/^new:/', $trow[
'__id__']) ){
398 $tval_new_existing[] = $trow;
400 else if ( isset($trow[
'__id__']) and $trow[
'__id__'] !=
'new' ){
401 $tval_existing[$trow[
'__id__']] = $trow;
402 }
else if ( isset($trow[
'__id__']) and $trow[
'__id__'] ==
'new'){
411 error_log(
'Failed to get related records for record '.$record->
getId().
' in its relationship '.$tfield[
'relationship']);
416 unset($trelationship);
417 unset($tval_existing);
425 foreach ($trecords as $trec){
426 $tid = $trec->getId();
428 if ( isset($tval_existing[$tid]) ){
433 foreach ( $tval_existing[$tid] as $k1=>$v1 ){
434 if ( $tmp->isDirty($k1) ){
441 $trec->setValues($tval_existing[$tid]);
442 if ( $orderCol ) $trec->setValue( $orderCol, $tval_existing[$tid][
'__order__']);
444 $res_t = $trec->save($this->lang, $secure);
448 error_log(
'Failed to save related record '.$trec->getId().
' while saving transient field '.$tfield[
'name'].
' in record '.$record->
getId().
'. The error returned was : '.$res_t->getMessage());
452 if ( $orderCol and $record->
checkPermission(
'reorder_related_records', array(
'relationship'=>$tfield[
'relationship'])) ){
453 $trec->setValue( $orderCol, $tval_existing[$tid][
'__order__']);
454 $res_t = $trec->save($this->lang,
false);
457 error_log(
'Failed to save related record '.$trec->getId().
' while saving transient field '.$tfield[
'name'].
' in record '.$record->
getId().
'. The error returned was : '.$res_t->getMessage());
477 foreach ($tval_new as $tval_to_add){
481 $temp_rrecord->setValues($tval_to_add);
482 if ( $orderCol ) $temp_rrecord->setValue( $orderCol, $tval_to_add[
'__order__']);
485 error_log(
'Failed to save related record '.$temp_rrecord->getId().
' while saving transient field '.$tfield[
'name'].
' in record '.$record->
getId().
'. The error returned was : '.$res_t->getMessage());
487 unset($temp_rrecord);
495 foreach ($tval_new_existing as $tval_to_add){
496 $tid = preg_replace(
'/^new:/',
'', $tval_to_add[
'__id__']);
497 $temp_record = df_get_record_by_id($tid);
508 if ( $orderCol ) $temp_rrecord->setValue( $orderCol, $tval_to_add[
'__order__']);
511 error_log(
'Failed to save related record '.$temp_rrecord->getId().
' while saving transient field '.$tfield[
'name'].
' in record '.$record->
getId().
'. The error returned was : '.$res_t->getMessage());
513 unset($temp_rrecord);
522 if ( isset($tval[
'__deleted__']) and is_array($tval[
'__deleted__']) and $trelationship->supportsRemove() ){
523 $tdelete_record = ($trelationship->isOneToMany() and !$trelationship->supportsAddExisting());
527 foreach ( $tval[
'__deleted__'] as $del_id ){
528 if ($del_id ==
'new' )
continue;
537 throw new Exception($mres->getMessage());
545 }
else if ( $tfield[
'widget'][
'type'] ==
'checkbox' ){
550 error_log(
'Failed to get related records for record '.$record->
getId().
' in its relationship '.$tfield[
'relationship']);
555 unset($trelationship);
556 unset($tval_existing);
559 $texistingIds = array();
560 foreach ($texisting as $terec){
561 $texistingIds[] = $terec->getId();
566 $tcheckedRecords = array();
567 $tcheckedIds = array();
568 $tcheckedId2ValsMap = array();
569 foreach ( $tval as $trkey=>$trval){
571 parse_str($trval, $trquery);
573 $trRecords[] =& $trRecord;
574 $tcheckedIds[] = $tid = $trRecord->getId();
575 $checkedId2ValsMap[$tid] = $trquery;
585 $tremoves = array_diff($texistingIds, $tcheckedIds);
586 $tadds = array_diff($tcheckedIds, $texistingIds);
588 foreach ($tremoves as $tid){
589 $trec = df_get_record_by_id($tid);
594 foreach ($tadds as $tid){
595 $trecvals = $checkedId2ValsMap[$tid];
600 unset($trec, $trecvals);
605 unset($tcheckedIds, $tcheckedId2ValsMap);
606 unset($tcheckedRecords);
608 unset($texistingIds);
615 unset($trelationship);
649 if ( !is_a($record,
"Dataface_Record") ){
652 'scripts.Dataface.IO.write.ERROR_PARAMETER_1',
653 "Dataface_IO::write() requires first parameter to be of type 'Dataface_Record' but received '".get_class($record).
"\n<br>",
654 array(
'class'=>get_class($record))
657 if (
$tablename === null and $this->_altTablename !== null ){
661 if ( $this->fireTriggers ){
688 'scripts.Dataface.IO.write.ERROR_SAVING',
689 "Error while saving record of table '".$this->_table->tablename.
"' in Dataface_IO::write() ",
690 array(
'tablename'=>$this->_table->tablename,
'line'=>0,
'file'=>
'_')
704 if ( $this->fireTriggers ){
711 if ( isset(
$app->_conf[
'history']) and ( @
$app->_conf[
'history'][
'enabled'] || !isset(
$app->_conf[
'history'][
'enabled']))){
714 import(
'Dataface/HistoryTool.php');
720 if ( isset(
$app->_conf[
'_index']) and @
$app->_conf[
'_index'][$record->table()->tablename]){
725 import(
'Dataface/Index.php');
727 $index->indexRecord($record);
731 $record->setSnapshot();
740 if ( !isset($record) )
return;
741 $id = $record->getId();
743 $sql =
"replace into dataface__record_mtimes
744 (recordhash, recordid, mtime) values
745 ('".addslashes($hash).
"','".addslashes($id).
"','".time().
"')";
748 }
catch ( Exception $ex){
754 $res = df_q(
"create table dataface__record_mtimes (
755 recordhash varchar(32) not null primary key,
756 recordid varchar(255) not null,
757 mtime int(11) not null)");
762 $del =& $this->_table->getDelegate();
763 if ( isset($del) and method_exists($del,
'getHistoryComments') ){
764 return $del->getHistoryComments($record);
767 $appdel =&
$app->getDelegate();
768 if ( isset($appdel) and method_exists($appdel,
'getHistoryComments') ){
769 return $appdel->getHistoryComments($record);
784 $this->lastVersionNumber = null;
785 if ( !is_a($record,
"Dataface_Record") ){
788 'scripts.Dataface.IO.recordExists.ERROR_PARAMETER_1',
789 "In Dataface_IO::recordExists() the first argument is expected to be either a 'Dataface_Record' object or an array of key values, but received neither.\n<br>"
792 if (
$tablename === null and $this->_altTablename !== null ){
796 $tempRecordCreated =
false;
797 if ( $record->snapshotExists() ){
798 $tempRecord =
new Dataface_Record($record->_table->tablename, $record->getSnapshot());
799 $tempRecordCreated =
true;
801 $tempRecord =& $record;
804 if (
$keys == null ){
807 $query = unserialize(serialize($tempRecord->getValues( array_keys($record->_table->keys()))));
813 $table_keys = array_keys($this->_table->keys());
815 foreach ( $table_keys as $key){
816 if ( !isset( $query[$key] ) or !$query[$key] ) {
822 foreach ( array_keys($query) as $key){
824 $query[$key] = $this->_serializer->serialize($key, $tempRecord->getValue($key) );
827 if ( $tempRecordCreated ) $tempRecord->__destruct();
831 if ( $record->table()->isVersioned() ){
832 $versionField =
"`".$record->table()->getVersionField().
"`";
834 $versionField =
"NULL";
836 $sql =
"select `".$table_keys[0].
"`, $versionField from `".$this->
tablename(
$tablename).
"` where ";
838 foreach ($query as $key=>$val){
839 $where[] =
'`'.$key.
'`="'.addslashes($val).
'"';
841 $sql .= implode(
' AND ', $where).
' limit 1';
843 $res = df_q($sql, $this->_table->db);
844 $num = mysql_num_rows($res);
845 $row = mysql_fetch_row($res);
846 @mysql_free_result($res);
850 $this->lastVersionNumber = intval($row[1]);
858 'recordExists failure. Too many rows returned.',
860 "Test for existence of record in recordExists() returned $rows records.
861 It should have max 1 record.
862 The query must be incorrect.
863 The query used was '$sql'. ",
865 array(
'table'=>$this->_table->tablename,
'line'=>0,
'file'=>
'_',
'sql'=>$sql)
869 throw new Exception($err->toString(), E_USER_ERROR);
883 if ( $secure && !$record->checkPermission(
'edit') ){
888 'scripts.Dataface.IO._update.PERMISSION_DENIED',
889 'Could not update record "'.$record->getTitle().
'" from table "'.$record->_table->tablename.
'" because you have insufficient permissions.',
890 array(
'title'=>$record->getTitle(),
'table'=>$record->_table->tablename)
895 foreach ( array_keys($record->_table->fields()) as
$fieldname ){
896 if ( $record->valueChanged($fieldname) and !@$record->vetoFields[
$fieldname] and !$record->checkPermission(
'edit', array(
'field'=>$fieldname)) ){
897 $field = $record->table()->getField($fieldname);
898 if ( @
$field[
'timestamp'] and
$field[
'timestamp'] ==
'update' ){
907 'scripts.Dataface.IO._update.PERMISSION_DENIED_FIELD',
908 'Could not update record "'.$record->getTitle().
'" in table "'.$record->_table->tablename.
'" because you do not have permission to modify the "'.$fieldname.
'" column.',
909 array(
'title'=>$record->getTitle(),
'table'=>$record->_table->tablename,
'field'=>
$fieldname)
918 if ( !is_a($record,
'Dataface_Record') ){
921 'scripts.Dataface.IO._update.ERROR_PARAMETER_1',
922 "In Dataface_IO::_update() the first argument is expected to be an object of type 'Dataface_Record' but received '".get_class($record).
"'.\n<br>",
923 array(
'class'=>get_class($record))
926 if (
$tablename === null and $this->_altTablename !== null ){
932 $exists->addUserInfo(
934 'scripts.Dataface.IO._update.ERROR_INCOMPLETE_INFORMATION',
935 "Attempt to update record with incomplete information.",
936 array(
'line'=>0,
'file'=>
'_')
944 'scripts.Dataface.IO._update.ERROR_RECORD_DOESNT_EXIST',
945 "Attempt to update record that doesn't exist in _update() ",
946 array(
'line'=>0,
'file'=>
"_")
950 if ( $record->table()->isVersioned()){
951 $currVersion = intval($record->getVersion());
952 $dbVersion = intval($this->lastVersionNumber);
953 if ( $currVersion !== $dbVersion ){
956 'scripts.Dataface.IO._update.ERROR_RECORD_VERSION_MISMATCH',
957 "Attempt to update record with a different version than the database version. Current version is $currVersion. DB Version is $dbVersion",
965 $delegate =& $s->getDelegate();
968 if ( $record->recordChanged(
true) ){
969 if ( $this->fireTriggers ){
980 $parentRecord =& $record->getParentRecord();
982 $res =
$parentIO->write($parentRecord, $parentRecord->snapshotKeys());
995 'scripts.Dataface.IO._update.ERROR_GENERATING_SQL',
996 "Error generating sql for update in IO::_update()",
997 array(
'line'=>0,
'file'=>
"_")
1002 if ( strlen($sql) > 0 ){
1007 $res =$this->dbObj->query($sql, $s->db, $this->lang);
1020 'scripts.Dataface.IO._update.ERROR_DUPLICATE_ENTRY',
1021 "Duplicate entry into table '".$s->tablename,
1022 array(
'tablename'=>$s->tablename)
1026 throw new Exception(
1028 'scripts.Dataface.IO._update.SQL_ERROR',
1029 "Failed to update due to sql error: ")
1030 .mysql_error($s->db), E_USER_ERROR);
1034 if ( $record->table()->isVersioned() ){
1035 $versionField = $record->table()->getVersionField();
1036 $record->setValue($versionField, $record->getVersion()+1);
1039 if ( $this->fireTriggers ){
1058 if ( $secure && !$record->checkPermission(
'new') ){
1063 'scripts.Dataface.IO._insert.PERMISSION_DENIED',
1064 'Could not insert record "'.$record->getTitle().
'" from table "'.$record->_table->tablename.
'" because you have insufficient permissions.',
1065 array(
'title'=>$record->getTitle(),
'table'=>$record->_table->tablename)
1070 foreach ( array_keys($record->_table->fields()) as
$fieldname ){
1071 if ( $record->valueChanged($fieldname) and !@$record->vetoFields[
$fieldname] and !$record->checkPermission(
'new', array(
'field'=>$fieldname)) ){
1076 if ( @
$field[
'timestamp'] ){
1084 'scripts.Dataface.IO._insert.PERMISSION_DENIED_FIELD',
1085 'Could not insert record "'.$record->getTitle().
'" into table "'.$record->_table->tablename.
'" because you do not have permission to modify the "'.$fieldname.
'" column.',
1086 array(
'title'=>$record->getTitle(),
'table'=>$record->_table->tablename,
'field'=>
$fieldname)
1094 if (
$tablename === null and $this->_altTablename !== null ){
1098 $delegate =& $s->getDelegate();
1100 if ( $this->fireTriggers ){
1109 $parentRecord =& $record->getParentRecord();
1110 $res =
$parentIO->write($parentRecord, $parentRecord->snapshotKeys());
1112 unset($parentRecord);
1119 throw new Exception(
1121 'scripts.Dataface.IO._insert.ERROR_GENERATING_SQL',
1122 "Error generating sql for insert in IO::_insert()")
1129 $res = $this->dbObj->query($sql, $s->db, $this->lang);
1142 "Failed to insert record because of duplicate entry",
1144 "Duplicate entry into table '".$s->tablename,
1146 array(
'table'=>$s->tablename)
1150 throw new Exception(
1152 'scripts.Dataface.IO._insert.ERROR_INSERTING_RECORD',
1153 "Error inserting record: ")
1154 .(
PEAR::isError($res)?$res->getMessage():mysql_error(df_db())).
": SQL: $sql", E_USER_ERROR);
1156 $id = df_insert_id($s->db);
1157 $this->insertIds[$this->_table->tablename] = $id;
1162 $autoIncrementField = $s->getAutoIncrementField();
1163 if ( $autoIncrementField !== null ){
1164 $record->setValue($autoIncrementField, $id);
1168 if ( $this->fireTriggers ){
1180 $rel =& $s->getRelationship($relname);
1185 'scripts.Dataface.IO._writeRelationship.ERROR_OBTAINING_RELATIONSHIP',
1186 "Error obtaining relationship $relname in IO::_writeRelationship()",
1187 array(
'relname'=>$relname,
'line'=>0,
'file'=>
"_")
1193 $tables =& $rel[
'selected_tables'];
1196 if ( count($tables) == 0 ){
1200 "Failed to write relationship because not table was selected",
1202 "Error writing relationship '$relname'. No tables were selected",
1204 array(
'relationship'=>$relname)
1210 $records =& $record->getRelatedRecords($relname);
1211 $record_keys = array_keys($records);
1213 $records->addUserInfo(
1215 'scripts.Dataface.IO._writeRelationship.ERROR_GETTING_RELATED_RECORDS',
1216 "Error getting related records in IO::_writeRelationship()",
1217 array(
'line'=>0,
'file'=>
"_")
1225 foreach ($tables as
$table){
1228 $keys = array_keys($rs->keys());
1231 if ( preg_match(
'/^'.$table.
'\.(\w+)/', $column, $matches) ){
1232 $cols[] = $matches[1];
1237 foreach ($record_keys as $record_key){
1240 $update_cols = array();
1243 foreach ( $cols as $column ){
1245 if ( $s->valueChanged($relname.
'.'.$column, $record_key) ){
1248 $update_cols[] = $column;
1253 if ( !$changed )
continue;
1257 $sql =
"UPDATE `$table` ";
1259 foreach ( $update_cols as $column ){
1260 $set .=
"SET $column = '".addslashes($rs->getSerializedValue($column, $records[$record_key][$column]) ).
"',";
1262 $set = trim(substr( $set, 0, strlen($set)-1));
1265 foreach (
$keys as $key){
1266 $where .=
"`$key` = '".addslashes($rs->getSerializedValue($key, $records[$record_key][$key]) ).
"' AND ";
1268 $where = trim(substr($where, 0, strlen($where)-5));
1270 if ( strlen($where)>0 ) $where =
' '.$where;
1271 if ( strlen($set)>0 ) $set =
' '.$set;
1273 $sql = $sql.$set.$where.
' LIMIT 1';
1276 $res = $this->dbObj->query($sql, $s->db, $this->lang);
1278 throw new Exception(
1280 'scripts.Dataface.IO._writeRelationship.ERROR_UPDATING_DATABASE',
1281 "Error updating database with query '$sql': ".mysql_error($s->db),
1282 array(
'sql'=>$sql,
'mysql_error'=>mysql_error($s->db))
1306 $names = array_keys($sql);
1307 $tables = implode(
'|', $names );
1311 if ( func_num_args() >= 2 ){
1312 $duplicates =& func_get_arg(1);
1313 if ( !is_array($duplicates) ){
1314 throw new Exception(
1316 'scripts.Dataface.IO.performSQL.ERROR_PARAMETER_2',
1317 "In Dataface_IO::performSQL() 2nd argument is expected to be an array but received '".get_class($duplicates).
"'.",
1318 array(
'class'=>get_class($duplicates))
1323 $duplicates = array();
1325 $queryAttempts = array();
1326 $numQueries = count($queue);
1327 while (count($queue) > 0 and $skips < $numQueries){
1328 $current_query = array_shift($queue);
1329 $current_table = array_shift($names);
1330 if ( !isset($queryAttempts[$current_query]) ) $queryAttempts[$current_query] = 1;
1331 else $queryAttempts[$current_query]++;
1334 if ( preg_match(
'/__('.$tables.
')__auto_increment__/', $current_query, $matches) ){
1336 if ( isset($ids[
$table]) ){
1337 $current_query = preg_replace(
'/__'.$table.
'__auto_increment__/', $ids[$table], $current_query);
1339 array_push($queue, $current_query);
1340 array_push($names, $current_table);
1348 $res = $this->dbObj->query($current_query, $this->_table->db, $this->lang);
1354 $duplicates[] = $current_table;
1361 array_push($queue, $current_query);
1362 array_push($names, $current_table);
1373 'scripts.Dataface.IO.performSQL.ERROR_FOREIGN_KEY',
1374 'Failed to save record because a foreign key constraint failed: %s'
1376 mysql_error(df_db())
1381 error_log($err->toString());
1387 'scripts.Dataface.IO.performSQL.ERROR_PERFORMING_QUERY',
1388 "Error performing query '$current_query'",
1389 array(
'line'=>0,
'file'=>
'_',
'current_query'=>$current_query)
1391 .mysql_errno($this->_table->db).
': '.mysql_error($this->_table->db));
1392 throw new Exception($err->toString(), E_USER_ERROR);
1395 $ids[$current_table] = df_insert_id();
1399 $this->insertids = $ids;
1412 if ( $secure && !$record->_record->checkPermission(
'add new related record', array(
'relationship'=>$record->_relationshipName) ) ){
1417 'scripts.Dataface.IO.addRelatedRecord.PERMISSION_DENIED',
1418 'Could not add record "'.$record->getTitle().
'" to relationship "'.$record->_relationshipName.
'" of record "'.$record->_record->getTitle().
'" because you have insufficient permissions.',
1419 array(
'title'=>$record->getTitle(),
'relationship'=>$record->_relationshipName,
'parent'=>$record->_record->getTitle())
1428 if ( $this->fireTriggers ){
1433 if ( $this->fireTriggers ){
1447 $drecords = $record->toRecords();
1450 foreach ( array_keys($drecords) as $recordIndex){
1451 $rio =
new Dataface_IO($drecords[$recordIndex]->_table->tablename);
1453 $drec_snapshot = $drecords[$recordIndex]->strvals();
1455 $res = $rio->fireBeforeSave($drecords[$recordIndex]);
1457 $res = $rio->fireBeforeInsert($drecords[$recordIndex]);
1460 $drec_post_snapshot = $drecords[$recordIndex]->strvals();
1462 foreach ( $drec_snapshot as $ss_key=>$ss_val ){
1464 if ( $drec_post_snapshot[$ss_key] != $ss_val ){
1466 $record->setValue($ss_key,$drec_post_snapshot[$ss_key]);
1470 unset($drec_snapshot);
1471 unset($drec_post_snapshot);
1476 $sql = $queryBuilder->addRelatedRecord($record);
1480 'scripts.Dataface.IO.addRelatedRecord.ERROR_GENERATING_SQL',
1481 "Error generating sql in ShortRelatedRecordForm::save()",
1482 array(
'line'=>0,
'file'=>
"_")
1494 $rfields = array_keys($record->vals());
1497 foreach ( array_keys($drecords) as $recordIndex){
1498 $currentRecord =& $drecords[$recordIndex];
1499 if ( isset($this->insertids[ $currentRecord->_table->tablename ] ) ){
1500 $idfield = $currentRecord->_table->getAutoIncrementField();
1502 $currentRecord->setValue($idfield, $this->insertids[ $currentRecord->_table->tablename ]);
1503 if ( in_array($idfield, $rfields) ){
1504 $record->setValue($idfield, $this->insertids[ $currentRecord->_table->tablename ]);
1510 unset($currentRecord);
1511 $rio =
new Dataface_IO($drecords[$recordIndex]->_table->tablename);
1513 $res = $rio->saveTransients($drecords[$recordIndex], null, null,
true);
1518 $res = $rio->fireAfterInsert($drecords[$recordIndex]);
1520 $res = $rio->fireAfterSave($drecords[$recordIndex]);
1528 if ( $this->fireTriggers ){
1544 if ( $secure && !$record->_record->checkPermission(
'add existing related record', array(
'relationship'=>$record->_relationshipName) ) ){
1549 'scripts.Dataface.IO.addExistingRelatedRecord.PERMISSION_DENIED',
1550 'Could not add record "'.$record->getTitle().
'" to relationship "'.$record->_relationshipName.
'" of record "'.$record->_record->getTitle().
'" because you have insufficient permissions.',
1551 array(
'title'=>$record->getTitle(),
'relationship'=>$record->_relationshipName,
'parent'=>$record->_record->getTitle())
1560 $domainRec = $record->toRecord($record->_relationship->getDomainTable());
1561 $domainRec2 = df_get_record_by_id($domainRec->getId());
1563 foreach ($domainRec2->vals() as $dreckey=>$drecval){
1564 if ( !$record->val($dreckey) ) $record->setValue($dreckey, $drecval);
1567 if ( $this->fireTriggers ){
1585 $drecords = $record->toRecords();
1588 if ( count($drecords) > 1 ){
1591 foreach ( array_keys($drecords) as $recordIndex){
1592 $currentRecord =& $drecords[$recordIndex];
1593 if ( isset($this->insertids[ $currentRecord->_table->tablename ] ) ){
1594 $idfield =& $currentRecord->_table->getAutoIncrementField();
1596 $currentRecord->setValue($idfield, $this->insertids[ $currentRecord->_table->tablename ]);
1600 unset($currentRecord);
1601 if ( $drecords[$recordIndex]->_table->tablename === $record->_relationship->getDomainTable() )
continue;
1604 $rio =
new Dataface_IO($drecords[$recordIndex]->_table->tablename);
1606 $drec_snapshot = $drecords[$recordIndex]->strvals();
1608 $res = $rio->fireBeforeSave($drecords[$recordIndex]);
1610 $res = $rio->fireBeforeInsert($drecords[$recordIndex]);
1613 $drec_post_snapshot = $drecords[$recordIndex]->strvals();
1615 foreach ( $drec_post_snapshot as $ss_key=>$ss_val ){
1616 if ( $drec_snapshot[$ss_key] != $ss_val ){
1617 $drecords[$recordIndex]->setValue($ss_key,$ss_val);
1621 unset($drec_post_snapshot);
1622 unset($drec_snapshot);
1628 if ( count($drecords) > 1 ){
1629 $sql = $builder->addExistingRelatedRecord($record);
1639 foreach ( array_keys($drecords) as $recordIndex){
1641 if ( $drecords[$recordIndex]->_table->tablename === $record->_relationship->getDomainTable() )
continue;
1644 $rio =
new Dataface_IO($drecords[$recordIndex]->_table->tablename);
1646 $res = $rio->fireAfterInsert($drecords[$recordIndex]);
1648 $res = $rio->fireAfterSave($drecords[$recordIndex]);
1659 $fkeys = $record->_relationship->getForeignKeyValues();
1660 $fkeyvals = $record->getForeignKeyValues();
1661 if ( isset($fkeys[$domainRec2->_table->tablename]) ){
1662 $drecid = $domainRec2->getId();
1664 $domainRec2 = df_get_record_by_id($drecid);
1665 if ( !$domainRec2 ){
1666 return PEAR::raiseError(
"Tried to get record with id $drecid but it doesn't exist");
1671 foreach ( array_keys($fkeys[$domainRec2->_table->tablename]) as $fkey){
1674 if ( $domainRec2->val($fkey) ){
1675 return PEAR::raiseError(
"Could not add existing related record '".$domainRec2->getTitle().
"' because it can only belong to a single relationship and it already belongs to one.");
1679 $domainRec2->setValue($fkey, $fkeyvals[$domainRec2->_table->tablename][$fkey]);
1683 $res = $domainRec2->save($secure);
1686 return PEAR::raiseError(
"Failed to add existing record because the domain table doesn't have any foreign keys in it.");
1693 if ( $this->fireTriggers ){
1714 if ( $secure && !$related_record->_record->checkPermission(
'remove related record', array(
'relationship'=>$related_record->_relationshipName) ) ){
1720 'scripts.Dataface.IO.removeRelatedRecord.PERMISSION_DENIED',
1721 'Could not remove record "'.$related_record->getTitle().
'" from relationship "'.$related_record->_relationshipName.
'" of record "'.$related_record->_record->getTitle().
'" because you have insufficient permissions.',
1722 array(
'title'=>$related_record->getTitle(),
'relationship'=>$related_record->_relationshipName,
'parent'=>$related_record->_record->getTitle())
1727 $res = $this->
fireEvent(
'beforeRemoveRelatedRecord', $related_record);
1734 $domainTable = $related_record->_relationship->getDomainTable();
1741 $domainTable = $related_record->_relationship->_schema[
'selected_tables'][0];
1758 $currKeyNames = array_keys($domainTable->keys());
1760 foreach ($currKeyNames as $keyName){
1761 $query[$keyName] = $related_record->strval($keyName);
1762 $absVals[$domainTable->tablename.
'.'.$keyName] = $query[$keyName];
1766 $fkeys = $related_record->_relationship->getForeignKeyValues($absVals, null, $related_record->_record);
1767 $warnings = array();
1768 $confirmations = array();
1769 foreach ( array_keys($fkeys) as $currTable){
1774 $res = $io->read($fkeys[$currTable], $record);
1777 if (!$io->recordExists($record,null,$currTable)){
1778 $warnings[] = df_translate(
1779 'scripts.Dataface.IO.removeRelatedRecord.ERROR_RECORD_DOESNT_EXIST',
1780 "Failed to delete entry for record '".$record->getTitle().
"' in table '$currTable' because record doesn't exist.",
1781 array(
'title'=>$record->getTitle(),
'currTable'=>$currTable)
1788 if ( $currTable == $domainTable->tablename and !$delete ){
1795 if ( count($fkeys) == 1 ){
1797 if (($currTable == $domainTable->tablename) and $secure and !$related_record->_record->checkPermission(
'remove related record', array(
'relationship'=>$related_record->_relationshipName)) ){
1798 $useSecurity =
true;
1801 $useSecurity =
false;
1804 $myfkeys = $related_record->_relationship->getForeignKeyValues();
1805 foreach ( $myfkeys[$currTable] as $colName=>$colVal ){
1806 $record->setValue($colName, null);
1811 $res = $record->save(null, $useSecurity);
1820 $confirmations[] = df_translate(
1821 'Successfully removed record',
1822 "Successfully removed entry for record '".$record->getTitle().
"' in table '$currTable'",
1823 array(
'title'=>$record->getTitle(),
'table'=>$currTable)
1841 if (($currTable == $domainTable->tablename) and $secure and !$related_record->_record->checkPermission(
'delete related record', array(
'relationship'=>$related_record->_relationshipName)) ){
1842 $useSecurity =
true;
1845 $useSecurity =
false;
1848 $res = $io->delete($record, $useSecurity);
1857 $confirmations[] = df_translate(
1858 'Successfully deleted record',
1859 "Successfully deleted entry for record '".$record->getTitle().
"' in table '$currTable'",
1860 array(
'title'=>$record->getTitle(),
'table'=>$currTable)
1863 $record->__destruct();
1869 $res = $this->
fireEvent(
'afterRemoveRelatedRecord', $related_record);
1872 if (count($confirmations)==0)
return false;
1903 function copy(&$sourceRecord, &$destParent, $destRelationship=null, $deepCopy=
false){
1904 throw new Exception(
"The method ".__METHOD__.
" is not implemented yet.", E_USER_ERROR);
1916 return $this->
fireEvent(
'beforeSave', $record);
1924 return $this->
fireEvent(
'afterSave', $record);
1932 return $this->
fireEvent(
'beforeUpdate', $record);
1941 return $this->
fireEvent(
'afterUpdate', $record);
1949 return $this->
fireEvent(
'beforeInsert', $record);
1957 return $this->
fireEvent(
'afterInsert', $record);
1965 return $this->
fireEvent(
'beforeAddRelatedRecord', $record);
1973 return $this->
fireEvent(
'afterAddRelatedRecord', $record);
1982 return $this->
fireEvent(
'beforeAddNewRelatedRecord', $record);
1990 return $this->
fireEvent(
'afterAddNewRelatedRecord', $record);
1998 return $this->
fireEvent(
'beforeAddExistingRelatedRecord', $record);
2006 return $this->
fireEvent(
'afterAddExistingRelatedRecord', $record);
2014 return $this->
fireEvent(
'beforeDelete', $record);
2022 return $this->
fireEvent(
'afterDelete', $record);
2031 $oldVeto = $record->vetoSecurity;
2032 $record->vetoSecurity =
true;
2033 $delegate =& $this->_table->getDelegate();
2034 if ( $delegate !== null and method_exists($delegate,$name) ){
2035 $res = $delegate->$name($record);
2039 'scripts.Dataface.IO.fireEvent.ERROR_WHILE_FIRING',
2040 "Error while firing event '$name' on table '".$this->_table->tablename.
"' in Dataface_IO::write() ",
2041 array(
'name'=>$name,
'tablename'=>$this->_table->tablename,
'line'=>0,
'file'=>
"_")
2044 $record->vetoSecurity = $oldVeto;
2051 $parentIO->fireEvent($name, $record,
false);
2056 $res =
$app->fireEvent($name, array(&$record, &$this));
2058 $record->vetoSecurity = $oldVeto;
2079 return $this->_table->tablename;
2159 function importData( &$record, $data, $importFilter=null, $relationshipName=null, $commit=
false, $defaultValues=array()){
2160 if ( $relationshipName === null ){
2173 $relationship =& $this->_table->getRelationship($relationshipName);
2174 $tablename = $relationship->getDomainTable();
2179 $destinationTables =& $relationship->getDestinationTables();
2180 if ( count($destinationTables) <= 0 ){
2181 throw new Exception(
2183 'scripts.Dataface.IO.importData.ERROR_NO_DESTINATION_TABLES',
2184 "Error occurred while attempting to parse import data into a table. The relationship '".$relationship->getName().
"' of table '".$this->_table->tablename.
"' has not destination tables listed. It should have at least one.\n",
2185 array(
'relationship'=>$relationship->getName(),
'table'=>$this->_table->tablename)
2189 $tablename = $destinationTables[0]->tablename;
2194 throw new Exception(
$tablename->toString(), E_USER_ERROR);
2204 $records =
$table->parseImportData($data, $importFilter, $defaultValues);
2210 $records =
$table->parseImportData($data, null, $defaultValues);
2223 $importData = array(
2224 'table' =>
$table->tablename,
2225 'relationship' => $relationshipName,
2226 'defaults' => $defaultValues,
2227 'importFilter' => $importFilter,
2231 if ( isset($record) ) $importData[
'record'] = $record->getId();
2233 foreach ($records as $r){
2234 if ( is_a($r,
'Dataface_ImportRecord') ){
2236 $importData[
'rows'][] = $r->toArray();
2238 $importData[
'rows'][] = $r->vals(array_keys($r->_table->fields(
false,
true)));
2243 $dumpFile = tempnam(sys_get_temp_dir(),
'dataface_import');
2244 $handle = fopen($dumpFile,
"w");
2246 throw new Exception(
"Could not write import data to dump file $dumpFile", E_USER_ERROR);
2248 fwrite($handle, serialize($importData));
2251 $_SESSION[
'__dataface__import_data__'] = $dumpFile;
2257 if ( !@$_SESSION[
'__dataface__import_data__'] ){
2258 throw new Exception(
"No import data to import", E_USER_ERROR);
2261 $dumpFile = $_SESSION[
'__dataface__import_data__'];
2262 $importData = unserialize(file_get_contents($dumpFile));
2265 if ( $importData[
'table'] !=
$table->tablename ){
2266 return PEAR::raiseError(
"Unexpected table name in import data. Expected ".
$table->tablename.
" but received ".$importData[
'table']);
2270 $inserted = array();
2272 foreach ( $importData[
'rows'] as $row ){
2273 if ( isset($row[
'__CLASS__']) and isset($row[
'__CLASSPATH__']) ){
2276 import($row[
'__CLASSPATH__']);
2277 $class = $row[
'__CLASS__'];
2278 $importRecord =
new $class($row);
2279 $res = $importRecord->commit($record, $relationshipName);
2285 foreach (array_keys($row) as $key){
2286 if ( !is_int($key) ){
2287 $values[$key] = $row[$key];
2290 if ( $relationshipName === null ){
2296 $defaults = array();
2298 foreach (array_keys($defaultValues) as $key){
2299 if ( strpos($key,
'.') !==
false ){
2301 if (
$tablename == $this->_table->tablename ){
2302 $defaults[
$fieldname] = $defaultValues[$key];
2307 $defaults[$key] = $defaultValues[$key];
2311 $values = array_merge($defaults, $values);
2313 $inserted[] =& $insrecord;
2314 $this->
write($insrecord);
2315 $insrecord->__destruct();
2322 foreach (array_keys($values) as $key){
2323 $values[
$table->tablename.
'.'.$key] = $values[$key];
2324 unset($values[$key]);
2327 $values = array_merge( $defaultValues, $values);
2335 foreach ( $values as $valkey=>$valval){
2336 if ( strpos($valkey,
'.') !==
false ){
2345 $rrecord->setValues($rvalues);
2350 if ( $io->recordExists($rrecord)){
2360 $result = $io->write($rrecord);
2362 throw new Exception(
$result->toString(), E_USER_ERROR);
2366 $inserted[] =& $relatedRecord;
2368 $sql = $qb->addExistingRelatedRecord($relatedRecord);
2372 unset($relatedRecord);
2378 $inserted[] =& $relatedRecord;
2380 $sql = $qb->addRelatedRecord($relatedRecord);
2384 unset($relatedRecord);
2398 unset($_SESSION[
'__dataface__import_data__']);
2460 if ( strpos($uri,
'?') ===
false )
return PEAR::raiseError(
"Invalid record id: ".$uri);
2461 $uri_parts = df_parse_uri($uri);
2463 if ( !isset($uri_parts[
'relationship']) ){
2467 if ( @$uri_parts[
'action'] and ( $uri_parts[
'action'] ==
'new' ) ){
2469 $record->setValues($uri_parts[
'query']);
2473 foreach ($uri_parts[
'query'] as $ukey=>$uval){
2474 if ( $uval and $uval{0}!=
'=' ) $uval =
'='.$uval;
2475 $uri_parts[
'query'][$ukey]=$uval;
2478 $record =& df_get_record($uri_parts[
'table'], $uri_parts[
'query']);
2480 if ( isset($uri_parts[
'field']) ){
2481 if ( isset($filter) and method_exists($record, $filter) ){
2482 $val =& $record->$filter($uri_parts[
'field']);
2485 $val =& $record->val($uri_parts[
'field']);
2489 else return $record;
2494 $record =& df_get_record($uri_parts[
'table'], $uri_parts[
'query']);
2495 if ( !$record )
return PEAR::raiseError(
"Could not find any records matching the query");
2498 if ( @$uri_parts[
'action'] and ( $uri_parts[
'action'] ==
'new' ) ){
2500 $related_record->setValues( $uri_parts[
'query']);
2501 return $related_record;
2506 $related_records =& $record->getRelatedRecordObjects($uri_parts[
'relationship'], 0,1, $uri_parts[
'related_where']);
2507 if ( count($related_records) == 0 ){
2509 return PEAR::raiseError(
"Could not find any related records matching the query: ".$uri_parts[
'related_where']);
2511 if ( isset($uri_parts[
'field']) ) {
2512 if ( isset($filter) and method_exists($related_records[0], $filter) ){
2513 $val =& $related_records[0]->$filter($uri_parts[
'field']);
2516 $val =& $related_records[0]->val($uri_parts[
'field']);
2520 else return $related_records[0];
2531 @list($uri,
$fieldname) = explode(
'#', $uri);
2535 if ( !is_object($record) )
return PEAR::raiseError(
"Could not find record matching '$uri'.");
2538 $res = $record->setValue(
$fieldname, $value);
2540 $res = $record->setValues($value);
2544 $res = $record->save();
2550 $sql =
"create table dataface__mtimes (
2551 `name` varchar(255) not null primary key,
2554 $res = mysql_query($sql, df_db());
2555 if ( !$res )
throw new Exception(mysql_error(df_db()));
2559 $sql =
"replace into dataface__mtimes (`name`,`mtime`) values ('".addslashes(
$table).
"','".addslashes(time()).
"')";
2560 $res = mysql_query($sql, df_db());
2563 $res = mysql_query($sql, df_db());
2564 if ( !$res )
throw new Exception(mysql_error(df_db()));