From b081288188bb1744c9d7bd075aa5936e0ccbb9c4 Mon Sep 17 00:00:00 2001
From: Frédéric Guillot <fred@kanboard.net>
Date: Fri, 14 Nov 2014 22:44:25 -0500
Subject: Use Pimple instead of Core\Registry and add Monolog for logging

---
 app/Action/Base.php                   |  20 ++---
 app/Auth/Base.php                     |  20 ++---
 app/Auth/RememberMe.php               |   5 +-
 app/Controller/Base.php               |  17 +++--
 app/Core/Registry.php                 |  83 ---------------------
 app/Core/Request.php                  |  14 ++++
 app/Core/Response.php                 |   2 +-
 app/Core/Router.php                   |  20 ++---
 app/Core/Session.php                  |   2 +-
 app/Core/Tool.php                     |  28 ++-----
 app/Event/Base.php                    |  16 ++--
 app/Event/ProjectActivityListener.php |   2 +-
 app/Model/Action.php                  |   2 +-
 app/Model/Authentication.php          |   6 +-
 app/Model/Base.php                    |  20 ++---
 app/Model/Notification.php            |   7 +-
 app/Model/Project.php                 |   2 +-
 app/Model/ProjectActivity.php         |   2 +-
 app/Model/Webhook.php                 |   4 +-
 app/ServiceProvider/Database.php      | 100 +++++++++++++++++++++++++
 app/ServiceProvider/Event.php         |  15 ++++
 app/ServiceProvider/Logging.php       |  21 ++++++
 app/ServiceProvider/Mailer.php        |  36 +++++++++
 app/common.php                        |  11 ++-
 app/functions.php                     | 135 ----------------------------------
 app/helpers.php                       |   4 +-
 26 files changed, 275 insertions(+), 319 deletions(-)
 delete mode 100644 app/Core/Registry.php
 create mode 100644 app/ServiceProvider/Database.php
 create mode 100644 app/ServiceProvider/Event.php
 create mode 100644 app/ServiceProvider/Logging.php
 create mode 100644 app/ServiceProvider/Mailer.php

(limited to 'app')

diff --git a/app/Action/Base.php b/app/Action/Base.php
index be9c3d48..a438ce04 100644
--- a/app/Action/Base.php
+++ b/app/Action/Base.php
@@ -2,8 +2,8 @@
 
 namespace Action;
 
+use Pimple\Container;
 use Core\Listener;
-use Core\Registry;
 use Core\Tool;
 
 /**
@@ -44,12 +44,12 @@ abstract class Base implements Listener
     protected $event_name = '';
 
     /**
-     * Registry instance
+     * Container instance
      *
      * @access protected
-     * @var \Core\Registry
+     * @var Pimple\Container
      */
-    protected $registry;
+    protected $container;
 
     /**
      * Execute the action
@@ -101,13 +101,13 @@ abstract class Base implements Listener
      * Constructor
      *
      * @access public
-     * @param  \Core\Registry   $registry         Regsitry instance
-     * @param  integer          $project_id       Project id
-     * @param  string           $event_name       Attached event name
+     * @param  Pimple\Container   $container        Container
+     * @param  integer            $project_id       Project id
+     * @param  string             $event_name       Attached event name
      */
-    public function __construct(Registry $registry, $project_id, $event_name)
+    public function __construct(Container $container, $project_id, $event_name)
     {
-        $this->registry = $registry;
+        $this->container = $container;
         $this->project_id = $project_id;
         $this->event_name = $event_name;
     }
@@ -132,7 +132,7 @@ abstract class Base implements Listener
      */
     public function __get($name)
     {
-        return Tool::loadModel($this->registry, $name);
+        return Tool::loadModel($this->container, $name);
     }
 
     /**
diff --git a/app/Auth/Base.php b/app/Auth/Base.php
index e174ff8f..e3a1c88c 100644
--- a/app/Auth/Base.php
+++ b/app/Auth/Base.php
@@ -3,7 +3,7 @@
 namespace Auth;
 
 use Core\Tool;
-use Core\Registry;
+use Pimple\Container;
 
 /**
  * Base auth class
@@ -26,34 +26,34 @@ abstract class Base
     protected $db;
 
     /**
-     * Registry instance
+     * Container instance
      *
      * @access protected
-     * @var \Core\Registry
+     * @var Pimple\Container
      */
