Command/ProcessHelpCommand.php
protected function findBestNextTask($branches, $taskList, ProcessConfiguration $process)
    {
        // Get resolvable tasks
        $taskCandidates = [];
        foreach ($taskList as $taskCode) {
            $task = $process->getTaskConfiguration($taskCode);
            if (empty($task->getPreviousTasksConfigurations())) {
                return $taskCode;
            }

            // Check if task has all necessary ancestors in branches
            $hasAllAncestors = array_reduce($task->getPreviousTasksConfigurations(), function ($result, TaskConfiguration $prevTask) use ($branches) {
                return $result && \in_array($prevTask->getCode(), $branches);
            }, true);

            if ($hasAllAncestors) {
                $taskCandidates[] = $taskCode;
            }
        }

        if (empty($taskCandidates)) {
            throw new \UnexpectedValueException('Cannot find a task to output');
        }

        // Try to find the task the most on the right
        $taskWeights = [];
        foreach ($taskCandidates as $taskCandidate) {
            $weight = 0;
            $task = $process->getTaskConfiguration($taskCandidate);
            foreach ($task->getPreviousTasksConfigurations() as $prevTask) {
                $key = array_search($prevTask->getCode(), $branches);

                // Should never be non-numeric...
                if (!is_numeric($key)) {
                    throw new \UnexpectedValueException('Invalid key type');
                }
                $weight += $key;
            }

            if (!empty($task->getPreviousTasksConfigurations())) {
                $weight = $weight / \count($task->getPreviousTasksConfigurations());
            }

            $taskWeights[$taskCandidate] = $weight;
        }

        arsort($taskWeights);
        $bestCandidate = key($taskWeights);
        $bestWeight = $taskWeights[$bestCandidate];

        $equalWeights = array_filter($taskWeights, function ($item) use ($bestWeight) {
            return $item == $bestWeight;
        });

        if (count($equalWeights) == 1) {
            return $bestCandidate;
        }

        // If a few tasks have the same weight, return the tasks with the lowest number of children
        $childCounts = [];
        foreach ($equalWeights as $taskCode => $weight) {
            $task = $process->getTaskConfiguration($taskCode);
            $childCounts[$taskCode] = $this->getTaskChildrenCount($task);
        }
        asort($childCounts);

        return key($childCounts);
    }
protected function findBestNextTask($branches, $taskList, ProcessConfiguration $process)
    {
        // Get resolvable tasks
        $taskCandidates = [];
        foreach ($taskList as $taskCode) {
            $task = $process->getTaskConfiguration($taskCode);
            if (empty($task->getPreviousTasksConfigurations())) {
                return $taskCode;
            }

            // Check if task has all necessary ancestors in branches
            $hasAllAncestors = array_reduce($task->getPreviousTasksConfigurations(), function ($result, TaskConfiguration $prevTask) use ($branches) {
                return $result && \in_array($prevTask->getCode(), $branches);
            }, true);

            if ($hasAllAncestors) {
                $taskCandidates[] = $taskCode;
            }
        }

        if (empty($taskCandidates)) {
            throw new \UnexpectedValueException('Cannot find a task to output');
        }

        // Try to find the task the most on the right
        $taskWeights = [];
        foreach ($taskCandidates as $taskCandidate) {
            $weight = 0;
            $task = $process->getTaskConfiguration($taskCandidate);
            foreach ($task->getPreviousTasksConfigurations() as $prevTask) {
                $key = array_search($prevTask->getCode(), $branches);

                // Should never be non-numeric...
                if (!is_numeric($key)) {
                    throw new \UnexpectedValueException('Invalid key type');
                }
                $weight += $key;
            }

            if (!empty($task->getPreviousTasksConfigurations())) {
                $weight = $weight / \count($task->getPreviousTasksConfigurations());
            }

            $taskWeights[$taskCandidate] = $weight;
        }

        arsort($taskWeights);
        $bestCandidate = key($taskWeights);
        $bestWeight = $taskWeights[$bestCandidate];

        $equalWeights = array_filter($taskWeights, function ($item) use ($bestWeight) {
            return $item == $bestWeight;
        });

        if (count($equalWeights) == 1) {
            return $bestCandidate;
        }

        // If a few tasks have the same weight, return the tasks with the lowest number of children
        $childCounts = [];
        foreach ($equalWeights as $taskCode => $weight) {
            $task = $process->getTaskConfiguration($taskCode);
            $childCounts[$taskCode] = $this->getTaskChildrenCount($task);
        }
        asort($childCounts);

        return key($childCounts);
    }
Try to find a best candidate for next display

@param                      $branches
@param                      $taskList
@param ProcessConfiguration $process

@return int|null|string