00001 <?php if(!function_exists('startedIndexPhp')) { header("location:../index.php"); exit();}
00002
00003
00004 require_once(confGet('DIR_STREBER') . "db/db.inc.php");
00005 require_once(confGet('DIR_STREBER') . "render/render_fields.inc.php");
00006
00033 class Field
00034 {
00035 public $type; #field
00036 public $download =FDOWNLOAD_ALWAYS; #loaded by default, on demand
00037 public $name ='';
00038 public $title =''; # label used in forms
00039 public $default;
00040 public $tooltip ='';
00041 public $invalid; # current value marked as invalid (use for rerendering forms with invalid data)
00042
00043 public $func_renderToForm; # function name for rendering the field / automatically defined
00044 public $func_parseForm; # functino name for parse entered data / automatically defined
00045 public $func_renderListHead;
00046 public $func_renderListRow;
00047 public $func_getFormElement;
00048 public $view_in_forms; # TODO: 1-alwayys, 2-details, etc.
00049 public $view_in_lists; # do we see this field in lists?
00050 public $log_changes = true; # by default all changes are logged
00051 public $export = true; # may be exported as csv or xml (should be false for passwords, etc)
00052
00053
00054 public $export_csv = false;
00060 public function __construct($args=NULL)
00061 {
00062 #--- set parameters ------
00063 if(!$args) {
00064 trigger_error("Can't construct a field without name parameters", E_USER_ERROR);
00065 }
00066 foreach($args as $key=>$value) {
00067 empty($this->$key); # cause php-notification if undefined property
00068 $this->$key= $value;
00069 }
00070
00071
00072 #--- try to automatically assign functions for rendering...
00073 if($this->view_in_forms) {
00074 foreach(array(
00075 '_renderToForm',
00076 '_parseForm',
00077 '_getFormElement'
00078 ) as $fn_append) {
00079 $fname= $this->type.$fn_append;
00080 $fn= 'func'.$fn_append;
00081 if(!$this->$fn) {
00082 if(function_exists($fname)) {
00083 $this->$fn= $fname;
00084 }
00085 }
00086 }
00087 }
00088 if($this->view_in_lists) {
00089 foreach(array('_renderListHead','_renderListRow') as $fn_append) {
00090 $fname= $this->type.$fn_append;
00091 $fn= 'func'.$fn_append;
00092 if(!$this->$fn) {
00093 if(function_exists($fname)) {
00094 $this->$fn= $fname;
00095 }
00096 }
00097 else {
00098 trigger_error("'$fname' is not defined", E_USER_ERROR);
00099 }
00100 }
00101 }
00102
00103 #--- some checks ---
00104 if(!$this->name) {
00105 trigger_error("Can't construct a field without name parameters",E_USER_ERROR);
00106 return;
00107 }
00108 if($this->download != FDOWNLOAD_ALWAYS && $this->download != FDOWNLOAD_ONDEMAND && $this->download != FDOWNLOAD_NEVER) {
00109 trigger_error("invalid value for download: $this->download",E_USER_ERROR);
00110 }
00111
00112 #--- try to figure title ----
00113 if(!$this->title) {
00114 $this->title= ucwords(str_replace('_',' ',$this->name));
00115 }
00116 }
00117
00118 #---------------------------------------------------------------------
00119 # converts a string into a valid value for database
00120 #---------------------------------------------------------------------
00121 public function value2db($value=FALSE)
00122 {
00123 return $value;
00124 }
00125
00126 #------------------------------------------------------------------------
00127 # converts values from db into meaningful string-formats
00128 #------------------------------------------------------------------------
00129 public function db2value($value=FALSE)
00130 {
00131 return $value;
00132 }
00133
00134 public function render2form(&$obj)
00135 {
00136 if(isset($this->func_renderToForm)) {
00137 $fn= $this->func_renderToForm;
00138 return $fn(&$this,&$obj);
00139 }
00140 return false; # TODO: add warning
00141 }
00142
00143 public function parseForm(&$obj)
00144 {
00145 if(isset($this->func_parseForm)) {
00146 $fn= $this->func_parseForm;
00147 return $fn(&$this, &$obj);
00148 }
00149 return false; # TODO: add warning
00150 }
00151
00155 public function getFormElement(&$obj, $title=NULL)
00156 {
00157 if(isset($this->func_getFormElement)) {
00158 $fn= $this->func_getFormElement;
00159 return $fn(&$this, &$obj, $title);
00160 }
00161 else {
00162 return new Form_CustomHTML('');
00163 }
00164 }
00165 }
00166
00167 #================================================================================================================
00168 class FieldHidden extends Field {
00169 public function __construct($args=NULL) {
00170 $this->type=__class__;
00171 $this->default= 0;
00172 $this->view_in_forms=true;
00173 parent::__construct($args);
00174 }
00175 }
00176
00177 #================================================================================================================
00178 class FieldInternal extends Field {
00179 public function __construct($args=NULL) {
00180 $this->type=__class__;
00181 $this->default= 0;
00182 $this->log_changes= false;
00183 $this->view_in_forms=false;
00184 $this->view_in_lists=false;
00185 parent::__construct($args);
00186 }
00187 }
00188
00189 #================================================================================================================
00190 class FieldString extends Field {
00191 public function __construct($args=NULL) {
00192 $this->default= '';
00193 $this->type=__class__;
00194 $this->view_in_forms=true;
00195 $this->view_in_lists=true;
00196 parent::__construct($args);
00197 }
00198 }
00199
00200 #================================================================================================================
00201 class FieldPassword extends Field {
00202 public function __construct($args=NULL) {
00203 $this->type=__class__;
00204 $this->default= '';
00205 $this->view_in_forms=true;
00206 $this->view_in_lists=false;
00207 parent::__construct($args);
00208 }
00209 }
00210
00211 #================================================================================================================
00212 class FieldBool extends Field {
00213 public function __construct($args=NULL) {
00214 $this->default= 0;
00215 $this->type=__class__;
00216 $this->view_in_forms=true;
00217 parent::__construct($args);
00218 }
00219 }
00220
00221 #================================================================================================================
00222 class FieldDate extends Field {
00223 public function __construct($args=NULL)
00224 {
00225 $this->default= '0000-00-00';
00226 $this->type=__class__;
00227 $this->view_in_forms=true;
00228 $this->view_in_lists=true;
00229 parent::__construct($args);
00230 }
00231
00232 }
00233
00234 #================================================================================================================
00235 class FieldTime extends Field {
00236 public function __construct($args=NULL) {
00237 $this->type=__class__;
00238 $this->view_in_forms=true;
00239 $this->view_in_lists=true;
00240 parent::__construct($args);
00241 }
00242 }
00243
00244 #================================================================================================================
00245 class FieldPercentage extends Field {
00246 public function __construct($args=NULL) {
00247 $this->default= 0;
00248 $this->type=__class__;
00249 $this->view_in_forms=true;
00250 $this->view_in_lists=true;
00251 parent::__construct($args);
00252 }
00253 }
00254
00255 #================================================================================================================
00256 class FieldDatetime extends Field {
00257 public function __construct($args=NULL) {
00258 $this->default= '0000-00-00 00:00:00';
00259 $this->type=__class__;
00260 $this->view_in_forms=true;
00261 $this->view_in_lists=true;
00262 parent::__construct($args);
00263 }
00264 }
00265
00266 #================================================================================================================
00267 class FieldInt extends Field {
00268 public function __construct($args=NULL) {
00269 $this->default= 0;
00270 $this->type=__class__;
00271 $this->view_in_forms=true;
00272 $this->view_in_lists=true;
00273 parent::__construct($args);
00274 }
00275 }
00276
00277 #================================================================================================================
00278 class FieldOption extends Field {
00279 public $options;
00280 public function __construct($args=NULL) {
00281 $this->default= 0;
00282 $this->type=__class__;
00283 $this->view_in_forms=true;
00284 $this->view_in_lists=true;
00285 $this->options=array();
00286 parent::__construct($args);
00287 }
00288 }
00289
00290 #================================================================================================================
00291 class FieldText extends Field {
00292 public function __construct($args=NULL) {
00293 $this->default= '';
00294 $this->type=__class__;
00295 $this->view_in_forms=true;
00296 parent::__construct($args);
00297 }
00298 }
00299
00300
00301 #================================================================================================================
00302 class FieldUser extends Field {
00303 public function __construct($args=NULL) {
00304 $this->type=__class__;
00305 parent::__construct($args);
00306 }
00307 }
00308
00309
00310
00311
00312
00313 abstract class DbItem {
00314 public $id=-1; # all items need to have an id
00315 public $_type; # name of table like "user", etc. Needed to be set by derived class
00316 public $fields; # reference to global assoc. array of Field-Objects
00317 private $field_states; # assoc. array of field-names and field states. Required for lazy loading.
00318 public static $fields_static;
00319
00320
00321 public function __construct($id = false)
00322 {
00323 if(!isset($this->_type)) {
00324 trigger_error("Constructing DbItem requires this->_type to be set", E_USER_ERROR);
00325 }
00326
00327 #--- create members for all fields ---
00328 $this->field_states=array();
00329 foreach($this->fields as $f) {
00330 $this->field_states[$f->name]=FSTATE_UNKNOWN;
00331 $tmp_name=$f->name;
00332
00333 #--- set default-values ---
00334 $def_value=$f->default;
00335 if($def_value === FINIT_NOW) {
00336 $def_value= getGMTString();
00337 }
00338 else if($def_value === FINIT_TODAY) {
00339 $def_value=gmdate("Y-m-d");
00340 }
00341 else if($def_value === FINIT_RAND_MD5) {
00342 $def_value= md5(time().microtime(). rand(12312,123213). rand(234423,123213)); #@@@ those numbers don't look very nice
00343 }
00344 else if($def_value === FINIT_CUR_USER) {
00345 global $auth;
00346 if($auth->cur_user) {
00347 $def_value= $auth->cur_user->id;
00348 }
00349 }
00350 $this->$tmp_name=$def_value;
00351 }
00352
00353 if($id === 0) {
00354 return NULL; # this is probably a failure...
00355 }
00356
00357 if($id === false) {
00358 return;
00359 }
00360
00361 #--- if id given, querry important fields from db
00362 $dbh = new DB_Mysql;
00363 $download_fields="";
00364 $delimiter= '';
00365 $fields=$this->fields;
00366 foreach($fields as $f) {
00367 if($f->download==FDOWNLOAD_ALWAYS) {
00368 $download_fields.= $delimiter.$f->name;
00369 $delimiter=',';
00370 }
00371 }
00372 $prefix= confGet('DB_TABLE_PREFIX');
00373 $query = "SELECT $download_fields from {$prefix}$this->_type WHERE id = 1";
00374
00375 $data = $dbh->prepare($query)->execute($id)->fetch_assoc();
00376 if($data) {
00377 foreach( $data as $attr => $value ) {
00378 $this->$attr = stripslashes($value);
00379 }
00380 }
00381 else {
00382 unset($this);
00383 return NULL; # returning false does not makes sense
00384 }
00385 }
00386
00387 #-------------------------------------------------
00388 # delete
00389 #-------------------------------------------------
00390 public function deleteFull()
00391 {
00392 if(!$this->id) {
00393 trigger_error("Deleting requires id",E_USER_ERROR);
00394 }
00395 $prefix= confGet('DB_TABLE_PREFIX');
00396 $query = "DELETE FROM {$prefix}{$this->_type} WHERE id = {$this->id}";
00397 $dbh = new DB_Mysql;
00398 $dbh->prepare($query)->execute($this->id);
00399
00400 #--- deleting yourself? ----
00401 unset($this);
00402 return true;
00403 }
00404
00405 #-------------------------------------------------
00406 # mark_delete (sets object-state to -1)
00407 #-------------------------------------------------
00408 public function delete()
00409 {
00410 if(!$this->id) {
00411 trigger_error("Deleting requires id", E_USER_ERROR);
00412 }
00413 $prefix= confGet('DB_TABLE_PREFIX');
00414 $query= "update {$prefix}{$this->_type} SET state=-1 WHERE id= $this->id";
00415 $dbh = new DB_Mysql;
00416 $dbh->prepare($query)->execute();
00417
00418 #--- deleting yourself? ----
00419 unset($this);
00420 return true;
00421 }
00422
00423
00424 #-------------------------------------------------
00425 # update() / write to db
00426 #-------------------------------------------------
00427 public function update($args=NULL, $update_modifier=true)
00428 {
00429 if(!$this->id) {
00430 trigger_error("needs id to call update()", E_USER_ERROR);
00431 }
00432 if(!isset($this->_type) || !$this->_type || $this->_type=="") {
00433 trigger_error("need _type to call update()", E_USER_ERROR);
00434 }
00435 if(!$args || !sizeof($args)) {
00436 $args=$this->field_states;
00437 }
00438 if(!sizeof($args)) {
00439 trigger_error("need members to update to database. e.g. 'firstname,lastname,data'", E_USER_ERROR);
00440 }
00441
00442 #--- build query-string like "update users SET firstname=:1, lastname=:2 where id=:3" --
00443 #--- build value-array ----
00444 $prefix= confGet('DB_TABLE_PREFIX');
00445 $query = "UPDATE {$prefix}{$this->_type} SET ";
00446 $values=array();
00447 $counter=1;
00448 $delimiter="";
00449 $value_str="VALUES(";
00450
00451 # TODO: filter changed fields before saving to db!
00452 foreach($this->field_states as $m_key => $m_state) {
00453 if(!isset($this->$m_key) && $this->$m_key!=NULL) {
00454 trigger_error("$m_key is not a member of '".get_class($this)."' and can't be passed to db", E_USER_ERROR);
00455 }
00456 $values[]= $this->$m_key;
00457 $query.= $delimiter.$m_key .'=' .$counter;
00458 $value_str.=$delimiter." ".$counter;
00459 ++$counter;
00460 $delimiter=", ";
00461 }
00462 $query.= " WHERE id=".$counter++;
00463 $values[]=$this->id;
00464
00465 $dbh = new DB_Mysql;
00466 $statement=$dbh->prepare($query);
00467 call_user_func_array(array($statement,'execute'),$values);
00468 return true;
00469 }
00470
00471
00472
00478 public function insert()
00479 {
00480 if($this->id) {
00481 trigger_error("User object which already has an id, can't be inserted", E_USER_ERROR);
00482 }
00483 if(!sizeof($this->field_states)) {
00484 trigger_error("need members to update to database. e.g. 'firstname,lastname,data'",E_USER_ERROR);
00485 }
00486
00487 #--- build query-string like "INSERT INTO users (firstname, lastname) VALUES(:1, :2)" --
00488 #--- build value-array ----
00489 $prefix= confGet('DB_TABLE_PREFIX');
00490 $t_values= array();
00491 $t_fields= array();
00492 foreach($this->field_states as $m_key => $m_state) {
00493 if(!isset($this->$m_key) && $this->$m_key!=NULL) {
00494 trigger_error("$m_key is not a member of $this and can't be passed to db", E_USER_ERROR);
00495 }
00496
00497 $t_fields[]= $m_key;
00498 $t_values[]="'".asSecureString($this->$m_key)."'";
00499 }
00500
00501 $dbh = new DB_Mysql;
00502 #$statement=$dbh->prepare($query);
00503 #call_user_func_array(array($statement,'execute'),$values);
00504
00505 $str_query = "INSERT INTO {$prefix}$this->_type "
00506 . '(' . join(', ', $t_fields ) .')'
00507 .' VALUES(' . join(', ', $t_values) .')';
00508
00509 $sth= $dbh->prepare($str_query);
00510
00511 $sth->execute("",1);
00512
00513 #$statement->execute($values);
00514 $this->id = $dbh->lastId();
00515 return true;
00516
00517 }
00518
00524 function getShort($length = false)
00525 {
00526 if(isset($this->short) && $this->short && $this->short !="") {
00527 return $this->short;
00528 }
00529 if(!$length) {
00530 $length= confGet('STRING_LENGTH_SHORT');
00531 }
00532 if(isset($this->name) && $this->name !="") {
00533 if(strlen($this->name) > $length) {
00534 if(function_exists('mb_substr')) {
00535 return mb_substr($this->name, 0 ,$length) . "...";
00536 }
00537 return substr($this->name, 0 ,$length) . "...";
00538 }
00539 return $this->name;
00540 }
00541 else {
00542 return __("unnamed");
00543 }
00544 }
00545
00546
00547
00551 function getShortWithTitle()
00552 {
00553 if(isset($this->short) && $this->short && $this->short !="") {
00554 return "<span title='$this->name'>".asHtml($this->short)."</span>";
00555 }
00556 $length= confGet('STRING_LENGTH_SHORT');
00557 if(isset($this->name) && $this->name !="") {
00558 ereg("(.{0,$length})(.*)",asHtml($this->name),$matches);
00559 if(!$matches[2]) {
00560 return $matches[1];
00561 }
00562 return "<span title='$this->name'>".$matches[1]."...</span>";
00563 }
00564 else {
00565 return __("unnamed");
00566 }
00567 }
00568
00569
00570
00571 static function getItemType($id)
00572 {
00573 $prefix= confGet('DB_TABLE_PREFIX');
00574 $dbh = new DB_Mysql;
00575 $sth= $dbh->prepare("SELECT type FROM {$prefix}item i
00576 WHERE
00577 i.id = $id
00578 " );
00579 $sth->execute("",1);
00580 $tmp=$sth->fetchall_assoc();
00581 return $tmp[0]['type'];
00582 }
00583
00584
00585
00586 static function getItemState($id)
00587 {
00588 $prefix= confGet('DB_TABLE_PREFIX');
00589 $dbh = new DB_Mysql;
00590 $sth= $dbh->prepare("SELECT state FROM {$prefix}item i
00591 WHERE
00592 i.id = $id
00593 " );
00594 $sth->execute("",1);
00595 $tmp=$sth->fetchall_assoc();
00596 return $tmp[0]['state'];
00597 }
00598
00599
00603 public function nowViewedByUser($user=NULL)
00604 {
00605 global $auth;
00606
00607 if(is_null($user)){
00608 if($auth->cur_user){
00609 $user = $auth->cur_user;
00610 }
00611 else{
00612 return NULL;
00613 }
00614 }
00615
00616 require_once(confGet('DIR_STREBER') . 'db/db_itemperson.inc.php');
00617
00618 if($view = ItemPerson::getAll(array('person'=>$user->id, 'item'=>$this->id))){
00619 $view[0]->viewed = true;
00620 $view[0]->viewed_last = getGMTString();
00621 $view[0]->update();
00622 }
00623 else{
00624 $new_view = new ItemPerson(array(
00625 'item' =>$this->id,
00626 'person' =>$user->id,
00627 'viewed' =>1,
00628 'viewed_last' =>getGMTString(),
00629 'is_bookmark' =>0,
00630 'notify_on_change'=>0));
00631 $new_view->insert();
00632 }
00633 }
00634
00635
00636
00641 public function isChangedForUser()
00642 {
00643 global $auth;
00644
00645 ### ignore, if too old
00646 if($this->modified < $auth->cur_user->date_highlight_changes) {
00647 return false;
00648 }
00649
00650 ### ignore self edited items ###
00651 if($this->modified_by == $auth->cur_user->id) {
00652 return false;
00653 }
00654
00655 require_once(confGet('DIR_STREBER') . 'db/db_itemperson.inc.php');
00656 if($item_persons = ItemPerson::getAll(array('person'=>$auth->cur_user->id,'item' => $this->id))) {
00657 $ip= $item_persons[0];
00658 if($ip->viewed_last < $this->modified) {
00659 return true;
00660 }
00661 else {
00662 return false;
00663 }
00664 }
00665 return true;
00666 }
00667
00668 public function nowChangedByUser()
00669 {
00670 require_once('std/mail.inc.php');
00671 require_once('db/db_itemperson.inc.php');
00672 ### if notify_if_unchanges is set ###
00673 if ($ip = ItemPerson::getAll(array('item'=>$this->id,'notify_if_unchanged_min'=>NOTIFY_1DAY))){
00674 if(isset($ip)){
00675 $ip[0]->notify_date = date('Y-m-d H:i:s', time());
00676 $ip[0]->update();
00677 }
00678 }
00679 }
00680
00681
00682
00683
00684 #--- set --------------------------------------
00685 function __set($name, $val)
00686 {
00687 if (isset($this->$name) || isset($this->field_states[$name])) {
00688 $this->$name = $val;
00689 }
00690 else {
00691 trigger_error("can't set dbItem->$name for object of type ".get_class($this),E_USER_ERROR);
00692 }
00693 }
00694
00695 #--- get --------------------------------------
00696 function __get($name)
00697 {
00698 if(isset($this->$name)) {
00699 return $this->$name;
00700 }
00701 else if(isset($this->fields[$name])) {
00702 trigger_error("can't read '$name' from object of type ".get_class($this),E_USER_ERROR);
00703 }
00704 else {
00705 trigger_error("can't read '$name' from object of type '".get_class($this)."' ",E_USER_WARNING);
00706 }
00707 }
00708 }
00709
00710
00711
00712 DbProjectItem::initItemFields();
00713
00714
00715 function addProjectItemFields(&$ref_fields) {
00716 global $g_item_fields;
00717 foreach($g_item_fields as $f) {
00718 $ref_fields[$f->name]=$f;
00719 }
00720 }
00721
00737 class DbProjectItem extends DbItem {
00738
00739 public $fields_project;
00740 private $_values_org=array();
00741 public $children= array();
00742
00746 public function __construct($id_or_array=NULL)
00747 {
00748
00754 $this->_type=strtolower(get_class($this));
00755
00756
00760 if(!$this->fields) {
00761 global $g_item_fields;
00762 $this->fields=&$g_item_fields;
00763 }
00764
00768 if(is_array($id_or_array)) {
00769 parent::__construct();
00770 foreach($id_or_array as $key => $value) {
00771 is_null($this->$key); ### cause E_NOTICE on undefined properties
00772 $this->_values_org[$key]= $this->$key=$value;
00773 }
00774 }
00775
00781 else if(is_int($id_or_array) || (is_string($id_or_array) and $id_or_array !== "0")){
00782
00783 parent::__construct(); # call constructor to initialize members from field-array
00784 $id=intval($id_or_array); # construction-param was an id
00785 if(!$id) {
00786 return;
00787 }
00788
00789 global $g_item_fields;
00790
00791
00792 #--- try to find in item-table ---
00793 {
00794 $dbh = new DB_Mysql;
00795 $str_download_fields="";
00796 $str_delimiter= '';
00797 foreach($g_item_fields as $f) {
00798 $str_download_fields.= $str_delimiter . $f->name;
00799 $str_delimiter=',';
00800 }
00801 $prefix= confGet('DB_TABLE_PREFIX');
00802 $query = "SELECT $str_download_fields from {$prefix}item WHERE id = $id";
00803 $data = $dbh->prepare($query)->execute()->fetch_assoc();
00804 if($data) {
00805 foreach( $data as $attr => $value ) {
00806
00807 is_null($this->$attr); # cause E_NOTICE if member not defined
00808 $this->_values_org[$attr]= $this->$attr = $value;
00809 }
00810 }
00811
00812 #--- not found in item-table ---
00813 else {
00817 #trigger_error("item id='$id' not found in table", E_USER_WARNING);
00818 unset($this); #@@@ not sure if abort called construction like this works
00819 return NULL;
00820 }
00821 }
00822
00823 #--- now find the other fields in the appropriate table ---
00824 if($this->_type && $this->_type != 'dbprojectitem') {
00825 $dbh = new DB_Mysql;
00826 $str_download_fields="";
00827 $str_delimiter= '';
00828 foreach($this->fields as $f) {
00829 #--- ignore project item fields ---
00830 if(!isset($g_item_fields[$f->name])) {
00831 $str_download_fields.= $str_delimiter . $f->name;
00832 $str_delimiter=',';
00833 }
00834 }
00835 $prefix= confGet('DB_TABLE_PREFIX');
00836 $query = "SELECT $str_download_fields from {$prefix}$this->_type WHERE id = $id";
00837 $data = $dbh->prepare($query)->execute()->fetch_assoc();
00838 if($data) {
00839 foreach( $data as $attr => $value ) {
00840 is_null($this->$attr); # cause E_NOTICE if member not defined
00841 #$this->_values_org[$attr]= $this->$attr = stripslashes(stripslashes(stripslashes($value))); #@@@ note this is a weird bug
00842
00847 #if(get_magic_quotes_gpc()) {
00848 # $this->_values_org[$attr]= $this->$attr = stripslashes($value);
00849 #}
00850 #else {
00851
00852 $this->_values_org[$attr]= $this->$attr = $value;
00853 #}
00854 }
00855 }
00856
00857 #--- not found in item-table ---
00858 else {
00859 trigger_error("item #$id not found in db-table '$this->_type'",E_USER_WARNING);
00860 return NULL;
00861 }
00862 }
00863
00864 }
00865 #--- just empty ----
00866 else {
00870 #trigger_error("can't construct zero-id item",E_USER_WARNING);
00871 parent::__construct();
00872 return NULL;
00873 }
00874 }
00875
00876 static function initItemFields() {
00877 global $g_item_fields;
00878 $g_item_fields=array();
00879
00880 foreach(array(
00881 ### internal fields ###
00882 new FieldInternal (array('name'=>'id',
00883 'default'=>0,
00884 'log_changes'=>false,
00885 )),
00886 new FieldInternal (array('name'=>'type',
00887 'default'=>0,
00888 'log_changes'=>false,
00889 )),
00890 new FieldUser (array('name'=>'created_by',
00891 'default'=> FINIT_CUR_USER,
00892 'view_in_forms'=>false,
00893 'log_changes'=>false,
00894 )),
00895 new FieldDatetime( array('name'=>'created',
00896 'default'=>FINIT_NOW,
00897 'view_in_forms'=>false,
00898 'log_changes'=>false,
00899 )),
00900 new FieldUser (array('name'=>'modified_by',
00901 'default'=> FINIT_CUR_USER,
00902 'view_in_forms'=>false,
00903 'log_changes'=>false,
00904 )),
00905 new FieldDate (array('name'=>'modified',
00906 'default'=>FINIT_NOW,
00907 'view_in_forms'=>false,
00908 'log_changes'=>false,
00909 )),
00910 new FieldUser (array('name'=>'deleted_by',
00911 'view_in_forms'=>false,
00912 'log_changes'=>false,
00913 'default'=>0,
00914 )),
00915 new FieldDate (array('name'=>'deleted',
00916 'default'=>FINIT_NEVER,
00917 'view_in_forms'=>false,
00918 'log_changes'=>false,
00919 )),
00920 new FieldInternal(array( 'name'=>'pub_level',
00921 'view_in_forms'=>false,
00922 'default'=>PUB_LEVEL_OPEN,
00923 'log_changes'=>true,
00924
00925 )),
00926 new FieldInternal (array('name'=>'state',
00927 'log_changes'=>true,
00928 'default'=>1,
00929 )),
00930 new FieldInternal (array('name'=>'project',
00931 'default'=>0,
00932 'log_changes'=>false,
00933 )),
00934
00935 ) as $f) {
00936 $g_item_fields[$f->name]=$f;
00937 }
00938 }
00939
00940
00941
00942
00943
00949 static function getById($id)
00950 {
00951 $i= new DbProjectItem($id);
00952 if($i->id) {
00953 return $i;
00954 }
00955 return NULL;
00956 }
00957
00958
00966 static function getVisibleById($id)
00967 {
00968 if($i= DbProjectItem::getById($id)) {
00969 if($i->type == ITEM_PROJECT) {
00970
00974 return $i;
00975 }
00976 else if($i->type == ITEM_PERSON) {
00977 if($p= Person::getVisibleById($id)) {
00978 return $i;
00979 }
00980 else {
00981 return NULL;
00982 }
00983
00984 }
00985 else if($i->type == ITEM_COMPANY) {
00986 require_once(confGet('DIR_STREBER') . 'db/class_company.inc.php');
00987
00988 if($c= Company::getVisibleById($id)) {
00989 return $i;
00990 }
00991 else {
00992 return NULL;
00993 }
00994
00995 }
00996 else {
00997 if($p= Project::getById($i->project)) {
00998 if($p->validateViewItem($i)) {
00999 return $i;
01000 }
01001 }
01002 else {
01003 trigger_error("item #$id (type= $i->type) has no project?",E_USER_WARNING);
01004 }
01005 }
01006
01007 }
01008 return NULL;
01009 }
01010
01014 static function getEditableById($id)
01015 {
01016 require_once(confGet('DIR_STREBER') . 'db/class_project.inc.php');
01017 if($i= DbProjectItem::getById($id)) {
01018 if($i->type == ITEM_PROJECT) {
01019 global $auth;
01020 if($auth->cur_user->user_rights & RIGHT_PROJECT_EDIT) {
01021 return $i;
01022 }
01023 }
01024 else if($p= Project::getById($i->project)) {
01025 if($p->validateEditItem($i)) {
01026 return $i;
01027 }
01028 }
01029 else {
01030 trigger_error("issue without project?",E_USER_WARNING);
01031 }
01032 }
01033 return NULL;
01034 }
01035
01036
01037
01038
01039
01040 public function insert()
01041 {
01042 global $g_item_fields;
01043
01044 if($this->id) {
01045 trigger_error("User object which already has an id, can't be inserted", E_USER_WARNING);
01046 }
01047 if(!sizeof($this->field_states)) {
01048 trigger_error("need members to update to database. e.g. 'firstname,lastname,data'", E_USER_WARNING);
01049 }
01050
01059 #--- first write item-fields ---
01060 #
01061 # build query-string like "INSERT INTO users (firstname, lastname) VALUES(tom, mann)"
01062 #
01063 {
01064 $dbh = new DB_Mysql;
01065
01066 $t_fields=array();
01067 $t_values=array();
01068 foreach($g_item_fields as $f) {
01069 $name= $f->name;
01070 if(!isset($this->$name) && $this->$name!=NULL) {
01071 trigger_error("$name is not a member of $this and can't be passed to db",E_USER_WARNING);
01072 }
01073 $t_fields[]=$name;
01074 $t_values[]="'".asSecureString($this->$name)."'";
01075 }
01076 $prefix= confGet('DB_TABLE_PREFIX');
01077 $str_query= 'INSERT INTO '
01078 .$prefix.'item '
01079 . '(' . join(', ', $t_fields ) .')'
01080 .' VALUES(' . join(', ', $t_values) .')';
01081
01082 $sth= $dbh->prepare($str_query);
01083 $sth->execute("",1);
01084 }
01085
01086 #--- extract the id of last inserted item ---
01087 $this->id = $dbh->lastId();
01088
01089 #--- now write non item-fields ---
01090 #
01091 # build query-string like "INSERT INTO users (firstname, lastname) VALUES(tom, mann)"
01092 #
01093 {
01094 $dbh = new DB_Mysql;
01095 $t_fields=array();
01096 $t_values=array();
01097
01098 foreach($this->fields as $f) {
01099 $name= $f->name;
01100
01101 ### skip project-item fields ###
01102 if(isset($this->fields[$name]) && isset($this->fields[$name]->in_db_object) || !isset($g_item_fields[$name])) {
01103 if(!isset($this->$name) && $this->$name!=NULL) {
01104 trigger_error("$name is not a member of $this and can't be passed to db", E_USER_WARNING);
01105 }
01106 $t_fields[]=$name;
01107 $t_values[]="'".asSecureString($this->$name)."'";
01108 }
01109 }
01110 $str_query= 'INSERT INTO '
01111 .$prefix.$this->_type
01112 . '(' . join(',', $t_fields ) .')'
01113 .' VALUES(' . join(',', $t_values) .')';
01114
01115
01116 $sth= $dbh->prepare($str_query);
01117 $sth->execute("",1);
01118 }
01119 return true;
01120 }
01121
01122
01123
01124
01125 public function update($args=NULL, $update_modifier=true)
01126 {
01127 global $auth;
01128 global $g_item_fields;
01129 $dbh = new DB_Mysql;
01130
01131 $update_fields=NULL;
01132
01133 ### build hash to fast access ##
01134 if($args) {
01135 $update_fields=array();
01136 foreach($args as $a) {
01137 $update_fields[$a]=true;
01138 }
01139 }
01140
01141 if(!$this->id) {
01142 trigger_error("User object without id can't be updated", E_USER_WARNING);
01143 }
01144 if(!sizeof($this->field_states)) {
01145 trigger_error("need members to update to database. e.g. 'firstname,lastname,data'", E_USER_WARNING);
01146 }
01147
01155 if($update_modifier && $auth->cur_user) {
01156 $this->modified_by= $auth->cur_user->id;
01157 $this->modified= getGMTString();
01158 if($update_fields) {
01159 $update_fields['modified_by']=true;
01160 $update_fields['modified']=true;
01161 }
01162 }
01163
01164
01165 $log_changed_fields= array();
01166
01167 #--- first write item-fields ---
01168 #
01169 #--- build query-string like "update users SET firstname=:1, lastname=:2 where id=:3" --
01170 {
01171 $t_pairs=array();
01172 foreach($g_item_fields as $f) {
01173 $name= $f->name;
01174 if($update_fields && !isset($update_fields[$name])) {
01175 continue;
01176 }
01177
01178 if(isset($this->_values_org[$name])) {
01179 if(!isset($this->$name) && $this->$name!=NULL) {
01180 trigger_error("$name is not a member of $this and can't be passed to db", E_USER_WARNING);
01181 }
01182
01183 if ( $this->_values_org[$name] == stripslashes($this->$name)) {
01184 continue;
01185 }
01186 else if($this->fields[$name]->log_changes) {
01187 $log_changed_fields[]=$name;
01188 }
01189 }
01190
01191 $t_pairs[]= $name."='".asSecureString($this->$name)."'";
01192 }
01193 $prefix= confGet('DB_TABLE_PREFIX');
01194 if(count($t_pairs)) {
01195 $str_query= 'UPDATE '
01196 .$prefix.'item '
01197 .'SET ' . join(', ', $t_pairs)
01198 .' WHERE id='.$this->id ;
01199
01200 $dbh = new DB_Mysql;
01201
01202 $sth= $dbh->prepare($str_query);
01203 $sth->execute("",1);
01204 }
01205 }
01206
01207 #--- now write non item-fields ---
01208 #
01209 #--- build query-string like "update users SET firstname=:1, lastname=:2 where id=:3" --
01210 #
01211 if($this->_type && $this->_type != 'dbprojectitem') {
01212
01213 $t_pairs=array(); # the 'id' field is skipped later, because it's defined as project-item-field. so we have to add it here
01214 foreach($this->fields as $f) {
01215 $name= $f->name;
01216
01217 ### selective updates ###
01218 if($update_fields && !isset($update_fields[$name])) {
01219 continue;
01220 }
01221
01222 ### skip project-item fields ###
01223 if(
01224 ( isset($this->fields[$name])
01225 && isset($this->fields[$name]->in_db_object)
01226 )
01227 || !isset($g_item_fields[$name])
01228 ){
01229 if(!isset($this->$name) && $this->$name!=NULL) {
01230 trigger_error("$name is not a member of $this and can't be passed to db", E_USER_WARNING);
01231 continue;
01232 }
01233 if(isset($this->_values_org[$name])) {
01234 if ( $this->_values_org[$name] == stripslashes($this->$name)) {
01235 continue;
01236 }
01237 else if($this->fields[$name]->log_changes) {
01238 $log_changed_fields[]=$name;
01239 }
01240 }
01241 global $sql_obj;
01242 $t_pairs[]= $bla= $name.'='."'". asSecureString($this->$name)."'";
01243 }
01244 }
01245 if(count($t_pairs)) {
01246 $str_query= 'UPDATE '
01247 .$prefix.$this->_type
01248 .' SET ' . join(', ', $t_pairs)
01249 .' WHERE id='.$this->id ;
01250
01251 $sth= $dbh->prepare($str_query);
01252 $sth->execute("",1);
01253 }
01254
01255 if($log_changed_fields) {
01256 require_once(confGet('DIR_STREBER') . "db/db_itemchange.inc.php");
01257 foreach($log_changed_fields as $name) {
01258
01262 $c= new ItemChange(array(
01263 'item'=> $this->id,
01264 'field'=> $name,
01265 'value_old'=>$this->_values_org[$name],
01266 ));
01267 $c->insert();
01268 }
01269 }
01270 }
01271 return true;
01272 }
01273
01277 public function delete()
01278 {
01279 global $auth;
01280 if(!$this->id) {
01281 trigger_error("Deleting requires id", E_USER_WARNING);
01282 }
01283
01284
01285 ### check user-rights ###
01286 if($pp= $this->getProjectPerson()) {
01287
01288
01289 $pub_level= $this->pub_level;
01290
01291 ### owned ###
01292 if($this->created_by == $pp->person) {
01293 $pub_level= PUB_LEVEL_OWNED;
01294 }
01295
01296 ### is item editable ?
01297 if($pub_level >= $pp->level_delete
01298 ) {
01299 ### AND below delete-level ###
01300 if($pub_level >= $pp->level_delete
01301 ) {
01302 $this->state = -1;
01303 $this->deleted_by= $auth->cur_user->id;
01304 $this->deleted= getGMTString();
01305
01306 $this->update();
01307
01308 #--- deleting yourself? ----
01309 return true;
01310
01311 }
01312 }
01313 }
01314 ### not a project-item? ###
01315 #
01316 #@@@ be sure that rights deleting project, companies and persons is validated somewhere else
01317 #
01318 else if($this->project == 0) {
01319
01320 if($auth->cur_user) {
01321 $this->state = -1;
01322 $this->deleted_by= $auth->cur_user->id;
01323 $this->deleted= getGMTString();
01324
01325 $this->update();
01326 return true;
01327 }
01328 else {
01329 return false;
01330 }
01331 }
01332 return true;
01333 }
01334
01341 public function deleteFromDb()
01342 {
01343 if(!$this->id) {
01344 trigger_error("Deleting requires id",E_USER_ERROR);
01345 }
01346 $prefix= confGet('DB_TABLE_PREFIX');
01347
01348 $query = "DELETE FROM {$prefix}{$this->_type} WHERE id = {$this->id}";
01349 $dbh = new DB_Mysql;
01350 $dbh->prepare($query)->execute($this->id);
01351
01352
01353 $query = "DELETE FROM {$prefix}item WHERE id = {$this->id}";
01354 $dbh = new DB_Mysql;
01355 $dbh->prepare($query)->execute($this->id);
01356
01357 #--- deleting yourself? ----
01358 return true;
01359 }
01360
01361
01362
01366 public function getProjectPerson() {
01367 global $auth;
01368
01369 $prefix= confGet('DB_TABLE_PREFIX');
01370
01371 #--- get the belonging project-person ---
01372 $dbh = new DB_Mysql;
01373
01374 $sth= $dbh->prepare(
01375 "SELECT i.*, upp.* from {$prefix}item i, {$prefix}projectperson upp
01376 WHERE
01377 upp.person = {$auth->cur_user->id}
01378 AND upp.state = 1
01379 AND upp.project = $this->project
01380
01381 AND i.type = '".ITEM_PROJECTPERSON."'
01382 AND i.id = upp.id
01383 ");
01384 $sth->execute("",1);
01385 $tmp=$sth->fetchall_assoc();
01386
01387 ### return nothing if no rights ###
01388 if(count($tmp) != 1) {
01389 return NULL;
01390 }
01391 require_once(confGet('DIR_STREBER') . 'db/class_projectperson.inc.php');
01392 $pp=new ProjectPerson($tmp[0]);
01393 return $pp;
01394 }
01395
01402 public function getValidUserSetPublevel()
01403 {
01404 global $g_pub_level_names;
01405
01406 ### get belonging project person ###
01407 if($pp= $this->getProjectPerson()) {
01408 ### can we edit this object ? ###
01409 if(
01410 $pp->level_edit <= $this->pub_level
01411 ||
01412 $this->created_by ==