3 * FusionForge project manager
5 * Copyright 1999-2000, Tim Perdue/Sourceforge
6 * Copyright 2002, Tim Perdue/GForge, LLC
7 * Copyright 2009, Roland Mas
9 * This file is part of FusionForge.
11 * FusionForge is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published
13 * by the Free Software Foundation; either version 2 of the License,
14 * or (at your option) any later version.
16 * FusionForge is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with FusionForge; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 require_once $gfcommon.'include/Error.class.php';
28 require_once $gfcommon.'include/Validator.class.php';
30 function &projecttask_get_object($project_task_id,$data=false) {
31 global $PROJECTTASK_OBJ;
32 if (!isset($PROJECTTASK_OBJ["_".$project_task_id."_"])) {
34 //the db result handle was passed in
36 $res = db_query_params ('SELECT * FROM project_task_vw WHERE project_task_id=$1',
37 array ($project_task_id)) ;
39 if (db_numrows($res) <1 ) {
40 $PROJECTTASK_OBJ["_".$project_task_id."_"]=false;
43 $data = db_fetch_array($res);
46 $ProjectGroup =& projectgroup_get_object($data["group_project_id"]);
47 $PROJECTTASK_OBJ["_".$project_task_id."_"]= new ProjectTask($ProjectGroup,$project_task_id,$data);
51 return $PROJECTTASK_OBJ["_".$project_task_id."_"];
55 Types of task dependencies
57 define('PM_LINK_DEFAULT','FS');
58 define('PM_LINK_START_START','SS');
59 define('PM_LINK_START_FINISH','SF');
60 define('PM_LINK_FINISH_START','FS');
61 define('PM_LINK_FINISH_FINISH','FF');
63 class ProjectTask extends Error {
66 * Associative array of data from db.
68 * @var array $data_array.
73 * The ProjectGroup object.
75 * @var object $ProjectGroup.
80 var $relatedartifacts;
85 * @param object The ProjectGroup object to which this ProjectTask is associated.
86 * @param int The project_task_id.
87 * @param array The associative array of data.
88 * @return boolean success.
90 function ProjectTask(&$ProjectGroup, $project_task_id=false, $arr=false) {
92 if (!$ProjectGroup || !is_object($ProjectGroup)) {
93 $this->setError('ProjectTask:: No Valid ProjectGroup Object');
96 if ($ProjectGroup->isError()) {
97 $this->setError('ProjectTask:: '.$ProjectGroup->getErrorMessage());
100 $this->ProjectGroup =& $ProjectGroup;
102 if ($project_task_id) {
103 if (!$arr || !is_array($arr)) {
104 if (!$this->fetchData($project_task_id)) {
108 $this->data_array =& $arr;
110 // Verify this message truly belongs to this ProjectGroup
112 if ($this->data_array['group_project_id'] != $this->ProjectGroup->getID()) {
113 $this->setError('Group_project_id in db result does not match ProjectGroup Object');
122 * create - create a new ProjectTask in the database.
124 * @param string The summary of this task.
125 * @param string The detailed description of this task.
126 * @param int The Priority of this task.
127 * @param int The Hours estimated to complete this task.
128 * @param int The (unix) start date of this task.
129 * @param int The (unix) end date of this task.
130 * @param int The category_id of this task.
131 * @param int The percentage of completion in integer format of this task.
132 * @param array An array of user_id's that are assigned this task.
133 * @param array An array of project_task_id's that this task depends on.
134 * @param int The duration of the task in days.
135 * @param int The id of the parent task, if any.
136 * @return boolean success.
138 function create($summary,$details,$priority,$hours,$start_date,$end_date,
139 $category_id,$percent_complete,&$assigned_arr,&$depend_arr,$duration=0,$parent_id=0) {
140 $v = new Validator();
141 $v->check($summary, "summary");
142 $v->check($details, "details");
143 $v->check($priority, "priority");
144 $v->check($hours, "hours");
145 $v->check($start_date, "start date");
146 $v->check($end_date, "end date");
147 $v->check($category_id, "category");
148 if (!$v->isClean()) {
149 $this->setError($v->formErrorMsg("Must include "));
158 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
159 $this->setPermissionDeniedError();
164 $res = db_query_params ('SELECT nextval($1) AS id',
165 array ('project_task_pk_seq'));
166 if (!$project_task_id=db_result($res,0,'id')) {
167 $this->setError( 'Could Not Get Next Project Task ID' );
172 $this->data_array['project_task_id']=$project_task_id;
174 $result = db_query_params ('INSERT INTO project_task (project_task_id,group_project_id,created_by,summary,details,start_date,end_date,status_id,category_id,priority,percent_complete,hours,duration,parent_id) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)',
175 array ($project_task_id,
176 $this->ProjectGroup->getID(),
178 htmlspecialchars($summary),
179 htmlspecialchars($details),
190 if (!$result || db_affected_rows($result) < 1) {
191 $this->setError('ProjectTask::create() Posting Failed '.db_error().$sql);
196 if (!$this->setDependentOn($depend_arr)) {
200 if (!$this->setAssignedTo($assigned_arr)) {
204 if (!$this->fetchData($project_task_id)) {
208 $this->sendNotice(1);
214 * fetchData - re-fetch the data for this ProjectTask from the database.
216 * @param int The project_task_id.
217 * @return boolean success.
219 function fetchData($project_task_id) {
220 $res = db_query_params ('SELECT * FROM project_task_vw
221 WHERE project_task_id=$1
222 AND group_project_id=$2',
223 array ($project_task_id,
224 $this->ProjectGroup->getID())) ;
225 if (!$res || db_numrows($res) < 1) {
226 $this->setError('ProjectTask::fetchData() Invalid Task ID'.db_error());
229 $this->data_array = db_fetch_array($res);
230 db_free_result($res);
235 * getProjectGroup - get the ProjectGroup object this ProjectTask is associated with.
237 * @return Object The ProjectGroup object.
239 function &getProjectGroup() {
240 return $this->ProjectGroup;
244 * getID - get this project_task_id.
246 * @return int The project_task_id.
249 return $this->data_array['project_task_id'];
253 * getSubmittedRealName - get the real name of the person who created this task.
255 * @return string The real name person who created this task.
257 function getSubmittedRealName() {
258 return $this->data_array['realname'];
262 * getDuration - the duration of the task.
264 * @return int The number of days of duration.
266 function getDuration() {
267 return $this->data_array['duration'];
271 * getParentID - the task_id of the parent task, if any.
273 * @return string The real name person who created this task.
275 function getParentID() {
276 return $this->data_array['parent_id'];
280 * getSubmittedUnixName - get the unix name of the person who created this task.
282 * @return string The unix name of the person who created this task.
284 function getSubmittedUnixName() {
285 return $this->data_array['user_name'];
289 * getSummary - get the subject/summary of this task.
291 * @return string The summary.
293 function getSummary() {
294 return $this->data_array['summary'];
298 * getDetails - get the body/details of this task.
300 * @return string The body/details.
302 function getDetails() {
303 return $this->data_array['details'];
307 * getPercentComplete - an integer between 0 and 100.
309 * @return int The percentage of completion of this task.
311 function getPercentComplete() {
312 return $this->data_array['percent_complete'];
316 * getPriority - the priority, between 1 and 9 of this task.
318 * @return int The priority.
320 function getPriority() {
321 return $this->data_array['priority'];
325 * getHours - the hours this task is expected to take.
327 * @return int The hours.
329 function getHours() {
330 return $this->data_array['hours'];
334 * getStartDate - the unix time that this task will start.
336 * @return int The unix start time of this task.
338 function getStartDate() {
339 return $this->data_array['start_date'];
343 * getEndDate - the unix time that this task will end.
345 * @return int The unix end time of this task.
347 function getEndDate() {
348 return $this->data_array['end_date'];
352 * getStatusID - the integer of the status of this task.
354 * @return int the status_id.
356 function getStatusID() {
357 return $this->data_array['status_id'];
361 * getStatusName - the string of the status of this task.
363 * @return string the status_name.
365 function getStatusName() {
366 return $this->data_array['status_name'];
370 * getCategoryID - the category_id of this task.
372 * @return int the category_id.
374 function getCategoryID() {
375 return $this->data_array['category_id'];
379 * getCategoryName - the category_name of this task.
381 * @return int the category_name.
383 function getCategoryName() {
384 return $this->data_array['category_name'];
388 * getLastModifiedDate - the last_modified_date of this task.
390 * @return int the last_modified_date.
392 function getLastModifiedDate() {
393 return $this->data_array['last_modified_date'];
397 * setExternalID - set a row in project_task_external_order which stores
398 * an id, for example an ID generated by MS Project, which needs to be restored later
400 function setExternalID($id) {
401 $res = db_query_params ('UPDATE project_task_external_order SET external_id=$1
402 WHERE project_task_id=$2',
405 if (db_affected_rows($res) < 1) {
406 $res = db_query_params ('INSERT INTO project_task_external_order (project_task_id,external_id) VALUES ($1, $2)',
407 array ($this->getID(),
413 * getExternalID - get the ID that MS Project uses to sort tasks
415 * @return int the id.
417 function getExternalID() {
418 return $this->data_array['external_id'];
422 * getRelatedArtifacts - Return a result set of artifacts which are related to this task.
424 * @returns Database result set.
426 function getRelatedArtifacts() {
427 if (!$this->relatedartifacts) {
428 $this->relatedartifacts=
429 db_query_params ('SELECT agl.group_id,agl.name,agl.group_artifact_id,a.artifact_id,a.open_date,a.summary
430 FROM artifact_group_list agl, artifact a
431 WHERE a.group_artifact_id=agl.group_artifact_id
432 AND EXISTS (SELECT artifact_id FROM project_task_artifact
433 WHERE artifact_id=a.artifact_id
434 AND project_task_id=$1)',
435 array ($this->getID())) ;
437 return $this->relatedartifacts;
441 * addRelatedArtifacts - take an array of artifact_id's and build relationships.
443 * @param array An array of artifact_id's to be attached to this task.
444 * @return boolean success.
446 function addRelatedArtifacts($art_array) {
447 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
448 $this->setPermissionDeniedError();
452 // SHOULD REALLY INSTANTIATE THIS ARTIFACT OBJECT TO ENSURE PROPER SECURITY - FUTURE
454 // new ArtifactFromID($id)
456 for ($i=0; $i<count($art_array); $i++) {
457 if ($art_array[$i] < 1) {
460 $res = db_query_params ('INSERT INTO project_task_artifact (project_task_id,artifact_id) VALUES ($1,$2)',
461 array ($this->getID(),
464 $this->setError('Error inserting artifact relationship: '.db_error());
472 * removeRelatedArtifacts - take an array of artifact_id's and delete relationships.
474 * @param array An array of artifact_id's to be removed from this task.
475 * @return boolean success.
477 function removeRelatedArtifacts($art_array) {
478 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
479 $this->setPermissionDeniedError();
483 for ($i=0; $i<count($art_array); $i++) {
484 $res = db_query_params ('DELETE FROM project_task_artifact
485 WHERE project_task_id=$1
487 array ($this->getID(),
490 $this->setError('Error deleting artifact relationship: '.db_error());
498 * delete - delete this tracker and all its related data.
500 * @param bool I'm Sure.
501 * @return bool true/false;
503 function delete($sure) {
505 $this->setMissingParamsError();
508 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
509 $this->setPermissionDeniedError();
514 $res = db_query_params ('DELETE FROM project_assigned_to WHERE project_task_id=$1',
515 array ($this->getID())) ;
517 $this->setError('Error deleting assigned users relationship: '.db_error());
521 $res = db_query_params ('DELETE FROM project_dependencies WHERE project_task_id=$1',
522 array ($this->getID())) ;
524 $this->setError('Error deleting dependencies: '.db_error());
528 $res = db_query_params ('DELETE FROM project_history WHERE project_task_id=$1',
529 array ($this->getID())) ;
531 $this->setError('Error deleting history: '.db_error());
535 $res = db_query_params ('DELETE FROM project_messages WHERE project_task_id=$1',
536 array ($this->getID())) ;
538 $this->setError('Error deleting messages: '.db_error());
542 $res = db_query_params ('DELETE FROM project_task_artifact WHERE project_task_id=$1',
543 array ($this->getID())) ;
545 $this->setError('Error deleting artifacts: '.db_error());
549 $res = db_query_params ('DELETE FROM rep_time_tracking WHERE project_task_id=$1',
550 array ($this->getID())) ;
552 $this->setError('Error deleting time tracking report: '.db_error());
556 $res = db_query_params ('DELETE FROM project_task WHERE project_task_id=$1',
557 array ($this->getID())) ;
559 $this->setError('Error deleting task: '.db_error());
569 * getOtherTasks - Return a result set of tasks in this subproject that do not equal
570 * the current task_id.
572 * @returns Database result set.
574 function getOtherTasks () {
576 // May not yet have an ID, if we are creating a NEW task
578 if ($this->getID()) {
579 return db_query_params ('SELECT project_task_id,summary
581 WHERE group_project_id=$1
582 AND project_task_id <> $2
583 ORDER BY project_task_id DESC',
584 array ($this->ProjectGroup->getID(),
587 return db_query_params ('SELECT project_task_id,summary
589 WHERE group_project_id=$1
590 ORDER BY project_task_id DESC',
591 array ($this->ProjectGroup->getID())) ;
596 * getHistory - returns a result set of audit trail for this ProjectTask.
598 * @return database result set.
600 function getHistory() {
601 return db_query_params ('SELECT *
602 FROM project_history_user_vw
603 WHERE project_task_id=$1
604 ORDER BY mod_date DESC',
605 array ($this->getID())) ;
609 * getMessages - get the list of messages attached to this ProjectTask.
611 * @return database result set.
613 function getMessages() {
614 return db_query_params ('SELECT *
615 FROM project_message_user_vw
616 WHERE project_task_id=$1
617 ORDER BY postdate DESC',
618 array ($this->getID())) ;
622 * addMessage - Handle the addition of a followup message to this task.
624 * @param string The message.
625 * @returns boolean success.
627 function addMessage($message) {
628 //prevent posting the same message
629 if ($this->getDetails() == htmlspecialchars($message)) {
632 $res = db_query_params ('SELECT * FROM project_messages
633 WHERE project_task_id=$1
635 array ($this->getID(),
636 htmlspecialchars($message))) ;
637 if (!$res || db_numrows($res) < 1) {
638 $res = db_query_params ('INSERT INTO project_messages (project_task_id,body,posted_by,postdate) VALUES ($1,$2,$3,$4)',
639 array ($this->getID(),
640 htmlspecialchars($message),
643 if (!$res || db_affected_rows($res) < 1) {
644 $this->setError('AddMessage():: '.db_error());
655 * addHistory - Handle the insertion of history for these parameters.
657 * @param string The field name.
658 * @param string The old value.
659 * @returns boolean success.
661 function addHistory ($field_name,$old_value) {
662 $result = db_query_params ('INSERT INTO project_history (project_task_id,field_name,old_value,mod_by,mod_date) VALUES ($1,$2,$3,$4,$5)',
663 array ($this->getID(),
669 $this->setError('ERROR IN AUDIT TRAIL - '.db_error());
677 * checkCircular - recursive function calls itself to look at all tasks you are dependent on.
679 * @param int The project_task_id you are dependent on.
680 * @param int The project_task_id you are checking circular dependencies for.
681 * @returns boolean success.
683 function checkCircular($depend_on_id, $original_id) {
684 //for msproject users - ms project has more complex logic than gforge
687 if ($depend_on_id == $original_id) {
688 $this->setError(_('Circular Dependency Detected\''));
692 $res = db_query_params ('SELECT is_dependent_on_task_id AS id
693 FROM project_dependencies
694 WHERE project_task_id=$1',
695 array ($depend_on_id)) ;
696 $rows=db_numrows($res);
698 for ($i=0; $i<$rows; $i++) {
699 if (!$this->checkCircular(db_result($res,$i,'id'), $original_id)) {
707 * setDependentOn - takes an array of project_task_id's and builds dependencies.
709 * @param array The array of project_task_id's.
710 * @returns boolean success.
712 function setDependentOn(&$arr_) {
713 //printr($arr_,'setDependentOn entry');
715 // IMPORTANT - MUST VERIFY NO CIRCULAR DEPENDENCY!!
717 if (!$arr_ || empty($arr_)) {
718 $arr_=array('100'=>PM_LINK_DEFAULT);
720 $arr = array_keys($arr_);
721 //get existing dependencies to diff against
722 $arr2 = array_keys($this->getDependentOn());
724 if (count($arr) || count($arr2)) {
725 $add_arr = array_values (array_diff ($arr, $arr2));
726 //echo "add arr: ".print_r($add_arr);
727 $del_arr = array_values (array_diff ($arr2, $arr));
728 //echo "del arr: ".print_r($del_arr);
729 for ($i=0; $i<count($del_arr); $i++) {
730 db_query_params ('DELETE FROM project_dependencies
731 WHERE project_task_id=$1
732 AND is_dependent_on_task_id=$2',
733 array ($this->getID(),
736 $this->setError('setDependentOn()-1:: '.db_error());
740 for ($i=0; $i<count($add_arr); $i++) {
742 // Check task for circular dependencies
744 if (!$this->checkCircular($add_arr[$i],$this->getID())) {
747 $lnk = $arr_[$add_arr[$i]];
749 $lnk=PM_LINK_DEFAULT;
751 db_query_params ('INSERT INTO project_dependencies (project_task_id,is_dependent_on_task_id,link_type) VALUES ($1,$2,$3)',
752 array ($this->getID(),
756 $this->setError('setDependentOn()-2:: '.db_error().$sql);
767 * convertDependentOn - converts a regular array of dependencies, such
768 * as from a multiple-select-box to an associative array with default
769 * link types. Should be called from web code as part of the create/update calls.
770 * Here we are converting an array like array(1,5,9,77) to array(1=>SS,5=>SF,9=>FS,77=>SS)
772 function &convertDependentOn($arr) {
773 $deps = $this->getDependentOn();
774 for ($i=0; $i<count($arr); $i++) {
775 if ($deps[$arr[$i]]) {
776 //use existing link_type if it exists
777 $new[$arr[$i]]=$deps[$arr[$i]];
779 //else create with default link type
780 $new[$arr[$i]]=PM_LINK_DEFAULT;
787 * getDependentOn - get an array of project_task_id's that you are dependent on.
789 * @return array The array of project_task_id's in this format:
790 * array($id=>$link_type,id2=>link_type2).
792 function getDependentOn() {
793 if (!$this->getID()) {
796 if (!$this->dependon) {
797 $res = db_query_params ('SELECT is_dependent_on_task_id,link_type
798 FROM project_dependencies
799 WHERE project_task_id=$1',
800 array ($this->getID())) ;
801 for ($i=0; $i<db_numrows($res); $i++) {
802 $this->dependon[db_result($res,$i,'is_dependent_on_task_id')] = db_result($res,$i,'link_type');
805 /* fix bug 319: if dependentlist is emtpy, set it to 100 (none) */
806 if (!$this->dependon) {
807 $this->dependon[100]=PM_LINK_DEFAULT;
809 return $this->dependon;
813 * setAssignedTo - takes an array of user_id's and builds assignments.
815 * @param array The array of user_id's.
816 * @returns boolean success.
818 function setAssignedTo(&$arr) {
819 $arr2 = $this->getAssignedTo();
820 $this->assignedto =& $arr;
822 //If no one is assigned, then assign it to "100" - NOBODY
823 if (!$arr || count($arr) < 1 || ((count($arr)==1) && ($arr[0]==''))) {
826 if (count($arr) || count($arr2)) {
827 $add_arr = array_values(array_diff ($arr, $arr2));
828 $del_arr = array_values(array_diff ($arr2, $arr));
829 for ($i=0; $i<count($del_arr); $i++) {
830 db_query_params ('DELETE FROM project_assigned_to
831 WHERE project_task_id=$1
832 AND assigned_to_id=$2',
833 array ($this->getID(),
836 $this->setError('setAssignedTo()-1:: '.db_error());
840 for ($i=0; $i<count($add_arr); $i++) {
841 db_query_params ('INSERT INTO project_assigned_to (project_task_id,assigned_to_id) VALUES ($1,$2)',
842 array ($this->getID(),
845 $this->setError('setAssignedTo()-2:: '.db_error());
856 * getAssignedTo - get an array of user_id's that you are assigned to.
858 * @return array The array of user_id's.
860 function getAssignedTo() {
861 if (!$this->getID()) {
864 if (!$this->assignedto) {
865 $this->assignedto =& util_result_column_to_array(db_query_params('SELECT assigned_to_id FROM project_assigned_to WHERE project_task_id=$1',
866 array ($this->getID()))) ;
868 return $this->assignedto;
872 * update - update this ProjectTask in the database.
874 * @param string The summary of this task.
875 * @param string The detailed description of this task.
876 * @param int The Priority of this task.
877 * @param int The Hours estimated to complete this task.
878 * @param int The (unix) start date of this task.
879 * @param int The (unix) end date of this task.
880 * @param int The status_id of this task.
881 * @param int The category_id of this task.
882 * @param int The percentage of completion in integer format of this task.
883 * @param array An array of user_id's that are assigned this task.
884 * @param array An array of project_task_id's that this task depends on.
885 * @param int The GroupProjectID of a new subproject that you want to move this Task to.
886 * @param int The duration of the task in days.
887 * @param int The id of the parent task, if any.
888 * @return boolean success.
890 function update($summary,$details,$priority,$hours,$start_date,$end_date,
891 $status_id,$category_id,$percent_complete,&$assigned_arr,&$depend_arr,
892 $new_group_project_id,$duration=0,$parent_id=0) {
893 $has_changes = false; // if any of the values passed is different from
895 $arrChangedAndInNotice = array("details"=>"","summary"=>"",
896 "complete"=>"","status"=>"","subproject"=>""); /* includes only
897 entries that changed and will be sended by E-Mail (sendNotice()) */
899 $v = new Validator();
900 $v->check($summary, "summary");
901 $v->check($priority, "priority");
902 $v->check($hours, "hours");
903 $v->check($start_date, "start date");
904 $v->check($end_date, "end date");
905 $v->check($status_id, "status");
906 $v->check($category_id, "category");
907 if (!$v->isClean()) {
908 $this->setError($v->formErrorMsg("Must include "));
914 if ( ($this->getParentID()) != $parent_id ) {
920 if ( ($this->getDuration()) != $duration ) {
924 if (!forge_check_perm ('pm', $this->ProjectGroup->getID(), 'manager')) {
925 $this->setPermissionDeniedError();
929 /*if ( ($this->getSummary() != $summary) || ($this->getDetails() != $details) ||
930 ($this->getPriority() != $priority) || ($this->getHours() != $hours) ||
931 ($this->getStartDate() != $start_date) || ($this->getEndDate() != $end_date) ||
932 ($this->getStatusID() != $status_id) || ($this->getCategoryID() != $category_id) ||
933 ($this->getPercentComplete() != $percent_complete) ) {
942 // Attempt to move this Task to a new Subproject
943 // need to instantiate new ProjectGroup obj and test if it works
945 $group_project_id = $this->ProjectGroup->getID();
946 if ($new_group_project_id != $group_project_id) {
947 $newProjectGroup= new ProjectGroup($this->ProjectGroup->getGroup(), $new_group_project_id);
948 if (!is_object($newProjectGroup) || $newProjectGroup->isError()) {
949 $this->setError('ProjectTask: Could not move to new ProjectGroup'. $newProjectGroup->getErrorMessage());
953 if (!forge_check_perm ('pm', $newProjectGroup->getID(), 'manager')) {
954 $this->setPermissionDeniedError();
959 // Now set ProjectGroup, Category, and Assigned to 100 in the new ProjectGroup
964 $assigned_to=array('100');
965 $this->ProjectGroup =& $newProjectGroup;
966 $this->addHistory ('group_project_id',$group_project_id);
968 $arrChangedAndInNotice['subproject'] = ">";
974 if($details != "" && $details != null) {$arrChangedAndInNotice['details'] = ">";}
976 if (!$this->addMessage($details)) {
981 if ($this->getStatusID() != $status_id) {
982 $this->addHistory ('status_id',$this->getStatusID());
984 $arrChangedAndInNotice['status'] = ">";
987 if ($this->getCategoryID() != $category_id) {
988 $this->addHistory ('category_id',$this->getCategoryID());
992 if ($this->getPriority() != $priority) {
993 $this->addHistory ('priority',$this->getPriority());
997 if ($this->getSummary() != htmlspecialchars($summary)) {
998 $this->addHistory ('summary',$this->getSummary());
1000 $arrChangedAndInNotice['summary'] = ">";
1003 if ($this->getPercentComplete() != $percent_complete) {
1004 $this->addHistory ('percent_complete',$this->getPercentComplete());
1005 $has_changes = true;
1006 $arrChangedAndInNotice['complete'] = ">";
1009 if ($this->getHours() != $hours) {
1010 $this->addHistory ('hours',$this->getHours());
1011 $has_changes = true;
1014 if ($this->getStartDate() != $start_date) {
1015 $this->addHistory ('start_date',$this->getStartDate());
1016 $has_changes = true;
1019 if ($this->getEndDate() != $end_date) {
1020 $this->addHistory ('end_date',$this->getEndDate());
1021 $has_changes = true;
1024 $old_assigned = $this->getAssignedTo();
1025 $diff_assigned_array=array_diff($old_assigned, $assigned_arr);
1026 if (count($diff_assigned_array)>0) {
1027 for ($tmp=0;$tmp<count($old_assigned);$tmp++) {
1028 $this->addHistory('assigned_to_id',$old_assigned[$tmp]);
1030 $has_changes = true;
1032 $old_array = array_keys($this->getDependentOn());
1033 $diff_array=array_diff($old_array,array_keys($depend_arr));
1034 if (count($diff_array)>0) {
1035 for ($tmp=0;$tmp<count($old_array);$tmp++) {
1036 $this->addHistory('dependent_on_id', $old_array[$tmp]);
1038 $has_changes = true;
1041 if (!$this->setDependentOn($depend_arr)) {
1044 } elseif (!$this->setAssignedTo($assigned_arr)) {
1048 $res = db_query_params ('UPDATE project_task SET
1055 percent_complete=$7,
1057 group_project_id=$9,
1060 WHERE group_project_id=$12
1061 AND project_task_id=$13',
1062 array (htmlspecialchars($summary),
1070 $new_group_project_id,
1076 $this->setError('Error On ProjectTask::update-5: '.db_error().$sql);
1080 if (!$this->fetchData($this->getID())) {
1081 $this->setError('Error On ProjectTask::update-6: '.db_error());
1085 if ($has_changes) { //only send email if there was any change
1086 $this->sendNotice(false, $arrChangedAndInNotice);
1097 * sendNotice - contains the logic for sending email/jabber updates.
1099 * @return boolean success.
1101 function sendNotice($first=false, $arrChangedAndInNotice=array()) {
1102 global $send_task_email;
1104 if ($send_task_email===false) {
1107 $ids = $this->getAssignedTo();
1110 // See if there is anyone to send messages to
1112 if (count($ids) < 1 && !$this->ProjectGroup->getSendAllPostsTo()) {
1116 $body = "Task #". $this->getID() ." has been updated. ".
1117 "\n\nProject: ". $this->ProjectGroup->Group->getPublicName();
1118 if (isset($arrChangedAndInNotice['subproject']))
1119 $body .= "\n". $arrChangedAndInNotice['subproject']."Subproject: ". $this->ProjectGroup->getName();
1121 if (isset($arrChangedAndInNotice['summary']))
1122 $body .= "\n". $arrChangedAndInNotice['summary']. "Summary: ".util_unconvert_htmlspecialchars( $this->getSummary() );
1124 if (isset($arrChangedAndInNotice['complete']))
1125 $body .= "\n". $arrChangedAndInNotice['complete']. "Complete: ". $this->getPercentComplete() ."%";
1127 if (isset($arrChangedAndInNotice['status']))
1128 $body .= "\n". $arrChangedAndInNotice['status']. "Status: ". $this->getStatusName();
1130 $body .= "\n\nDescription: ". util_unconvert_htmlspecialchars( $this->getDetails() );
1133 Now get the followups to this task
1135 $result2=$this->getMessages();
1137 $rows=db_numrows($result2);
1139 if ($result2 && $rows > 0) {
1140 $body .= "\n\nFollow-Ups:";
1141 for ($i=0; $i<$rows;$i++) {
1142 if($i===0){ $temp = $arrChangedAndInNotice['details']; } else {$temp = "";}
1143 $body .= "\n\n-------------------------------------------------------";
1144 $body .= "\nDate: ". date(_('Y-m-d H:i'),db_result($result2,$i,'postdate'));
1145 $body .= "\nBy: ".db_result($result2,$i,'user_name');
1146 $body .= "\n\n". $temp ."Comment:\n".util_unconvert_htmlspecialchars(db_result($result2,$i,'body'));
1150 $body .= "\n\n-------------------------------------------------------".
1151 "\nFor more info, visit:".
1152 "\n\n".util_make_url ('/pm/task.php?func=detailtask&project_task_id='.$this->getID().
1153 "&group_id=".$this->ProjectGroup->Group->getID().
1154 "&group_project_id=".$this->ProjectGroup->getID());
1156 $subject=sprintf (_('[%1$s - %2$s] [Task #%3$d] '),
1157 $this->ProjectGroup->Group->getUnixName(),
1158 $this->ProjectGroup->getName(),
1160 util_unconvert_htmlspecialchars( $this->getSummary() );
1162 util_handle_message(array_unique($ids),$subject,$body,$this->ProjectGroup->getSendAllPostsTo());
1170 // c-file-style: "bsd"