From ae708a712a5dd932c01e734f8450b899b1407a70 Mon Sep 17 00:00:00 2001 From: Frederic Guillot Date: Tue, 20 Dec 2016 20:06:39 -0500 Subject: Offer the possibility to override internal formatter objects from plugins --- app/Api/Procedure/BoardProcedure.php | 3 +- app/Controller/BoardAjaxController.php | 3 +- app/Controller/BoardViewController.php | 5 ++- app/Controller/GroupAjaxController.php | 6 ++-- app/Controller/ICalendarController.php | 5 +-- app/Controller/ProjectGanttController.php | 3 +- app/Controller/TaskAjaxController.php | 6 ++-- app/Controller/TaskGanttController.php | 3 +- app/Controller/TaskMovePositionController.php | 3 +- app/Controller/UserAjaxController.php | 10 ++---- app/Core/Base.php | 15 +++++++++ app/Core/Filter/FormatterInterface.php | 2 +- app/Core/Tool.php | 25 +++++++++++++- app/Formatter/BoardColumnFormatter.php | 2 +- app/Formatter/BoardFormatter.php | 2 +- app/Formatter/BoardSwimlaneFormatter.php | 2 +- app/Formatter/GroupAutoCompleteFormatter.php | 22 ++++-------- app/Formatter/UserAutoCompleteFormatter.php | 2 +- app/Helper/CalendarHelper.php | 9 ++--- app/Helper/ICalHelper.php | 11 +++--- app/Helper/ProjectActivityHelper.php | 9 +++-- app/ServiceProvider/FormatterProvider.php | 48 +++++++++++++++++++++++++++ app/common.php | 1 + 23 files changed, 125 insertions(+), 72 deletions(-) create mode 100644 app/ServiceProvider/FormatterProvider.php (limited to 'app') diff --git a/app/Api/Procedure/BoardProcedure.php b/app/Api/Procedure/BoardProcedure.php index 674b5466..69daaf09 100644 --- a/app/Api/Procedure/BoardProcedure.php +++ b/app/Api/Procedure/BoardProcedure.php @@ -3,7 +3,6 @@ namespace Kanboard\Api\Procedure; use Kanboard\Api\Authorization\ProjectAuthorization; -use Kanboard\Formatter\BoardFormatter; /** * Board API controller @@ -17,7 +16,7 @@ class BoardProcedure extends BaseProcedure { ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getBoard', $project_id); - return BoardFormatter::getInstance($this->container) + return $this->boardFormatter ->withProjectId($project_id) ->withQuery($this->taskFinderModel->getExtendedQuery()) ->format(); diff --git a/app/Controller/BoardAjaxController.php b/app/Controller/BoardAjaxController.php index 484ef67d..ecb76e9c 100644 --- a/app/Controller/BoardAjaxController.php +++ b/app/Controller/BoardAjaxController.php @@ -3,7 +3,6 @@ namespace Kanboard\Controller; use Kanboard\Core\Controller\AccessForbiddenException; -use Kanboard\Formatter\BoardFormatter; use Kanboard\Model\UserMetadataModel; /** @@ -139,7 +138,7 @@ class BoardAjaxController extends BaseController 'board_highlight_period' => $this->configModel->get('board_highlight_period'), 'swimlanes' => $this->taskLexer ->build($this->userSession->getFilters($project_id)) - ->format(BoardFormatter::getInstance($this->container)->withProjectId($project_id)) + ->format($this->boardFormatter->withProjectId($project_id)) )); } } diff --git a/app/Controller/BoardViewController.php b/app/Controller/BoardViewController.php index 10165908..9ef77e54 100644 --- a/app/Controller/BoardViewController.php +++ b/app/Controller/BoardViewController.php @@ -3,7 +3,6 @@ namespace Kanboard\Controller; use Kanboard\Core\Controller\AccessForbiddenException; -use Kanboard\Formatter\BoardFormatter; use Kanboard\Model\TaskModel; /** @@ -35,7 +34,7 @@ class BoardViewController extends BaseController $this->response->html($this->helper->layout->app('board/view_public', array( 'project' => $project, - 'swimlanes' => BoardFormatter::getInstance($this->container) + 'swimlanes' => $this->boardFormatter ->withProjectId($project['id']) ->withQuery($query) ->format() @@ -68,7 +67,7 @@ class BoardViewController extends BaseController 'board_highlight_period' => $this->configModel->get('board_highlight_period'), 'swimlanes' => $this->taskLexer ->build($search) - ->format(BoardFormatter::getInstance($this->container)->withProjectId($project['id'])) + ->format($this->boardFormatter->withProjectId($project['id'])) ))); } } diff --git a/app/Controller/GroupAjaxController.php b/app/Controller/GroupAjaxController.php index 496e9ef2..308bba9e 100644 --- a/app/Controller/GroupAjaxController.php +++ b/app/Controller/GroupAjaxController.php @@ -2,8 +2,6 @@ namespace Kanboard\Controller; -use Kanboard\Formatter\GroupAutoCompleteFormatter; - /** * Group Ajax Controller * @@ -20,7 +18,7 @@ class GroupAjaxController extends BaseController public function autocomplete() { $search = $this->request->getStringParam('term'); - $formatter = new GroupAutoCompleteFormatter($this->groupManager->find($search)); - $this->response->json($formatter->format()); + $groups = $this->groupManager->find($search); + $this->response->json($this->groupAutoCompleteFormatter->withGroups($groups)->format()); } } diff --git a/app/Controller/ICalendarController.php b/app/Controller/ICalendarController.php index e354c6f1..4fe8b78a 100644 --- a/app/Controller/ICalendarController.php +++ b/app/Controller/ICalendarController.php @@ -7,7 +7,6 @@ use Kanboard\Core\Filter\QueryBuilder; use Kanboard\Filter\TaskAssigneeFilter; use Kanboard\Filter\TaskProjectFilter; use Kanboard\Filter\TaskStatusFilter; -use Kanboard\Formatter\TaskICalFormatter; use Kanboard\Model\TaskModel; use Eluceo\iCal\Component\Calendar as iCalendar; @@ -94,8 +93,6 @@ class ICalendarController extends BaseController $end = $this->request->getStringParam('end', strtotime('+6 months')); $this->helper->ical->addTaskDateDueEvents($queryBuilder, $calendar, $start, $end); - - $formatter = new TaskICalFormatter($this->container); - $this->response->ical($formatter->setCalendar($calendar)->format()); + $this->response->ical($this->taskICalFormatter->setCalendar($calendar)->format()); } } diff --git a/app/Controller/ProjectGanttController.php b/app/Controller/ProjectGanttController.php index a70d9eee..8239005e 100644 --- a/app/Controller/ProjectGanttController.php +++ b/app/Controller/ProjectGanttController.php @@ -5,7 +5,6 @@ namespace Kanboard\Controller; use Kanboard\Filter\ProjectIdsFilter; use Kanboard\Filter\ProjectStatusFilter; use Kanboard\Filter\ProjectTypeFilter; -use Kanboard\Formatter\ProjectGanttFormatter; use Kanboard\Model\ProjectModel; /** @@ -30,7 +29,7 @@ class ProjectGanttController extends BaseController $filter->getQuery()->asc(ProjectModel::TABLE.'.start_date'); $this->response->html($this->helper->layout->app('project_gantt/show', array( - 'projects' => $filter->format(new ProjectGanttFormatter($this->container)), + 'projects' => $filter->format($this->projectGanttFormatter), 'title' => t('Gantt chart for all projects'), ))); } diff --git a/app/Controller/TaskAjaxController.php b/app/Controller/TaskAjaxController.php index 609dd23c..6d0b3fc2 100644 --- a/app/Controller/TaskAjaxController.php +++ b/app/Controller/TaskAjaxController.php @@ -8,8 +8,6 @@ use Kanboard\Filter\TaskProjectsFilter; use Kanboard\Filter\TaskStartsWithIdFilter; use Kanboard\Filter\TaskStatusFilter; use Kanboard\Filter\TaskTitleFilter; -use Kanboard\Formatter\TaskAutoCompleteFormatter; -use Kanboard\Formatter\TaskSuggestMenuFormatter; use Kanboard\Model\TaskModel; /** @@ -46,7 +44,7 @@ class TaskAjaxController extends BaseController $filter->withFilter(new TaskTitleFilter($search)); } - $this->response->json($filter->format(new TaskAutoCompleteFormatter($this->container))); + $this->response->json($filter->format($this->taskAutoCompleteFormatter)); } } @@ -66,7 +64,7 @@ class TaskAjaxController extends BaseController ->withFilter(new TaskStatusFilter(TaskModel::STATUS_OPEN)) ->withFilter(new TaskStartsWithIdFilter($taskId)); - $this->response->json($filter->format(new TaskSuggestMenuFormatter($this->container))); + $this->response->json($filter->format($this->taskSuggestMenuFormatter)); } } } diff --git a/app/Controller/TaskGanttController.php b/app/Controller/TaskGanttController.php index 868368e1..b03b9d00 100644 --- a/app/Controller/TaskGanttController.php +++ b/app/Controller/TaskGanttController.php @@ -3,7 +3,6 @@ namespace Kanboard\Controller; use Kanboard\Filter\TaskProjectFilter; -use Kanboard\Formatter\TaskGanttFormatter; use Kanboard\Model\TaskModel; /** @@ -35,7 +34,7 @@ class TaskGanttController extends BaseController 'title' => $project['name'], 'description' => $this->helper->projectHeader->getDescription($project), 'sorting' => $sorting, - 'tasks' => $filter->format(new TaskGanttFormatter($this->container)), + 'tasks' => $filter->format($this->taskGanttFormatter), ))); } diff --git a/app/Controller/TaskMovePositionController.php b/app/Controller/TaskMovePositionController.php index cb4afd04..caa074c9 100644 --- a/app/Controller/TaskMovePositionController.php +++ b/app/Controller/TaskMovePositionController.php @@ -3,7 +3,6 @@ namespace Kanboard\Controller; use Kanboard\Core\Controller\AccessForbiddenException; -use Kanboard\Formatter\BoardFormatter; use Kanboard\Model\TaskModel; /** @@ -20,7 +19,7 @@ class TaskMovePositionController extends BaseController $this->response->html($this->template->render('task_move_position/show', array( 'task' => $task, - 'board' => BoardFormatter::getInstance($this->container) + 'board' => $this->boardFormatter ->withProjectId($task['project_id']) ->withQuery($this->taskFinderModel->getExtendedQuery() ->eq(TaskModel::TABLE.'.is_active', TaskModel::STATUS_OPEN) diff --git a/app/Controller/UserAjaxController.php b/app/Controller/UserAjaxController.php index d93bfe9a..17567a00 100644 --- a/app/Controller/UserAjaxController.php +++ b/app/Controller/UserAjaxController.php @@ -3,8 +3,6 @@ namespace Kanboard\Controller; use Kanboard\Filter\UserNameFilter; -use Kanboard\Formatter\UserAutoCompleteFormatter; -use Kanboard\Formatter\UserMentionFormatter; use Kanboard\Model\UserModel; /** @@ -25,7 +23,7 @@ class UserAjaxController extends BaseController $search = $this->request->getStringParam('term'); $filter = $this->userQuery->withFilter(new UserNameFilter($search)); $filter->getQuery()->asc(UserModel::TABLE.'.name')->asc(UserModel::TABLE.'.username'); - $this->response->json($filter->format(new UserAutoCompleteFormatter($this->container))); + $this->response->json($filter->format($this->userAutoCompleteFormatter)); } /** @@ -39,11 +37,7 @@ class UserAjaxController extends BaseController $query = $this->request->getStringParam('search'); $users = $this->projectPermissionModel->findUsernames($project_id, $query); - $this->response->json( - UserMentionFormatter::getInstance($this->container) - ->withUsers($users) - ->format() - ); + $this->response->json($this->userMentionFormatter->withUsers($users)->format()); } /** diff --git a/app/Core/Base.php b/app/Core/Base.php index 881cccbd..d3c264d1 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -62,6 +62,21 @@ use Pimple\Container; * @property \Kanboard\Decorator\ColumnRestrictionCacheDecorator $columnRestrictionCacheDecorator * @property \Kanboard\Decorator\ColumnMoveRestrictionCacheDecorator $columnMoveRestrictionCacheDecorator * @property \Kanboard\Decorator\ProjectRoleRestrictionCacheDecorator $projectRoleRestrictionCacheDecorator + * @property \Kanboard\Formatter\BoardColumnFormatter $boardColumnFormatter + * @property \Kanboard\Formatter\BoardFormatter $boardFormatter + * @property \Kanboard\Formatter\BoardSwimlaneFormatter $boardSwimlaneFormatter + * @property \Kanboard\Formatter\BoardTaskFormatter $boardTaskFormatter + * @property \Kanboard\Formatter\GroupAutoCompleteFormatter $groupAutoCompleteFormatter + * @property \Kanboard\Formatter\ProjectActivityEventFormatter $projectActivityEventFormatter + * @property \Kanboard\Formatter\ProjectGanttFormatter $projectGanttFormatter + * @property \Kanboard\Formatter\SubtaskTimeTrackingCalendarFormatter $subtaskTimeTrackingCalendarFormatter + * @property \Kanboard\Formatter\TaskAutoCompleteFormatter $taskAutoCompleteFormatter + * @property \Kanboard\Formatter\TaskCalendarFormatter $taskCalendarFormatter + * @property \Kanboard\Formatter\TaskGanttFormatter $taskGanttFormatter + * @property \Kanboard\Formatter\TaskICalFormatter $taskICalFormatter + * @property \Kanboard\Formatter\TaskSuggestMenuFormatter $taskSuggestMenuFormatter + * @property \Kanboard\Formatter\UserAutoCompleteFormatter $userAutoCompleteFormatter + * @property \Kanboard\Formatter\UserMentionFormatter $userMentionFormatter * @property \Kanboard\Model\ActionModel $actionModel * @property \Kanboard\Model\ActionParameterModel $actionParameterModel * @property \Kanboard\Model\AvatarFileModel $avatarFileModel diff --git a/app/Core/Filter/FormatterInterface.php b/app/Core/Filter/FormatterInterface.php index b7c04c51..0ff84976 100644 --- a/app/Core/Filter/FormatterInterface.php +++ b/app/Core/Filter/FormatterInterface.php @@ -17,7 +17,7 @@ interface FormatterInterface * * @access public * @param Table $query - * @return FormatterInterface + * @return $this */ public function withQuery(Table $query); diff --git a/app/Core/Tool.php b/app/Core/Tool.php index 9b8820eb..6e457641 100644 --- a/app/Core/Tool.php +++ b/app/Core/Tool.php @@ -41,7 +41,7 @@ class Tool } /** - * Build dependency injection container from an array + * Build dependency injection containers from an array * * @static * @access public @@ -63,6 +63,29 @@ class Tool return $container; } + /** + * Build dependency injection container from an array + * + * @static + * @access public + * @param Container $container + * @param array $namespaces + * @return Container + */ + public static function buildFactories(Container $container, array $namespaces) + { + foreach ($namespaces as $namespace => $classes) { + foreach ($classes as $name) { + $class = '\\Kanboard\\'.$namespace.'\\'.$name; + $container[lcfirst($name)] = $container->factory(function ($c) use ($class) { + return new $class($c); + }); + } + } + + return $container; + } + /** * Build dependency injection container for custom helpers from an array * diff --git a/app/Formatter/BoardColumnFormatter.php b/app/Formatter/BoardColumnFormatter.php index 85d31b5c..0d59f54e 100644 --- a/app/Formatter/BoardColumnFormatter.php +++ b/app/Formatter/BoardColumnFormatter.php @@ -79,7 +79,7 @@ class BoardColumnFormatter extends BaseFormatter implements FormatterInterface { foreach ($this->columns as &$column) { $column['id'] = (int) $column['id']; - $column['tasks'] = BoardTaskFormatter::getInstance($this->container) + $column['tasks'] = $this->boardTaskFormatter ->withTasks($this->tasks) ->withTags($this->tags) ->withSwimlaneId($this->swimlaneId) diff --git a/app/Formatter/BoardFormatter.php b/app/Formatter/BoardFormatter.php index df443a52..3f47bfa9 100644 --- a/app/Formatter/BoardFormatter.php +++ b/app/Formatter/BoardFormatter.php @@ -59,7 +59,7 @@ class BoardFormatter extends BaseFormatter implements FormatterInterface $task_ids = array_column($tasks, 'id'); $tags = $this->taskTagModel->getTagsByTasks($task_ids); - return BoardSwimlaneFormatter::getInstance($this->container) + return $this->boardSwimlaneFormatter ->withSwimlanes($swimlanes) ->withColumns($columns) ->withTasks($tasks) diff --git a/app/Formatter/BoardSwimlaneFormatter.php b/app/Formatter/BoardSwimlaneFormatter.php index ce67c8a8..18db259d 100644 --- a/app/Formatter/BoardSwimlaneFormatter.php +++ b/app/Formatter/BoardSwimlaneFormatter.php @@ -82,7 +82,7 @@ class BoardSwimlaneFormatter extends BaseFormatter implements FormatterInterface foreach ($this->swimlanes as &$swimlane) { $swimlane['id'] = (int) $swimlane['id']; - $swimlane['columns'] = BoardColumnFormatter::getInstance($this->container) + $swimlane['columns'] = $this->boardColumnFormatter ->withSwimlaneId($swimlane['id']) ->withColumns($this->columns) ->withTasks($this->tasks) diff --git a/app/Formatter/GroupAutoCompleteFormatter.php b/app/Formatter/GroupAutoCompleteFormatter.php index 4d552886..d811de7f 100644 --- a/app/Formatter/GroupAutoCompleteFormatter.php +++ b/app/Formatter/GroupAutoCompleteFormatter.php @@ -12,36 +12,26 @@ use PicoDb\Table; * @package formatter * @author Frederic Guillot */ -class GroupAutoCompleteFormatter implements FormatterInterface +class GroupAutoCompleteFormatter extends BaseFormatter implements FormatterInterface { /** * Groups found * - * @access private + * @access protected * @var GroupProviderInterface[] */ - private $groups; + protected $groups; /** - * Format groups for the ajax auto-completion + * Set groups * * @access public * @param GroupProviderInterface[] $groups + * @return $this */ - public function __construct(array $groups) + public function withGroups(array $groups) { $this->groups = $groups; - } - - /** - * Set query - * - * @access public - * @param Table $query - * @return FormatterInterface - */ - public function withQuery(Table $query) - { return $this; } diff --git a/app/Formatter/UserAutoCompleteFormatter.php b/app/Formatter/UserAutoCompleteFormatter.php index cd23a2a4..32a83608 100644 --- a/app/Formatter/UserAutoCompleteFormatter.php +++ b/app/Formatter/UserAutoCompleteFormatter.php @@ -14,7 +14,7 @@ use Kanboard\Core\Filter\FormatterInterface; class UserAutoCompleteFormatter extends BaseFormatter implements FormatterInterface { /** - * Format the tasks for the ajax autocompletion + * Format the tasks for the ajax auto-completion * * @access public * @return array diff --git a/app/Helper/CalendarHelper.php b/app/Helper/CalendarHelper.php index 4f78b673..0942177d 100644 --- a/app/Helper/CalendarHelper.php +++ b/app/Helper/CalendarHelper.php @@ -5,8 +5,6 @@ namespace Kanboard\Helper; use Kanboard\Core\Base; use Kanboard\Core\Filter\QueryBuilder; use Kanboard\Filter\TaskDueDateRangeFilter; -use Kanboard\Formatter\SubtaskTimeTrackingCalendarFormatter; -use Kanboard\Formatter\TaskCalendarFormatter; /** * Calendar Helper @@ -44,7 +42,7 @@ class CalendarHelper extends Base */ public function getTaskDateDueEvents(QueryBuilder $queryBuilder, $start, $end) { - $formatter = new TaskCalendarFormatter($this->container); + $formatter = $this->taskCalendarFormatter; $formatter->setFullDay(); $formatter->setColumns('date_due'); @@ -73,7 +71,7 @@ class CalendarHelper extends Base 'date_due' )); - $formatter = new TaskCalendarFormatter($this->container); + $formatter = $this->taskCalendarFormatter; $formatter->setColumns($startColumn, 'date_due'); return $queryBuilder->format($formatter); @@ -90,8 +88,7 @@ class CalendarHelper extends Base */ public function getSubtaskTimeTrackingEvents($user_id, $start, $end) { - $formatter = new SubtaskTimeTrackingCalendarFormatter($this->container); - return $formatter + return $this->subtaskTimeTrackingCalendarFormatter ->withQuery($this->subtaskTimeTrackingModel->getUserQuery($user_id) ->addCondition($this->getCalendarCondition( $this->dateParser->getTimestampFromIsoFormat($start), diff --git a/app/Helper/ICalHelper.php b/app/Helper/ICalHelper.php index dc399bf8..95723417 100644 --- a/app/Helper/ICalHelper.php +++ b/app/Helper/ICalHelper.php @@ -5,7 +5,6 @@ namespace Kanboard\Helper; use Kanboard\Core\Base; use Kanboard\Core\Filter\QueryBuilder; use Kanboard\Filter\TaskDueDateRangeFilter; -use Kanboard\Formatter\TaskICalFormatter; use Eluceo\iCal\Component\Calendar as iCalendar; /** @@ -29,10 +28,10 @@ class ICalHelper extends Base { $queryBuilder->withFilter(new TaskDueDateRangeFilter(array($start, $end))); - $formatter = new TaskICalFormatter($this->container); - $formatter->setColumns('date_due'); - $formatter->setCalendar($calendar); - $formatter->withQuery($queryBuilder->getQuery()); - $formatter->addFullDayEvents(); + $this->taskICalFormatter + ->setColumns('date_due') + ->setCalendar($calendar) + ->withQuery($queryBuilder->getQuery()) + ->addFullDayEvents(); } } diff --git a/app/Helper/ProjectActivityHelper.php b/app/Helper/ProjectActivityHelper.php index 704cd4fe..480db3d5 100644 --- a/app/Helper/ProjectActivityHelper.php +++ b/app/Helper/ProjectActivityHelper.php @@ -6,7 +6,6 @@ use Kanboard\Core\Base; use Kanboard\Filter\ProjectActivityProjectIdFilter; use Kanboard\Filter\ProjectActivityProjectIdsFilter; use Kanboard\Filter\ProjectActivityTaskIdFilter; -use Kanboard\Formatter\ProjectActivityEventFormatter; use Kanboard\Model\ProjectActivityModel; /** @@ -38,7 +37,7 @@ class ProjectActivityHelper extends Base ->limit(500) ; - $events = $queryBuilder->format(new ProjectActivityEventFormatter($this->container)); + $events = $queryBuilder->format($this->projectActivityEventFormatter); } return $events; @@ -62,7 +61,7 @@ class ProjectActivityHelper extends Base ->limit($limit) ; - return $queryBuilder->format(new ProjectActivityEventFormatter($this->container)); + return $queryBuilder->format($this->projectActivityEventFormatter); } /** @@ -83,7 +82,7 @@ class ProjectActivityHelper extends Base ->limit($limit) ; - return $queryBuilder->format(new ProjectActivityEventFormatter($this->container)); + return $queryBuilder->format($this->projectActivityEventFormatter); } /** @@ -100,6 +99,6 @@ class ProjectActivityHelper extends Base $queryBuilder->getQuery()->desc(ProjectActivityModel::TABLE.'.id'); - return $queryBuilder->format(new ProjectActivityEventFormatter($this->container)); + return $queryBuilder->format($this->projectActivityEventFormatter); } } diff --git a/app/ServiceProvider/FormatterProvider.php b/app/ServiceProvider/FormatterProvider.php new file mode 100644 index 00000000..dbba3f3c --- /dev/null +++ b/app/ServiceProvider/FormatterProvider.php @@ -0,0 +1,48 @@ + array( + 'BoardColumnFormatter', + 'BoardFormatter', + 'BoardSwimlaneFormatter', + 'BoardTaskFormatter', + 'GroupAutoCompleteFormatter', + 'ProjectActivityEventFormatter', + 'ProjectGanttFormatter', + 'SubtaskTimeTrackingCalendarFormatter', + 'TaskAutoCompleteFormatter', + 'TaskCalendarFormatter', + 'TaskGanttFormatter', + 'TaskICalFormatter', + 'TaskSuggestMenuFormatter', + 'UserAutoCompleteFormatter', + 'UserMentionFormatter', + ) + ); + + /** + * Registers services on the given container. + * + * @param Container $container + * @return Container + */ + public function register(Container $container) + { + Tool::buildFactories($container, $this->formatters); + return $container; + } +} diff --git a/app/common.php b/app/common.php index 6ebb839e..fd55c0bb 100644 --- a/app/common.php +++ b/app/common.php @@ -48,6 +48,7 @@ $container->register(new Kanboard\ServiceProvider\ExternalLinkProvider()); $container->register(new Kanboard\ServiceProvider\ExternalTaskProvider()); $container->register(new Kanboard\ServiceProvider\AvatarProvider()); $container->register(new Kanboard\ServiceProvider\FilterProvider()); +$container->register(new Kanboard\ServiceProvider\FormatterProvider()); $container->register(new Kanboard\ServiceProvider\JobProvider()); $container->register(new Kanboard\ServiceProvider\QueueProvider()); $container->register(new Kanboard\ServiceProvider\ApiProvider()); -- cgit v1.2.3