Location: PHPKode > projects > Streber > db/class_task.inc.php
<?php if(!function_exists('startedIndexPhp')) { header("location:../index.php"); exit();}

require_once("db_item.inc.php");

/**
* cache some db-elements
*
* assoc. arrays hold references to objects from database
*
*/
global $g_cache_tasks;
$g_cache_tasks=array();



/**
* Task
* - items holding tasks, bug-reports, folders, milestones or documentation topics
*/
class Task extends DbProjectItem
{

    public $level;              # level if child of parent-tasks
    public $num_subtasks;       # temp cache for tree-lists


    /**
    * needs separate functions for translation fieldnames on runtime
    */
    public static function init()
    {
        #self::$type= ITEM_TASK;
        addProjectItemFields(&self::$fields_static);

        foreach(array(
            new FieldInternal(array('name'=>'id',
                'default'=>0,
                'in_db_object'=>1,
                'in_db_item'=>1,
                'log_changes'=>false,
            )),
            new FieldString   (array('name'=>'name',
                'title'=>__('Name'),
                'view_in_forms'=>true,
                'required'=>true,
            )),
            new FieldString   (array('name'=>'short',
                'title'         =>__('Short'),
                'view_in_forms' =>true,
            )),
            new FieldDate     (array('name'=>'date_start',
                'title'         =>__('Date start'),
                'view_in_forms' =>true,
                'default'       =>FINIT_TODAY,
                'log_changes'   => false,
            )),
            new FieldDate     (array('name'=>'date_closed',
                'title'         =>__('Date closed'),
                'view_in_forms' =>true,
                'default'       =>FINIT_NEVER,
                'log_changes'   => false,
            )),
            new FieldOption   (array('name'=>'status',
                'title'=>__('Status'),
                'view_in_forms'=>true,
                'default'=>2,
            )),

            new FieldInt      (array('name'=>'prio',
                'title'=>__('Priority'),
                'view_in_forms'=>true,
                'default'=>3,
            )),
            new FieldInt      (array('name'=>'for_milestone',
                'title'=>__('For Milestone'),
                'view_in_forms'=>true,
                'default'=>0,
            )),
            new FieldInt      (array('name'=>'resolved_version',
                'title'=>__('resolved in version'),
                'view_in_forms'=>true,
                'default'=>0,
            )),
            new FieldInt      (array('name'=>'resolve_reason',
                'title'=>__('Resolve reason'),
                'view_in_forms'=>true,
                'default'=> RESOLVED_UNDEFINED,
            )),

            new FieldText     (array('name'=>'description',
                'title'=>__('Description'),
                'view_in_forms'=>true,
            )),

            /**
            * DEPRECIATED !
            */
            new FieldBool(  array('name'=>'is_folder',
                'title'=>__('show as folder (may contain other tasks)'),
                'view_in_forms'=>true,
                'default'   =>0,
            )),

            /**
            * DEPRECIATED !
            */
            new FieldBool(  array('name'=>'is_milestone',
                'title'=>__('is a milestone'),
                'tooltip'=> __('milestones are shown in a different list'),
                'view_in_forms'=>false,
                'default'   =>0,
            )),

            new FieldInternal(  array('name'=>'is_released',
                'title'         =>__('released'),
                'view_in_forms' =>false,
                'default'       =>RELEASED_UNDEFINED,
                'log_changes'   => true,
            )),
            new FieldDatetime(  array('name'=>'time_released',
                'title'         =>__('release time'),
                'view_in_forms' =>true,
                'default'       =>FINIT_NEVER
            )),

            new FieldPercentage(array('name'=>'completion',
                'title'=>__('Completion'),
                'view_in_forms'=>true,
                'default'       =>0,
            )),
            new FieldInternal(  array('name'=>'parent_task',
                'view_in_forms'=>true,
                'log_changes'   => true,
            )),
            /**
            * estimated time in seconds
            *
            */
            new FieldInt(      array('name'=>'estimated',
                'title'=>__('Estimated time'),
                'view_in_forms'=>true,
            )),
            new FieldInt(      array('name'=>'estimated_max',
                'title'=>__('Estimated worst case'),
                'view_in_forms'=>true,
            )),

            new FieldInternal(  array('name'=>'issue_report',
                'log_changes'=>false,
            )),
            new FieldOption    (array('name'=>'label',
                'title'=>__('Label'),
                'view_in_forms'=>true,
                'log_changes'=>true,
            )),
            new FieldDateTime      (array('name'=>'planned_start',
                'title'=>__('Planned Start'),
                'view_in_forms'=>true,
                'default'=>FINIT_NEVER,
            )),
            new FieldDateTime      (array('name'=>'planned_end',
                'title'=>__('Planned End'),
                'view_in_forms'=>true,
                'default'=>FINIT_NEVER,
            )),
            new FieldInternal      (array('name'=>'view_collapsed',
                'default'=>0,
                'log_changes'=>false,
            )),
            new FieldInternal      (array('name'=>'category',
                'default'=>TCATEGORY_TASK,
                'log_changes'   => true,
            )),

            /**
            * additional int for defining position in lists
            */
            new FieldInt      (array('name'=>'order_id',
                'title'=>__('Order Id'),
                'default'       => 0,
                'log_changes'   => true,
            )),

			new FieldString(array('name'=>'calculation',
			    'title'=>__('Calculation') . " " . __('in Euro'),
				'default'=>0.0,
			)),

            new FieldBool(  array('name'=>'is_news',
                'title'=>__('Display in project news'),
                'tooltip'=> __('List title and description in project overview'),
                'view_in_forms'=> true,
                'default'   =>0,
                'log_changes' => true,
            )),
            new FieldBool(array('name'=>'show_folder_as_documentation',
                'title'=>__('Display folder as topic'),
                'view_in_forms'=> true,
                'default'   =>0,
                'log_changes' => true,
            )),


        ) as $f) {
            self::$fields_static[$f->name] = $f;
        }
    }