-    protected $registry;
+    protected $container;
 
     /**
      * Constructor
      *
      * @access public
-     * @param  \Core\Registry  $registry  Registry instance
+     * @param  Pimple\Container    $container
      */
-    public function __construct(Registry $registry)
+    public function __construct(Container $container)
     {
-        $this->registry = $registry;
-        $this->db = $this->registry->shared('db');
+        $this->container = $container;
+        $this->db = $this->container['db'];
     }
 
     /**
      * Load automatically models
      *
      * @access public
-     * @param  string $name Model name
+     * @param  string     $name    Model name
      * @return mixed
      */
     public function __get($name)
     {
-        return Tool::loadModel($this->registry, $name);
+        return Tool::loadModel($this->container, $name);
     }
 }
diff --git a/app/Auth/RememberMe.php b/app/Auth/RememberMe.php
index 380abbed..2585e96c 100644
--- a/app/Auth/RememberMe.php
+++ b/app/Auth/RememberMe.php
@@ -4,7 +4,6 @@ namespace Auth;
 
 use Core\Request;
 use Core\Security;
-use Core\Tool;
 
 /**
  * RememberMe model
@@ -311,7 +310,7 @@ class RememberMe extends Base
             $expiration,
             BASE_URL_DIRECTORY,
             null,
-            Tool::isHTTPS(),
+            Request::isHTTPS(),
             true
         );
     }
@@ -344,7 +343,7 @@ class RememberMe extends Base
             time() - 3600,
             BASE_URL_DIRECTORY,
             null,
-            Tool::isHTTPS(),
+            Request::isHTTPS(),
             true
         );
     }
diff --git a/app/Controller/Base.php b/app/Controller/Base.php
index 2c8fb221..da08a130 100644
--- a/app/Controller/Base.php
+++ b/app/Controller/Base.php
@@ -2,6 +2,7 @@
 
 namespace Controller;
 
+use Pimple\Container;
 use Core\Tool;
 use Core\Registry;
 use Core\Security;
@@ -75,34 +76,34 @@ abstract class Base
     public $session;
 
     /**
-     * Registry instance
+     * Container instance
      *
      * @access private
-     * @var \Core\Registry
+     * @var Pimple\Container
      */
-    private $registry;
+    private $container;
 
     /**
      * Constructor
      *
      * @access public
-     * @param  \Core\Registry  $registry   Registry instance
+     * @param  Pimple\Container   $container
      */
