1<?php 2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4include_once('Services/Calendar/classes/class.ilDate.php'); 5include_once('./Services/Calendar/interfaces/interface.ilDatePeriod.php'); 6 7define('IL_CAL_TRANSLATION_NONE', 0); 8define('IL_CAL_TRANSLATION_SYSTEM', 1); 9 10 11/** 12* Model for a calendar entry. 13* 14* @author Stefan Meyer <meyer@leifos.com> 15* @version $Id$ 16* 17* 18* @ingroup ServicesCalendar 19*/ 20class ilCalendarEntry implements ilDatePeriod 21{ 22 protected $log; 23 protected $db; 24 25 26 protected $entry_id; 27 protected $last_update; 28 protected $title; 29 protected $subtitle; 30 protected $description; 31 protected $location; 32 protected $further_informations; 33 protected $start = null; 34 protected $fullday; 35 protected $end = null; 36 protected $is_auto_generated = false; 37 protected $context_id = 0; 38 protected $context_info = ''; 39 protected $translation_type = IL_CAL_TRANSLATION_NONE; 40 protected $is_milestone = false; 41 protected $completion = 0; 42 43 protected $notification = false; 44 45 /** 46 * Constructor 47 * 48 * @access public 49 * @param int cal_entry id 50 * 51 */ 52 public function __construct($a_id = 0) 53 { 54 global $DIC; 55 56 $ilDB = $DIC['ilDB']; 57 $this->log = $DIC->logger()->cal(); 58 59 $this->db = $ilDB; 60 61 if ($this->entry_id = $a_id) { 62 $this->read(); 63 } 64 } 65 66 /** 67 * clone instance 68 */ 69 public function __clone() 70 { 71 $this->entry_id = null; 72 } 73 74 /** 75 * delete entry 76 * 77 * @access public 78 * @static 79 * 80 */ 81 public static function _delete($a_entry_id) 82 { 83 global $DIC; 84 85 $ilDB = $DIC['ilDB']; 86 87 include_once('./Services/Calendar/classes/class.ilCalendarRecurrence.php'); 88 ilCalendarRecurrence::_delete($a_entry_id); 89 90 $query = "DELETE FROM cal_entries " . 91 "WHERE cal_id = " . $ilDB->quote($a_entry_id, 'integer') . " "; 92 $res = $ilDB->manipulate($query); 93 94 return true; 95 } 96 97 /** 98 * Set context info 99 * @param $a_info 100 */ 101 public function setContextInfo($a_info) 102 { 103 $this->context_info = $a_info; 104 } 105 106 /** 107 * @return string 108 */ 109 public function getContextInfo() 110 { 111 return $this->context_info; 112 } 113 114 /** 115 * get entry id 116 * 117 * @access public 118 * 119 */ 120 public function getEntryId() 121 { 122 return $this->entry_id; 123 } 124 125 /** 126 * get last update 127 * 128 * @access public 129 * @param 130 * @return 131 */ 132 public function getLastUpdate() 133 { 134 return $this->last_update ? $this->last_update : new ilDateTime(time(), IL_CAL_UNIX); 135 } 136 137 /** 138 * set last update 139 * 140 * @access public 141 * @param 142 * @return 143 */ 144 public function setLastUpdate($a_date) 145 { 146 $this->last_update = $a_date; 147 } 148 149 150 /** 151 * get start 152 * 153 * @access public 154 * @return 155 */ 156 public function getStart() 157 { 158 return $this->start; 159 } 160 161 /** 162 * 163 * @access public 164 * @param 165 * @return 166 */ 167 public function setStart($a_start) 168 { 169 $this->start = $a_start; 170 } 171 172 /** 173 * get end 174 * @access public 175 * @return ilDateTime end 176 */ 177 public function getEnd() 178 { 179 return $this->end; 180 } 181 182 /** 183 * set end 184 * @access public 185 * @param 186 */ 187 public function setEnd($a_end) 188 { 189 $this->end = $a_end; 190 } 191 192 /** 193 * set title 194 * 195 * @access public 196 * @param string title 197 * 198 */ 199 public function setTitle($a_title) 200 { 201 $this->title = $a_title; 202 } 203 204 /** 205 * get title 206 * 207 * @access public 208 * 209 */ 210 public function getTitle() 211 { 212 return $this->title; 213 } 214 215 /** 216 * get title for presentation. 217 * Special handling for auto generated appointments 218 * 219 * @access public 220 * @return 221 */ 222 public function getPresentationTitle($a_shorten = true) 223 { 224 global $DIC; 225 226 $lng = $DIC['lng']; 227 228 if ($this->getTranslationType() == IL_CAL_TRANSLATION_NONE) { 229 $title = $this->getTitle(); 230 } elseif (strlen($this->getSubtitle())) { 231 // parse dynamic title? 232 if (preg_match("/#([a-z]+)#/", $this->getSubtitle(), $matches)) { 233 $subtitle = $this->parseDynamicTitle($matches[1]); 234 } else { 235 $subtitle = $lng->txt($this->getSubtitle()); 236 } 237 $title = $this->getTitle() . 238 (strlen($subtitle) 239 ? ' (' . $subtitle . ')' 240 : ''); 241 } else { 242 $title = $lng->txt($this->getTitle()); 243 } 244 245 if ($a_shorten) { 246 return ilUtil::shortenText(ilUtil::shortenWords($title, 20), 40, true); 247 } 248 return $title; 249 } 250 251 public function getPresentationStyle() 252 { 253 // see parseDynamicTitle() 254 return $this->presentation_style; 255 } 256 257 protected function parseDynamicTitle($a_type) 258 { 259 global $DIC; 260 261 $lng = $DIC['lng']; 262 263 $title = $style = ""; 264 switch ($a_type) { 265 case "consultationhour": 266 include_once 'Services/Booking/classes/class.ilBookingEntry.php'; 267 $entry = new ilBookingEntry($this->getContextId()); 268 if ($entry) { 269 if ($entry->isOwner()) { 270 $max = (int) $entry->getNumberOfBookings(); 271 $current = (int) $entry->getCurrentNumberOfBookings($this->getEntryId()); 272 if (!$current) { 273 $style = ';border-left-width: 5px; border-left-style: solid; border-left-color: green'; 274 $title = $lng->txt('cal_book_free'); 275 } elseif ($current >= $max) { 276 $style = ';border-left-width: 5px; border-left-style: solid; border-left-color: red'; 277 $title = $lng->txt('cal_booked_out'); 278 } else { 279 $style = ';border-left-width: 5px; border-left-style: solid; border-left-color: yellow'; 280 $title = $current . '/' . $max; 281 } 282 } else { 283 /* 284 * if($entry->hasBooked($this->getEntryId())) 285 */ 286 include_once 'Services/Calendar/classes/ConsultationHours/class.ilConsultationHourAppointments.php'; 287 $apps = ilConsultationHourAppointments::getAppointmentIds($entry->getObjId(), $this->getContextId(), $this->getStart()); 288 $orig_event = $apps[0]; 289 if ($entry->hasBooked($orig_event)) { 290 $style = ';border-left-width: 5px; border-left-style: solid; border-left-color: green'; 291 $title = $lng->txt('cal_date_booked'); 292 } 293 } 294 } 295 break; 296 } 297 298 if ($style) { 299 $this->presentation_style = $style; 300 } 301 return $title; 302 } 303 304 /** 305 * set subtitle 306 * Used for automatic generated appointments. 307 * Will be appended to the title. 308 * 309 * @access public 310 * @param string subtitle 311 * @return 312 */ 313 public function setSubtitle($a_subtitle) 314 { 315 $this->subtitle = $a_subtitle; 316 } 317 318 /** 319 * get subtitle 320 * 321 * @access public 322 * @return 323 */ 324 public function getSubtitle() 325 { 326 return $this->subtitle; 327 } 328 329 /** 330 * set description 331 * 332 * @access public 333 * @param string description 334 * 335 */ 336 public function setDescription($a_description) 337 { 338 $this->description = $a_description; 339 } 340 341 /** 342 * get description 343 * 344 * @access public 345 */ 346 public function getDescription() 347 { 348 return $this->description; 349 } 350 351 /** 352 * set location 353 * 354 * @access public 355 * @param string location 356 * 357 */ 358 public function setLocation($a_location) 359 { 360 $this->location = $a_location; 361 } 362 363 /** 364 * get location 365 * 366 * @access public 367 */ 368 public function getLocation() 369 { 370 return $this->location; 371 } 372 373 /** 374 * set further informations 375 * 376 * @access public 377 * @param string further informations 378 * 379 */ 380 public function setFurtherInformations($a_informations) 381 { 382 $this->further_informations = $a_informations; 383 } 384 385 /** 386 * get further informations 387 * 388 * @access public 389 */ 390 public function getFurtherInformations() 391 { 392 return $this->further_informations; 393 } 394 395 /** 396 * set fullday event 397 * Fullday events do not change their time in different timezones. 398 * It is possible to create fullday events with a duration of more than one day. 399 * 400 * @access public 401 * @param bool fullday 402 * 403 */ 404 public function setFullday($a_fullday) 405 { 406 $this->fullday = (bool) $a_fullday; 407 } 408 409 /** 410 * is fullday 411 * 412 * @access public 413 */ 414 public function isFullday() 415 { 416 return (bool) $this->fullday; 417 } 418 419 /** 420 * is auto generated 421 * 422 * @access public 423 * @param 424 * @return 425 */ 426 public function isAutoGenerated() 427 { 428 return (bool) $this->is_auto_generated; 429 } 430 431 /** 432 * set auto generated 433 * 434 * @access public 435 * @param 436 * @return 437 */ 438 public function setAutoGenerated($a_status) 439 { 440 $this->is_auto_generated = $a_status; 441 } 442 443 /** 444 * is milestone 445 * 446 * @access public 447 * @param 448 * @return 449 */ 450 public function isMilestone() 451 { 452 return (bool) $this->is_milestone; 453 } 454 455 /** 456 * set milestone 457 * 458 * @access public 459 * @param 460 * @return 461 */ 462 public function setMilestone($a_status) 463 { 464 $this->is_milestone = $a_status; 465 } 466 467 /** 468 * Set Completion. 469 * 470 * @param int $a_completion Completion 471 */ 472 public function setCompletion($a_completion) 473 { 474 $this->completion = $a_completion; 475 } 476 477 /** 478 * Get Completion. 479 * 480 * @return int Completion 481 */ 482 public function getCompletion() 483 { 484 return $this->completion; 485 } 486 487 /** 488 * set context id 489 * 490 * @access public 491 * @param int context id 492 * @return 493 */ 494 public function setContextId($a_context_id) 495 { 496 $this->context_id = $a_context_id; 497 } 498 499 /** 500 * get context id 501 * 502 * @access public 503 * @return 504 */ 505 public function getContextId() 506 { 507 return $this->context_id; 508 } 509 510 /** 511 * 512 * 513 * @access public 514 * @param 515 * @return 516 */ 517 public function setTranslationType($a_type) 518 { 519 $this->translation_type = $a_type; 520 } 521 522 /** 523 * get translation type 524 * 525 * @access public 526 * @return int translation type 527 */ 528 public function getTranslationType() 529 { 530 return $this->translation_type; 531 } 532 533 /** 534 * Enable course group notification 535 * @param bool $a_status 536 */ 537 public function enableNotification($a_status) 538 { 539 $this->notification = $a_status; 540 } 541 542 /** 543 * Check if course group notification is enabled 544 * @return bool 545 */ 546 public function isNotificationEnabled() 547 { 548 return (bool) $this->notification; 549 } 550 551 /** 552 * update 553 * 554 * @access public 555 * 556 */ 557 public function update() 558 { 559 global $DIC; 560 561 $ilDB = $DIC['ilDB']; 562 563 $now = new ilDateTime(time(), IL_CAL_UNIX); 564 $utc_timestamp = $now->get(IL_CAL_DATETIME, '', ilTimeZone::UTC); 565 566 567 $query = "UPDATE cal_entries " . 568 "SET title = " . $this->db->quote($this->getTitle(), 'text') . ", " . 569 "last_update = " . $ilDB->quote($utc_timestamp, 'timestamp') . ", " . 570 "subtitle = " . $this->db->quote($this->getSubtitle(), 'text') . ", " . 571 "description = " . $this->db->quote($this->getDescription(), 'text') . ", " . 572 "location = " . $this->db->quote($this->getLocation(), 'text') . ", " . 573 "fullday = " . $ilDB->quote($this->isFullday() ? 1 : 0, 'integer') . ", " . 574 "starta = " . $this->db->quote($this->getStart()->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ", " . 575 "enda = " . $this->db->quote($this->getEnd()->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ", " . 576 "informations = " . $this->db->quote($this->getFurtherInformations(), 'text') . ", " . 577 "auto_generated = " . $this->db->quote($this->isAutoGenerated(), 'integer') . ", " . 578 "translation_type = " . $this->db->quote($this->getTranslationType(), 'integer') . ", " . 579 "context_id = " . $this->db->quote($this->getContextId(), 'integer') . ", " . 580 'context_info = ' . $this->db->quote($this->getContextInfo(), 'text') . ', ' . 581 "completion = " . $this->db->quote($this->getCompletion(), 'integer') . ", " . 582 "is_milestone = " . $this->db->quote($this->isMilestone() ? 1 : 0, 'integer') . ", " . 583 'notification = ' . $this->db->quote($this->isNotificationEnabled() ? 1 : 0, 'integer') . ' ' . 584 "WHERE cal_id = " . $this->db->quote($this->getEntryId(), 'integer') . " "; 585 $res = $ilDB->manipulate($query); 586 587 return true; 588 } 589 590 /** 591 * save one entry 592 * 593 * @access public 594 * 595 */ 596 public function save() 597 { 598 global $DIC; 599 600 $ilDB = $DIC['ilDB']; 601 602 $next_id = $ilDB->nextId('cal_entries'); 603 $now = new ilDateTime(time(), IL_CAL_UNIX); 604 $utc_timestamp = $now->get(IL_CAL_DATETIME, '', ilTimeZone::UTC); 605 606 $query = "INSERT INTO cal_entries (cal_id,title,last_update,subtitle,description,location,fullday,starta,enda, " . 607 "informations,auto_generated,context_id,context_info,translation_type, completion, is_milestone, notification) " . 608 "VALUES( " . 609 $ilDB->quote($next_id, 'integer') . ", " . 610 $this->db->quote($this->getTitle(), 'text') . ", " . 611 $ilDB->quote($utc_timestamp, 'timestamp') . ", " . 612 $this->db->quote($this->getSubtitle(), 'text') . ", " . 613 $this->db->quote($this->getDescription(), 'text') . ", " . 614 $this->db->quote($this->getLocation(), 'text') . ", " . 615 $ilDB->quote($this->isFullday() ? 1 : 0, 'integer') . ", " . 616 $this->db->quote($this->getStart()->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ", " . 617 $this->db->quote($this->getEnd()->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ", " . 618 $this->db->quote($this->getFurtherInformations(), 'text') . ", " . 619 $this->db->quote($this->isAutoGenerated(), 'integer') . ", " . 620 $this->db->quote($this->getContextId(), 'integer') . ", " . 621 $this->db->quote($this->getContextInfo(), 'text') . ', ' . 622 $this->db->quote($this->getTranslationType(), 'integer') . ", " . 623 $this->db->quote($this->getCompletion(), 'integer') . ", " . 624 $this->db->quote($this->isMilestone() ? 1 : 0, 'integer') . ", " . 625 $this->db->quote($this->isNotificationEnabled() ? 1 : 0, 'integer') . ' ' . 626 ")"; 627 $res = $ilDB->manipulate($query); 628 629 $this->entry_id = $next_id; 630 return true; 631 } 632 633 /** 634 * delete 635 * 636 * @access public 637 * @return 638 */ 639 public function delete() 640 { 641 global $DIC; 642 643 $ilDB = $DIC['ilDB']; 644 645 include_once('./Services/Calendar/classes/class.ilCalendarRecurrence.php'); 646 ilCalendarRecurrence::_delete($this->getEntryId()); 647 648 $query = "DELETE FROM cal_entries " . 649 "WHERE cal_id = " . $this->db->quote($this->getEntryId(), 'integer') . " "; 650 $res = $ilDB->manipulate($query); 651 652 include_once './Services/Calendar/classes/class.ilCalendarCategoryAssignments.php'; 653 ilCalendarCategoryAssignments::_deleteByAppointmentId($this->getEntryId()); 654 655 return true; 656 } 657 658 /** 659 * validate 660 * 661 * @access public 662 * @return 663 */ 664 public function validate() 665 { 666 global $DIC; 667 668 $ilErr = $DIC['ilErr']; 669 $lng = $DIC['lng']; 670 671 $success = true; 672 $ilErr->setMessage(''); 673 if (!strlen($this->getTitle())) { 674 $success = false; 675 $ilErr->appendMessage($lng->txt('err_missing_title')); 676 } 677 if (!$this->getStart() || !$this->getEnd()) { 678 $success = false; 679 } elseif (ilDateTime::_before($this->getEnd(), $this->getStart(), '')) { 680 $success = false; 681 $ilErr->appendMessage($lng->txt('err_end_before_start')); 682 } 683 return $success; 684 } 685 686 687 688 /** 689 * @access protected 690 * @param 691 * 692 */ 693 protected function read() 694 { 695 global $DIC; 696 697 $ilDB = $DIC['ilDB']; 698 699 $query = "SELECT * FROM cal_entries WHERE cal_id = " . $this->db->quote($this->getEntryId(), 'integer') . " "; 700 $res = $this->db->query($query); 701 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) { 702 $this->setLastUpdate(new ilDateTime($row->last_update, IL_CAL_DATETIME, 'UTC')); 703 $this->setTitle($row->title); 704 $this->setSubtitle($row->subtitle); 705 $this->setDescription($row->description); 706 $this->setLocation($row->location); 707 $this->setFurtherInformations($row->informations); 708 $this->setFullday((bool) $row->fullday); 709 $this->setAutoGenerated($row->auto_generated); 710 $this->setContextId($row->context_id); 711 $this->setContextInfo($row->context_info); 712 $this->setTranslationType($row->translation_type); 713 $this->setCompletion($row->completion); 714 $this->setMilestone($row->is_milestone); 715 $this->enableNotification((bool) $row->notification); 716 717 if ($this->isFullday()) { 718 $this->start = new ilDate($row->starta, IL_CAL_DATETIME); 719 $this->end = new ilDate($row->enda, IL_CAL_DATETIME); 720 } else { 721 $this->start = new ilDateTime($row->starta, IL_CAL_DATETIME, 'UTC'); 722 $this->end = new ilDateTime($row->enda, IL_CAL_DATETIME, 'UTC'); 723 } 724 } 725 } 726 727 /** 728 * 729 * @param ilLanguage $lng 730 * @return 731 */ 732 public function appointmentToMailString($lng) 733 { 734 $body = $lng->txt('cal_details'); 735 $body .= "\n\n"; 736 $body .= $lng->txt('title') . ': ' . $this->getTitle() . "\n"; 737 738 ilDatePresentation::setUseRelativeDates(false); 739 $body .= $lng->txt('date') . ': ' . ilDatePresentation::formatPeriod($this->getStart(), $this->getEnd()) . "\n"; 740 ilDatePresentation::setUseRelativeDates(true); 741 742 if (strlen($this->getLocation())) { 743 $body .= $lng->txt('cal_where') . ': ' . $this->getLocation() . "\n"; 744 } 745 746 if (strlen($this->getDescription())) { 747 $body .= $lng->txt('description') . ': ' . $this->getDescription() . "\n"; 748 } 749 return $body; 750 } 751 752 753 /** 754 * Write users responsible for a milestone 755 */ 756 public function writeResponsibleUsers($a_users) 757 { 758 global $DIC; 759 760 $ilDB = $DIC['ilDB']; 761 762 $ilDB->manipulateF( 763 "DELETE FROM cal_entry_responsible WHERE cal_id = %s", 764 array("integer"), 765 array($this->getEntryId()) 766 ); 767 768 if (is_array($a_users)) { 769 foreach ($a_users as $user_id) { 770 $ilDB->manipulateF( 771 "INSERT INTO cal_entry_responsible (cal_id, user_id) " . 772 " VALUES (%s,%s)", 773 array("integer", "integer"), 774 array($this->getEntryId(), $user_id) 775 ); 776 } 777 } 778 779 $this->responsible_users = $a_users; 780 } 781 782 /** 783 * Read responsible users 784 */ 785 public function readResponsibleUsers() 786 { 787 global $DIC; 788 789 $ilDB = $DIC['ilDB']; 790 791 $set = $ilDB->queryF( 792 "SELECT * FROM cal_entry_responsible WHERE cal_id = %s", 793 array("integer"), 794 array($this->getEntryId()) 795 ); 796 797 $return = array(); 798 while ($rec = $ilDB->fetchAssoc($set)) { 799 $n = ilObjUser::_lookupName($rec["user_id"]); 800 $return[] = array_merge( 801 $n, 802 array("login" => ilObjUser::_lookupLogin($rec["user_id"])) 803 ); 804 } 805 806 return $return; 807 } 808} 809