    //=== constructor ================================================
    function __construct ($id_or_array=false)
    {
        $this->fields= &self::$fields_static;

        parent::__construct($id_or_array);
        if(!$this->type){
            $this->type= ITEM_TASK;
        }

    }

/*
Task::query(array(
    Task::Filter('project','=',0),
    Task::Filter('name','matches','tom'),
))
-> url go=tasksQuery&filter_project_is=0&filter_name_matches=tom

$filters_str= get('filter_*');
$f= array();
foreach($filters_str as $fs=>$value) {
  preg_matches("/(.*)_(.*)/", $fs, $matches);
  list($count, $name, $type)= $matches;
  if($count == 2) {
    $f[]= new Filter($name, $type, $value);
  }
}

    public static function Filter($field_name, $type, $value)
    {
        if(isset(self::$fields_static[$field_name])) {
            $field= self::$fields_static[$field_name];
            switch($type) {
                case '=': return new FilterIs($field, $value);
                case '!=': return new FilterIsNot($field, $value);
                case '<=': return new FilterLessEqual($field, $value);
            }

        }
    }
*/

    /**
    * query from db
    *
    * - returns NULL if failed
    */
    static function getById($id)
    {
        if($id) {
            $t= new Task(intval($id));
            if($t->type != ITEM_TASK) {
                return NULL;
            }
            if($t->id) {
                return $t;
            }
        }
        return NULL;
    }


    /**
    * query if visible for current user
    *
    * - returns NULL if failed
    */
    static function getVisibleById($id)
    {
        if($id && $t= Task::getById(intval($id))) {
            if($p= Project::getById($t->project)) {
                if($p->validateViewItem($t)) {
                    return $t;
                }
            }
        }
        return NULL;
    }

    /**
    * query if editable for current user
    */
    static function getEditableById($id)
    {
        if($t= Task::getById($id)) {
            if($p= Project::getById($t->project)) {
                if($p->validateEditItem($t, false)) {
                    return $t;
                }
            }
        }
        return NULL;
    }



    function getProject()
    {
        require_once(confGet('DIR_STREBER') . 'db/class_project.inc.php');
        if(!$project= Project::getById($this->project)) {
            trigger_error("Task:getProject. project-id not set",E_USER_WARNING);
        }
        return $project;
    }



    function getProjectLink()
    {
        if($project= $this->getProject()) {
            return "<nobr>".$project->getLink().'</nobr>';
        }
        else {
            return '';
        }
    }




    /**
    * NOTE: this is not recursive!
    */
    function getSubtasks($order_by=NULL)
    {

        if(!$project = Project::getById($this->project)) {
            $PH->abortWarning(__("task without project?"), ERROR_BUG);
        }


        return $project->getTasks(array(
            'order_by'      => $order_by,
            'sort_hierarchical'=>false,
            'parent_task'=> $this->id,
            'show_folders'=>true,
            'status_min'=> STATUS_UPCOMING,
            'status_max'=> STATUS_CLOSED,
        ));
    }

    function getSubtasksRecursive()
    {

        if(!$project = Project::getById($this->project)) {
            $PH->abortWarning(__("task without project?"), ERROR_BUG);
        }

        $tasks= array();

        foreach($project->getTasks(array(
            'sort_hierarchical'=>false,
            'parent_task'=> $this->id,
            'show_folders'=>true,
            'status_min'=> STATUS_UPCOMING,
            'status_max'=> STATUS_CLOSED,
        )) as $t) {
            $tasks[]= $t;
            if($t->category == TCATEGORY_FOLDER) {
                foreach($t->getSubtasksRecursive() as $st) {
                    $tasks[] = $st;
                }
            }
        }
        return $tasks;
    }



    function getMilestoneTasks($order_by=NULL)
    {

        if(!$project = Project::getById($this->project)) {
            $PH->abortWarning(__("task without project?"), ERROR_BUG);
        }

        return $project->getTasks(array(
            'order_by'      => $order_by,
            'sort_hierarchical'=>false,
            'for_milestone'=> $this->id,
            'show_folders'=>true,
        ));
    }