-    public function __construct(Registry $registry)
+    public function __construct(Container $container)
     {
-        $this->registry = $registry;
+        $this->container = $container;
     }
 
     /**
      * Load automatically models
      *
      * @access public
-     * @param  string $name Model name
+     * @param  string    $name    Model name
      * @return mixed
      */
     public function __get($name)
     {
-        return Tool::loadModel($this->registry, $name);
+        return Tool::loadModel($this->container, $name);
     }
 
     /**
diff --git a/app/Core/Registry.php b/app/Core/Registry.php
deleted file mode 100644
index d8b9063e..00000000
--- a/app/Core/Registry.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-namespace Core;
-
-use RuntimeException;
-
-/**
- * The registry class is a dependency injection container
- *
- * @property mixed db
- * @property mixed event
- * @package core
- * @author  Frederic Guillot
- */
-class Registry
-{
-    /**
-     * Contains all dependencies
-     *
-     * @access private
-     * @var array
-     */
-    private $container = array();
-
-    /**
-     * Contains all instances
-     *
-     * @access private
-     * @var array
-     */
-    private $instances = array();
-
-    /**
-     * Set a dependency
-     *
-     * @access public
-     * @param  string   $name   Unique identifier for the service/parameter
-     * @param  mixed    $value  The value of the parameter or a closure to define an object
-     */
-    public function __set($name, $value)
-    {
-        $this->container[$name] = $value;
-    }
-
-    /**
-     * Get a dependency
-     *
-     * @access public
-     * @param  string   $name   Unique identifier for the service/parameter
-     * @return mixed            The value of the parameter or an object
-     * @throws RuntimeException If the identifier is not found
-     */
-    public function __get($name)
-    {
-        if (isset($this->container[$name])) {
-
-            if (is_callable($this->container[$name])) {
-                return $this->container[$name]();
-            }
-            else {
-                return $this->container[$name];
-            }
-        }
-
-        throw new \RuntimeException('Identifier not found in the registry: '.$name);
-    }
-
-    /**
-     * Return a shared instance of a dependency
-     *
-     * @access public
-     * @param  string   $name   Unique identifier for the service/parameter
-     * @return mixed            Same object instance of the dependency
-     */
-    public function shared($name)
-    {
-        if (! isset($this->instances[$name])) {
-            $this->instances[$name] = $this->$name;
-        }
-
-        return $this->instances[$name];
-    }
-}
diff --git a/app/Core/Request.php b/app/Core/Request.php
index 1b643208..c7ca3184 100644
--- a/app/Core/Request.php
+++ b/app/Core/Request.php
@@ -124,6 +124,20 @@ class Request
         return $this->getHeader('X-Requested-With') === 'XMLHttpRequest';
     }
 
+    /**
+     * Check if the page is requested through HTTPS
+     *
+     * Note: IIS return the value 'off' and other web servers an empty value when it's not HTTPS
+     *
+     * @static
+     * @access public
+     * @return boolean
+     */
+    public static function isHTTPS()
+    {
+        return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== '' && $_SERVER['HTTPS'] !== 'off';
+    }
+
     /**
      * Return a HTTP header value
      *
diff --git a/app/Core/Response.php b/app/Core/Response.php
index 347cdde7..6534d64f 100644
--- a/app/Core/Response.php
+++ b/app/Core/Response.php
@@ -246,7 +246,7 @@ class Response
      */
     public function hsts()
     {
-        if (Tool::isHTTPS()) {
+        if (Request::isHTTPS()) {
             header('Strict-Transport-Security: max-age=31536000');
         }
     }
diff --git a/app/Core/Router.php b/app/Core/Router.php
index c9af6e2c..1750753c 100644
--- a/app/Core/Router.php
+++ b/app/Core/Router.php
@@ -2,6 +2,8 @@
 
 namespace Core;
 
+use Pimple\Container;
+
 /**
  * Router class
  *
@@ -27,24 +29,24 @@ class Router
     private $action = '';
 
     /**
-     * Registry instance
+     * Container instance
      *
      * @access private
-     * @var \Core\Registry
+     * @var Pimple\Container
      */
-    private $registry;
+    private $container;
 
     /**
      * Constructor
      *
      * @access public
-     * @param  Registry        $registry     Registry instance
-     * @param  string          $controller   Controller name
-     * @param  string          $action       Action name
+     * @param  Pimple\Container   $container     Container instance
+     * @param  string             $controller   Controller name
+     * @param  string             $action       Action name
      */
-    public function __construct(Registry $registry, $controller = '', $action = '')
+    public function __construct(Container $container, $controller = '', $action = '')
     {
-        $this->registry = $registry;
+        $this->container = $container;
         $this->controller = empty($_GET['controller']) ? $controller : $_GET['controller'];
         $this->action = empty($_GET['action']) ? $action : $_GET['action'];
     }
@@ -81,7 +83,7 @@ class Router
                 return false;
             }
 
-            $instance = new $class($this->registry);
+            $instance = new $class($this->container);
             $instance->request = new Request;
             $instance->response = new Response;
             $instance->session = new Session;
