From 34d7450d3c13342715e90ec21bceaa13e1baa876 Mon Sep 17 00:00:00 2001 From: Frédéric Guillot Date: Sun, 28 Dec 2014 11:28:50 -0500 Subject: Template helpers refactoring --- app/Controller/Analytic.php | 2 +- app/Controller/App.php | 3 +- app/Controller/Base.php | 24 +- app/Controller/Board.php | 18 +- app/Controller/Config.php | 2 +- app/Controller/File.php | 2 +- app/Controller/Project.php | 2 +- app/Controller/Task.php | 6 +- app/Controller/User.php | 2 +- app/Core/Helper.php | 629 +++++++++++++++++++ app/Core/Session.php | 50 +- app/Core/Template.php | 12 +- app/Model/Acl.php | 24 +- app/Model/Base.php | 2 + app/Model/Config.php | 11 +- app/Model/Notification.php | 7 +- app/Model/ProjectActivity.php | 8 +- app/Model/ProjectPermission.php | 4 + app/Model/User.php | 25 +- app/ServiceProvider/ClassProvider.php | 72 +++ app/ServiceProvider/ModelProvider.php | 63 -- app/Template/action/event.php | 14 +- app/Template/action/index.php | 42 +- app/Template/action/params.php | 48 +- app/Template/action/remove.php | 6 +- app/Template/analytic/cfd.php | 14 +- app/Template/analytic/layout.php | 8 +- app/Template/analytic/sidebar.php | 6 +- app/Template/analytic/tasks.php | 4 +- app/Template/analytic/users.php | 4 +- app/Template/app/dashboard.php | 22 +- app/Template/app/projects.php | 16 +- app/Template/app/subtasks.php | 18 +- app/Template/app/tasks.php | 16 +- app/Template/board/assignee.php | 14 +- app/Template/board/category.php | 14 +- app/Template/board/comments.php | 4 +- app/Template/board/description.php | 2 +- app/Template/board/edit.php | 26 +- app/Template/board/files.php | 4 +- app/Template/board/filters.php | 16 +- app/Template/board/index.php | 4 +- app/Template/board/public.php | 2 +- app/Template/board/remove.php | 4 +- app/Template/board/show.php | 6 +- app/Template/board/subtasks.php | 6 +- app/Template/board/swimlane.php | 10 +- app/Template/board/task.php | 30 +- app/Template/category/edit.php | 12 +- app/Template/category/index.php | 16 +- app/Template/category/remove.php | 4 +- app/Template/comment/create.php | 12 +- app/Template/comment/edit.php | 12 +- app/Template/comment/remove.php | 6 +- app/Template/comment/show.php | 12 +- app/Template/config/about.php | 8 +- app/Template/config/api.php | 6 +- app/Template/config/application.php | 20 +- app/Template/config/board.php | 20 +- app/Template/config/layout.php | 2 +- app/Template/config/sidebar.php | 10 +- app/Template/config/webhook.php | 18 +- app/Template/event/comment_create.php | 6 +- app/Template/event/comment_update.php | 4 +- app/Template/event/subtask_create.php | 6 +- app/Template/event/subtask_update.php | 6 +- app/Template/event/task_assignee_change.php | 6 +- app/Template/event/task_close.php | 4 +- app/Template/event/task_create.php | 4 +- app/Template/event/task_move_column.php | 4 +- app/Template/event/task_move_position.php | 4 +- app/Template/event/task_open.php | 4 +- app/Template/event/task_update.php | 4 +- app/Template/file/new.php | 8 +- app/Template/file/open.php | 4 +- app/Template/file/remove.php | 6 +- app/Template/file/show.php | 6 +- app/Template/layout.php | 22 +- app/Template/notification/comment_creation.php | 6 +- app/Template/notification/comment_update.php | 6 +- app/Template/notification/file_creation.php | 4 +- app/Template/notification/subtask_creation.php | 12 +- app/Template/notification/subtask_update.php | 14 +- app/Template/notification/task_assignee_change.php | 6 +- app/Template/notification/task_close.php | 4 +- app/Template/notification/task_creation.php | 12 +- app/Template/notification/task_due.php | 6 +- app/Template/notification/task_move_column.php | 8 +- app/Template/notification/task_move_position.php | 8 +- app/Template/notification/task_open.php | 4 +- app/Template/notification/task_update.php | 12 +- app/Template/project/activity.php | 10 +- app/Template/project/disable.php | 4 +- app/Template/project/duplicate.php | 4 +- app/Template/project/edit.php | 10 +- app/Template/project/enable.php | 4 +- app/Template/project/events.php | 6 +- app/Template/project/export_daily_summary.php | 14 +- app/Template/project/export_tasks.php | 14 +- app/Template/project/feed.php | 12 +- app/Template/project/index.php | 10 +- app/Template/project/layout.php | 6 +- app/Template/project/new.php | 14 +- app/Template/project/remove.php | 4 +- app/Template/project/search.php | 16 +- app/Template/project/share.php | 10 +- app/Template/project/show.php | 14 +- app/Template/project/sidebar.php | 36 +- app/Template/project/tasks.php | 8 +- app/Template/project/users.php | 26 +- app/Template/subtask/create.php | 22 +- app/Template/subtask/edit.php | 30 +- app/Template/subtask/remove.php | 6 +- app/Template/subtask/show.php | 24 +- app/Template/swimlane/edit.php | 12 +- app/Template/swimlane/index.php | 26 +- app/Template/swimlane/remove.php | 4 +- app/Template/swimlane/table.php | 14 +- app/Template/task/close.php | 6 +- app/Template/task/comments.php | 6 +- app/Template/task/details.php | 14 +- app/Template/task/duplicate.php | 4 +- app/Template/task/duplicate_project.php | 12 +- app/Template/task/edit.php | 40 +- app/Template/task/edit_description.php | 12 +- app/Template/task/layout.php | 4 +- app/Template/task/move_project.php | 12 +- app/Template/task/new.php | 50 +- app/Template/task/open.php | 6 +- app/Template/task/public.php | 10 +- app/Template/task/remove.php | 6 +- app/Template/task/show.php | 14 +- app/Template/task/show_description.php | 4 +- app/Template/task/sidebar.php | 24 +- app/Template/task/table.php | 30 +- app/Template/task/time.php | 18 +- app/Template/task/timesheet.php | 6 +- app/Template/user/edit.php | 30 +- app/Template/user/external.php | 12 +- app/Template/user/index.php | 32 +- app/Template/user/last.php | 6 +- app/Template/user/layout.php | 8 +- app/Template/user/login.php | 20 +- app/Template/user/new.php | 34 +- app/Template/user/notifications.php | 10 +- app/Template/user/password.php | 20 +- app/Template/user/remove.php | 4 +- app/Template/user/sessions.php | 6 +- app/Template/user/show.php | 8 +- app/Template/user/sidebar.php | 20 +- app/common.php | 2 +- app/helpers.php | 675 --------------------- composer.json | 1 - composer.lock | 2 +- tests/units/Base.php | 2 +- 155 files changed, 1606 insertions(+), 1610 deletions(-) create mode 100644 app/Core/Helper.php create mode 100644 app/ServiceProvider/ClassProvider.php delete mode 100644 app/ServiceProvider/ModelProvider.php delete mode 100644 app/helpers.php diff --git a/app/Controller/Analytic.php b/app/Controller/Analytic.php index 6c49089b..115f75f0 100644 --- a/app/Controller/Analytic.php +++ b/app/Controller/Analytic.php @@ -21,7 +21,7 @@ class Analytic extends Base private function layout($template, array $params) { $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); - $params['analytic_content_for_layout'] = $this->template->load($template, $params); + $params['analytic_content_for_layout'] = $this->template->render($template, $params); return $this->template->layout('analytic/layout', $params); } diff --git a/app/Controller/App.php b/app/Controller/App.php index eb1d83af..56e81179 100644 --- a/app/Controller/App.php +++ b/app/Controller/App.php @@ -3,7 +3,6 @@ namespace Controller; use Model\SubTask as SubTaskModel; -use Helper; /** * Application controller @@ -192,7 +191,7 @@ class App extends Base $this->response->html('

'.t('Nothing to preview...').'

'); } else { - $this->response->html(Helper\markdown($payload['text'])); + $this->response->html($this->template->markdown($payload['text'])); } } diff --git a/app/Controller/Base.php b/app/Controller/Base.php index 19eb7f12..18f21ee8 100644 --- a/app/Controller/Base.php +++ b/app/Controller/Base.php @@ -17,6 +17,8 @@ use Symfony\Component\EventDispatcher\Event; * @package controller * @author Frederic Guillot * + * @property \Core\Session $session + * @property \Core\Template $template * @property \Model\Acl $acl * @property \Model\Authentication $authentication * @property \Model\Action $action @@ -69,22 +71,6 @@ abstract class Base */ protected $response; - /** - * Template instance - * - * @accesss protected - * @var \Core\Template - */ - protected $template; - - /** - * Session instance - * - * @accesss public - * @var \Core\Session - */ - protected $session; - /** * Container instance * @@ -104,8 +90,6 @@ abstract class Base $this->container = $container; $this->request = new Request; $this->response = new Response; - $this->session = new Session; - $this->template = new Template; } /** @@ -265,7 +249,7 @@ abstract class Base $params['hide_remove_menu'] = true; } - $content = $this->template->load($template, $params); + $content = $this->template->render($template, $params); $params['task_content_for_layout'] = $content; $params['title'] = $params['task']['project_name'].' > '.$params['task']['title']; $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); @@ -283,7 +267,7 @@ abstract class Base */ protected function projectLayout($template, array $params) { - $content = $this->template->load($template, $params); + $content = $this->template->render($template, $params); $params['project_content_for_layout'] = $content; $params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' > '.$params['title']; $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); diff --git a/app/Controller/Board.php b/app/Controller/Board.php index 072acf26..2c10e105 100644 --- a/app/Controller/Board.php +++ b/app/Controller/Board.php @@ -39,7 +39,7 @@ class Board extends Base $task = $this->getTask(); $project = $this->project->getById($task['project_id']); - $this->response->html($this->template->load('board/assignee', array( + $this->response->html($this->template->render('board/assignee', array( 'values' => $task, 'users_list' => $this->projectPermission->getMemberList($project['id']), 'project' => $project, @@ -78,7 +78,7 @@ class Board extends Base $task = $this->getTask(); $project = $this->project->getById($task['project_id']); - $this->response->html($this->template->load('board/category', array( + $this->response->html($this->template->render('board/category', array( 'values' => $task, 'categories_list' => $this->category->getList($project['id']), 'project' => $project, @@ -360,7 +360,7 @@ class Board extends Base } $this->response->html( - $this->template->load('board/show', array( + $this->template->render('board/show', array( 'project' => $this->project->getById($project_id), 'swimlanes' => $this->board->getBoard($project_id), 'categories' => $this->category->getList($project_id, false), @@ -394,7 +394,7 @@ class Board extends Base } $this->response->html( - $this->template->load('board/show', array( + $this->template->render('board/show', array( 'project' => $this->project->getById($project_id), 'swimlanes' => $this->board->getBoard($project_id), 'categories' => $this->category->getList($project_id, false), @@ -412,7 +412,7 @@ class Board extends Base public function subtasks() { $task = $this->getTask(); - $this->response->html($this->template->load('board/subtasks', array( + $this->response->html($this->template->render('board/subtasks', array( 'subtasks' => $this->subTask->getAll($task['id']) ))); } @@ -427,7 +427,7 @@ class Board extends Base $task = $this->getTask(); $this->subTask->toggleStatus($this->request->getIntegerParam('subtask_id')); - $this->response->html($this->template->load('board/subtasks', array( + $this->response->html($this->template->render('board/subtasks', array( 'subtasks' => $this->subTask->getAll($task['id']) ))); } @@ -441,7 +441,7 @@ class Board extends Base { $task = $this->getTask(); - $this->response->html($this->template->load('board/files', array( + $this->response->html($this->template->render('board/files', array( 'files' => $this->file->getAll($task['id']) ))); } @@ -455,7 +455,7 @@ class Board extends Base { $task = $this->getTask(); - $this->response->html($this->template->load('board/comments', array( + $this->response->html($this->template->render('board/comments', array( 'comments' => $this->comment->getAll($task['id']) ))); } @@ -469,7 +469,7 @@ class Board extends Base { $task = $this->getTask(); - $this->response->html($this->template->load('board/description', array( + $this->response->html($this->template->render('board/description', array( 'task' => $task ))); } diff --git a/app/Controller/Config.php b/app/Controller/Config.php index 199259d7..4093b7a1 100644 --- a/app/Controller/Config.php +++ b/app/Controller/Config.php @@ -23,7 +23,7 @@ class Config extends Base $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); $params['values'] = $this->config->getAll(); $params['errors'] = array(); - $params['config_content_for_layout'] = $this->template->load($template, $params); + $params['config_content_for_layout'] = $this->template->render($template, $params); return $this->template->layout('config/layout', $params); } diff --git a/app/Controller/File.php b/app/Controller/File.php index ae44cac0..1585a701 100644 --- a/app/Controller/File.php +++ b/app/Controller/File.php @@ -75,7 +75,7 @@ class File extends Base $file = $this->file->getById($this->request->getIntegerParam('file_id')); if ($file['task_id'] == $task['id']) { - $this->response->html($this->template->load('file/open', array( + $this->response->html($this->template->render('file/open', array( 'file' => $file ))); } diff --git a/app/Controller/Project.php b/app/Controller/Project.php index 5395a5a4..9037a91a 100644 --- a/app/Controller/Project.php +++ b/app/Controller/Project.php @@ -447,7 +447,7 @@ class Project extends Base $this->forbidden(true); } - $this->response->xml($this->template->load('project/feed', array( + $this->response->xml($this->template->render('project/feed', array( 'events' => $this->projectActivity->getProject($project['id']), 'project' => $project, ))); diff --git a/app/Controller/Task.php b/app/Controller/Task.php index 33b4b039..284cbec0 100644 --- a/app/Controller/Task.php +++ b/app/Controller/Task.php @@ -89,7 +89,7 @@ class Task extends Base public function create(array $values = array(), array $errors = array()) { $project = $this->getProject(); - $method = $this->request->isAjax() ? 'load' : 'layout'; + $method = $this->request->isAjax() ? 'render' : 'layout'; if (empty($values)) { @@ -179,7 +179,7 @@ class Task extends Base ); if ($ajax) { - $this->response->html($this->template->load('task/edit', $params)); + $this->response->html($this->template->render('task/edit', $params)); } else { $this->response->html($this->taskLayout('task/edit', $params)); @@ -410,7 +410,7 @@ class Task extends Base ); if ($ajax) { - $this->response->html($this->template->load('task/edit_description', $params)); + $this->response->html($this->template->render('task/edit_description', $params)); } else { $this->response->html($this->taskLayout('task/edit_description', $params)); diff --git a/app/Controller/User.php b/app/Controller/User.php index 93b5ca18..619bbc90 100644 --- a/app/Controller/User.php +++ b/app/Controller/User.php @@ -76,7 +76,7 @@ class User extends Base */ private function layout($template, array $params) { - $content = $this->template->load($template, $params); + $content = $this->template->render($template, $params); $params['user_content_for_layout'] = $content; $params['board_selector'] = $this->projectPermission->getAllowedProjects($this->acl->getUserId()); diff --git a/app/Core/Helper.php b/app/Core/Helper.php new file mode 100644 index 00000000..86034692 --- /dev/null +++ b/app/Core/Helper.php @@ -0,0 +1,629 @@ +container = $container; + } + + /** + * Load automatically models + * + * @access public + * @param string $name Model name + * @return mixed + */ + public function __get($name) + { + return $this->container[$name]; + } + + /** + * Return the user full name + * + * @param array $user User properties + * @return string + */ + public function getFullname(array $user = array()) + { + return $this->user->getFullname(empty($user) ? $_SESSION['user'] : $user); + } + + /** + * HTML escaping + * + * @param string $value Value to escape + * @return string + */ + public function e($value) + { + return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false); + } + + /** + * Add a Javascript asset + * + * @param string $filename Filename + * @return string + */ + public function js($filename) + { + return ''; + } + + /** + * Add a stylesheet asset + * + * @param string $filename Filename + * @return string + */ + public function css($filename) + { + return ''; + } + + /** + * Display the form error class + * + * @param array $errors Error list + * @param string $name Field name + * @return string + */ + public function errorClass(array $errors, $name) + { + return ! isset($errors[$name]) ? '' : ' form-error'; + } + + /** + * Display a list of form errors + * + * @param array $errors List of errors + * @param string $name Field name + * @return string + */ + public function errorList(array $errors, $name) + { + $html = ''; + + if (isset($errors[$name])) { + + $html .= ''; + } + + return $html; + } + + /** + * Get an escaped form value + * + * @param mixed $values Values + * @param string $name Field name + * @return string + */ + public function formValue($values, $name) + { + if (isset($values->$name)) { + return 'value="'.$this->e($values->$name).'"'; + } + + return isset($values[$name]) ? 'value="'.$this->e($values[$name]).'"' : ''; + } + + /** + * Hidden CSRF token field + * + * @return string + */ + public function formCsrf() + { + return ''; + } + + /** + * Display a hidden form field + * + * @param string $name Field name + * @param array $values Form values + * @return string + */ + public function formHidden($name, array $values = array()) + { + return 'formValue($values, $name).'/>'; + } + + /** + * Display a select field + * + * @param string $name Field name + * @param array $options Options + * @param array $values Form values + * @param array $errors Form errors + * @param string $class CSS class + * @return string + */ + public function formSelect($name, array $options, array $values = array(), array $errors = array(), $class = '') + { + $html = ''; + $html .= $this->errorList($errors, $name); + + return $html; + } + + /** + * Display a radio field group + * + * @param string $name Field name + * @param array $options Options + * @param array $values Form values + * @return string + */ + public function formRadios($name, array $options, array $values = array()) + { + $html = ''; + + foreach ($options as $value => $label) { + $html .= $this->formRadio($name, $label, $value, isset($values[$name]) && $values[$name] == $value); + } + + return $html; + } + + /** + * Display a radio field + * + * @param string $name Field name + * @param string $label Form label + * @param string $value Form value + * @param boolean $selected Field selected or not + * @param string $class CSS class + * @return string + */ + public function formRadio($name, $label, $value, $selected = false, $class = '') + { + return ''; + } + + /** + * Display a checkbox field + * + * @param string $name Field name + * @param string $label Form label + * @param string $value Form value + * @param boolean $checked Field selected or not + * @param string $class CSS class + * @return string + */ + public function formCheckbox($name, $label, $value, $checked = false, $class = '') + { + return ''; + } + + /** + * Display a form label + * + * @param string $name Field name + * @param string $label Form label + * @param array $attributes HTML attributes + * @return string + */ + public function formLabel($label, $name, array $attributes = array()) + { + return ''; + } + + /** + * Display a textarea + * + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formTextarea($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + $class .= $this->errorClass($errors, $name); + + $html = ''; + $html .= $this->errorList($errors, $name); + + return $html; + } + + /** + * Display a input field + * + * @param string $type HMTL input tag type + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formInput($type, $name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + $class .= $this->errorClass($errors, $name); + + $html = 'formValue($values, $name).' class="'.$class.'" '; + $html .= implode(' ', $attributes).'/>'; + if (in_array('required', $attributes)) $html .= '*'; + $html .= $this->errorList($errors, $name); + + return $html; + } + + /** + * Display a text field + * + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formText($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + return $this->formInput('text', $name, $values, $errors, $attributes, $class); + } + + /** + * Display a password field + * + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formPassword($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + return $this->formInput('password', $name, $values, $errors, $attributes, $class); + } + + /** + * Display an email field + * + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formEmail($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + return $this->formInput('email', $name, $values, $errors, $attributes, $class); + } + + /** + * Display a number field + * + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formNumber($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + return $this->formInput('number', $name, $values, $errors, $attributes, $class); + } + + /** + * Display a numeric field (allow decimal number) + * + * @param string $name Field name + * @param array $values Form values + * @param array $errors Form errors + * @param array $attributes HTML attributes + * @param string $class CSS class + * @return string + */ + public function formNumeric($name, $values = array(), array $errors = array(), array $attributes = array(), $class = '') + { + return $this->formInput('text', $name, $values, $errors, $attributes, $class.' form-numeric'); + } + + /** + * Link + * + * a('link', 'task', 'show', array('task_id' => $task_id)) + * + * @param string $label Link label + * @param string $controller Controller name + * @param string $action Action name + * @param array $params Url parameters + * @param boolean $csrf Add a CSRF token + * @param string $class CSS class attribute + * @param boolean $new_tab Open the link in a new tab + * @return string + */ + public function a($label, $controller, $action, array $params = array(), $csrf = false, $class = '', $title = '', $new_tab = false) + { + return ''.$label.''; + } + + /** + * URL query string + * + * u('task', 'show', array('task_id' => $task_id)) + * + * @param string $controller Controller name + * @param string $action Action name + * @param array $params Url parameters + * @param boolean $csrf Add a CSRF token + * @return string + */ + public function u($controller, $action, array $params = array(), $csrf = false) + { + $html = '?controller='.$controller.'&action='.$action; + + if ($csrf) { + $params['csrf_token'] = Security::getCSRFToken(); + } + + foreach ($params as $key => $value) { + $html .= '&'.$key.'='.$value; + } + + return $html; + } + + /** + * Pagination links + * + * @param array $pagination Pagination information + * @return string + */ + public function paginate(array $pagination) + { + extract($pagination); + + if ($pagination['offset'] === 0 && ($total - $pagination['offset']) <= $limit) { + return ''; + } + + $html = ''; + + return $html; + } + + /** + * Column sorting (work with pagination) + * + * @param string $label Column title + * @param string $column SQL column name + * @param array $pagination Pagination information + * @return string + */ + public function order($label, $column, array $pagination) + { + extract($pagination); + + $prefix = ''; + + if ($order === $column) { + $prefix = $direction === 'DESC' ? '▼ ' : '▲ '; + $direction = $direction === 'DESC' ? 'ASC' : 'DESC'; + } + + $order = $column; + + return $prefix.$this->a($label, $controller, $action, $params + compact('offset', 'order', 'direction')); + } + + /** + * Markdown transformation + * + * @param string $text Markdown content + * @param array $link Link parameters for replacement + * @return string + */ + public function markdown($text, array $link = array('controller' => 'task', 'action' => 'show', 'params' => array())) + { + $html = Parsedown::instance() + ->setMarkupEscaped(true) # escapes markup (HTML) + ->text($text); + + // Replace task #123 by a link to the task + $html = preg_replace_callback('!#(\d+)!i', function($matches) use ($link) { // TODO: Fix that + return a( + $matches[0], + $link['controller'], + $link['action'], + $link['params'] + array('task_id' => $matches[1]) + ); + }, $html); + + return $html; + } + + /** + * Get the current URL without the querystring + * + * @return string + */ + public function getCurrentBaseUrl() + { + $url = Request::isHTTPS() ? 'https://' : 'http://'; + $url .= $_SERVER['SERVER_NAME']; + $url .= $_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443 ? '' : ':'.$_SERVER['SERVER_PORT']; + $url .= dirname($_SERVER['PHP_SELF']) !== '/' ? dirname($_SERVER['PHP_SELF']).'/' : '/'; + + return $url; + } + + /** + * Dispplay the flash session message + * + * @param string $html HTML wrapper + * @return string + */ + public function flash($html) + { + $data = ''; + + if (isset($_SESSION['flash_message'])) { + $data = sprintf($html, $this->e($_SESSION['flash_message'])); + unset($_SESSION['flash_message']); + } + + return $data; + } + + /** + * Display the flash session error message + * + * @param string $html HTML wrapper + * @return string + */ + public function flashError($html) + { + $data = ''; + + if (isset($_SESSION['flash_error_message'])) { + $data = sprintf($html, $this->e($_SESSION['flash_error_message'])); + unset($_SESSION['flash_error_message']); + } + + return $data; + } + + /** + * Format a file size + * + * @param integer $size Size in bytes + * @param integer $precision Precision + * @return string + */ + public function formatBytes($size, $precision = 2) + { + $base = log($size) / log(1024); + $suffixes = array('', 'k', 'M', 'G', 'T'); + + return round(pow(1024, $base - floor($base)), $precision).$suffixes[(int)floor($base)]; + } + + /** + * Truncate a long text + * + * @param string $value Text + * @param integer $max_length Max Length + * @param string $end Text end + * @return string + */ + public function summary($value, $max_length = 85, $end = '[...]') + { + $length = strlen($value); + + if ($length > $max_length) { + return substr($value, 0, $max_length).' '.$end; + } + + return $value; + } + + /** + * Return true if needle is contained in the haystack + * + * @param string $haystack Haystack + * @param string $needle Needle + * @return boolean + */ + public function contains($haystack, $needle) + { + return strpos($haystack, $needle) !== false; + } + + /** + * Return a value from a dictionary + * + * @param mixed $id Key + * @param array $listing Dictionary + * @param string $default_value Value displayed when the key doesn't exists + * @return string + */ + public function inList($id, array $listing, $default_value = '?') + { + if (isset($listing[$id])) { + return $this->e($listing[$id]); + } + + return $default_value; + } +} diff --git a/app/Core/Session.php b/app/Core/Session.php index 3305eca3..0e5f7426 100644 --- a/app/Core/Session.php +++ b/app/Core/Session.php @@ -2,13 +2,15 @@ namespace Core; +use ArrayAccess; + /** * Session class * * @package core * @author Frederic Guillot */ -class Session +class Session implements ArrayAccess { /** * Sesion lifetime @@ -59,7 +61,7 @@ class Session ini_set('session.entropy_length', '32'); ini_set('session.hash_bits_per_character', 6); - // If session was autostarted with session.auto_start = 1 in php.ini destroy it + // If the session was autostarted with session.auto_start = 1 in php.ini destroy it if (isset($_SESSION)) { session_destroy(); } @@ -88,19 +90,17 @@ class Session $_SESSION = array(); // Destroy the session cookie - if (ini_get('session.use_cookies')) { - $params = session_get_cookie_params(); - - setcookie( - session_name(), - '', - time() - 42000, - $params['path'], - $params['domain'], - $params['secure'], - $params['httponly'] - ); - } + $params = session_get_cookie_params(); + + setcookie( + session_name(), + '', + time() - 42000, + $params['path'], + $params['domain'], + $params['secure'], + $params['httponly'] + ); // Destroy session data session_destroy(); @@ -127,4 +127,24 @@ class Session { $_SESSION['flash_error_message'] = $message; } + + public function offsetSet($offset, $value) + { + $_SESSION[$offset] = $value; + } + + public function offsetExists($offset) + { + return isset($_SESSION[$offset]); + } + + public function offsetUnset($offset) + { + unset($_SESSION[$offset]); + } + + public function offsetGet($offset) + { + return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null; + } } diff --git a/app/Core/Template.php b/app/Core/Template.php index da61f579..9688c2a5 100644 --- a/app/Core/Template.php +++ b/app/Core/Template.php @@ -10,7 +10,7 @@ use LogicException; * @package core * @author Frederic Guillot */ -class Template +class Template extends Helper { /** * Template path @@ -20,18 +20,18 @@ class Template const PATH = 'app/Template/'; /** - * Load a template + * Render a template * * Example: * - * $template->load('template_name', ['bla' => 'value']); + * $template->render('template_name', ['bla' => 'value']); * * @access public * @params string $__template_name Template name * @params array $__template_args Key/Value map of template variables * @return string */ - public function load($__template_name, array $__template_args = array()) + public function render($__template_name, array $__template_args = array()) { $__template_file = self::PATH.$__template_name.'.php'; @@ -57,9 +57,9 @@ class Template */ public function layout($template_name, array $template_args = array(), $layout_name = 'layout') { - return $this->load( + return $this->render( $layout_name, - $template_args + array('content_for_layout' => $this->load($template_name, $template_args)) + $template_args + array('content_for_layout' => $this->render($template_name, $template_args)) ); } } diff --git a/app/Model/Acl.php b/app/Model/Acl.php index b8353b58..3f454885 100644 --- a/app/Model/Acl.php +++ b/app/Model/Acl.php @@ -42,6 +42,7 @@ class Acl extends Base 'category' => array('index', 'save', 'edit', 'update', 'confirm', 'remove'), 'action' => array('index', 'event', 'params', 'create', 'confirm', 'remove'), 'analytic' => array('tasks', 'users', 'cfd'), + 'swimlane' => array('index', 'save', 'change', 'edit', 'update', 'confirm', 'remove', 'disable', 'enable', 'moveup', 'movedown'), ); /** @@ -96,7 +97,7 @@ class Acl extends Base */ public function isAdminUser() { - return isset($_SESSION['user']['is_admin']) && $_SESSION['user']['is_admin'] === true; + return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === true; } /** @@ -107,7 +108,7 @@ class Acl extends Base */ public function isRegularUser() { - return isset($_SESSION['user']['is_admin']) && $_SESSION['user']['is_admin'] === false; + return isset($this->session['user']['is_admin']) && $this->session['user']['is_admin'] === false; } /** @@ -118,7 +119,18 @@ class Acl extends Base */ public function getUserId() { - return isset($_SESSION['user']['id']) ? (int) $_SESSION['user']['id'] : 0; + return isset($this->session['user']['id']) ? (int) $this->session['user']['id'] : 0; + } + + /** + * Check if the given user_id is the connected user + * + * @param integer $user_id User id + * @return boolean + */ + public function isCurrentUser($user_id) + { + return $this->acl->getUserId() == $user_id; } /** @@ -129,7 +141,7 @@ class Acl extends Base */ public function isLogged() { - return ! empty($_SESSION['user']); + return ! empty($this->session['user']); } /** @@ -142,10 +154,10 @@ class Acl extends Base public function isRememberMe($value = null) { if ($value !== null) { - $_SESSION['is_remember_me'] = $value; + $this->session['is_remember_me'] = $value; } - return empty($_SESSION['is_remember_me']) ? false : $_SESSION['is_remember_me']; + return empty($this->session['is_remember_me']) ? false : $this->session['is_remember_me']; } /** diff --git a/app/Model/Base.php b/app/Model/Base.php index ed96e5be..dfac12ae 100644 --- a/app/Model/Base.php +++ b/app/Model/Base.php @@ -10,6 +10,8 @@ use Pimple\Container; * @package model * @author Frederic Guillot * + * @property \Core\Session $session + * @property \Core\Template $template * @property \Model\Acl $acl * @property \Model\Action $action * @property \Model\Authentication $authentication diff --git a/app/Model/Config.php b/app/Model/Config.php index 16e9bf45..54d9d7cd 100644 --- a/app/Model/Config.php +++ b/app/Model/Config.php @@ -76,12 +76,13 @@ class Config extends Base return $value ?: $default_value; } - if (! isset($_SESSION['config'][$name])) { - $_SESSION['config'] = $this->getAll(); + // Cache config in session + if (! isset($this->session['config'][$name])) { + $this->session['config'] = $this->getAll(); } - if (! empty($_SESSION['config'][$name])) { - return $_SESSION['config'][$name]; + if (isset($this->session['config'][$name])) { + return $this->session['config'][$name]; } return $default_value; @@ -126,7 +127,7 @@ class Config extends Base */ public function reload() { - $_SESSION['config'] = $this->getAll(); + $this->session['config'] = $this->getAll(); $this->setupTranslations(); } diff --git a/app/Model/Notification.php b/app/Model/Notification.php index 0fa4c9da..99db78ad 100644 --- a/app/Model/Notification.php +++ b/app/Model/Notification.php @@ -3,7 +3,6 @@ namespace Model; use Core\Session; -use Core\Template; use Swift_Message; use Swift_Mailer; use Swift_TransportException; @@ -184,8 +183,10 @@ class Notification extends Base */ public function getMailContent($template, array $data) { - $tpl = new Template; - return $tpl->load('notification/'.$template, $data + array('application_url' => $this->config->get('application_url'))); + return $this->template->render( + 'notification/'.$template, + $data + array('application_url' => $this->config->get('application_url')) + ); } /** diff --git a/app/Model/ProjectActivity.php b/app/Model/ProjectActivity.php index bc2948f0..87c9bb56 100644 --- a/app/Model/ProjectActivity.php +++ b/app/Model/ProjectActivity.php @@ -2,8 +2,6 @@ namespace Model; -use Core\Template; - /** * Project activity model * @@ -134,8 +132,10 @@ class ProjectActivity extends Base */ public function getContent(array $params) { - $tpl = new Template; - return $tpl->load('event/'.str_replace('.', '_', $params['event_name']), $params); + return $this->template->render( + 'event/'.str_replace('.', '_', $params['event_name']), + $params + ); } /** diff --git a/app/Model/ProjectPermission.php b/app/Model/ProjectPermission.php index 3b42751a..bcb11eca 100644 --- a/app/Model/ProjectPermission.php +++ b/app/Model/ProjectPermission.php @@ -264,6 +264,10 @@ class ProjectPermission extends Base */ public function adminAllowed($project_id, $user_id) { + if ($this->user->isAdmin($user_id)) { + return true; + } + if ($this->isUserAllowed($project_id, $user_id) && $this->project->isPrivate($project_id)) { return true; } diff --git a/app/Model/User.php b/app/Model/User.php index 8fdfa815..3754b918 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -28,6 +28,17 @@ class User extends Base */ const EVERYBODY_ID = -1; + /** + * Return the full name + * + * @param array $user User properties + * @return string + */ + public function getFullname(array $user) + { + return $user['name'] ?: $user['username']; + } + /** * Return true is the given user id is administrator * @@ -54,7 +65,7 @@ class User extends Base */ public function getFavoriteProjectId() { - return isset($_SESSION['user']['default_project_id']) ? $_SESSION['user']['default_project_id'] : 0; + return isset($this->session['user']['default_project_id']) ? $this->session['user']['default_project_id'] : 0; } /** @@ -65,7 +76,7 @@ class User extends Base */ public function getLastSeenProjectId() { - return empty($_SESSION['user']['last_show_project_id']) ? 0 : $_SESSION['user']['last_show_project_id']; + return empty($this->session['last_show_project_id']) ? 0 : $this->session['last_show_project_id']; } /** @@ -76,7 +87,7 @@ class User extends Base */ public function storeLastSeenProjectId($project_id) { - $_SESSION['user']['last_show_project_id'] = (int) $project_id; + $this->session['last_show_project_id'] = (int) $project_id; } /** @@ -276,7 +287,7 @@ class User extends Base $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values); // If the user is connected refresh his session - if (Session::isOpen() && $_SESSION['user']['id'] == $values['id']) { + if (Session::isOpen() && $this->acl->getUserId() == $values['id']) { $this->updateSession(); } @@ -326,7 +337,7 @@ class User extends Base public function updateSession(array $user = array()) { if (empty($user)) { - $user = $this->getById($_SESSION['user']['id']); + $user = $this->getById($this->acl->getUserId()); } if (isset($user['password'])) { @@ -338,7 +349,7 @@ class User extends Base $user['is_admin'] = (bool) $user['is_admin']; $user['is_ldap_user'] = (bool) $user['is_ldap_user']; - $_SESSION['user'] = $user; + $this->session['user'] = $user; } /** @@ -457,7 +468,7 @@ class User extends Base if ($v->execute()) { // Check password - if ($this->authentication->authenticate($_SESSION['user']['username'], $values['current_password'])) { + if ($this->authentication->authenticate($this->session['user']['username'], $values['current_password'])) { return array(true, array()); } else { diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php new file mode 100644 index 00000000..02e5004e --- /dev/null +++ b/app/ServiceProvider/ClassProvider.php @@ -0,0 +1,72 @@ + array( + 'Acl', + 'Action', + 'Authentication', + 'Board', + 'Category', + 'Color', + 'Comment', + 'Config', + 'DateParser', + 'File', + 'GithubWebhook', + 'LastLogin', + 'Notification', + 'Project', + 'ProjectActivity', + 'ProjectAnalytics', + 'ProjectDailySummary', + 'ProjectPaginator', + 'ProjectPermission', + 'SubTask', + 'SubtaskPaginator', + 'Swimlane', + 'Task', + 'TaskCreation', + 'TaskDuplication', + 'TaskExport', + 'TaskFinder', + 'TaskModification', + 'TaskPaginator', + 'TaskPermission', + 'TaskPosition', + 'TaskStatus', + 'TaskValidator', + 'TimeTracking', + 'User', + 'Webhook', + ), + 'Core' => array( + 'Template', + 'Session', + ), + ); + + public function register(Container $container) + { + foreach ($this->classes as $namespace => $classes) { + + foreach ($classes as $name) { + + $class = '\\'.$namespace.'\\'.$name; + + $container[lcfirst($name)] = function ($c) use ($class) { + return new $class($c); + }; + } + } + } +} diff --git a/app/ServiceProvider/ModelProvider.php b/app/ServiceProvider/ModelProvider.php deleted file mode 100644 index 1a940058..00000000 --- a/app/ServiceProvider/ModelProvider.php +++ /dev/null @@ -1,63 +0,0 @@ -models as $model) { - - $class = '\Model\\'.$model; - - $container[lcfirst($model)] = function ($c) use ($class) { - return new $class($c); - }; - } - } -} diff --git a/app/Template/action/event.php b/app/Template/action/event.php index 565e900c..67a65c19 100644 --- a/app/Template/action/event.php +++ b/app/Template/action/event.php @@ -3,15 +3,15 @@

-
+ - + formCsrf() ?> - - + formHidden('project_id', $values) ?> + formHidden('action_name', $values) ?> - -
+ formLabel(t('Event'), 'event_name') ?> + formSelect('event_name', $events, $values) ?>
@@ -20,6 +20,6 @@
- $project['id'])) ?> + a(t('cancel'), 'action', 'index', array('project_id' => $project['id'])) ?>
\ No newline at end of file diff --git a/app/Template/action/index.php b/app/Template/action/index.php index 54f13691..e388fbc9 100644 --- a/app/Template/action/index.php +++ b/app/Template/action/index.php @@ -15,26 +15,26 @@ - - + inList($action['event_name'], $available_events) ?> + inList($action['action_name'], $available_actions) ?>
  • - = + inList($param['name'], $available_params) ?> = - - - - - - - - - - - - + contains($param['name'], 'column_id')): ?> + inList($param['value'], $columns_list) ?> + contains($param['name'], 'user_id')): ?> + inList($param['value'], $users_list) ?> + contains($param['name'], 'project_id')): ?> + inList($param['value'], $projects_list) ?> + contains($param['name'], 'color_id')): ?> + inList($param['value'], $colors_list) ?> + contains($param['name'], 'category_id')): ?> + inList($param['value'], $categories_list) ?> + contains($param['name'], 'label')): ?> + e($param['value']) ?>
  • @@ -42,7 +42,7 @@
- $project['id'], 'action_id' => $action['id'])) ?> + a(t('Remove'), 'action', 'confirm', array('project_id' => $project['id'], 'action_id' => $action['id'])) ?> @@ -51,12 +51,12 @@

-
- - + + formCsrf() ?> + formHidden('project_id', $values) ?> - -
+ formLabel(t('Action'), 'action_name') ?> + formSelect('action_name', $available_actions, $values) ?>
diff --git a/app/Template/action/params.php b/app/Template/action/params.php index f221d92e..3a5ecb86 100644 --- a/app/Template/action/params.php +++ b/app/Template/action/params.php @@ -3,34 +3,34 @@

- + - + formCsrf() ?> - - - + formHidden('project_id', $values) ?> + formHidden('event_name', $values) ?> + formHidden('action_name', $values) ?> $param_desc): ?> - - -
- - -
- - -
- - -
- - -
- - - + contains($param_name, 'column_id')): ?> + formLabel($param_desc, $param_name) ?> + formSelect('params['.$param_name.']', $columns_list, $values) ?>
+ contains($param_name, 'user_id')): ?> + formLabel($param_desc, $param_name) ?> + formSelect('params['.$param_name.']', $users_list, $values) ?>
+ contains($param_name, 'project_id')): ?> + formLabel($param_desc, $param_name) ?> + formSelect('params['.$param_name.']', $projects_list, $values) ?>
+ contains($param_name, 'color_id')): ?> + formLabel($param_desc, $param_name) ?> + formSelect('params['.$param_name.']', $colors_list, $values) ?>
+ contains($param_name, 'category_id')): ?> + formLabel($param_desc, $param_name) ?> + formSelect('params['.$param_name.']', $categories_list, $values) ?>
+ contains($param_name, 'label')): ?> + formLabel($param_desc, $param_name) ?> + formText('params['.$param_name.']', $values) ?> @@ -38,6 +38,6 @@
- $project['id'])) ?> + a(t('cancel'), 'action', 'index', array('project_id' => $project['id'])) ?>
\ No newline at end of file diff --git a/app/Template/action/remove.php b/app/Template/action/remove.php index 131c2b54..672c08a7 100644 --- a/app/Template/action/remove.php +++ b/app/Template/action/remove.php @@ -4,12 +4,12 @@

- + inList($action['event_name'], $available_events).'/'.$this->inList($action['action_name'], $available_actions)) ?>

- $project['id'], 'action_id' => $action['id']), true, 'btn btn-red') ?> + a(t('Yes'), 'action', 'remove', array('project_id' => $project['id'], 'action_id' => $action['id']), true, 'btn btn-red') ?> - $project['id'])) ?> + a(t('cancel'), 'action', 'index', array('project_id' => $project['id'])) ?>
\ No newline at end of file diff --git a/app/Template/analytic/cfd.php b/app/Template/analytic/cfd.php index d8dd5517..58115e77 100644 --- a/app/Template/analytic/cfd.php +++ b/app/Template/analytic/cfd.php @@ -6,24 +6,24 @@

-
+

-
+ - + formCsrf() ?>
- - + formLabel(t('Start Date'), 'from') ?> + formText('from', $values, array(), array('required', 'placeholder="'.$this->inList($date_format, $date_formats).'"'), 'form-date') ?>
- - + formLabel(t('End Date'), 'to') ?> + formText('to', $values, array(), array('required', 'placeholder="'.$this->inList($date_format, $date_formats).'"'), 'form-date') ?>
diff --git a/app/Template/analytic/layout.php b/app/Template/analytic/layout.php index 2dd7a4f5..f2506917 100644 --- a/app/Template/analytic/layout.php +++ b/app/Template/analytic/layout.php @@ -1,15 +1,15 @@ - - +js('assets/js/d3.v3.4.8.min.js') ?> +js('assets/js/dimple.v2.1.0.min.js') ?>
    -
  • -
  • -
  • +
  • e($timesheet['time_estimated']) ?>
  • +
  • e($timesheet['time_spent']) ?>
  • +
  • e($timesheet['time_remaining']) ?>
\ No newline at end of file diff --git a/app/Template/user/edit.php b/app/Template/user/edit.php index bc942567..6766f952 100644 --- a/app/Template/user/edit.php +++ b/app/Template/user/edit.php @@ -1,32 +1,32 @@ -
+ - + formCsrf() ?> - - + formHidden('id', $values) ?> + formHidden('is_ldap_user', $values) ?> - -
+ formLabel(t('Username'), 'username') ?> + formText('username', $values, $errors, array('required', $values['is_ldap_user'] == 1 ? 'readonly' : '')) ?>
- -
+ formLabel(t('Name'), 'name') ?> + formText('name', $values, $errors) ?>
- -
+ formLabel(t('Email'), 'email') ?> + formEmail('email', $values, $errors) ?>
- -
+ formLabel(t('Default project'), 'default_project_id') ?> + formSelect('default_project_id', $projects, $values, $errors) ?>
- -
+ acl->isAdminUser()): ?> + formCheckbox('is_admin', t('Administrator'), 1, isset($values['is_admin']) && $values['is_admin'] == 1 ? true : false) ?>
- $user['id'])) ?> + a(t('cancel'), 'user', 'show', array('user_id' => $user['id'])) ?>
\ No newline at end of file diff --git a/app/Template/user/external.php b/app/Template/user/external.php index 31ffcb75..6ee1e459 100644 --- a/app/Template/user/external.php +++ b/app/Template/user/external.php @@ -6,11 +6,11 @@

- + acl->isCurrentUser($user['id'])): ?> - + a(t('Link my Google Account'), 'user', 'google', array(), true) ?> - + a(t('Unlink my Google Account'), 'user', 'unlinkGoogle', array(), true) ?> @@ -22,11 +22,11 @@

- + acl->isCurrentUser($user['id'])): ?> - + a(t('Link my GitHub Account'), 'user', 'github', array(), true) ?> - + a(t('Unlink my GitHub Account'), 'user', 'unlinkGitHub', array(), true) ?> diff --git a/app/Template/user/index.php b/app/Template/user/index.php index 73612b0b..a6da9f65 100644 --- a/app/Template/user/index.php +++ b/app/Template/user/index.php @@ -1,8 +1,8 @@

@@ -12,35 +12,35 @@ - - - - - - - + + + + + + + - +
order(t('Id'), 'id', $pagination) ?>order(t('Username'), 'username', $pagination) ?>order(t('Name'), 'name', $pagination) ?>order(t('Email'), 'email', $pagination) ?>order(t('Administrator'), 'is_admin', $pagination) ?>order(t('Default project'), 'default_project_id', $pagination) ?>order(t('Notifications'), 'notifications_enabled', $pagination) ?> order(t('Account type'), 'is_ldap_user', $pagination) ?>
- $user['id'])) ?> + a('#'.$user['id'], 'user', 'show', array('user_id' => $user['id'])) ?> - $user['id'])) ?> + a($this->e($user['username']), 'user', 'show', array('user_id' => $user['id'])) ?> - + e($user['name']) ?> - + e($user['email']) ?> - + e($projects[$user['default_project_id']]) : t('None'); ?> @@ -66,7 +66,7 @@
- + paginate($pagination) ?>
diff --git a/app/Template/user/last.php b/app/Template/user/last.php index 0b55b0d5..317334b8 100644 --- a/app/Template/user/last.php +++ b/app/Template/user/last.php @@ -15,9 +15,9 @@ - - - + e($login['auth_type']) ?> + e($login['ip']) ?> + e($this->summary($login['user_agent'])) ?> diff --git a/app/Template/user/layout.php b/app/Template/user/layout.php index 0778b716..94610000 100644 --- a/app/Template/user/layout.php +++ b/app/Template/user/layout.php @@ -1,15 +1,15 @@