    /**
    * recursively count number of subtasks
    *
    * although this function uses cached objects it can getSubtasks
    * extremely slow on large project since all(!) sub-tasks are counted
    */
    function getNumSubtasks()
    {
        global $auth;

        if(!$project= Project::getById($this->project)) {
            $PH->abortWarning(__("task without project?"), ERROR_BUG);
        }
        $subtasks = Task::getAll(array(
            'folders_only'      =>false,
            'show_folders'      =>true,
            'sort_hierarchical' =>true,
            'use_collapsed'     =>false,
            'parent_task'       =>$this->id,

        ));
        $count= 0;
        foreach($subtasks as $t) {
            if(!$t->is_folder) {
                $count++;
            }
        }
        return $count;
    }



    #----------------------------
    # get folder
    #----------------------------
    # returns array of tasks
    function getFolder()
    {
        $folder=array();
        $folder_ids=array();  #hash to detect cycle-lock

        $cur_task=$this;
        while($cur_task && intval($cur_task->parent_task)) {
            if(isset($folder_ids[$cur_task->parent_task])) {
                trigger_error('Cycle lock for task '.$cur_task->parent_task.'! Possibly invalid database structure', E_USER_WARNING);
                break;

            }
            else if($cur_task=Task::getVisibleById(intval($cur_task->parent_task))) {
                $folder_ids[$cur_task->id]= true;
                $folder[]=$cur_task;
            }
        }
        return array_reverse($folder);
    }


    /**
    * render links to parent objects (including project, if given)
    */
    function getFolderLinks($shortnames=true, $project= NULL)
    {
        measure_start('col_TaskFolderlinks');
        global $PH;
        $link_list= array();

        if($project) {
            $link_list[]= "<b>". $project->getLink() . "</b>";
        }

        foreach($this->getFolder() as $f) {
            if($shortnames) {
                $link_list[]= $PH->getLink('taskView',$f->getShort(),array('tsk'=>$f->id));
            }
            else {
                $link_list[]= $PH->getLink('taskView',$f->name,array('tsk'=>$f->id));
            }
        }
        measure_stop('col_TaskFolderlinks');
        return implode('<em> &gt; </em>', $link_list);
    }

    #------------------------------------------------------------------------------------------------
    # ungroup subtasks
    # - when deleting a folder (or changing it into a normal task) we need to ungroup the subtasks
    # - returns number of ungrouped tasks
    #------------------------------------------------------------------------------------------------
    public function ungroupSubtasks()
    {
        $tasks=$this->getSubtasks();
        foreach($tasks as $t) {
            $t->parent_task= $this->parent_task;
            $t->update();
        }

        if($this->isMilestoneOrVersion()) {
            $tasks= $this->getMilestoneTasks();
            foreach($tasks as $t) {
                $t->for_milestone= 0;
                $t->update();
            }
        }
        return count($tasks);
    }


    function getComments($args=array())
    {
        if($project= Project::getVisibleById($this->project)) {
            $args['on_task']= $this->id;

            $comments= $project->getComments($args);
            return $comments;
        }
    }


    function getLatestComment($args=array())
    {
        if($project= Project::getVisibleById($this->project)) {
            $args['on_task']= $this->id;
            $args['order_by']= 'created ASC';
            #$args['limit']=    1;

            $comments= $project->getComments($args);
            return $comments[0];
        }
    }

    /**
    * @@@ todo: this should by mapped to Project::getNumComments()
    */
    function getNumComments()
    {
        global $auth;
        $prefix= confGet('DB_TABLE_PREFIX');
        require_once(confGet('DIR_STREBER') . 'db/class_comment.inc.php');
        $dbh = new DB_Mysql;
        $sth= $dbh->prepare(
            "SELECT COUNT(*) from {$prefix}item i, {$prefix}comment c, {$prefix}projectperson upp
            WHERE
                    upp.person = {$auth->cur_user->id}
                AND upp.project = $this->project
                AND upp.state = 1

                AND i.type = '".ITEM_COMMENT."'
                AND i.project = $this->project
                AND i.state = 1
                AND ( i.pub_level >= upp.level_view
                      OR
                      i.created_by = {$auth->cur_user->id}
                )

                AND c.id = i.id
                AND c.task=$this->id    /* only  task-comments*/
             "
        );
        $sth->execute("",1);
        $tmp=$sth->fetchall_assoc();
        return $tmp[0]['COUNT(*)'];
    }