diff --git a/app/Core/Session.php b/app/Core/Session.php
index 6028f0b9..e50c36b3 100644
--- a/app/Core/Session.php
+++ b/app/Core/Session.php
@@ -49,7 +49,7 @@ class Session
             self::SESSION_LIFETIME,
             $base_path ?: '/',
             null,
-            Tool::isHTTPS(),
+            Request::isHTTPS(),
             true
         );
 
diff --git a/app/Core/Tool.php b/app/Core/Tool.php
index e54a0d3b..c010d932 100644
--- a/app/Core/Tool.php
+++ b/app/Core/Tool.php
@@ -2,6 +2,8 @@
 
 namespace Core;
 
+use Pimple\Container;
+
 /**
  * Tool class
  *
@@ -37,31 +39,17 @@ class Tool
      *
      * @static
      * @access public
-     * @param  Core\Registry    $registry    DPI container
-     * @param  string           $name        Model name
+     * @param  Pimple\Container    $container     Container instance
+     * @param  string              $name          Model name
      * @return mixed
      */
-    public static function loadModel(Registry $registry, $name)
+    public static function loadModel(Container $container, $name)
     {
-        if (! isset($registry->$name)) {
+        if (! isset($container[$name])) {
             $class = '\Model\\'.ucfirst($name);
-            $registry->$name = new $class($registry);
+            $container[$name] = new $class($container);
         }
 
-        return $registry->shared($name);
-    }
-
-    /**
-     * Check if the page is requested through HTTPS
-     *
-     * Note: IIS return the value 'off' and other web servers an empty value when it's not HTTPS
-     *
-     * @static
-     * @access public
-     * @return boolean
-     */
-    public static function isHTTPS()
-    {
-        return isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== '' && $_SERVER['HTTPS'] !== 'off';
+        return $container[$name];
     }
 }
diff --git a/app/Event/Base.php b/app/Event/Base.php
index 745871a5..5381471a 100644
--- a/app/Event/Base.php
+++ b/app/Event/Base.php
@@ -2,8 +2,8 @@
 
 namespace Event;
 
+use Pimple\Container;
 use Core\Listener;
-use Core\Registry;
 use Core\Tool;
 
 /**
@@ -25,19 +25,19 @@ abstract class Base implements Listener
      * Registry instance
      *
      * @access protected
-     * @var \Core\Registry
+     * @var Pimple\Container
      */
-    protected $registry;
+    protected $container;
 
     /**
      * Constructor
      *
      * @access public
-     * @param  \Core\Registry     $registry     Regsitry instance
+     * @param  Pimple\Container    $container
      */
-    public function __construct(Registry $registry)
+    public function __construct(Container $container)
     {
-        $this->registry = $registry;
+        $this->container = $container;
     }
 
     /**
@@ -60,7 +60,7 @@ abstract class Base implements Listener
      */
     public function __get($name)
     {
-        return Tool::loadModel($this->registry, $name);
+        return Tool::loadModel($this->container, $name);
     }
 
     /**
@@ -73,7 +73,7 @@ abstract class Base implements Listener
      */
     public function getEventNamespace()
     {
-        $event_name = $this->registry->event->getLastTriggeredEvent();
+        $event_name = $this->container['event']->getLastTriggeredEvent();
         return substr($event_name, 0, strpos($event_name, '.'));
     }
 }
diff --git a/app/Event/ProjectActivityListener.php b/app/Event/ProjectActivityListener.php
index 8958bd2b..75efe65d 100644
--- a/app/Event/ProjectActivityListener.php
+++ b/app/Event/ProjectActivityListener.php
@@ -27,7 +27,7 @@ class ProjectActivityListener extends Base
                 $values['task']['project_id'],
                 $values['task']['id'],
                 $this->acl->getUserId(),
-                $this->registry->event->getLastTriggeredEvent(),
+                $this->container['event']->getLastTriggeredEvent(),
                 $values
             );
         }
