summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.htaccess9
-rw-r--r--app/Api/Project.php6
-rw-r--r--app/Api/Task.php2
-rw-r--r--app/Auth/RememberMe.php4
-rw-r--r--app/Controller/Action.php8
-rw-r--r--app/Controller/Base.php19
-rw-r--r--app/Controller/Category.php8
-rw-r--r--app/Controller/Comment.php8
-rw-r--r--app/Controller/Config.php6
-rw-r--r--app/Controller/Project.php25
-rw-r--r--app/Controller/Search.php2
-rw-r--r--app/Controller/Subtask.php12
-rw-r--r--app/Controller/Swimlane.php18
-rw-r--r--app/Controller/Task.php30
-rw-r--r--app/Controller/User.php22
-rw-r--r--app/Core/Router.php195
-rw-r--r--app/Core/Session.php2
-rw-r--r--app/Helper/Asset.php4
-rw-r--r--app/Helper/Url.php96
-rw-r--r--app/ServiceProvider/ClassProvider.php1
-rw-r--r--app/Template/app/overview.php4
-rw-r--r--app/Template/config/integrations.php18
-rw-r--r--app/Template/config/webhook.php2
-rw-r--r--app/Template/feed/project.php6
-rw-r--r--app/Template/feed/user.php6
-rw-r--r--app/Template/layout.php10
-rw-r--r--app/Template/project/filters.php4
-rw-r--r--app/Template/project/integrations.php12
-rw-r--r--app/Template/search/index.php2
-rw-r--r--app/common.php92
-rw-r--r--app/constants.php6
-rw-r--r--config.default.php4
-rw-r--r--index.php7
-rw-r--r--tests/units/RouterTest.php79
-rw-r--r--tests/units/UrlHelperTest.php18
35 files changed, 543 insertions, 204 deletions
diff --git a/.htaccess b/.htaccess
new file mode 100644
index 00000000..0d873f58
--- /dev/null
+++ b/.htaccess
@@ -0,0 +1,9 @@
+<IfModule mod_rewrite.c>
+ Options -MultiViews
+
+ SetEnv HTTP_MOD_REWRITE On
+
+ RewriteEngine On
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteRule ^ index.php [QSA,L]
+</IfModule>
diff --git a/app/Api/Project.php b/app/Api/Project.php
index faf2a3da..4e4e10b8 100644
--- a/app/Api/Project.php
+++ b/app/Api/Project.php
@@ -87,9 +87,9 @@ class Project extends Base
{
if (! empty($project)) {
$project['url'] = array(
- 'board' => $this->helper->url->base().$this->helper->url->to('board', 'show', array('project_id' => $project['id'])),
- 'calendar' => $this->helper->url->base().$this->helper->url->to('calendar', 'show', array('project_id' => $project['id'])),
- 'list' => $this->helper->url->base().$this->helper->url->to('listing', 'show', array('project_id' => $project['id'])),
+ 'board' => $this->helper->url->to('board', 'show', array('project_id' => $project['id']), '', true),
+ 'calendar' => $this->helper->url->to('calendar', 'show', array('project_id' => $project['id']), '', true),
+ 'list' => $this->helper->url->to('listing', 'show', array('project_id' => $project['id']), '', true),
);
}
diff --git a/app/Api/Task.php b/app/Api/Task.php
index ade49a6d..3b8c1ec8 100644
--- a/app/Api/Task.php
+++ b/app/Api/Task.php
@@ -119,7 +119,7 @@ class Task extends Base
private function formatTask($task)
{
if (! empty($task)) {
- $task['url'] = $this->helper->url->base().$this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']));
+ $task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
}
return $task;
diff --git a/app/Auth/RememberMe.php b/app/Auth/RememberMe.php
index eebf4f4b..54e60422 100644
--- a/app/Auth/RememberMe.php
+++ b/app/Auth/RememberMe.php
@@ -282,7 +282,7 @@ class RememberMe extends Base
self::COOKIE_NAME,
$this->encodeCookie($token, $sequence),
$expiration,
- BASE_URL_DIRECTORY,
+ $this->helper->url->dir(),
null,
Request::isHTTPS(),
true
@@ -315,7 +315,7 @@ class RememberMe extends Base
self::COOKIE_NAME,
'',
time() - 3600,
- BASE_URL_DIRECTORY,
+ $this->helper->url->dir(),
null,
Request::isHTTPS(),
true
diff --git a/app/Controller/Action.php b/app/Controller/Action.php
index cd24453a..74a5326d 100644
--- a/app/Controller/Action.php
+++ b/app/Controller/Action.php
@@ -46,7 +46,7 @@ class Action extends Base
$values = $this->request->getValues();
if (empty($values['action_name']) || empty($values['project_id'])) {
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('action/event', array(
@@ -68,7 +68,7 @@ class Action extends Base
$values = $this->request->getValues();
if (empty($values['action_name']) || empty($values['project_id']) || empty($values['event_name'])) {
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
$action = $this->action->load($values['action_name'], $values['project_id'], $values['event_name']);
@@ -125,7 +125,7 @@ class Action extends Base
}
}
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
/**
@@ -163,6 +163,6 @@ class Action extends Base
$this->session->flashError(t('Unable to remove this action.'));
}
- $this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
}
diff --git a/app/Controller/Base.php b/app/Controller/Base.php
index 9f5d6dc6..18187162 100644
--- a/app/Controller/Base.php
+++ b/app/Controller/Base.php
@@ -101,7 +101,7 @@ abstract class Base extends \Core\Base
public function beforeAction($controller, $action)
{
// Start the session
- $this->session->open(BASE_URL_DIRECTORY);
+ $this->session->open($this->helper->url->dir());
$this->sendHeaders($action);
$this->container['dispatcher']->dispatch('session.bootstrap', new Event);
@@ -223,17 +223,6 @@ abstract class Base extends \Core\Base
}
/**
- * Redirection when there is no project in the database
- *
- * @access protected
- */
- protected function redirectNoProject()
- {
- $this->session->flash(t('There is no active project, the first step is to create a new project.'));
- $this->response->redirect('?controller=project&action=create');
- }
-
- /**
* Common layout for task views
*
* @access protected
@@ -301,7 +290,7 @@ abstract class Base extends \Core\Base
if (empty($project)) {
$this->session->flashError(t('Project not found.'));
- $this->response->redirect('?controller=project');
+ $this->response->redirect($this->helper->url->to('project', 'index'));
}
return $project;
@@ -344,10 +333,10 @@ abstract class Base extends \Core\Base
'controller' => $controller,
'action' => $action,
'project_id' => $project['id'],
- 'search' => $search,
+ 'search' => urldecode($search),
);
- $this->userSession->setFilters($project['id'], $search);
+ $this->userSession->setFilters($project['id'], $filters['search']);
return array(
'project' => $project,
diff --git a/app/Controller/Category.php b/app/Controller/Category.php
index 515cc9c8..e8d83f2d 100644
--- a/app/Controller/Category.php
+++ b/app/Controller/Category.php
@@ -23,7 +23,7 @@ class Category extends Base
if (empty($category)) {
$this->session->flashError(t('Category not found.'));
- $this->response->redirect('?controller=category&action=index&project_id='.$project_id);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project_id)));
}
return $category;
@@ -63,7 +63,7 @@ class Category extends Base
if ($this->category->create($values)) {
$this->session->flash(t('Your category have been created successfully.'));
- $this->response->redirect('?controller=category&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to create your category.'));
@@ -107,7 +107,7 @@ class Category extends Base
if ($this->category->update($values)) {
$this->session->flash(t('Your category have been updated successfully.'));
- $this->response->redirect('?controller=category&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update your category.'));
@@ -151,6 +151,6 @@ class Category extends Base
$this->session->flashError(t('Unable to remove this category.'));
}
- $this->response->redirect('?controller=category&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('category', 'index', array('project_id' => $project['id'])));
}
}
diff --git a/app/Controller/Comment.php b/app/Controller/Comment.php
index a5f6b1f8..ca701a88 100644
--- a/app/Controller/Comment.php
+++ b/app/Controller/Comment.php
@@ -90,10 +90,10 @@ class Comment extends Base
}
if ($ajax) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), 'comments');
}
$this->create($values, $errors);
@@ -140,7 +140,7 @@ class Comment extends Base
$this->session->flashError(t('Unable to update your comment.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comment-'.$comment['id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), 'comment-'.$comment['id']);
}
$this->edit($values, $errors);
@@ -181,6 +181,6 @@ class Comment extends Base
$this->session->flashError(t('Unable to remove this comment.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#comments');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), 'comments');
}
}
diff --git a/app/Controller/Config.php b/app/Controller/Config.php
index 19bc2767..1e6b3dc8 100644
--- a/app/Controller/Config.php
+++ b/app/Controller/Config.php
@@ -60,7 +60,7 @@ class Config extends Base
$this->session->flashError(t('Unable to save your settings.'));
}
- $this->response->redirect('?controller=config&action='.$redirect);
+ $this->response->redirect($this->helper->url->to('config', $redirect));
}
}
@@ -199,7 +199,7 @@ class Config extends Base
$this->checkCSRFParam();
$this->config->optimizeDatabase();
$this->session->flash(t('Database optimization done.'));
- $this->response->redirect('?controller=config');
+ $this->response->redirect($this->helper->url->to('config', 'index'));
}
/**
@@ -215,6 +215,6 @@ class Config extends Base
$this->config->regenerateToken($type.'_token');
$this->session->flash(t('Token regenerated.'));
- $this->response->redirect('?controller=config&action='.$type);
+ $this->response->redirect($this->helper->url->to('config', $type));
}
}
diff --git a/app/Controller/Project.php b/app/Controller/Project.php
index faebac38..45bc2a46 100644
--- a/app/Controller/Project.php
+++ b/app/Controller/Project.php
@@ -73,11 +73,12 @@ class Project extends Base
if ($this->project->{$switch.'PublicAccess'}($project['id'])) {
$this->session->flash(t('Project updated successfully.'));
- } else {
+ }
+ else {
$this->session->flashError(t('Unable to update this project.'));
}
- $this->response->redirect('?controller=project&action=share&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'share', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('project/share', array(
@@ -150,7 +151,7 @@ class Project extends Base
if ($this->project->update($values)) {
$this->session->flash(t('Project updated successfully.'));
- $this->response->redirect('?controller=project&action=edit&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'edit', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update this project.'));
@@ -197,7 +198,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $project['id'])));
}
/**
@@ -220,7 +221,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $values['project_id'])));
}
/**
@@ -250,7 +251,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $values['project_id'])));
}
/**
@@ -279,7 +280,7 @@ class Project extends Base
}
}
- $this->response->redirect('?controller=project&action=users&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('project', 'users', array('project_id' => $values['project_id'])));
}
/**
@@ -301,7 +302,7 @@ class Project extends Base
$this->session->flashError(t('Unable to remove this project.'));
}
- $this->response->redirect('?controller=project');
+ $this->response->redirect($this->helper->url->to('project', 'index'));
}
$this->response->html($this->projectLayout('project/remove', array(
@@ -329,7 +330,7 @@ class Project extends Base
$this->session->flashError(t('Unable to clone this project.'));
}
- $this->response->redirect('?controller=project');
+ $this->response->redirect($this->helper->url->to('project', 'index'));
}
$this->response->html($this->projectLayout('project/duplicate', array(
@@ -357,7 +358,7 @@ class Project extends Base
$this->session->flashError(t('Unable to disable this project.'));
}
- $this->response->redirect('?controller=project&action=show&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('project/disable', array(
@@ -385,7 +386,7 @@ class Project extends Base
$this->session->flashError(t('Unable to activate this project.'));
}
- $this->response->redirect('?controller=project&action=show&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project['id'])));
}
$this->response->html($this->projectLayout('project/enable', array(
@@ -428,7 +429,7 @@ class Project extends Base
if ($project_id > 0) {
$this->session->flash(t('Your project have been created successfully.'));
- $this->response->redirect('?controller=project&action=show&project_id='.$project_id);
+ $this->response->redirect($this->helper->url->to('project', 'show', array('project_id' => $project_id)));
}
$this->session->flashError(t('Unable to create your project.'));
diff --git a/app/Controller/Search.php b/app/Controller/Search.php
index 519f9ce4..f6dc7a32 100644
--- a/app/Controller/Search.php
+++ b/app/Controller/Search.php
@@ -13,7 +13,7 @@ class Search extends Base
public function index()
{
$projects = $this->projectPermission->getAllowedProjects($this->userSession->getId());
- $search = $this->request->getStringParam('search');
+ $search = urldecode($this->request->getStringParam('search'));
$nb_tasks = 0;
$paginator = $this->paginator
diff --git a/app/Controller/Subtask.php b/app/Controller/Subtask.php
index 6ee94333..87f3fcb4 100644
--- a/app/Controller/Subtask.php
+++ b/app/Controller/Subtask.php
@@ -75,10 +75,10 @@ class Subtask extends Base
}
if (isset($values['another_subtask']) && $values['another_subtask'] == 1) {
- $this->response->redirect('?controller=subtask&action=create&task_id='.$task['id'].'&another_subtask=1&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('subtask', 'create', array('project_id' => $task['project_id'], 'task_id' => $task['id'], 'another_subtask' => 1)));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'));
}
$this->create($values, $errors);
@@ -126,7 +126,7 @@ class Subtask extends Base
$this->session->flashError(t('Unable to update your sub-task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'));
}
$this->edit($values, $errors);
@@ -166,7 +166,7 @@ class Subtask extends Base
$this->session->flashError(t('Unable to remove this sub-task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'].'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id']), 'subtasks'));
}
/**
@@ -256,7 +256,7 @@ class Subtask extends Base
case 'dashboard':
$this->response->redirect($this->helper->url->to('app', 'index'));
default:
- $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])).'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), 'subtasks'));
}
}
@@ -275,6 +275,6 @@ class Subtask extends Base
$method = $direction === 'up' ? 'moveUp' : 'moveDown';
$this->subtask->$method($task_id, $subtask_id);
- $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id)).'#subtasks');
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $project_id, 'task_id' => $task_id), 'subtasks'));
}
}
diff --git a/app/Controller/Swimlane.php b/app/Controller/Swimlane.php
index c6862d47..054fa4ba 100644
--- a/app/Controller/Swimlane.php
+++ b/app/Controller/Swimlane.php
@@ -25,7 +25,7 @@ class Swimlane extends Base
if (empty($swimlane)) {
$this->session->flashError(t('Swimlane not found.'));
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project_id);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project_id)));
}
return $swimlane;
@@ -67,7 +67,7 @@ class Swimlane extends Base
if ($this->swimlane->create($project['id'], $values['name'])) {
$this->session->flash(t('Your swimlane have been created successfully.'));
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to create your swimlane.'));
@@ -93,7 +93,7 @@ class Swimlane extends Base
if ($this->swimlane->updateDefault($values)) {
$this->session->flash(t('The default swimlane have been updated successfully.'));
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update this swimlane.'));
@@ -137,7 +137,7 @@ class Swimlane extends Base
if ($this->swimlane->rename($values['id'], $values['name'])) {
$this->session->flash(t('Swimlane updated successfully.'));
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
else {
$this->session->flashError(t('Unable to update this swimlane.'));
@@ -181,7 +181,7 @@ class Swimlane extends Base
$this->session->flashError(t('Unable to remove this swimlane.'));
}
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -201,7 +201,7 @@ class Swimlane extends Base
$this->session->flashError(t('Unable to update this swimlane.'));
}
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -221,7 +221,7 @@ class Swimlane extends Base
$this->session->flashError(t('Unable to update this swimlane.'));
}
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -236,7 +236,7 @@ class Swimlane extends Base
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
$this->swimlane->moveUp($project['id'], $swimlane_id);
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
/**
@@ -251,6 +251,6 @@ class Swimlane extends Base
$swimlane_id = $this->request->getIntegerParam('swimlane_id');
$this->swimlane->moveDown($project['id'], $swimlane_id);
- $this->response->redirect('?controller=swimlane&action=index&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('swimlane', 'index', array('project_id' => $project['id'])));
}
}
diff --git a/app/Controller/Task.php b/app/Controller/Task.php
index 0d85f411..16bb408f 100644
--- a/app/Controller/Task.php
+++ b/app/Controller/Task.php
@@ -163,10 +163,10 @@ class Task extends Base
if (isset($values['another_task']) && $values['another_task'] == 1) {
unset($values['title']);
unset($values['description']);
- $this->response->redirect('?controller=task&action=create&'.http_build_query($values));
+ $this->response->redirect($this->helper->url->to('task', 'create', $values));
}
else {
- $this->response->redirect('?controller=board&action=show&project_id='.$project['id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $project['id'])));
}
}
else {
@@ -231,10 +231,10 @@ class Task extends Base
$this->session->flash(t('Task updated successfully.'));
if ($this->request->getIntegerParam('ajax')) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
else {
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
else {
@@ -264,7 +264,7 @@ class Task extends Base
$this->session->flashError(t('Unable to update your task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
/**
@@ -326,7 +326,7 @@ class Task extends Base
$this->session->flashError(t('Unable to open this task.'));
}
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
$this->response->html($this->taskLayout('task/open', array(
@@ -357,7 +357,7 @@ class Task extends Base
$this->session->flashError(t('Unable to remove this task.'));
}
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
$this->response->html($this->taskLayout('task/remove', array(
@@ -381,10 +381,10 @@ class Task extends Base
if ($task_id) {
$this->session->flash(t('Task created successfully.'));
- $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
} else {
$this->session->flashError(t('Unable to create this task.'));
- $this->response->redirect('?controller=task&action=duplicate&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'duplicate', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
@@ -419,10 +419,10 @@ class Task extends Base
}
if ($ajax) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
else {
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
}
@@ -472,10 +472,10 @@ class Task extends Base
}
if ($ajax) {
- $this->response->redirect('?controller=board&action=show&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('board', 'show', array('project_id' => $task['project_id'])));
}
else {
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$task['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
}
}
@@ -526,7 +526,7 @@ class Task extends Base
if ($this->taskDuplication->moveToProject($task['id'], $values['project_id'])) {
$this->session->flash(t('Task updated successfully.'));
- $this->response->redirect('?controller=task&action=show&task_id='.$task['id'].'&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
else {
$this->session->flashError(t('Unable to update your task.'));
@@ -565,7 +565,7 @@ class Task extends Base
$task_id = $this->taskDuplication->duplicateToProject($task['id'], $values['project_id']);
if ($task_id) {
$this->session->flash(t('Task created successfully.'));
- $this->response->redirect('?controller=task&action=show&task_id='.$task_id.'&project_id='.$values['project_id']);
+ $this->response->redirect($this->helper->url->to('task', 'show', array('project_id' => $task['project_id'], 'task_id' => $task['id'])));
}
else {
$this->session->flashError(t('Unable to create your task.'));
diff --git a/app/Controller/User.php b/app/Controller/User.php
index 119041e5..edebf5ba 100644
--- a/app/Controller/User.php
+++ b/app/Controller/User.php
@@ -178,7 +178,7 @@ class User extends Base
$this->checkCSRFParam();
$user = $this->getUser();
$this->authentication->backend('rememberMe')->remove($this->request->getIntegerParam('id'));
- $this->response->redirect('?controller=user&action=sessions&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'session', array('user_id' => $user['id'])));
}
/**
@@ -194,7 +194,7 @@ class User extends Base
$values = $this->request->getValues();
$this->notification->saveSettings($user['id'], $values);
$this->session->flash(t('User updated successfully.'));
- $this->response->redirect('?controller=user&action=notifications&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'notifications', array('user_id' => $user['id'])));
}
$this->response->html($this->layout('user/notifications', array(
@@ -272,7 +272,7 @@ class User extends Base
$this->session->flashError(t('Unable to change the password.'));
}
- $this->response->redirect('?controller=user&action=show&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id'])));
}
}
@@ -321,7 +321,7 @@ class User extends Base
$this->session->flashError(t('Unable to update your user.'));
}
- $this->response->redirect('?controller=user&action=show&user_id='.$user['id']);
+ $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user['id'])));
}
}
@@ -353,7 +353,7 @@ class User extends Base
$this->session->flashError(t('Unable to remove this user.'));
}
- $this->response->redirect('?controller=user');
+ $this->response->redirect($this->helper->url->to('user', 'index'));
}
$this->response->html($this->layout('user/remove', array(
@@ -386,10 +386,10 @@ class User extends Base
$this->session->flashError(t('Unable to link your Google Account.'));
}
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
+ $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId())));
}
else if ($this->authentication->backend('google')->authenticate($profile['id'])) {
- $this->response->redirect('?controller=app');
+ $this->response->redirect($this->helper->url->to('app', 'index'));
}
else {
$this->response->html($this->template->layout('auth/index', array(
@@ -421,7 +421,7 @@ class User extends Base
$this->session->flashError(t('Unable to unlink your Google Account.'));
}
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
+ $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId())));
}
/**
@@ -448,10 +448,10 @@ class User extends Base
$this->session->flashError(t('Unable to link your GitHub Account.'));
}
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
+ $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId())));
}
else if ($this->authentication->backend('gitHub')->authenticate($profile['id'])) {
- $this->response->redirect('?controller=app');
+ $this->response->redirect($this->helper->url->to('app', 'index'));
}
else {
$this->response->html($this->template->layout('auth/index', array(
@@ -486,6 +486,6 @@ class User extends Base
$this->session->flashError(t('Unable to unlink your GitHub Account.'));
}
- $this->response->redirect('?controller=user&action=external&user_id='.$this->userSession->getId());
+ $this->response->redirect($this->helper->url->to('user', 'external', array('user_id' => $this->userSession->getId())));
}
}
diff --git a/app/Core/Router.php b/app/Core/Router.php
index 36c11a0a..ae989de5 100644
--- a/app/Core/Router.php
+++ b/app/Core/Router.php
@@ -2,53 +2,151 @@
namespace Core;
-use Pimple\Container;
-
/**
* Router class
*
* @package core
* @author Frederic Guillot
*/
-class Router
+class Router extends Base
{
/**
- * Controller name
+ * Store routes for path lookup
*
* @access private
- * @var string
+ * @var array
*/
- private $controller = '';
+ private $paths = array();
/**
- * Action name
+ * Store routes for url lookup
*
* @access private
- * @var string
+ * @var array
*/
- private $action = '';
+ private $urls = array();
/**
- * Container instance
+ * Get the path to compare patterns
*
- * @access private
- * @var \Pimple\Container
+ * @access public
+ * @param string $uri
+ * @param string $query_string
+ * @return string
*/
- private $container;
+ public function getPath($uri, $query_string = '')
+ {
+ $path = substr($uri, strlen($this->helper->url->dir()));
+
+ if (! empty($query_string)) {
+ $path = substr($path, 0, - strlen($query_string) - 1);
+ }
+
+ if ($path{0} === '/') {
+ $path = substr($path, 1);
+ }
+
+ return $path;
+ }
+
+ /**
+ * Add route
+ *
+ * @access public
+ * @param string $path
+ * @param string $controller
+ * @param string $action
+ * @param array $params
+ */
+ public function addRoute($path, $controller, $action, array $params = array())
+ {
+ $pattern = explode('/', $path);
+
+ $this->paths[] = array(
+ 'pattern' => $pattern,
+ 'count' => count($pattern),
+ 'controller' => $controller,
+ 'action' => $action,
+ );
+
+ $this->urls[$controller][$action][] = array(
+ 'path' => $path,
+ 'params' => array_flip($params),
+ 'count' => count($params),
+ );
+ }
+
+ /**
+ * Find a route according to the given path
+ *
+ * @access public
+ * @param string $path
+ * @return array
+ */
+ public function findRoute($path)
+ {
+ $parts = explode('/', $path);
+ $count = count($parts);
+
+ foreach ($this->paths as $route) {
+
+ if ($count === $route['count']) {
+
+ $params = array();
+
+ for ($i = 0; $i < $count; $i++) {
+
+ if ($route['pattern'][$i]{0} === ':') {
+ $params[substr($route['pattern'][$i], 1)] = $parts[$i];
+ }
+ else if ($route['pattern'][$i] !== $parts[$i]) {
+ break;
+ }
+ }
+
+ if ($i === $count) {
+ $_GET = array_merge($_GET, $params);
+ return array($route['controller'], $route['action']);
+ }
+ }
+ }
+
+ return array('app', 'index');
+ }
/**
- * Constructor
+ * Find route url
*
* @access public
- * @param \Pimple\Container $container Container instance
- * @param string $controller Controller name
- * @param string $action Action name
+ * @param string $controller
+ * @param string $action
+ * @param array $params
+ * @return string
*/
- public function __construct(Container $container, $controller = '', $action = '')
+ public function findUrl($controller, $action, array $params = array())
{
- $this->container = $container;
- $this->controller = empty($_GET['controller']) ? $controller : $_GET['controller'];
- $this->action = empty($_GET['action']) ? $action : $_GET['action'];
+ if (! isset($this->urls[$controller][$action])) {
+ return '';
+ }
+
+ foreach ($this->urls[$controller][$action] as $pattern) {
+
+ if (array_diff_key($params, $pattern['params']) === array()) {
+ $url = $pattern['path'];
+ $i = 0;
+
+ foreach ($params as $variable => $value) {
+ $url = str_replace(':'.$variable, $value, $url);
+ $i++;
+ }
+
+ if ($i === $pattern['count']) {
+ return $url;
+ }
+ }
+ }
+
+ return '';
}
/**
@@ -65,15 +163,42 @@ class Router
}
/**
- * Load a controller and execute the action
+ * Find controller/action from the route table or from get arguments
*
* @access public
- * @param string $filename Controller filename
- * @param string $class Class name
- * @param string $method Method name
+ * @param string $uri
+ * @param string $query_string
+ * @return boolean
+ */
+ public function dispatch($uri, $query_string = '')
+ {
+ if (! empty($_GET['controller']) && ! empty($_GET['action'])) {
+ $controller = $this->sanitize($_GET['controller'], 'app');
+ $action = $this->sanitize($_GET['action'], 'index');
+ }
+ else {
+ list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string));
+ }
+
+ return $this->load(
+ __DIR__.'/../Controller/'.ucfirst($controller).'.php',
+ $controller,
+ '\Controller\\'.ucfirst($controller),
+ $action
+ );
+ }
+
+ /**
+ * Load a controller and execute the action
+ *
+ * @access private
+ * @param string $filename
+ * @param string $controller
+ * @param string $class
+ * @param string $method
* @return bool
*/
- public function load($filename, $class, $method)
+ private function load($filename, $controller, $class, $method)
{
if (file_exists($filename)) {
@@ -84,7 +209,7 @@ class Router
}
$instance = new $class($this->container);
- $instance->beforeAction($this->controller, $this->action);
+ $instance->beforeAction($controller, $method);
$instance->$method();
return true;
@@ -92,20 +217,4 @@ class Router
return false;
}
-
- /**
- * Find a route
- *
- * @access public
- */
- public function execute()
- {
- $this->controller = $this->sanitize($this->controller, 'app');
- $this->action = $this->sanitize($this->action, 'index');
- $filename = __DIR__.'/../Controller/'.ucfirst($this->controller).'.php';
-
- if (! $this->load($filename, '\Controller\\'.$this->controller, $this->action)) {
- die('Page not found!');
- }
- }
}
diff --git a/app/Core/Session.php b/app/Core/Session.php
index c35014cd..0e5f7426 100644
--- a/app/Core/Session.php
+++ b/app/Core/Session.php
@@ -41,8 +41,6 @@ class Session implements ArrayAccess
*/
public function open($base_path = '/')
{
- $base_path = str_replace('\\', '/', $base_path);
-
// HttpOnly and secure flags for session cookie
session_set_cookie_params(
self::SESSION_LIFETIME,
diff --git a/app/Helper/Asset.php b/app/Helper/Asset.php
index 1b1e47c5..fd555e07 100644
--- a/app/Helper/Asset.php
+++ b/app/Helper/Asset.php
@@ -18,7 +18,7 @@ class Asset extends \Core\Base
*/
public function js($filename, $async = false)
{
- return '<script '.($async ? 'async' : '').' type="text/javascript" src="'.$filename.'?'.filemtime($filename).'"></script>';
+ return '<script '.($async ? 'async' : '').' type="text/javascript" src="'.$this->helper->url->dir().$filename.'?'.filemtime($filename).'"></script>';
}
/**
@@ -31,7 +31,7 @@ class Asset extends \Core\Base
*/
public function css($filename, $is_file = true, $media = 'screen')
{
- return '<link rel="stylesheet" href="'.$filename.($is_file ? '?'.filemtime($filename) : '').'" media="'.$media.'">';
+ return '<link rel="stylesheet" href="'.$this->helper->url->dir().$filename.($is_file ? '?'.filemtime($filename) : '').'" media="'.$media.'">';
}
/**
diff --git a/app/Helper/Url.php b/app/Helper/Url.php
index 8de63f8d..964e0762 100644
--- a/app/Helper/Url.php
+++ b/app/Helper/Url.php
@@ -13,6 +13,9 @@ use Core\Security;
*/
class Url extends \Core\Base
{
+ private $base = '';
+ private $directory = '';
+
/**
* HTML Link tag
*
@@ -33,7 +36,7 @@ class Url extends \Core\Base
}
/**
- * Hyperlink
+ * HTML Hyperlink
*
* @access public
* @param string $controller Controller name
@@ -41,22 +44,12 @@ class Url extends \Core\Base
* @param array $params Url parameters
* @param boolean $csrf Add a CSRF token
* @param string $anchor Link Anchor
+ * @param boolean $absolute Absolute or relative link
* @return string
*/
- public function href($controller, $action, array $params = array(), $csrf = false, $anchor = '')
+ public function href($controller, $action, array $params = array(), $csrf = false, $anchor = '', $absolute = false)
{
- $values = array(
- 'controller' => $controller,
- 'action' => $action,
- );
-
- if ($csrf) {
- $params['csrf_token'] = Security::getCSRFToken();
- }
-
- $values += $params;
-
- return '?'.http_build_query($values, '', '&amp;').(empty($anchor) ? '' : '#'.$anchor);
+ return $this->build('&amp;', $controller, $action, $params, $csrf, $anchor, $absolute);
}
/**
@@ -66,18 +59,13 @@ class Url extends \Core\Base
* @param string $controller Controller name
* @param string $action Action name
* @param array $params Url parameters
+ * @param string $anchor Link Anchor
+ * @param boolean $absolute Absolute or relative link
* @return string
*/
- public function to($controller, $action, array $params = array())
+ public function to($controller, $action, array $params = array(), $anchor = '', $absolute = false)
{
- $values = array(
- 'controller' => $controller,
- 'action' => $action,
- );
-
- $values += $params;
-
- return '?'.http_build_query($values, '', '&');
+ return $this->build('&', $controller, $action, $params, false, $anchor, $absolute);
}
/**
@@ -88,7 +76,28 @@ class Url extends \Core\Base
*/
public function base()
{
- return $this->config->get('application_url') ?: $this->server();
+ if (empty($this->base)) {
+ $this->base = $this->config->get('application_url') ?: $this->server();
+ }
+
+ return $this->base;
+ }
+
+ /**
+ * Get application base directory
+ *
+ * @access public
+ * @return string
+ */
+ public function dir()
+ {
+ if (empty($this->directory) && isset($_SERVER['REQUEST_METHOD'])) {
+ $this->directory = str_replace('\\', '/', dirname($_SERVER['PHP_SELF']));
+ $this->directory = $this->directory !== '/' ? $this->directory.'/' : '/';
+ $this->directory = str_replace('//', '/', $this->directory);
+ }
+
+ return $this->directory;
}
/**
@@ -103,13 +112,46 @@ class Url extends \Core\Base
return 'http://localhost/';
}
- $self = str_replace('\\', '/', dirname($_SERVER['PHP_SELF']));
-
$url = Request::isHTTPS() ? 'https://' : 'http://';
$url .= $_SERVER['SERVER_NAME'];
$url .= $_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443 ? '' : ':'.$_SERVER['SERVER_PORT'];
- $url .= $self !== '/' ? $self.'/' : '/';
+ $url .= $this->dir() ?: '/';
return $url;
}
+
+ /**
+ * Build relative url
+ *
+ * @access private
+ * @param string $separator Querystring argument separator
+ * @param string $controller Controller name
+ * @param string $action Action name
+ * @param array $params Url parameters
+ * @param boolean $csrf Add a CSRF token
+ * @param string $anchor Link Anchor
+ * @param boolean $absolute Absolute or relative link
+ * @return string
+ */
+ private function build($separator, $controller, $action, array $params = array(), $csrf = false, $anchor = '', $absolute = false)
+ {
+ $path = $this->router->findUrl($controller, $action, $params);
+ $qs = array();
+
+ if (empty($path)) {
+ $qs['controller'] = $controller;
+ $qs['action'] = $action;
+ $qs += $params;
+ }
+
+ if ($csrf) {
+ $qs['csrf_token'] = Security::getCSRFToken();
+ }
+
+ if (! empty($qs)) {
+ $path .= '?'.http_build_query($qs, '', $separator);
+ }
+
+ return ($absolute ? $this->base() : $this->dir()).$path.(empty($anchor) ? '' : '#'.$anchor);
+ }
}
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index 8c55457d..ef772f58 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -72,6 +72,7 @@ class ClassProvider implements ServiceProviderInterface
'Lexer',
'MemoryCache',
'Request',
+ 'Router',
'Session',
'Template',
),
diff --git a/app/Template/app/overview.php b/app/Template/app/overview.php
index fa7866af..1b160496 100644
--- a/app/Template/app/overview.php
+++ b/app/Template/app/overview.php
@@ -1,7 +1,7 @@
<div class="search">
- <form method="get" action="?" class="search">
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', array('controller' => 'search')) ?>
- <?= $this->form->hidden('action', array('controller' => 'index')) ?>
+ <?= $this->form->hidden('action', array('action' => 'index')) ?>
<?= $this->form->text('search', array(), array(), array('placeholder="'.t('Search').'"'), 'form-input-large') ?>
</form>
diff --git a/app/Template/config/integrations.php b/app/Template/config/integrations.php
index 9c80b499..44cfc7d1 100644
--- a/app/Template/config/integrations.php
+++ b/app/Template/config/integrations.php
@@ -6,30 +6,30 @@
<?= $this->form->csrf() ?>
- <h3><img src="assets/img/mailgun-icon.png"/>&nbsp;<?= t('Mailgun (incoming emails)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/mailgun-icon.png"/>&nbsp;<?= t('Mailgun (incoming emails)') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'mailgun', array('token' => $values['webhook_token'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'mailgun', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/mailgun" target="_blank"><?= t('Help on Mailgun integration') ?></a></p>
</div>
- <h3><img src="assets/img/sendgrid-icon.png"/>&nbsp;<?= t('Sendgrid (incoming emails)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/sendgrid-icon.png"/>&nbsp;<?= t('Sendgrid (incoming emails)') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'sendgrid', array('token' => $values['webhook_token'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'sendgrid', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/sendgrid" target="_blank"><?= t('Help on Sendgrid integration') ?></a></p>
</div>
- <h3><img src="assets/img/postmark-icon.png"/>&nbsp;<?= t('Postmark (incoming emails)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/postmark-icon.png"/>&nbsp;<?= t('Postmark (incoming emails)') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'postmark', array('token' => $values['webhook_token'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'postmark', array('token' => $values['webhook_token']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/postmark" target="_blank"><?= t('Help on Postmark integration') ?></a></p>
</div>
- <h3><img src="assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/gravatar-icon.png"/>&nbsp;<?= t('Gravatar') ?></h3>
<div class="listing">
<?= $this->form->checkbox('integration_gravatar', t('Enable Gravatar images'), 1, $values['integration_gravatar'] == 1) ?>
</div>
- <h3><img src="assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
<div class="listing">
<?= $this->form->checkbox('integration_jabber', t('Send notifications to Jabber'), 1, $values['integration_jabber'] == 1) ?>
@@ -55,7 +55,7 @@
<p class="form-help"><a href="http://kanboard.net/documentation/jabber" target="_blank"><?= t('Help on Jabber integration') ?></a></p>
</div>
- <h3><img src="assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
<div class="listing">
<?= $this->form->checkbox('integration_hipchat', t('Send notifications to Hipchat'), 1, $values['integration_hipchat'] == 1) ?>
diff --git a/app/Template/config/webhook.php b/app/Template/config/webhook.php
index 73ca3598..f1a98f8b 100644
--- a/app/Template/config/webhook.php
+++ b/app/Template/config/webhook.php
@@ -26,7 +26,7 @@
</li>
<li>
<?= t('URL for task creation:') ?>
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'task', array('token' => $values['webhook_token'])) ?>">
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'task', array('token' => $values['webhook_token']), false, '', true) ?>">
</li>
<li>
<?= $this->url->link(t('Reset token'), 'config', 'token', array('type' => 'webhook'), true) ?>
diff --git a/app/Template/feed/project.php b/app/Template/feed/project.php
index 60b7ee96..76cf6cf0 100644
--- a/app/Template/feed/project.php
+++ b/app/Template/feed/project.php
@@ -2,15 +2,15 @@
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title><?= t('%s\'s activity', $project['name']) ?></title>
<link rel="alternate" type="text/html" href="<?= $this->url->base() ?>"/>
- <link rel="self" type="application/atom+xml" href="<?= $this->url->base().$this->url->href('feed', 'project', array('token' => $project['token'])) ?>"/>
+ <link rel="self" type="application/atom+xml" href="<?= $this->url->href('feed', 'project', array('token' => $project['token']), false, '', true) ?>"/>
<updated><?= date(DATE_ATOM) ?></updated>
- <id><?= $this->url->base().$this->url->href('feed', 'project', array('token' => $project['token'])) ?></id>
+ <id><?= $this->url->href('feed', 'project', array('token' => $project['token']), false, '', true) ?></id>
<icon><?= $this->url->base() ?>assets/img/favicon.png</icon>
<?php foreach ($events as $e): ?>
<entry>
<title type="text"><?= $e['event_title'] ?></title>
- <link rel="alternate" href="<?= $this->url->base().$this->url->href('task', 'show', array('task_id' => $e['task_id'])) ?>"/>
+ <link rel="alternate" href="<?= $this->url->href('task', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
<id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id>
<published><?= date(DATE_ATOM, $e['date_creation']) ?></published>
<updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated>
diff --git a/app/Template/feed/user.php b/app/Template/feed/user.php
index b3279a0c..3e9606c6 100644
--- a/app/Template/feed/user.php
+++ b/app/Template/feed/user.php
@@ -2,15 +2,15 @@
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
<title><?= t('Project activities for %s', $user['name'] ?: $user['username']) ?></title>
<link rel="alternate" type="text/html" href="<?= $this->url->base() ?>"/>
- <link rel="self" type="application/atom+xml" href="<?= $this->url->base().$this->url->href('feed', 'user', array('token' => $user['token'])) ?>"/>
+ <link rel="self" type="application/atom+xml" href="<?= $this->url->href('feed', 'user', array('token' => $user['token']), false, '', true) ?>"/>
<updated><?= date(DATE_ATOM) ?></updated>
- <id><?= $this->url->base().$this->url->href('feed', 'user', array('token' => $user['token'])) ?></id>
+ <id><?= $this->url->href('feed', 'user', array('token' => $user['token']), false, '', true) ?></id>
<icon><?= $this->url->base() ?>assets/img/favicon.png</icon>
<?php foreach ($events as $e): ?>
<entry>
<title type="text"><?= $e['event_title'] ?></title>
- <link rel="alternate" href="<?= $this->url->base().$this->url->href('task', 'show', array('task_id' => $e['task_id'])) ?>"/>
+ <link rel="alternate" href="<?= $this->url->href('task', 'show', array('task_id' => $e['task_id']), false, '', true) ?>"/>
<id><?= $e['id'].'-'.$e['event_name'].'-'.$e['task_id'].'-'.$e['date_creation'] ?></id>
<published><?= date(DATE_ATOM, $e['date_creation']) ?></published>
<updated><?= date(DATE_ATOM, $e['date_creation']) ?></updated>
diff --git a/app/Template/layout.php b/app/Template/layout.php
index a9f1cbc3..d02ba08d 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -20,11 +20,11 @@
<?= $this->asset->css('assets/css/print.css', true, 'print') ?>
<?= $this->asset->customCss() ?>
- <link rel="icon" type="image/png" href="assets/img/favicon.png">
- <link rel="apple-touch-icon" href="assets/img/touch-icon-iphone.png">
- <link rel="apple-touch-icon" sizes="72x72" href="assets/img/touch-icon-ipad.png">
- <link rel="apple-touch-icon" sizes="114x114" href="assets/img/touch-icon-iphone-retina.png">
- <link rel="apple-touch-icon" sizes="144x144" href="assets/img/touch-icon-ipad-retina.png">
+ <link rel="icon" type="image/png" href="<?= $this->url->dir() ?>assets/img/favicon.png">
+ <link rel="apple-touch-icon" href="<?= $this->url->dir() ?>assets/img/touch-icon-iphone.png">
+ <link rel="apple-touch-icon" sizes="72x72" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad.png">
+ <link rel="apple-touch-icon" sizes="114x114" href="<?= $this->url->dir() ?>assets/img/touch-icon-iphone-retina.png">
+ <link rel="apple-touch-icon" sizes="144x144" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad-retina.png">
<title><?= isset($title) ? $this->e($title) : 'Kanboard' ?></title>
</head>
diff --git a/app/Template/project/filters.php b/app/Template/project/filters.php
index 3beb2f44..cb6f11d3 100644
--- a/app/Template/project/filters.php
+++ b/app/Template/project/filters.php
@@ -40,10 +40,10 @@
<?= $this->url->link(t('List'), 'listing', 'show', array('project_id' => $project['id'], 'search' => $filters['search']), false, 'view-listing', t('Keyboard shortcut: "%s"', 'v l')) ?>
</li>
</ul>
- <form method="get" action="?" class="search">
- <?= $this->form->hidden('project_id', $filters) ?>
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', $filters) ?>
<?= $this->form->hidden('action', $filters) ?>
+ <?= $this->form->hidden('project_id', $filters) ?>
<?= $this->form->text('search', $filters, array(), array('placeholder="'.t('Filter').'"'), 'form-input-large') ?>
</form>
<?= $this->render('app/filters_helper', array('reset' => 'status:open')) ?>
diff --git a/app/Template/project/integrations.php b/app/Template/project/integrations.php
index 445e7bfb..12a7ee4e 100644
--- a/app/Template/project/integrations.php
+++ b/app/Template/project/integrations.php
@@ -8,26 +8,26 @@
<h3><i class="fa fa-github fa-fw"></i>&nbsp;<?= t('Github webhooks') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'github', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/github-webhooks" target="_blank"><?= t('Help on Github webhooks') ?></a></p>
</div>
- <h3><img src="assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/gitlab-icon.png"/>&nbsp;<?= t('Gitlab webhooks') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'gitlab', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/gitlab-webhooks" target="_blank"><?= t('Help on Gitlab webhooks') ?></a></p>
</div>
<h3><i class="fa fa-bitbucket fa-fw"></i>&nbsp;<?= t('Bitbucket webhooks') ?></h3>
<div class="listing">
- <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->base().$this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id'])) ?>"/><br/>
+ <input type="text" class="auto-select" readonly="readonly" value="<?= $this->url->href('webhook', 'bitbucket', array('token' => $webhook_token, 'project_id' => $project['id']), false, '', true) ?>"/><br/>
<p class="form-help"><a href="http://kanboard.net/documentation/bitbucket-webhooks" target="_blank"><?= t('Help on Bitbucket webhooks') ?></a></p>
</div>
- <h3><img src="assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/jabber-icon.png"/> <?= t('Jabber (XMPP)') ?></h3>
<div class="listing">
<?= $this->form->checkbox('jabber', t('Send notifications to Jabber'), 1, isset($values['jabber']) && $values['jabber'] == 1) ?>
@@ -58,7 +58,7 @@
</div>
- <h3><img src="assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
+ <h3><img src="<?= $this->url->dir() ?>assets/img/hipchat-icon.png"/> <?= t('Hipchat') ?></h3>
<div class="listing">
<?= $this->form->checkbox('hipchat', t('Send notifications to Hipchat'), 1, isset($values['hipchat']) && $values['hipchat'] == 1) ?>
diff --git a/app/Template/search/index.php b/app/Template/search/index.php
index 3d0d6ff9..8940a24e 100644
--- a/app/Template/search/index.php
+++ b/app/Template/search/index.php
@@ -9,7 +9,7 @@
</div>
<div class="search">
- <form method="get" action="?" class="search">
+ <form method="get" action="<?= $this->url->dir() ?>" class="search">
<?= $this->form->hidden('controller', $values) ?>
<?= $this->form->hidden('action', $values) ?>
<?= $this->form->text('search', $values, array(), array(empty($values['search']) ? 'autofocus' : '', 'placeholder="'.t('Search').'"'), 'form-input-large') ?>
diff --git a/app/common.php b/app/common.php
index b5871673..3acf9573 100644
--- a/app/common.php
+++ b/app/common.php
@@ -12,7 +12,7 @@ if (getenv('DATABASE_URL')) {
define('DB_PASSWORD', $dbopts["pass"]);
define('DB_HOSTNAME', $dbopts["host"]);
define('DB_PORT', isset($dbopts["port"]) ? $dbopts["port"] : null);
- define('DB_NAME', ltrim($dbopts["path"],'/'));
+ define('DB_NAME', ltrim($dbopts["path"], '/'));
}
// Include custom config file
@@ -28,3 +28,93 @@ $container->register(new ServiceProvider\LoggingProvider);
$container->register(new ServiceProvider\DatabaseProvider);
$container->register(new ServiceProvider\ClassProvider);
$container->register(new ServiceProvider\EventDispatcherProvider);
+
+if (ENABLE_URL_REWRITE) {
+
+ // Dashboard
+ $container['router']->addRoute('dashboard', 'app', 'index');
+ $container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id'));
+ $container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id'));
+
+ // Search routes
+ $container['router']->addRoute('search', 'search', 'index');
+ $container['router']->addRoute('search/:search', 'search', 'index', array('search'));
+
+ // Project routes
+ $container['router']->addRoute('projects', 'project', 'index');
+ $container['router']->addRoute('project/create', 'project', 'create');
+ $container['router']->addRoute('project/create/:private', 'project', 'create', array('private'));
+ $container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id'));
+ $container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id'));
+ $container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id'));
+ $container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id'));
+ $container['router']->addRoute('project/:project_id/integration', 'project', 'integration', array('project_id'));
+ $container['router']->addRoute('project/:project_id/users', 'project', 'users', array('project_id'));
+ $container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id'));
+ $container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id'));
+ $container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id'));
+ $container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id'));
+
+ // Action routes
+ $container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id'));
+
+ // Column routes
+ $container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id'));
+ $container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id'));
+ $container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction'));
+
+ // Swimlane routes
+ $container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id'));
+
+ // Category routes
+ $container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id'));
+ $container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id'));
+ $container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id'));
+
+ // Task routes
+ $container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id'));
+ $container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id'));
+ $container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/column/:column_id', 'task', 'create', array('project_id', 'swimlane_id', 'column_id'));
+ $container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token'));
+
+ // Board routes
+ $container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id'));
+ $container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id'));
+ $container['router']->addRoute('board/:project_id/:search', 'board', 'show', array('project_id', 'search'));
+ $container['router']->addRoute('board/collapse/:project_id', 'board', 'collapse', array('project_id'));
+ $container['router']->addRoute('board/expand/:project_id', 'board', 'expand', array('project_id'));
+ $container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token'));
+
+ // Calendar routes
+ $container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id'));
+ $container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id'));
+ $container['router']->addRoute('calendar/:project_id/:search', 'calendar', 'show', array('project_id', 'search'));
+
+ // Listing routes
+ $container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id'));
+ $container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id'));
+ $container['router']->addRoute('list/:project_id/:search', 'listing', 'show', array('project_id', 'search'));
+
+ // Subtask routes
+ $container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id', 'subtask', 'remove', array('project_id', 'task_id', 'subtask_id'));
+
+ // Feed routes
+ $container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token'));
+ $container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token'));
+
+ // Ical routes
+ $container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token'));
+ $container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token'));
+}
diff --git a/app/constants.php b/app/constants.php
index 9b66b746..cd1c0d1c 100644
--- a/app/constants.php
+++ b/app/constants.php
@@ -7,9 +7,6 @@ defined('DEBUG_FILE') or define('DEBUG_FILE', __DIR__.'/../data/debug.log');
// Application version
defined('APP_VERSION') or define('APP_VERSION', 'master');
-// Base directory
-define('BASE_URL_DIRECTORY', dirname($_SERVER['PHP_SELF']));
-
// Database driver: sqlite, mysql or postgres
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');
@@ -84,3 +81,6 @@ defined('MARKDOWN_ESCAPE_HTML') or define('MARKDOWN_ESCAPE_HTML', true);
// API alternative authentication header, the default is HTTP Basic Authentication defined in RFC2617
defined('API_AUTHENTICATION_HEADER') or define('API_AUTHENTICATION_HEADER', '');
+
+// Enable/disable url rewrite
+defined('ENABLE_URL_REWRITE') or define('ENABLE_URL_REWRITE', isset($_SERVER['HTTP_MOD_REWRITE']));
diff --git a/config.default.php b/config.default.php
index 7c6955e8..514a8121 100644
--- a/config.default.php
+++ b/config.default.php
@@ -150,3 +150,7 @@ define('MARKDOWN_ESCAPE_HTML', true);
// API alternative authentication header, the default is HTTP Basic Authentication defined in RFC2617
define('API_AUTHENTICATION_HEADER', '');
+
+// Enable/disable url rewrite
+define('ENABLE_URL_REWRITE', false);
+
diff --git a/index.php b/index.php
index 4c49416f..7c5fe6d1 100644
--- a/index.php
+++ b/index.php
@@ -2,7 +2,6 @@
require __DIR__.'/app/common.php';
-use Core\Router;
-
-$router = new Router($container);
-$router->execute();
+if (! $container['router']->dispatch($_SERVER['REQUEST_URI'], $_SERVER['QUERY_STRING'])) {
+ die('Page not found!');
+}
diff --git a/tests/units/RouterTest.php b/tests/units/RouterTest.php
new file mode 100644
index 00000000..e4582121
--- /dev/null
+++ b/tests/units/RouterTest.php
@@ -0,0 +1,79 @@
+<?php
+
+require_once __DIR__.'/Base.php';
+
+use Core\Router;
+
+class RouterTest extends Base
+{
+ public function testSanitize()
+ {
+ $r = new Router($this->container);
+
+ $this->assertEquals('plop', $r->sanitize('PloP', 'default'));
+ $this->assertEquals('default', $r->sanitize('', 'default'));
+ $this->assertEquals('default', $r->sanitize('123-AB', 'default'));
+ $this->assertEquals('default', $r->sanitize('R&D', 'default'));
+ $this->assertEquals('default', $r->sanitize('Test123', 'default'));
+ }
+
+ public function testPath()
+ {
+ $r = new Router($this->container);
+
+ $this->assertEquals('a/b/c', $r->getPath('/a/b/c'));
+ $this->assertEquals('a/b/something', $r->getPath('/a/b/something?test=a', 'test=a'));
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $_SERVER['PHP_SELF'] = '/a/index.php';
+
+ $this->assertEquals('b/c', $r->getPath('/a/b/c'));
+ $this->assertEquals('b/c', $r->getPath('/a/b/c?e=f', 'e=f'));
+ }
+
+ public function testFindRouteWithEmptyTable()
+ {
+ $r = new Router($this->container);
+ $this->assertEquals(array('app', 'index'), $r->findRoute(''));
+ $this->assertEquals(array('app', 'index'), $r->findRoute('/'));
+ }
+
+ public function testFindRouteWithoutPlaceholders()
+ {
+ $r = new Router($this->container);
+ $r->addRoute('a/b', 'controller', 'action');
+ $this->assertEquals(array('app', 'index'), $r->findRoute('a/b/c'));
+ $this->assertEquals(array('controller', 'action'), $r->findRoute('a/b'));
+ }
+
+ public function testFindRouteWithPlaceholders()
+ {
+ $r = new Router($this->container);
+ $r->addRoute('a/:myvar1/b/:myvar2', 'controller', 'action');
+ $this->assertEquals(array('app', 'index'), $r->findRoute('a/123/b'));
+ $this->assertEquals(array('controller', 'action'), $r->findRoute('a/456/b/789'));
+ $this->assertEquals(array('myvar1' => 456, 'myvar2' => 789), $_GET);
+ }
+
+ public function testFindMultipleRoutes()
+ {
+ $r = new Router($this->container);
+ $r->addRoute('a/b', 'controller1', 'action1');
+ $r->addRoute('a/b', 'duplicate', 'duplicate');
+ $r->addRoute('a', 'controller2', 'action2');
+ $this->assertEquals(array('controller1', 'action1'), $r->findRoute('a/b'));
+ $this->assertEquals(array('controller2', 'action2'), $r->findRoute('a'));
+ }
+
+ public function testFindUrl()
+ {
+ $r = new Router($this->container);
+ $r->addRoute('a/b', 'controller1', 'action1');
+ $r->addRoute('a/:myvar1/b/:myvar2', 'controller2', 'action2', array('myvar1', 'myvar2'));
+
+ $this->assertEquals('a/1/b/2', $r->findUrl('controller2', 'action2', array('myvar1' => 1, 'myvar2' => 2)));
+ $this->assertEquals('', $r->findUrl('controller2', 'action2', array('myvar1' => 1)));
+ $this->assertEquals('a/b', $r->findUrl('controller1', 'action1'));
+ $this->assertEquals('', $r->findUrl('controller1', 'action2'));
+ }
+}
diff --git a/tests/units/UrlHelperTest.php b/tests/units/UrlHelperTest.php
index 3ef3402a..ebfe9c99 100644
--- a/tests/units/UrlHelperTest.php
+++ b/tests/units/UrlHelperTest.php
@@ -34,6 +34,22 @@ class UrlHelperTest extends Base
);
}
+ public function testDir()
+ {
+ $h = new Url($this->container);
+ $this->assertEquals('', $h->dir());
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $_SERVER['PHP_SELF'] = '/plop/index.php';
+ $h = new Url($this->container);
+ $this->assertEquals('/plop/', $h->dir());
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $_SERVER['PHP_SELF'] = '';
+ $h = new Url($this->container);
+ $this->assertEquals('/', $h->dir());
+ }
+
public function testServer()
{
$h = new Url($this->container);
@@ -57,11 +73,13 @@ class UrlHelperTest extends Base
$_SERVER['SERVER_NAME'] = 'kb';
$_SERVER['SERVER_PORT'] = 1234;
+ $h = new Url($this->container);
$this->assertEquals('http://kb:1234/', $h->base());
$c = new Config($this->container);
$c->save(array('application_url' => 'https://mykanboard/'));
+ $h = new Url($this->container);
$this->assertEquals('https://mykanboard/', $c->get('application_url'));
$this->assertEquals('https://mykanboard/', $h->base());
}