    /**
    * sum up visible(!) efforts for tasks (including sub-tasks)
    *
    * since this functions obeys pub_level the sum might be less than expected
    *
    * it also checks efforts of deleted subtasks!
    */
    function getSumEfforts()
    {
        global $auth;
        $sum=0;

        $prefix= confGet('DB_TABLE_PREFIX');
        require_once(confGet('DIR_STREBER') . 'db/class_effort.inc.php');
        $dbh = new DB_Mysql;
        $query_str=

            "SELECT SUM(unix_timestamp(e.time_end) - unix_timestamp(e.time_start)) from {$prefix}item i, {$prefix}effort e, {$prefix}projectperson upp
            WHERE
                    upp.person = {$auth->cur_user->id}
                AND upp.project = $this->project
                AND upp.state = 1

                AND i.type = '".ITEM_EFFORT."'
                AND i.state=1
                AND i.project = $this->project
                AND ( i.pub_level >= upp.level_view
                      OR
                      i.created_by = {$auth->cur_user->id}
                )

                AND e.id = i.id
                AND e.task=$this->id    /* only  task-efforts*/
            ";

        $sth= $dbh->prepare($query_str);
        $sth->execute("",1);
        $tmp= $sth->fetch_row();
        if($tmp) {
            $sum+= $tmp[0];
        }

        ### recursively go through sub-tasks ###
        if($subtasks=$this->getSubtasks()) {
            foreach($subtasks as $st){
                $sum+= $st->getSumEfforts();
            }
        }
        return $sum;
    }
    
    function getSumTaskEfforts()
    {
        global $auth;
        $sum=0;

        $prefix= confGet('DB_TABLE_PREFIX');
        require_once(confGet('DIR_STREBER') . 'db/class_effort.inc.php');
        $dbh = new DB_Mysql;
        $query_str=

            "SELECT SUM(unix_timestamp(e.time_end) - unix_timestamp(e.time_start)) from {$prefix}item i, {$prefix}effort e
            WHERE
                    i.type = '".ITEM_EFFORT."'
                AND i.state=1
                AND i.project = $this->project
                AND e.id = i.id
                AND e.task=$this->id    /* only  task-efforts*/
            ";

        $sth= $dbh->prepare($query_str);
        $sth->execute("",1);
        $tmp= $sth->fetch_row();
        if($tmp) {
            $sum+= $tmp[0];
        }

        ### recursively go through sub-tasks ###
        if($subtasks=$this->getSubtasks()) {
			$sum = 0;
            foreach($subtasks as $st){
                $sum+= $st->getSumTaskEfforts();
            }
        }
        return $sum;
    }



    /**
    * returns assoc. array
    * 
    * Note: - "num_open" counts all tasks with status between New and Completed
    *       - to differentiate between open and needs approval subtract num_need_approval
    */
    function getMilestoneTasksSummary()

    #function getMilestoneTasks()
    {
        ### get subtasks if expanded
        $tasks_open= Task::getAll(array(
            'for_milestone' => $this->id,
            'status_min'    => STATUS_NEW,
            'status_max'    => STATUS_COMPLETED,
            'project'       => $this->project,
            'show_folders'  => false,
        ));
        $tasks_closed= Task::getAll(array(
            'for_milestone' => $this->id,
            'status_min'    => STATUS_APPROVED,
            'status_max'    => STATUS_CLOSED,
            'project'       => $this->project,
            'show_folders'  => false,
        ));

        $num_closed= count($tasks_closed);
        $num_open  = count($tasks_open);
        $num_need_approval= 0;
        $sum_estimated_min= 0;
        $sum_estimated_max= 0;
        $sum_completion_min= 0;
        $sum_completion_max= 0;

        foreach($tasks_open  as $tt) {
            $sum_estimated_min+= $tt->estimated;
            $sum_estimated_max+= $tt->estimated_max
                               ? $tt->estimated_max
                               : $tt->estimated;

            if($tt->status > STATUS_BLOCKED) {
                $num_need_approval++;
                $sum_completion_min+= $tt->estimated;
                $sum_completion_max+= $tt->estimated_max;
            }
            else {
                $sum_completion_min+= $tt->estimated * $tt->completion / 100;
            }
        }

        foreach($tasks_closed  as $tt) {

            $sum_estimated_min+= $tt->estimated;
            $sum_estimated_max+= $tt->estimated_max
                               ? $tt->estimated_max
                               : $tt->estimated;

            $sum_completion_min+= $tt->estimated;
            $sum_completion_max+= $tt->estimated_max;
        }

        return array(
            'tasks_closed'          => $tasks_closed,
            'tasks_open'            => $tasks_open,
            'num_open'              => $num_open,
            'num_need_approval'     => $num_need_approval,
            'num_closed'            => $num_closed,
            'num_need_approval'     => $num_need_approval,
            'sum_estimated_min'     => $sum_estimated_min,
            'sum_estimated_max'     => $sum_estimated_max,
            'sum_completion_min'    => $sum_completion_min,
            'sum_completion_max'    => $sum_completion_max,
        );
    }