diff --git a/app/Model/Action.php b/app/Model/Action.php
index c3acdc5b..f8dbd88e 100644
--- a/app/Model/Action.php
+++ b/app/Model/Action.php
@@ -264,7 +264,7 @@ class Action extends Base
     public function load($name, $project_id, $event)
     {
         $className = '\Action\\'.$name;
-        return new $className($this->registry, $project_id, $event);
+        return new $className($this->container, $project_id, $event);
     }
 
     /**
diff --git a/app/Model/Authentication.php b/app/Model/Authentication.php
index b9ebcfe2..a0e9684f 100644
--- a/app/Model/Authentication.php
+++ b/app/Model/Authentication.php
@@ -24,12 +24,12 @@ class Authentication extends Base
      */
     public function backend($name)
     {
-        if (! isset($this->registry->$name)) {
+        if (! isset($this->container[$name])) {
             $class = '\Auth\\'.ucfirst($name);
-            $this->registry->$name = new $class($this->registry);
+            $this->container[$name] = new $class($this->container);
         }
 
-        return $this->registry->shared($name);
+        return $this->container[$name];
     }
 
     /**
diff --git a/app/Model/Base.php b/app/Model/Base.php
index 72d91c3c..5a8d8f1c 100644
--- a/app/Model/Base.php
+++ b/app/Model/Base.php
@@ -4,7 +4,7 @@ namespace Model;
 
 use Core\Event;
 use Core\Tool;
-use Core\Registry;
+use Pimple\Container;
 use PicoDb\Database;
 
 /**
@@ -58,24 +58,24 @@ abstract class Base
     public $event;
 
     /**
-     * Registry instance
+     * Container instance
      *
      * @access protected
-     * @var \Core\Registry
+     * @var Pimple\Container
      */
-    protected $registry;
+    protected $container;
 
     /**
      * Constructor
      *
      * @access public
-     * @param  \Core\Registry  $registry  Registry instance
+     * @param  Pimple\Container   $container
      */
-    public function __construct(Registry $registry)
+    public function __construct(Container $container)
     {
-        $this->registry = $registry;
-        $this->db = $this->registry->shared('db');
-        $this->event = $this->registry->shared('event');
+        $this->container = $container;
+        $this->db = $this->container['db'];
+        $this->event = $this->container['event'];
     }
 
     /**
@@ -87,7 +87,7 @@ abstract class Base
      */
     public function __get($name)
     {
-        return Tool::loadModel($this->registry, $name);
+        return Tool::loadModel($this->container, $name);
     }
 
     /**
diff --git a/app/Model/Notification.php b/app/Model/Notification.php
index d2fcf525..32765041 100644
--- a/app/Model/Notification.php
+++ b/app/Model/Notification.php
@@ -117,7 +117,7 @@ class Notification extends Base
 
         foreach ($events as $event_name => $template_name) {
 
-            $listener = new NotificationListener($this->registry);
+            $listener = new NotificationListener($this->container);
             $listener->setTemplate($template_name);
 
             $this->event->attach($event_name, $listener);
@@ -135,8 +135,7 @@ class Notification extends Base
     public function sendEmails($template, array $users, array $data)
     {
         try {
-            $transport = $this->registry->shared('mailer');
-            $mailer = Swift_Mailer::newInstance($transport);
+            $mailer = Swift_Mailer::newInstance($this->container['mailer']);
 
             $message = Swift_Message::newInstance()
                             ->setSubject($this->getMailSubject($template, $data))
@@ -149,7 +148,7 @@ class Notification extends Base
             }
         }
         catch (Swift_TransportException $e) {
-            debug($e->getMessage());
+            $this->container['logger']->addError($e->getMessage());
         }
     }
 
diff --git a/app/Model/Project.php b/app/Model/Project.php
index 305e3f1e..2abee2aa 100644
--- a/app/Model/Project.php
+++ b/app/Model/Project.php
@@ -546,7 +546,7 @@ class Project extends Base
             GithubWebhook::EVENT_COMMIT,
         );
 
-        $listener = new ProjectModificationDateListener($this->registry);
+        $listener = new ProjectModificationDateListener($this->container);
 
         foreach ($events as $event_name) {
             $this->event->attach($event_name, $listener);
diff --git a/app/Model/ProjectActivity.php b/app/Model/ProjectActivity.php
index 6d6ef454..9d7ecfac 100644
--- a/app/Model/ProjectActivity.php
+++ b/app/Model/ProjectActivity.php
@@ -147,7 +147,7 @@ class ProjectActivity extends Base
             SubTask::EVENT_CREATE,
         );
 
-        $listener = new ProjectActivityListener($this->registry);
+        $listener = new ProjectActivityListener($this->container);
 
         foreach ($events as $event_name) {
             $this->event->attach($event_name, $listener);
diff --git a/app/Model/Webhook.php b/app/Model/Webhook.php
index b84728cf..14d50684 100644
--- a/app/Model/Webhook.php
+++ b/app/Model/Webhook.php
@@ -93,7 +93,7 @@ class Webhook extends Base
             Task::EVENT_ASSIGNEE_CHANGE,
         );
 
-        $listener = new WebhookListener($this->registry);
+        $listener = new WebhookListener($this->container);
         $listener->setUrl($this->url_task_modification);
 
         foreach ($events as $event_name) {
@@ -108,7 +108,7 @@ class Webhook extends Base
      */
     public function attachCreateEvents()
     {
-        $listener = new WebhookListener($this->registry);
+        $listener = new WebhookListener($this->container);
         $listener->setUrl($this->url_task_creation);
 
         $this->event->attach(Task::EVENT_CREATE, $listener);
diff --git a/app/ServiceProvider/Database.php b/app/ServiceProvider/Database.php
new file mode 100644
index 00000000..75e1f73e
--- /dev/null
+++ b/app/ServiceProvider/Database.php
@@ -0,0 +1,100 @@
+<?php
+
+namespace ServiceProvider;
+
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+use PicoDb\Database as Dbal;
+
+class Database implements ServiceProviderInterface
+{
+    public function register(Container $container)
+    {
+        $container['db'] = $this->getInstance();
+    }
+
+    /**
+     * Setup the database driver and execute schema migration
+     *
+     * @return PicoDb\Database
+     */
+    public function getInstance()
+    {
+        switch (DB_DRIVER) {
+            case 'sqlite':
+                $db = $this->getSqliteInstance();
+                break;
+
+            case 'mysql':
+                $db = $this->getMysqlInstance();
+                break;
+
+            case 'postgres':
+                $db = $this->getPostgresInstance();
+                break;
+
+            default:
+                die('Database driver not supported');
+        }
+
+        if ($db->schema()->check(\Schema\VERSION)) {
+            return $db;
+        }
+        else {
+            $errors = $db->getLogMessages();
+            die('Unable to migrate database schema: <br/><br/><strong>'.(isset($errors[0]) ? $errors[0] : 'Unknown error').'</strong>');
+        }
+    }
+
+    /**
+     * Setup the Sqlite database driver
+     *
+     * @return PicoDb\Database
+     */
+    function getSqliteInstance()
+    {
+        require_once __DIR__.'/../Schema/Sqlite.php';
+
+        return new Dbal(array(
+            'driver' => 'sqlite',
+            'filename' => DB_FILENAME
+        ));
+    }
+
+    /**
+     * Setup the Mysql database driver
+     *
+     * @return PicoDb\Database
+     */
+    function getMysqlInstance()
+    {
+        require_once __DIR__.'/../Schema/Mysql.php';
+
+        return new Dbal(array(
+            'driver'   => 'mysql',
+            'hostname' => DB_HOSTNAME,
+            'username' => DB_USERNAME,
+            'password' => DB_PASSWORD,
+            'database' => DB_NAME,
+            'charset'  => 'utf8',
+        ));
+    }
+
+    /**
+     * Setup the Postgres database driver
+     *
+     * @return PicoDb\Database
+     */
+    public function getPostgresInstance()
+    {
+        require_once __DIR__.'/../Schema/Postgres.php';
+
+        return new Dbal(array(
+            'driver'   => 'postgres',
+            'hostname' => DB_HOSTNAME,
+            'username' => DB_USERNAME,
+            'password' => DB_PASSWORD,
+            'database' => DB_NAME,
+        ));
+    }
+}
diff --git a/app/ServiceProvider/Event.php b/app/ServiceProvider/Event.php
new file mode 100644
index 00000000..0436aa7b
--- /dev/null
+++ b/app/ServiceProvider/Event.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace ServiceProvider;
+
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+use Core\Event as EventDispatcher;
+
+class Event implements ServiceProviderInterface
+{
+    public function register(Container $container)
+    {
+        $container['event'] = new EventDispatcher;
+    }
+}
diff --git a/app/ServiceProvider/Logging.php b/app/ServiceProvider/Logging.php
new file mode 100644
index 00000000..9737cadc
--- /dev/null
+++ b/app/ServiceProvider/Logging.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace ServiceProvider;
+
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+use Monolog\Logger;
+use Monolog\Handler\StreamHandler;
+use Monolog\Handler\SyslogHandler;
+
+class Logging implements ServiceProviderInterface
+{
+    public function register(Container $container)
+    {
+        $logger = new Logger('app');
+        $logger->pushHandler(new StreamHandler(__DIR__.'/../../data/debug.log', Logger::DEBUG));
+        $logger->pushHandler(new SyslogHandler('kanboard', LOG_USER, Logger::DEBUG));
+
+        $container['logger'] = $logger;
+    }
+}
diff --git a/app/ServiceProvider/Mailer.php b/app/ServiceProvider/Mailer.php
new file mode 100644
index 00000000..c82c16f6
--- /dev/null
+++ b/app/ServiceProvider/Mailer.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace ServiceProvider;
+
+use Pimple\Container;
+use Pimple\ServiceProviderInterface;
+use Swift_SmtpTransport;
+use Swift_SendmailTransport;
+use Swift_MailTransport;
+
+class Mailer implements ServiceProviderInterface
+{
+    public function register(Container $container)
+    {
+        $container['mailer'] = $this->getInstance();
+    }
+
+    public function getInstance()
+    {
+        switch (MAIL_TRANSPORT) {
+            case 'smtp':
+                $transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT);
+                $transport->setUsername(MAIL_SMTP_USERNAME);
+                $transport->setPassword(MAIL_SMTP_PASSWORD);
+                $transport->setEncryption(MAIL_SMTP_ENCRYPTION);
+                break;
+            case 'sendmail':
+                $transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND);
+                break;
+            default:
+                $transport = Swift_MailTransport::newInstance();
+        }
+
+        return $transport;
+    }
+}
diff --git a/app/common.php b/app/common.php
index 613d4501..addfe874 100644
--- a/app/common.php
+++ b/app/common.php
@@ -1,7 +1,5 @@
 <?php
 
