getParameter( 'mode' , 'GET' ); } catch ( ParameterException $e ) { $mode = 'active'; } if ( $mode == 'active' ) { $tasks = Loader::DAO( 'tasks' )->getAllActiveTasks( ); $title = 'Active tasks'; $bTitle = 'Display active tasks'; $bMode = 'blocked'; } elseif ( $mode == 'blocked' ) { $tasks = Loader::DAO( 'tasks' )->getAllBlockedTasks( ); $title = 'Blocked tasks'; $bTitle = 'Display all tasks'; $bMode = 'all'; } else { $mode = 'all'; $tasks = Loader::DAO( 'tasks' )->getAllTasks( ); $title = 'All tasks'; $bTitle = 'Display active tasks only'; $bMode = 'active'; } $tree = Loader::DAO( 'items' )->getTree( ); $box = Loader::View( 'box' , $title , Loader::View( 'tasks_list' , $tasks ) ) ->addButton( BoxButton::create( $bTitle , 'tasks?mode=' . $bMode ) ->setClass( 'icon refresh' ) ); if ( !empty( $tree ) ) { $box ->addButton( BoxButton::create( 'New task' , 'tasks/add' ) ->setClass( 'list-add' ) ); } return $box; } } abstract class Ctrl_TaskFormBase extends Controller { protected final function createPrioritySelector( ) { $select = Loader::Create( 'Field' , 'priority' , 'select' ) ->setDescription( 'Priority:' ) ->setValidator( Loader::Create( 'Validator_IntValue' , 'Priorité invalide' ) ->setMinValue( 1 )->setMaxValue( 5 ) ); $tasks = Loader::DAO( 'tasks' ); for ( $i = 5 ; $i >= 1 ; $i -- ) { $select->addOption( $i , $tasks->translatePriority( $i ) ); } return $select; } } class Ctrl_AddTaskForm extends Ctrl_TaskFormBase { public function handle( Page $page ) { try { $target = (int) $this->getParameter( 'to' ); $targetIsItem = true; } catch ( ParameterException $e ) { try { $target = (int) $this->getParameter( 'parent' ); $targetIsItem = false; } catch ( ParameterException $e ) { $target = null; $targetIsItem = null; } } $form = Loader::Create( 'Form' , 'Add this task' , 'create-task' ); if ( $target === null ) { $returnURL = 'tasks'; if ( ! $this->addItemSelector( $form ) ) { return 'items'; } $form->addField( Loader::Create( 'Field' , 'nested' , 'hidden' ) ->setDefaultValue( 0 ) ); } elseif ( $targetIsItem ) { $item = Loader::DAO( 'items' )->get( $target ); if ( $item === null ) { return 'tasks'; } $returnURL = 'items/view?id=' . $target; $form->addField( Loader::Create( 'Field' , 'to' , 'hidden' ) ->setDefaultValue( $target ) ) ->addField( Loader::Create( 'Field' , 'nested' , 'hidden' ) ->setDefaultValue( 0 ) ) ->addField( Loader::Create( 'Field' , 'item' , 'hidden' ) ->setDefaultValue( $target ) ) ->addField( Loader::Create( 'Field' , 'item-name' , 'label' ) ->setMandatory( false ) ->setDescription( 'Item:' ) ->setDefaultValue( $item->name ) ); } else { $parent = Loader::DAO( 'tasks' )->get( $target ); if ( $parent === null ) { return 'tasks'; } $returnURL = 'tasks/view?id=' . $target; if ( $parent->completed_by !== null ) { return $returnURL; } $form->addField( Loader::Create( 'Field' , 'parent' , 'hidden' ) ->setDefaultValue( $target ) ) ->addField( Loader::Create( 'Field' , 'nested' , 'hidden' ) ->setDefaultValue( 1 ) ) ->addField( Loader::Create( 'Field' , 'item-name' , 'label' ) ->setMandatory( false ) ->setDescription( 'Sub-task of:' ) ->setDefaultValue( $parent->title ) ); } $page->setTitle( 'New task' ); return $form->addField( Loader::Create( 'Field' , 'title' , 'text' ) ->setDescription( 'Task title:' ) ->setModifier( Loader::Create( 'Modifier_TrimString' ) ) ->setValidator( Loader::Create( 'Validator_StringLength' , 'This title' , 5 , 256 ) ) ) ->addField( $this->createPrioritySelector( ) ->setDefaultValue( 3 ) ) ->addField( Loader::Create( 'Field' , 'description' , 'textarea' ) ->setDescription( 'Description:' ) ->setMandatory( false ) ) ->setURL( $returnURL ) ->addController( Loader::Ctrl( 'add_task' ) ) ->controller( ); } private function addItemSelector( $form ) { $form->addField( $select = Loader::Create( 'Field' , 'item' , 'select' ) ->setDescription( 'Item:' ) ->addOption( '' , '(please select an item)' ) ); $items = Loader::DAO( 'items' )->getTreeList( ); if ( empty( $items ) ) { return false; } foreach ( $items as $item ) { $name = '-' . str_repeat( '--' , $item->depth ) . ' ' . $item->name; $select->addOption( $item->id , $name ); } return true; } } class Ctrl_ViewTask extends Controller { public function handle( Page $page ) { try { $id = (int) $this->getParameter( 'id' , 'GET' ); } catch ( ParameterException $e ) { return 'tasks'; } $task = Loader::DAO( 'tasks' )->get( $id ); if ( $task === null ) { return 'tasks'; } $page->setTitle( $task->title . ' (task)' ); $result = array( Loader::Ctrl( 'task_details' , $task ) ); if ( $task->completed_by === null || ! empty( $task->subtasks ) ) { $result[] = Loader::Ctrl( 'task_list_subtasks' , $task ); } $result[] = Loader::Ctrl( 'task_dependencies' , $task ); if ( $task->completed_by === null ) { array_push( $result , Loader::Ctrl( 'add_task_note_form' , $task ) ); } array_push( $result , Loader::Ctrl( 'task_notes' , $task ) ); return $result; } } class Ctrl_DeleteTaskForm extends Controller { public function handle( Page $page ) { // Check selected task try { $id = (int) $this->getParameter( 'id' ); } catch ( ParameterException $e ) { return 'tasks'; } $tasks = Loader::DAO( 'tasks' ); $task = $tasks->get( $id ); if ( $task === null ) { return 'tasks'; } if ( ! $tasks->canDelete( $task ) ) { return 'tasks/view?id=' . $id; } $page->setTitle( $task->title . ' (task)' ); // Create parent URL from either the item or parent task if ( $task->parent_task === null ) { $parentURL = 'items/view?id=' . $task->item; } else { $parentURL = 'tasks/view?id=' . $task->parent_task; } // Generate confirmation text $confText = HTML::make( 'div' ) ->appendElement( HTML::make( 'p' ) ->appendText( "You are about to delete this task, and any comment attached to it." ) ) ->appendElement( HTML::make( 'p' ) ->appendText( "This operation cannot be undone." ) ); // Generate form return Loader::Create( 'Form' , 'Delete the task' , 'delete-task' , 'Task deletion' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $task->id ) ) ->addField( Loader::Create( 'Field' , 'confirm' , 'html' )->setDefaultValue( $confText ) ) ->setCancelURL( 'tasks/view?id=' . $task->id ) ->setSuccessURL( $parentURL ) ->addController( Loader::Ctrl( 'delete_task' ) ) ->controller( ); } } class Ctrl_EditTaskForm extends Ctrl_TaskFormBase { public function handle( Page $page ) { try { $id = (int) $this->getParameter( 'id' ); } catch ( ParameterException $e ) { return 'tasks'; } $task = Loader::DAO( 'tasks' )->get( $id ); if ( $task === null ) { return 'tasks'; } if ( $task->completed_at !== null ) { return 'tasks/view?id=' . $id; } $page->setTitle( $task->title . ' (task)' ); $form = Loader::Create( 'Form' , 'Update task' , 'edit-task' , 'Editing task' ) ->setURL( 'tasks/view?id=' . $task->id ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $task->id ) ) ->addField( Loader::Create( 'Field' , 'nested' , 'hidden' ) ->setDefaultValue( $task->parent_task === null ? 0 : 1 ) ); if ( $task->parent_task === null ) { $form->addField( $this->createItemSelector( ) ->setDefaultValue( $task->item ) ); } return $form->addField( Loader::Create( 'Field' , 'title' , 'text' ) ->setDescription( 'Title:' ) ->setModifier( Loader::Create( 'Modifier_TrimString' ) ) ->setValidator( Loader::Create( 'Validator_StringLength' , 'This title' , 5 , 256 ) ) ->setDefaultValue( $task->title ) ) ->addField( $this->createPrioritySelector( ) ->setDefaultValue( $task->priority ) ) ->addField( Loader::Create( 'Field' , 'description' , 'textarea' ) ->setDescription( 'Description:' ) ->setMandatory( false ) ->setDefaultValue( $task->description ) ) ->addField( $this->createAssigneeSelector( ) ->setDefaultValue( $task->assigned_id ) ) ->addController( Loader::Ctrl( 'edit_task' ) ) ->controller( ); } private function createItemSelector( ) { $select = Loader::Create( 'Field' , 'item' , 'select' ) ->setDescription( 'On item:' ); $items = Loader::DAO( 'items' )->getTreeList( ); foreach ( $items as $item ) { $name = '-' . str_repeat( '--' , $item->depth ) . ' ' . $item->name; $select->addOption( $item->id , $name ); } return $select; } private function createAssigneeSelector( ) { $select = Loader::Create( 'Field' , 'assigned-to' , 'select' ) ->setDescription( 'Assigned to:' ) ->setMandatory( false ); $select->addOption( '' , '(unassigned task)' ); $users = Loader::DAO( 'users' )->getUsers( ); foreach ( $users as $user ) { $select->addOption( $user->user_id , $user->user_view_name ); } return $select; } } class Ctrl_DeleteNoteForm extends Controller { public function handle( Page $page ) { // Check selected note try { $id = (int) $this->getParameter( 'id' ); } catch ( ParameterException $e ) { return 'tasks'; } $tasks = Loader::DAO( 'tasks' ); $note = $tasks->getNote( $id ); if ( $note === null ) { return 'tasks'; } if ( !$note->editable ) { return 'tasks/view?id=' . $note->task; } $task = $tasks->get( $note->task ); $page->setTitle( $task->title . ' (task)' ); // Generate confirmation text $confText = HTML::make( 'div' ) ->appendElement( HTML::make( 'p' ) ->appendText( 'You are about to delete a comment attached to this task.' ) ) ->appendElement( HTML::make( 'p' ) ->appendText( 'This operation cannot be undone.' ) ); // Generate form return Loader::Create( 'Form' , 'Delete this comment' , 'delete-note' , 'Comment deletion' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $note->id ) ) ->addField( Loader::Create( 'Field' , 'confirm' , 'html' )->setDefaultValue( $confText ) ) ->setURL( 'tasks/view?id=' . $note->task ) ->addController( Loader::Ctrl( 'delete_note' ) ) ->controller( ); } } class Ctrl_EditNoteForm extends Controller { public function handle( Page $page ) { // Check selected note try { $id = (int) $this->getParameter( 'id' ); } catch ( ParameterException $e ) { return 'tasks'; } $tasks = Loader::DAO( 'tasks' ); $note = $tasks->getNote( $id ); if ( $note === null ) { return 'tasks'; } if ( !$note->editable ) { return 'tasks/view?id=' . $note->task; } $task = $tasks->get( $note->task ); $page->setTitle( $task->title . ' (task)' ); // Generate form return Loader::Create( 'Form' , 'Update comment' , 'edit-note' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $note->id ) ) ->addField( Loader::Create( 'Field' , 'text' , 'textarea' ) ->setDescription( 'Comment:' ) ->setValidator( Loader::Create( 'Validator_StringLength' , 'This comment' , 5 ) ) ->setDefaultValue( $note->text ) ) ->setURL( 'tasks/view?id=' . $note->task ) ->addController( Loader::Ctrl( 'edit_note' ) ) ->controller( ); } } class Ctrl_DependencyAddForm extends Controller { public function handle( Page $page ) { // Check selected note try { $id = (int) $this->getParameter( 'to' ); } catch ( ParameterException $e ) { return 'tasks'; } $tasks = Loader::DAO( 'tasks' ); $task = $tasks->get( $id ); if ( $task === null ) { return 'tasks'; } if ( $task->completed_at !== null || empty( $task->possibleDependencies ) ) { return 'tasks/view?id=' . $id; } $page->setTitle( $task->title . ' (task)' ); // Generate form $form = Loader::Create( 'Form' , 'Add dependency' , 'add-dep' ) ->addField( Loader::Create( 'Field' , 'to' , 'hidden' ) ->setDefaultValue( $id ) ); $this->addDependencySelector( $form , $task->possibleDependencies , $task->parent_task === null ); return $form->setURL( 'tasks/view?id=' . $id ) ->addController( Loader::Ctrl( 'dependency_add' ) ) ->controller( ); } private function addDependencySelector( $form , $possibleDependencies , $topLevel ) { $form->addField( $select = Loader::Create( 'Field' , 'dependency' , 'select' ) ->setDescription( 'Dependency to add:' ) ->addOption( '' , '(please select a task)' ) ); if ( $topLevel ) { $depsByItem = $this->getDependenciesByItem( $possibleDependencies ); $items = $this->getItemsToDisplay( $depsByItem ); foreach ( $items as $item ) { $prefix = '-' . str_repeat( '--' , $item->depth ); $name = $prefix . ' ' . $item->name; $select->addOption( 'I' . $item->id , $name , true ); if ( ! array_key_exists( $item->id , $depsByItem ) ) { continue; } foreach ( $depsByItem[ $item->id ] as $task ) { $select->addOption( $task->id , $prefix . '-> ' . $task->title ); } } } else { foreach ( $possibleDependencies as $task ) { $select->addOption( $task->id , $task->title ); } } return true; } private function getDependenciesByItem( $possibleDependencies ) { $dbi = array( ); foreach ( $possibleDependencies as $pDep ) { $dbi[ $pDep->item ][] = $pDep; } return $dbi; } private function getItemsToDisplay( $depsByItem ) { $dao = Loader::DAO( 'items' ); $allItems = $dao->getTreeList( ); $found = array( ); foreach ( array_keys( $depsByItem ) as $id ) { if ( array_key_exists( $id , $found ) ) { continue; } $item = $dao->get( $id ); foreach ( $dao->getLineage( $item ) as $parent ) { $found[ $parent ] = 1; } $found[ $id ] = 1; } $result = array( ); foreach ( $allItems as $item ) { if ( array_key_exists( $item->id , $found ) ) { array_push( $result , $item ); } } return $result; } } class Ctrl_DependencyDeleteForm extends Controller { public function handle( Page $page ) { $tasks = Loader::DAO( 'tasks' ); // Get the task a dependency is being removed from try { $from = (int) $this->getParameter( 'from' ); } catch ( ParameterException $e ) { return 'tasks'; } $task = $tasks->get( $from ); if ( $task === null ) { return 'tasks'; } $page->setTitle( $task->title . ' (task)' ); if ( $task->completed_at !== null ) { return 'tasks/view?id=' . $from; } // Get the dependency being deleted try { $to = (int) $this->getParameter( 'to' ); } catch ( ParameterException $e ) { return 'tasks/view?id=' . $from; } $dependency = $tasks->get( $to ); if ( $dependency === null || ! $this->checkDependency( $task , $to ) ) { return 'tasks/view?id=' . $from; } // Generate confirmation text $confText = HTML::make( 'div' ) ->appendElement( HTML::make( 'p' ) ->appendText( 'The selected task will no longer depend on ' ) ->appendElement( HTML::make( 'strong' ) ->appendText( $dependency->title ) ) ->appendText( '.' ) ); // Generate form return Loader::Create( 'Form' , 'Delete dependency' , 'delete-dep' ) ->addField( Loader::Create( 'Field' , 'from' , 'hidden' ) ->setDefaultValue( $from ) ) ->addField( Loader::Create( 'Field' , 'to' , 'hidden' ) ->setDefaultValue( $to ) ) ->addField( Loader::Create( 'Field' , 'confirm' , 'html' )->setDefaultValue( $confText ) ) ->setURL( 'tasks/view?id=' . $from ) ->addController( Loader::Ctrl( 'dependency_delete' ) ) ->controller( ); } private function checkDependency( $task , $to ) { foreach ( $task->dependencies as $dep ) { if ( $dep->id == $to ) { return true; } } return false; } } class Ctrl_TaskMoveDown extends Controller { public function __construct( ) { $this->dao = Loader::DAO( 'tasks' ); } public function handle( Page $page ) { try { $id = (int) $this->getParameter( 'id' ); } catch ( ParameterException $e ) { return 'tasks'; } $task = $this->dao->get( $id ); if ( $task === null ) { return 'tasks'; } if ( empty( $task->moveDownTargets ) ) { return 'tasks/view?id=' . $id; } $page->setTitle( $task->title . ' (task)' ); $sibling = $this->getSibling( $task ); if ( $sibling != null ) { if ( $this->handleSelectedSibling( $task , $sibling ) ) { return 'tasks/view?id=' . $id; } else { return $this->confirmationForm( $task , $sibling ); } } return $this->siblingSelectionForm( $task ); } private function getSibling( $task ) { try { $sibling = (int) $this->getParameter( 'sibling' ); $okSiblings = array_map( function( $item ) { return $item->target_id; } , $task->moveDownTargets ); if ( ! in_array( $sibling , $okSiblings ) ) { $sibling = null; } } catch ( ParameterException $e ) { $sibling = null; } return $sibling; } private function handleSelectedSibling( $task , $sibling ) { try { $force = (bool) $this->getParameter( 'force' ); } catch ( ParameterException $e ) { $force = false; } return $this->dao->moveDown( $task , $sibling , $force ); } private function confirmationForm( $task , $sibling ) { $sibling = $this->dao->get( $sibling ); $confText = HTML::make( 'div' ) ->appendElement( HTML::make( 'p' ) ->appendText( 'All dependencies and reverse dependencies of the ' . 'selected task will be lost when it is moved into ' ) ->appendElement( HTML::make( 'strong' )->appendText( $sibling->title ) ) ->appendText( '.' ) ) ->appendElement( HTML::make( 'p' ) ->appendText( 'Please confirm.' ) ); return Loader::Create( 'Form' , 'Move task' , 'move-down' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $task->id ) ) ->addField( Loader::Create( 'Field' , 'sibling' , 'hidden' ) ->setDefaultValue( $sibling->id ) ) ->addField( Loader::Create( 'Field' , 'force' , 'hidden' ) ->setDefaultValue( 1 ) ) ->addField( Loader::Create( 'Field' , 'confirm' , 'html' )->setDefaultValue( $confText ) ) ->setURL( 'tasks/view?id=' . $task->id ) ->controller( ); } private function siblingSelectionForm( $task ) { $selector = Loader::Create( 'Field' , 'sibling' , 'select' ) ->setDescription( 'Move task into: ' ); foreach ( $task->moveDownTargets as $target ) { $selector->addOption( $target->target_id , $target->target_title ); } return Loader::Create( 'Form' , 'Move task' , 'move-down' , 'Move task to sibling' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $task->id ) ) ->addField( $selector ) ->setURL( 'tasks/view?id=' . $task->id ) ->controller( ); } } class Ctrl_TaskMoveUp extends Controller { public function handle( Page $page ) { try { $id = (int) $this->getParameter( 'id' ); } catch ( ParameterException $e ) { return 'tasks'; } $dao = Loader::DAO( 'tasks' ); $task = $dao->get( $id ); if ( $task === null ) { return 'tasks'; } if ( ! $task->can_move_up ) { return 'tasks/view?id=' . $id; } $page->setTitle( $task->title . ' (task)' ); try { $confirmed = (bool) $this->getParameter( 'confirmed' ); } catch ( ParameterException $e ) { $confirmed = false; } if ( ! $confirmed ) { return $this->showConfirmationForm( $task ); } try { $force = (bool) $this->getParameter( 'force' ); } catch ( ParameterException $e ) { $force = false; } if ( $dao->moveUp( $task , $force ) ) { return 'tasks/view?id=' . $id; } return $this->showForceForm( $task ); } private function showConfirmationForm( $task ) { $confText = HTML::make( 'div' ) ->appendElement( HTML::make( 'p' ) ->appendText( 'You are about to move this sub-task into its ' . 'grand-parent.' ) ) ->appendElement( HTML::make( 'p' ) ->appendText( 'Please confirm.' ) ); return Loader::Create( 'Form' , 'Move task' , 'move-up' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $task->id ) ) ->addField( Loader::Create( 'Field' , 'confirmed' , 'hidden' ) ->setDefaultValue( 1 ) ) ->addField( Loader::Create( 'Field' , 'confirm' , 'html' )->setDefaultValue( $confText ) ) ->setURL( 'tasks/view?id=' . $task->id ) ->controller( ); } private function showForceForm( $task ) { $confText = HTML::make( 'div' ) ->appendElement( HTML::make( 'p' ) ->appendText( 'All dependencies and reverse dependencies of the ' . 'selected task will be lost when it is moved.' ) ) ->appendElement( HTML::make( 'p' ) ->appendText( 'Please confirm.' ) ); return Loader::Create( 'Form' , 'Move task' , 'move-up' ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $task->id ) ) ->addField( Loader::Create( 'Field' , 'confirmed' , 'hidden' ) ->setDefaultValue( 1 ) ) ->addField( Loader::Create( 'Field' , 'force' , 'hidden' ) ->setDefaultValue( 1 ) ) ->addField( Loader::Create( 'Field' , 'confirm' , 'html' )->setDefaultValue( $confText ) ) ->setURL( 'tasks/view?id=' . $task->id ) ->controller( ); } } class Ctrl_TaskMoveForm extends Controller { public function __construct( ) { $this->dTasks = Loader::DAO( 'tasks' ); $this->dItems = Loader::DAO( 'items' ); } public function handle( Page $page ) { try { $id = (int) $this->getParameter( 'id' ); $type = $this->getParameter( 'type' ); } catch ( ParameterException $e ) { return 'tasks'; } $subtasks = ( $type === 's' ); $failure = $subtasks ? 'tasks' : 'items'; // Get the parent if ( $subtasks ) { $parent = $this->dTasks->get( $id ); } else { $parent = $this->dItems->get( $id ); } if ( $parent === null ) { return $failure; } // If the parent's empty, go back to displaying it $failure .= '/view?id=' . $id; if ( $subtasks ) { $tasks = $parent->subtasks; $name = $parent->title; } else { $tasks = $this->dTasks->getTasksAt( $parent ); $name = $parent->name; } if ( empty( $tasks ) ) { return $failure; } // Form header $page->setTitle( $name . ': move tasks' ); $form = Loader::Create( 'Form' , 'Move tasks' , 'move-tasks' ) ->setURL( $failure ) ->addController( Loader::Ctrl( 'task_move' ) ) ->addField( Loader::Create( 'Field' , 'type' , 'hidden' ) ->setDefaultValue( $subtasks ? 's' : 'i' ) ) ->addField( Loader::Create( 'Field' , 'id' , 'hidden' ) ->setDefaultValue( $id ) ); // List of targets $tSel = Loader::Create( 'Field' , 'target' , 'select' ) ->setDescription( 'Move to:' ) ->addOption( '' , '(please select a target)' ); $this->addTargets( $tSel , $subtasks , $id ); $form->addField( $tSel ); // List of tasks $tSel = Loader::Create( 'Field' , 'tasks[]' , 'select' , array( 'multiple' ) ) ->setDescription( 'Tasks to move:' ); foreach ( $tasks as $t ) { $tSel->addOption( $t->id , $t->title ); } $form->addField( $tSel ); return $form->controller( ); } private function addTargets( Field $field , $isTask , $id ) { $items = $this->dItems->getTreeList( ); $tasks = $this->dTasks->getActiveTasksAssoc( ); foreach ( $items as $item ) { $title = str_repeat( '--' , $item->depth ) . ' ' . strtoupper( $item->name ); $disabled = !$isTask && $item->id == $id; $iid = 'I' . $item->id; $field->addOption( $iid , $title , $disabled ); $this->addTargetTasks( $field , $iid , $tasks , $isTask , $id , $item->depth + 1 ); } } private function addTargetTasks( Field $field , $iid , $tasks , $isTask , $id , $depth ) { if ( !array_key_exists( $iid , $tasks ) ) { return; } foreach ( $tasks[ $iid ] as $task ) { $title = str_repeat( '--' , $depth ) . '> ' . $task->title; $disabled = $isTask && $task->id == $id; $tid = 'T' . $task->id; $field->addOption( $tid , $title , $disabled ); $this->addTargetTasks( $field , $tid , $tasks , $isTask , $id , $depth + 1 ); } } }