    /**
    * getHomeTasks($project=false)
    */
    public static function getHomeTasks($order_by=" is_folder DESC,  parent_task, prio ASC, project, name")
    {
        global $auth;
        $prefix= confGet('DB_TABLE_PREFIX');
        $dbh = new DB_Mysql;

        #--- select all visible tasks in home ---
        switch($auth->cur_user->show_tasks_at_home) {
        case SHOW_ASSIGNED_ONLY:

            $query_str= "
            SELECT  i.*, t.* from {$prefix}item i, {$prefix}task t, {$prefix}project p, {$prefix}projectperson upp, {$prefix}taskperson tp, {$prefix}item itp
            WHERE
                    upp.person = {$auth->cur_user->id}
                AND upp.state = 1
                AND upp.project = p.id   /* all user projectpersons */

                AND p.state = 1
                AND p.status >=1
                AND p.status <= ".STATUS_OPEN."

                AND p.id = i.project

                AND i.type = '".ITEM_TASK."'
                AND t.is_folder = 0
                AND i.pub_level >= upp.level_view
                AND i.state = 1
                AND i.project = p.id

                AND t.id= i.id
                AND t.status <= ". STATUS_COMPLETED."

                /* filter assigned */
                AND t.id = tp.task
                       AND tp.person = {$auth->cur_user->id}
                       AND tp.id = itp.id
                               AND itp.state = 1
                               AND (itp.pub_level >= upp.level_view
                                    OR
                                   itp.created_by = {$auth->cur_user->id}
                               )



            ". getOrderByString($order_by);
            break;



        case SHOW_ALSO_UNASSIGNED:
            trigger_error("filtering unassigned tasks has not been implemented yet",E_USER_NOTICE);
        case SHOW_ALL_OPEN:

            $query_str= "SELECT  i.*, t.* from {$prefix}item i, {$prefix}task t, {$prefix}project p, {$prefix}projectperson upp
            WHERE
                    upp.person = {$auth->cur_user->id}
                AND upp.state = 1
                AND upp.project = p.id   /* all user projectpersons */

                AND p.state = 1
                AND p.status >=1
                AND p.status <= ".STATUS_OPEN."

                AND p.id = i.project

                AND i.type = '".ITEM_TASK."'
                AND t.is_folder = 0
                AND i.pub_level >= upp.level_view   /* @@@ add created_by support */
                AND i.state = 1
                AND i.project = p.id

                AND t.id= i.id
                AND t.status <= ".STATUS_BLOCKED."

            ". getOrderByString($order_by);
            break;
        default:
            trigger_error("Unknown setting for home task-list",E_USER_NOTICE);
        }

        $sth= $dbh->prepare($query_str);
        $sth->execute("",1);
        $tmp=$sth->fetchall_assoc();

        $tasks=array();
        foreach($tmp as $t) {

            unset($t['due_sort']);                          # remove temporary sql-variable
            $task=new Task($t);

            $tasks[]=$task;
        }
        return $tasks;
    }