-// Common file between cli and web interface
-
 require 'vendor/autoload.php';
 
 // Include custom config file
@@ -11,7 +9,8 @@ if (file_exists('config.php')) {
 
 require __DIR__.'/constants.php';
 
-$registry = new Core\Registry;
-$registry->db = setup_db();
-$registry->event = setup_events();
-$registry->mailer = function() { return setup_mailer(); };
+$container = new Pimple\Container;
+$container->register(new ServiceProvider\Logging);
+$container->register(new ServiceProvider\Database);
+$container->register(new ServiceProvider\Event);
+$container->register(new ServiceProvider\Mailer);
diff --git a/app/functions.php b/app/functions.php
index 5fe218ce..d45e78e7 100644
--- a/app/functions.php
+++ b/app/functions.php
@@ -1,141 +1,6 @@
 <?php
 
-use Core\Event;
 use Core\Translator;
-use PicoDb\Database;
-
-/**
- * Send a debug message to the log files
- *
- * @param mixed $message Variable or string
- */
-function debug($message)
-{
-    if (! is_string($message)) {
-        $message = var_export($message, true);
-    }
-
-    error_log($message.PHP_EOL, 3, 'data/debug.log');
-}
-
-/**
- * Setup events
- *
- * @return Core\Event
- */
-function setup_events()
-{
-    return new Event;
-}
-
-/**
- * Setup the mailer according to the configuration
- *
- * @return Swift_SmtpTransport
- */
-function setup_mailer()
-{
-    switch (MAIL_TRANSPORT) {
-        case 'smtp':
-            $transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT);
-            $transport->setUsername(MAIL_SMTP_USERNAME);
-            $transport->setPassword(MAIL_SMTP_PASSWORD);
-            $transport->setEncryption(MAIL_SMTP_ENCRYPTION);
-            break;
-        case 'sendmail':
-            $transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND);
-            break;
-        default:
-            $transport = Swift_MailTransport::newInstance();
-    }
-
-    return $transport;
-}
-
-/**
- * Setup the database driver and execute schema migration
- *
- * @return PicoDb\Database
- */
-function setup_db()
-{
-    switch (DB_DRIVER) {
-        case 'sqlite':
-            $db = setup_sqlite();
-            break;
-
-        case 'mysql':
-            $db = setup_mysql();
-            break;
-
-        case 'postgres':
-            $db = setup_postgres();
-            break;
-
-        default:
-            die('Database driver not supported');
-    }
-
-    if ($db->schema()->check(Schema\VERSION)) {
-        return $db;
-    }
-    else {
-        $errors = $db->getLogMessages();
-        die('Unable to migrate database schema: <br/><br/><strong>'.(isset($errors[0]) ? $errors[0] : 'Unknown error').'</strong>');
-    }
-}
-
-/**
- * Setup the Sqlite database driver
- *
- * @return PicoDb\Database
- */
-function setup_sqlite()
-{
-    require_once __DIR__.'/Schema/Sqlite.php';
-
-    return new Database(array(
-        'driver' => 'sqlite',
-        'filename' => DB_FILENAME
-    ));
-}
-
-/**
- * Setup the Mysql database driver
- *
- * @return PicoDb\Database
- */
-function setup_mysql()
-{
-    require_once __DIR__.'/Schema/Mysql.php';
-
-    return new Database(array(
-        'driver'   => 'mysql',
-        'hostname' => DB_HOSTNAME,
-        'username' => DB_USERNAME,
-        'password' => DB_PASSWORD,
-        'database' => DB_NAME,
-        'charset'  => 'utf8',
-    ));
-}
-
-/**
- * Setup the Postgres database driver
- *
- * @return PicoDb\Database
- */
-function setup_postgres()
-{
-    require_once __DIR__.'/Schema/Postgres.php';
-
-    return new Database(array(
-        'driver'   => 'postgres',
-        'hostname' => DB_HOSTNAME,
-        'username' => DB_USERNAME,
-        'password' => DB_PASSWORD,
-        'database' => DB_NAME,
-    ));
-}
 
 /**
  * Translate a string
diff --git a/app/helpers.php b/app/helpers.php
index f25db0f0..14d6a5ee 100644
--- a/app/helpers.php
+++ b/app/helpers.php
@@ -8,7 +8,7 @@ namespace Helper;
  */
 use Core\Security;
 use Core\Template;
-use Core\Tool;
+use Core\Request;
 use Parsedown;
 
 /**
@@ -142,7 +142,7 @@ function markdown($text, array $link = array('controller' => 'task', 'action' =>
  */
 function get_current_base_url()
 {
-    $url = Tool::isHTTPS() ? 'https://' : 'http://';
+    $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']).'/' : '/';
-- 
cgit v1.2.3