    /**
    * return tasks of project
    *
    *
    *
    * @params
    *   show_folders=true,
    *   order_by=NULL,
    *   status_min=2,
    *   status_max=4,
    *   visible_only=true,
    *   alive_only=true,
    *   parent_task=NULL)  # if NULL parent-task is ignored
    */
    static function getAll( $args=NULL)
    {
        global $auth;
        $prefix = confGet('DB_TABLE_PREFIX');

        ### default params ###
        $project        = NULL;
        $show_folders   = true;
        $order_by       = "is_folder DESC, parent_task, prio ASC,project,name";
        $status_min     = STATUS_NEW;
        $status_max     = STATUS_BLOCKED;
        $visible_only   = NULL;       # use project rights settings
        $alive_only     = true;       # ignore deleted
        $parent_task    = NULL;       #
        $sort_hierarchical= false;
        $use_collapsed  = false;      # by default ignore collapsed folders
        $issues_only    = false;
        $folders_only   = false;
        $level          = 0;         # hierarchical depth in trees
        $assigned_to_person=0;      # skip by default
        $search         = NULL;
        $name           = NULL;
        $is_milestone   = NULL;
        $for_milestone  = NULL;
        $resolved_version = NULL;
        $is_released_min= NULL;
        $is_released_max= NULL;
        $id             = NULL;
        $modified_by    = NULL;
        $not_modified_by    = NULL;
        $resolve_reason_min= NULL;
        $category       = NULL;
        $category_in    = NULL;
        $label          = NULL;
        $person         = 0;
        $is_news        = NULL;
		
        ### filter params ###
        if($args) {
            foreach($args as $key=>$value) {
                if(!isset($$key) && !is_null($$key) && !$$key==="") {
                    trigger_error("unknown parameter",E_USER_NOTICE);
                }
                else {
                    $$key= $value;
                }
            }
        }
        
        if($sort_hierarchical && is_null($parent_task)) {
            $parent_task=0;
        }
        $str_project= $project
            ? 'AND upp.project='.intval($project)
            : '';
        $str_project2= $project
            ? 'AND i.project='.intval($project)
            : '';

        $str_is_alive= $alive_only
            ? 'AND i.state='. ITEM_STATE_OK
            : '';

        $str_is_issue= $issues_only
            ? 'AND t.issue_report!=0'
            : '';

        $str_is_folder= $show_folders
            ? ''
            : 'AND t.is_folder=0';
		
        $str_modified_by= $modified_by
            ? 'AND i.modified_by ='. intval($modified_by)
            : '';

        $str_not_modified_by= $not_modified_by
            ? 'AND i.modified_by !='. intval($not_modified_by)
            : '';


        $str_id= $id
           ? 'AND t.id='.intval($id)
           : '';


        if(!is_null($label)) {
            $str_label= 'AND t.label=' . intval($label);
        }
        else {
            $str_label= '';
        }


        if(!is_null($is_milestone)) {
            $str_is_milestone= $is_milestone
                ? 'AND t.is_milestone=1'
                : 'AND t.is_milestone=0';
        }
        else {
            $str_is_milestone='';
        }

        if(!is_null($category)) {
            $str_category='AND t.category='. intval($category);
        }
        else {
            $str_category='';
        }
        if(!is_null($category_in)) {
            $clean_array= array();
            foreach($category_in as $c) {
                $clean_array[]= intval($c);
            }
            $str_category_in='AND t.category IN('. join(",",$clean_array) .')';
        }
        else {
            $str_category_in='';
        }

        if(!is_null($is_news)) {
            $str_is_news='AND t.is_news=' . intval($is_news);
        }
        else {
            $str_is_news='';
        }

        $str_is_released_min= $is_released_min
            ? 'AND t.is_released >= '. intval($is_released_min)
            : '';


        if($resolve_reason_min !== NULL) {
            $str_resolve_reason_min= $resolve_reason_min
                ? 'AND t.resovle_reason >= '. intval($resolve_reason_min)
                : '';
        }
        else {
            $str_reasolve_reason_min= '';
        }


        $str_is_released_max= $is_released_max
            ? 'AND t.is_released <= '. intval($is_released_max)
            : '';

        $str_has_name= $name
            ? "AND (t.name='".asSecureString($name)."' or t.short='".asSecureString($name)."')"
            : "";

        if(!is_null($for_milestone)) {
            $str_for_milestone=  'AND t.for_milestone='. intval($for_milestone);
        }
        else {
            $str_for_milestone= '';
        }

        if(!is_null($resolved_version)) {
            $str_resolved_version=  'AND t.resolved_version='.intval($resolved_version);
        }
        else {
            $str_resolved_version= '';
        }


        if($folders_only) {
            $str_is_folder= 'AND t.is_folder=1';
        }

        $str_parent_task= !is_null($parent_task)
            ? 'AND t.parent_task='.intval($parent_task)
            : '';

        $str_match= $search
            ? "AND MATCH (t.name,t.short,t.description) AGAINST ('". asCleanString($search) ."*' IN BOOLEAN MODE)"
        : '';
		
		$str_person = $person
		            ? $person
					: $auth->cur_user->id;
					
        if(is_null($visible_only)) {

            $visible_only   = $auth->cur_user && ($auth->cur_user->user_rights & RIGHT_VIEWALL)
                            ? false
                            : true                            ;
        }
        if($visible_only) {

            ### only filter assigned to person ###
            if($assigned_to_person) {
                $str_query=
                "SELECT i.*, t.* from {$prefix}item i, {$prefix}task t, {$prefix}taskperson tp, {$prefix}projectperson upp, {$prefix}item itp
                WHERE

                    upp.person = {$auth->cur_user->id}
					/*upp.person = $str_person*/
                    $str_project
                    AND i.type = '".ITEM_TASK."'
                    AND i.project=upp.project
                    $str_is_alive
                    $str_project2
                    $str_modified_by
                    $str_not_modified_by

                    $str_is_issue

                    AND ( i.pub_level >= upp.level_view
                          OR
                          /*i.created_by = {$auth->cur_user->id}*/
						  i.created_by = $str_person
                    )

                    AND t.id = i.id
                    $str_id
                    $str_category
                    $str_category_in
                    $str_is_folder
                    $str_is_issue
                    $str_label
                    $str_parent_task
                    $str_has_name
                    $str_is_milestone
                    $str_is_released_min
                    $str_is_released_max
                    $str_for_milestone
                    $str_resolved_version
                    $str_is_news
                    AND t.status >= ". intval($status_min)."
                    AND t.status <= ". intval($status_max)."

                    AND i.id = tp.task
                           AND tp.person = ". intval($assigned_to_person) ."
                           AND itp.id = tp.id
                           AND itp.state = 1
                           ".
                           #        AND (itp.pub_level >= upp.level_view
                           #            OR
                           #            itp.created_by = {$auth->cur_user->id}
                           #        )
                           "
                    $str_match

                " . getOrderByString($order_by);
            }
            else {
                $str_query=
                "SELECT i.*, t.* from {$prefix}item i, {$prefix}task t, {$prefix}projectperson upp
                WHERE
                        /*upp.person = {$auth->cur_user->id}*/
						upp.person = $str_person
                    $str_project
                    AND i.type = '".ITEM_TASK."'
                    AND i.project = upp.project
                    $str_is_alive
                    $str_project2
                    $str_category
                    $str_category_in
                    $str_modified_by
                    $str_not_modified_by
                    $str_is_issue
                    $str_is_milestone
                    $str_is_released_min
                    $str_is_released_max
                    $str_for_milestone
                    $str_label
                    $str_resolved_version
                    $str_is_news
                    AND ( i.pub_level >= upp.level_view
                          OR
                          /*i.created_by = {$auth->cur_user->id}*/
						  i.created_by = $str_person
                    )

                    AND t.id = i.id
                    $str_is_folder
                    $str_is_issue
                    $str_parent_task
                    $str_has_name
                    $str_id
                    AND t.status >= ".intval($status_min)."
                    AND t.status <= ".intval($status_max)."
                    $str_match

                " . getOrderByString($order_by);
            }
        }
        ### show all ###
        else {
            if($assigned_to_person) {
                $str_query=
                "SELECT i.*, t.* from {$prefix}item i, {$prefix}task t, {$prefix}taskperson tp ,{$prefix}item itp
                WHERE
                    i.type = '".ITEM_TASK."'
                $str_project2
                $str_is_alive
                $str_modified_by
                $str_not_modified_by

                AND t.id = i.id
                $str_id
                $str_is_folder
                $str_is_issue
                $str_category
                $str_category_in
                $str_parent_task
                $str_has_name
                $str_label
                $str_is_milestone
                $str_is_released_min
                $str_is_released_max
                $str_for_milestone
                $str_is_news
                $str_resolved_version
                AND t.status >= ".intval($status_min)."
                AND t.status <= ".intval($status_max)."
                $str_match
                AND i.id = tp.task
                AND tp.person = " .intval($assigned_to_person) . "
                       AND tp.id = itp.id
                       AND itp.state = 1
                " . getOrderByString($order_by);
            }
            else {
                $str_query=
                "SELECT i.*, t.* from {$prefix}item i, {$prefix}task t
                WHERE
                    i.type = '".ITEM_TASK."'
                $str_project2
                $str_is_alive
                $str_modified_by
                $str_not_modified_by

                AND t.id = i.id
                $str_category
                $str_category_in
                $str_id
                $str_is_folder
                $str_is_issue
                $str_is_milestone
                $str_for_milestone
                $str_label
                $str_resolved_version
                $str_is_news

                $str_is_released_min
                $str_is_released_max
                $str_parent_task
                $str_has_name
                AND t.status >= ".intval($status_min)."
                AND t.status <= ".intval($status_max)."
                $str_match

                " . getOrderByString($order_by);
            }
        }
        
        $dbh = new DB_Mysql;
        $sth= $dbh->prepare($str_query);

        $sth->execute("",1);
        $tmp=$sth->fetchall_assoc();
		
        $tasks=array();
        foreach($tmp as $t) {
            $task=new Task($t);
            $task->level= $level;
            $tasks[]=$task;

            ### hierarchical / recursive sorting ###
            if($sort_hierarchical && $task->is_folder && (!$use_collapsed || !$task->view_collapsed)) {
                if($sub_tasks=Task::getAll(array(
                    'sort_hierarchical' =>true,

                    'use_collapsed'=> $use_collapsed,
                    'parent_task'   => $task->id,
                    'order_by'      => $order_by,
                    'visible_only'  => $visible_only,
                    'alive_only'    => $alive_only,
                    'issues_only'   => $issues_only,
                    'status_min'    => $status_min,
                    'status_max'    => $status_max,
                    'level'         => $level+1,
                    'folders_only'  => $folders_only,
                    'project'       => $project,
                ))) {
                    foreach($sub_tasks as &$st) {
                        $tasks[]= $st;
                    }
                }
            }
        }
        return $tasks;
    }

    /**
    * getAssignments
    */
    function getAssignments() {
        $prefix = confGet('DB_TABLE_PREFIX');
        require_once(confGet('DIR_STREBER') . 'db/class_taskperson.inc.php');
        $dbh = new DB_Mysql;

        $order_by="pers.name";

        ### all projects ###
        #
        # TODO @@@ CHECK projeckt-assigment / visible persons...
        # if( $auth->cur_user->user_rights & RIGHT_PROJECT_ASSIGN) {
        $query_str=
            "SELECT itp.*, tp.* from {$prefix}item itp, {$prefix}person pers, {$prefix}taskperson tp
            WHERE
                pers.state = 1

            AND pers.id = tp.person
                      AND tp.task= $this->id
                      AND tp.id = itp.id
                              AND itp.state = 1

            ORDER BY $order_by";

        $sth= $dbh->prepare($query_str);
        $sth->execute("",1);
        $tmp=$sth->fetchall_assoc();
        $tps=array();
        foreach($tmp as $tp) {
            $tps[]=new TaskPerson($tp);
        }
        return $tps;
    }


    /**
    * getAssignments
    */
    function isAssignedToPerson($person)
    {

        if($person instanceof Person) {
            $person_id= $person->id;
        }
        else {
            $person_id= intval($person);
        }

        $prefix = confGet('DB_TABLE_PREFIX');
        $dbh = new DB_Mysql;

        ### all projects ###
        $query_str=
            "SELECT COUNT(*) from {$prefix}item itp, {$prefix}taskperson tp
            WHERE
                itp.state= 1
            AND itp.id = tp.id
            AND             tp.person= $person_id
            AND             tp.task= $this->id";


        $sth= $dbh->prepare($query_str);
        $sth->execute("",1);

        $tmp=$sth->fetchall_assoc();
        return $tmp[0]['COUNT(*)'];
    }



    /**
    * getAssignedPersons
    */
    function getAssignedPersons($visible_only=true) {
        global $auth;

        $prefix = confGet('DB_TABLE_PREFIX');
        $dbh = new DB_Mysql;

        $order_by="pers.name";

        $query_str=
            "SELECT i.*, pers.* from {$prefix}item i, {$prefix}person pers, {$prefix}taskperson tp, {$prefix}item itp
            WHERE
                pers.state = 1

            AND pers.id = i.id
            AND pers.id = tp.person
                      AND tp.task= $this->id
                      AND tp.id = itp.id
                              AND itp.state = 1

            ORDER BY $order_by";

        $sth= $dbh->prepare($query_str);
        $sth->execute("",1);
        $tmp=$sth->fetchall_assoc();

        $persons=array();


        #--- return all ---
        if(!$visible_only || $auth->cur_user->user_rights & RIGHT_PROJECT_ASSIGN) {
            foreach($tmp as $t) {
                $persons[]=new Person($t);
            }

            return $persons;
        }
        else {
            $project= Project::getById($this->project);
            foreach($tmp as $t) {

                $p=new Person($t);
                if($project->isPersonVisibleTeamMember($p)) {
                    $persons[]= $p;
                }
            }
            return $persons;
        }
    }
	

    public function getLink($short_name= true, $strikeDone= true)
    {

        
        $style_isdone=   ($this->isOfCategory(array(TCATEGORY_TASK, TCATEGORY_BUG))) && ($strikeDone && $this->status >= STATUS_COMPLETED)
                    ? 'isDone'
                    : '';

        global $PH;
        if($short_name) {
            return '<span  title="'.asHtml($this->name).'" class="item task">'.$PH->getLink('taskView',$this->getShort(),array('tsk'=>$this->id),$style_isdone).'</span>';
        }
        else {
            return $PH->getLink('taskView',$this->name,array('tsk'=>$this->id),$style_isdone);
        }
    }


    public function getLabel()
    {
        if($this->is_folder) {
            return __('Folder');
        }
        else if($this->category == TCATEGORY_MILESTONE) {
            return __('Milestone');
            
        }
        else if ($this->category == TCATEGORY_VERSION) {
            return __('Released Milestone');
        }
        else if ($this->category == TCATEGORY_DOCU) {
            return __('Topic');
        }
        else if ($this->category == TCATEGORY_BUG) {
            return __('Bug');
        }

        else if($this->label) {
            if(!$project= Project::getById($this->project)) {
                trigger_error("task without project?", E_USER_WARNING);
            }
            $labels=preg_split("/,/",$project->labels);
            $value= $labels[$this->label-1];
            return $value;
        }
        else {
            return __('Task');
        }
    }



    /**
    * gets documentation sub tasks and folders of a task
    *
    */
    public static function getDocuTasks($project_id, $parent_task_id= NULL)
    {
        $tasks= array();
        $tmp_options= array(
            'use_collapsed'     => true,
            'order_by'          => 'order_id, i.id',
            'parent_task'       => $parent_task_id,
            'status_min'        => 0,
            'status_max'        => 100,
            'project'           => $project_id,
            'category_in'       => array(TCATEGORY_DOCU, TCATEGORY_FOLDER),
        );

        foreach($pages= Task::getAll($tmp_options) as $p) {
            ### filter only folders with docu ###
            if($p->category == TCATEGORY_FOLDER)
            {
                $found_docu= $p->show_folder_as_documentation;
                foreach($subtasks= $p->getSubtasksRecursive() as $subtask) {
                    if($subtask->category == TCATEGORY_DOCU) {
                        $found_docu= true;
                        break;
                    }
                }
                if($found_docu) {
                    $tasks[]= $p;
                }
            }
            else {
                $tasks[]= $p;
            }
        }
        return $tasks;
    }
    
    public function isMilestoneOrVersion()
    {
        return $this->isOfCategory(array(TCATEGORY_MILESTONE, TCATEGORY_VERSION));
    }

    
    public function isOfCategory($cat)
    {
        if(is_array($cat)) {
            foreach($cat as $c) {
                if($this->category == $c) {
                    return true;
                }
            }
            return false;
        }
        elseif($this->category == $cat) {
            return true;
        }
        return false;        
    }
    
    public function isDocumentation() {
        return isOfCategory(TCATEGORY_DOCU);
    }

    public function isBug() {
        return isOfCategory(TCATEGORY_BUG);
    }

}

Task::init();


?>
Return current item: Streber