summaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
Diffstat (limited to 'models')
-rw-r--r--models/acl.php2
-rw-r--r--models/action.php247
-rw-r--r--models/base.php48
-rw-r--r--models/board.php10
-rw-r--r--models/comment.php6
-rw-r--r--models/config.php2
-rw-r--r--models/project.php37
-rw-r--r--models/schema.php23
-rw-r--r--models/task.php175
-rw-r--r--models/user.php2
10 files changed, 459 insertions, 93 deletions
diff --git a/models/acl.php b/models/acl.php
index 86db3c32..25386254 100644
--- a/models/acl.php
+++ b/models/acl.php
@@ -2,6 +2,8 @@
namespace Model;
+require_once __DIR__.'/base.php';
+
class Acl extends Base
{
// Controllers and actions allowed from outside
diff --git a/models/action.php b/models/action.php
new file mode 100644
index 00000000..9b18d461
--- /dev/null
+++ b/models/action.php
@@ -0,0 +1,247 @@
+<?php
+
+namespace Model;
+
+require_once __DIR__.'/base.php';
+require_once __DIR__.'/task.php';
+
+use \SimpleValidator\Validator;
+use \SimpleValidator\Validators;
+
+class Action extends Base
+{
+ const TABLE = 'actions';
+ const TABLE_PARAMS = 'action_has_params';
+
+ /**
+ * Return the name and description of available actions
+ *
+ * @access public
+ * @return array
+ */
+ public function getAvailableActions()
+ {
+ return array(
+ 'TaskClose' => t('Close the task'),
+ 'TaskAssignSpecificUser' => t('Assign the task to a specific user'),
+ 'TaskAssignCurrentUser' => t('Assign the task to the person who does the action'),
+ 'TaskDuplicateAnotherProject' => t('Duplicate the task to another project'),
+ );
+ }
+
+ /**
+ * Return the name and description of available actions
+ *
+ * @access public
+ * @return array
+ */
+ public function getAvailableEvents()
+ {
+ return array(
+ Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
+ Task::EVENT_MOVE_POSITION => t('Move a task to another position in the same column'),
+ Task::EVENT_UPDATE => t('Task modification'),
+ Task::EVENT_CREATE => t('Task creation'),
+ Task::EVENT_OPEN => t('Open a closed task'),
+ Task::EVENT_CLOSE => t('Closing a task'),
+ );
+ }
+
+ /**
+ * Return actions and parameters for a given project
+ *
+ * @access public
+ * @return array
+ */
+ public function getAllByProject($project_id)
+ {
+ $actions = $this->db->table(self::TABLE)->eq('project_id', $project_id)->findAll();
+
+ foreach ($actions as &$action) {
+ $action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action['id'])->findAll();
+ }
+
+ return $actions;
+ }
+
+ /**
+ * Return all actions and parameters
+ *
+ * @access public
+ * @return array
+ */
+ public function getAll()
+ {
+ $actions = $this->db->table(self::TABLE)->findAll();
+
+ foreach ($actions as &$action) {
+ $action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action['id'])->findAll();
+ }
+
+ return $actions;
+ }
+
+ /**
+ * Get all required action parameters for all registered actions
+ *
+ * @access public
+ * @return array All required parameters for all actions
+ */
+ public function getAllActionParameters()
+ {
+ $params = array();
+
+ foreach ($this->getAll() as $action) {
+
+ $action = $this->load($action['action_name'], $action['project_id']);
+ $params += $action->getActionRequiredParameters();
+ }
+
+ return $params;
+ }
+
+ /**
+ * Fetch an action
+ *
+ * @access public
+ * @param integer $action_id Action id
+ * @return array Action data
+ */
+ public function getById($action_id)
+ {
+ $action = $this->db->table(self::TABLE)->eq('id', $action_id)->findOne();
+ $action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action_id)->findAll();
+
+ return $action;
+ }
+
+ /**
+ * Remove an action
+ *
+ * @access public
+ * @param integer $action_id Action id
+ * @return bool Success or not
+ */
+ public function remove($action_id)
+ {
+ return $this->db->table(self::TABLE)->eq('id', $action_id)->remove();
+ }
+
+ /**
+ * Create an action
+ *
+ * @access public
+ * @param array $values Required parameters to save an action
+ * @return bool Success or not
+ */
+ public function create(array $values)
+ {
+ $this->db->startTransaction();
+
+ $action = array(
+ 'project_id' => $values['project_id'],
+ 'event_name' => $values['event_name'],
+ 'action_name' => $values['action_name'],
+ );
+
+ if (! $this->db->table(self::TABLE)->save($action)) {
+ $this->db->cancelTransaction();
+ return false;
+ }
+
+ $action_id = $this->db->getConnection()->getLastId();
+
+ foreach ($values['params'] as $param_name => $param_value) {
+
+ $action_param = array(
+ 'action_id' => $action_id,
+ 'name' => $param_name,
+ 'value' => $param_value,
+ );
+
+ if (! $this->db->table(self::TABLE_PARAMS)->save($action_param)) {
+ $this->db->cancelTransaction();
+ return false;
+ }
+ }
+
+ $this->db->closeTransaction();
+
+ return true;
+ }
+
+ /**
+ * Load all actions and attach events
+ *
+ * @access public
+ */
+ public function attachEvents()
+ {
+ foreach ($this->getAll() as $action) {
+
+ $listener = $this->load($action['action_name'], $action['project_id']);
+
+ foreach ($action['params'] as $param) {
+ $listener->setParam($param['name'], $param['value']);
+ }
+
+ $this->event->attach($action['event_name'], $listener);
+ }
+ }
+
+ /**
+ * Load an action
+ *
+ * @access public
+ * @param string $name Action class name
+ * @param integer $project_id Project id
+ * @return mixed Action Instance
+ * @throw LogicException
+ */
+ public function load($name, $project_id)
+ {
+ switch ($name) {
+ case 'TaskClose':
+ require_once __DIR__.'/../actions/task_close.php';
+ $className = '\Action\TaskClose';
+ return new $className($project_id, new Task($this->db, $this->event));
+ case 'TaskAssignCurrentUser':
+ require_once __DIR__.'/../actions/task_assign_current_user.php';
+ $className = '\Action\TaskAssignCurrentUser';
+ return new $className($project_id, new Task($this->db, $this->event), new Acl($this->db, $this->event));
+ case 'TaskAssignSpecificUser':
+ require_once __DIR__.'/../actions/task_assign_specific_user.php';
+ $className = '\Action\TaskAssignSpecificUser';
+ return new $className($project_id, new Task($this->db, $this->event));
+ case 'TaskDuplicateAnotherProject':
+ require_once __DIR__.'/../actions/task_duplicate_another_project.php';
+ $className = '\Action\TaskDuplicateAnotherProject';
+ return new $className($project_id, new Task($this->db, $this->event));
+ default:
+ throw new \LogicException('Action not found: '.$name);
+ }
+ }
+
+ /**
+ * Validate action creation
+ *
+ * @access public
+ * @param array $values Required parameters to save an action
+ * @return array $valid, $errors [0] = Success or not, [1] = List of errors
+ */
+ public function validateCreation(array $values)
+ {
+ $v = new Validator($values, array(
+ new Validators\Required('project_id', t('The project id is required')),
+ new Validators\Integer('project_id', t('This value must be an integer')),
+ new Validators\Required('event_name', t('This value is required')),
+ new Validators\Required('action_name', t('This value is required')),
+ new Validators\Required('params', t('This value is required')),
+ ));
+
+ return array(
+ $v->execute(),
+ $v->getErrors()
+ );
+ }
+}
diff --git a/models/base.php b/models/base.php
index 97022576..6a1dea97 100644
--- a/models/base.php
+++ b/models/base.php
@@ -13,45 +13,22 @@ require __DIR__.'/../vendor/SimpleValidator/Validators/Equals.php';
require __DIR__.'/../vendor/SimpleValidator/Validators/AlphaNumeric.php';
require __DIR__.'/../vendor/SimpleValidator/Validators/GreaterThan.php';
require __DIR__.'/../vendor/SimpleValidator/Validators/Date.php';
-require __DIR__.'/../vendor/PicoDb/Database.php';
-require __DIR__.'/schema.php';
abstract class Base
{
- const APP_VERSION = 'master';
- const DB_VERSION = 9;
-
- private static $dbInstance = null;
protected $db;
+ protected $event;
- public function __construct()
- {
- if (self::$dbInstance === null) {
- self::$dbInstance = $this->getDatabaseInstance();
- }
-
- $this->db = self::$dbInstance;
- }
-
- public function getDatabaseInstance()
+ public function __construct(\PicoDb\Database $db, \Core\Event $event)
{
- $db = new \PicoDb\Database(array(
- 'driver' => 'sqlite',
- 'filename' => DB_FILENAME
- ));
-
- if ($db->schema()->check(self::DB_VERSION)) {
- return $db;
- }
- else {
- die('Unable to migrate database schema!');
- }
+ $this->db = $db;
+ $this->event = $event;
}
// Generate a random token from /dev/urandom or with uniqid()
public static function generateToken()
{
- if (ini_get('open_basedir') === '' and strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
+ if (ini_get('open_basedir') === '' && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$token = file_get_contents('/dev/urandom', false, null, 0, 30);
}
else {
@@ -60,19 +37,4 @@ abstract class Base
return hash('crc32b', $token);
}
-
- public function getTimestampFromDate($value, $format)
- {
- $date = \DateTime::createFromFormat($format, $value);
-
- if ($date !== false) {
- $errors = \DateTime::getLastErrors();
- if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
- $timestamp = $date->getTimestamp();
- return $timestamp > 0 ? $timestamp : 0;
- }
- }
-
- return 0;
- }
}
diff --git a/models/board.php b/models/board.php
index 1a5b8b81..2835f02f 100644
--- a/models/board.php
+++ b/models/board.php
@@ -2,6 +2,9 @@
namespace Model;
+require_once __DIR__.'/base.php';
+require_once __DIR__.'/task.php';
+
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
@@ -14,8 +17,8 @@ class Board extends Base
{
$this->db->startTransaction();
- $taskModel = new \Model\Task;
$results = array();
+ $taskModel = new Task($this->db, $this->event);
foreach ($values as $value) {
$results[] = $taskModel->move(
@@ -30,7 +33,7 @@ class Board extends Base
return ! in_array(false, $results, true);
}
- // Create board with default columns => must executed inside a transaction
+ // Create board with default columns => must be executed inside a transaction
public function create($project_id, array $columns)
{
$position = 0;
@@ -75,11 +78,10 @@ class Board extends Base
// Get columns and tasks for each column
public function get($project_id)
{
- $taskModel = new \Model\Task;
-
$this->db->startTransaction();
$columns = $this->getColumns($project_id);
+ $taskModel = new Task($this->db, $this->event);
foreach ($columns as &$column) {
$column['tasks'] = $taskModel->getAllByColumnId($project_id, $column['id'], array(1));
diff --git a/models/comment.php b/models/comment.php
index 9e5cf8fd..c476e693 100644
--- a/models/comment.php
+++ b/models/comment.php
@@ -2,6 +2,8 @@
namespace Model;
+require_once __DIR__.'/base.php';
+
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
@@ -17,9 +19,9 @@ class Comment extends Base
self::TABLE.'.id',
self::TABLE.'.date',
self::TABLE.'.comment',
- \Model\User::TABLE.'.username'
+ User::TABLE.'.username'
)
- ->join(\Model\User::TABLE, 'id', 'user_id')
+ ->join(User::TABLE, 'id', 'user_id')
->orderBy(self::TABLE.'.date', 'ASC')
->eq(self::TABLE.'.task_id', $task_id)
->findAll();
diff --git a/models/config.php b/models/config.php
index 8f818a3b..d2cbe785 100644
--- a/models/config.php
+++ b/models/config.php
@@ -2,6 +2,8 @@
namespace Model;
+require_once __DIR__.'/base.php';
+
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
diff --git a/models/project.php b/models/project.php
index 238a60b4..b2a54571 100644
--- a/models/project.php
+++ b/models/project.php
@@ -2,6 +2,11 @@
namespace Model;
+require_once __DIR__.'/base.php';
+require_once __DIR__.'/acl.php';
+require_once __DIR__.'/board.php';
+require_once __DIR__.'/task.php';
+
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
@@ -13,16 +18,20 @@ class Project extends Base
const INACTIVE = 0;
// Get a list of people that can by assigned for tasks
- public function getUsersList($project_id)
+ public function getUsersList($project_id, $prepend = true)
{
$allowed_users = $this->getAllowedUsers($project_id);
+ $userModel = new User($this->db, $this->event);
if (empty($allowed_users)) {
- $userModel = new User;
$allowed_users = $userModel->getList();
}
- return array(t('Unassigned')) + $allowed_users;
+ if ($prepend) {
+ return array(t('Unassigned')) + $allowed_users;
+ }
+
+ return $allowed_users;
}
// Get a list of allowed people for a project
@@ -30,7 +39,7 @@ class Project extends Base
{
return $this->db
->table(self::TABLE_USERS)
- ->join(\Model\User::TABLE, 'id', 'user_id')
+ ->join(User::TABLE, 'id', 'user_id')
->eq('project_id', $project_id)
->asc('username')
->listing('user_id', 'username');
@@ -44,7 +53,7 @@ class Project extends Base
'not_allowed' => array(),
);
- $userModel = new User;
+ $userModel = new User($this->db, $this->event);
$all_users = $userModel->getList();
$users['allowed'] = $this->getAllowedUsers($project_id);
@@ -90,7 +99,7 @@ class Project extends Base
// Check if user has admin rights
$nb_users = $this->db
- ->table(\Model\User::TABLE)
+ ->table(User::TABLE)
->eq('id', $user_id)
->eq('is_admin', 1)
->count();
@@ -133,9 +142,9 @@ class Project extends Base
->asc('name')
->findAll();
- $taskModel = new \Model\Task;
- $boardModel = new \Model\Board;
- $aclModel = new \Model\Acl;
+ $boardModel = new Board($this->db, $this->event);
+ $taskModel = new Task($this->db, $this->event);
+ $aclModel = new Acl($this->db, $this->event);
foreach ($projects as $pkey => &$project) {
@@ -163,9 +172,13 @@ class Project extends Base
return $projects;
}
- public function getList()
+ public function getList($prepend = true)
{
- return array(t('None')) + $this->db->table(self::TABLE)->asc('name')->listing('id', 'name');
+ if ($prepend) {
+ return array(t('None')) + $this->db->table(self::TABLE)->asc('name')->listing('id', 'name');
+ }
+
+ return $this->db->table(self::TABLE)->asc('name')->listing('id', 'name');
}
public function getAllByStatus($status)
@@ -218,7 +231,7 @@ class Project extends Base
$project_id = $this->db->getConnection()->getLastId();
- $boardModel = new \Model\Board;
+ $boardModel = new Board($this->db, $this->event);
$boardModel->create($project_id, array(
t('Backlog'),
t('Ready'),
diff --git a/models/schema.php b/models/schema.php
index 14604e60..621bc981 100644
--- a/models/schema.php
+++ b/models/schema.php
@@ -2,6 +2,29 @@
namespace Schema;
+function version_10($pdo)
+{
+ $pdo->exec(
+ 'CREATE TABLE actions (
+ id INTEGER PRIMARY KEY,
+ project_id INTEGER,
+ event_name TEXT,
+ action_name TEXT,
+ FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
+ )'
+ );
+
+ $pdo->exec(
+ 'CREATE TABLE action_has_params (
+ id INTEGER PRIMARY KEY,
+ action_id INTEGER,
+ name TEXT,
+ value TEXT,
+ FOREIGN KEY(action_id) REFERENCES actions(id) ON DELETE CASCADE
+ )'
+ );
+}
+
function version_9($pdo)
{
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_due INTEGER");
diff --git a/models/task.php b/models/task.php
index 017c7806..fe0f6350 100644
--- a/models/task.php
+++ b/models/task.php
@@ -2,12 +2,21 @@
namespace Model;
+require_once __DIR__.'/base.php';
+require_once __DIR__.'/comment.php';
+
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;
class Task extends Base
{
- const TABLE = 'tasks';
+ const TABLE = 'tasks';
+ const EVENT_MOVE_COLUMN = 'task.move.column';
+ const EVENT_MOVE_POSITION = 'task.move.position';
+ const EVENT_UPDATE = 'task.update';
+ const EVENT_CREATE = 'task.create';
+ const EVENT_CLOSE = 'task.close';
+ const EVENT_OPEN = 'task.open';
public function getColors()
{
@@ -42,13 +51,13 @@ class Task extends Base
self::TABLE.'.position',
self::TABLE.'.is_active',
self::TABLE.'.score',
- \Model\Project::TABLE.'.name AS project_name',
- \Model\Board::TABLE.'.title AS column_title',
- \Model\User::TABLE.'.username'
+ Project::TABLE.'.name AS project_name',
+ Board::TABLE.'.title AS column_title',
+ User::TABLE.'.username'
)
- ->join(\Model\Project::TABLE, 'id', 'project_id')
- ->join(\Model\Board::TABLE, 'id', 'column_id')
- ->join(\Model\User::TABLE, 'id', 'owner_id')
+ ->join(Project::TABLE, 'id', 'project_id')
+ ->join(Board::TABLE, 'id', 'column_id')
+ ->join(User::TABLE, 'id', 'owner_id')
->eq(self::TABLE.'.id', $task_id)
->findOne();
}
@@ -75,11 +84,11 @@ class Task extends Base
self::TABLE.'.position',
self::TABLE.'.is_active',
self::TABLE.'.score',
- \Model\Board::TABLE.'.title AS column_title',
- \Model\User::TABLE.'.username'
+ Board::TABLE.'.title AS column_title',
+ User::TABLE.'.username'
)
- ->join(\Model\Board::TABLE, 'id', 'column_id')
- ->join(\Model\User::TABLE, 'id', 'owner_id')
+ ->join(Board::TABLE, 'id', 'column_id')
+ ->join(User::TABLE, 'id', 'owner_id')
->eq(self::TABLE.'.project_id', $project_id)
->in('is_active', $status)
->desc('date_completed')
@@ -107,7 +116,7 @@ class Task extends Base
->asc('position')
->findAll();
- $commentModel = new Comment;
+ $commentModel = new Comment($this->db, $this->event);
foreach ($tasks as &$task) {
$task['nb_comments'] = $commentModel->count($task['id']);
@@ -126,19 +135,60 @@ class Task extends Base
->count();
}
+ public function duplicateToAnotherProject($task_id, $project_id)
+ {
+ $this->db->startTransaction();
+
+ $boardModel = new Board($this->db, $this->event);
+
+ // Get the original task
+ $task = $this->getById($task_id);
+
+ // Cleanup data
+ unset($task['id']);
+ unset($task['date_completed']);
+
+ // Assign new values
+ $task['date_creation'] = time();
+ $task['owner_id'] = 0;
+ $task['is_active'] = 1;
+ $task['column_id'] = $boardModel->getFirstColumn($project_id);
+ $task['project_id'] = $project_id;
+ $task['position'] = $this->countByColumnId($task['project_id'], $task['column_id']);
+
+ // Save task
+ if (! $this->db->table(self::TABLE)->save($task)) {
+ $this->db->cancelTransaction();
+ return false;
+ }
+
+ $task_id = $this->db->getConnection()->getLastId();
+
+ $this->db->closeTransaction();
+
+ // Trigger events
+ $this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $task);
+
+ return $task_id;
+ }
+
public function create(array $values)
{
$this->db->startTransaction();
- unset($values['another_task']);
+ // Prepare data
+ if (isset($values['another_task'])) {
+ unset($values['another_task']);
+ }
- if (! empty($values['date_due'])) {
+ if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
}
$values['date_creation'] = time();
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']);
+ // Save task
if (! $this->db->table(self::TABLE)->save($values)) {
$this->db->cancelTransaction();
return false;
@@ -148,38 +198,83 @@ class Task extends Base
$this->db->closeTransaction();
+ // Trigger events
+ $this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $values);
+
return $task_id;
}
public function update(array $values)
{
- if (! empty($values['date_due'])) {
+ // Prepare data
+ if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
}
- return $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
+ $original_task = $this->getById($values['id']);
+ $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
+
+ // Trigger events
+ if ($result) {
+
+ $events = array();
+
+ if ($this->event->getLastTriggeredEvent() !== self::EVENT_UPDATE) {
+ $events[] = self::EVENT_UPDATE;
+ }
+
+ if (isset($values['column_id']) && $original_task['column_id'] != $values['column_id']) {
+ $events[] = self::EVENT_MOVE_COLUMN;
+ }
+ else if (isset($values['position']) && $original_task['position'] != $values['position']) {
+ $events[] = self::EVENT_MOVE_POSITION;
+ }
+
+ $event_data = array_merge($original_task, $values);
+ $event_data['task_id'] = $original_task['id'];
+
+ foreach ($events as $event) {
+ $this->event->trigger($event, $event_data);
+ }
+ }
+
+ return $result;
}
// Mark a task closed
public function close($task_id)
{
- return $this->db->table(self::TABLE)
- ->eq('id', $task_id)
- ->update(array(
- 'is_active' => 0,
- 'date_completed' => time()
- ));
+ $result = $this->db
+ ->table(self::TABLE)
+ ->eq('id', $task_id)
+ ->update(array(
+ 'is_active' => 0,
+ 'date_completed' => time()
+ ));
+
+ if ($result) {
+ $this->event->trigger(self::EVENT_CLOSE, array('task_id' => $task_id) + $this->getById($task_id));
+ }
+
+ return $result;
}
// Mark a task open
public function open($task_id)
{
- return $this->db->table(self::TABLE)
- ->eq('id', $task_id)
- ->update(array(
- 'is_active' => 1,
- 'date_completed' => ''
- ));
+ $result = $this->db
+ ->table(self::TABLE)
+ ->eq('id', $task_id)
+ ->update(array(
+ 'is_active' => 1,
+ 'date_completed' => ''
+ ));
+
+ if ($result) {
+ $this->event->trigger(self::EVENT_OPEN, array('task_id' => $task_id) + $this->getById($task_id));
+ }
+
+ return $result;
}
// Remove a task
@@ -191,10 +286,11 @@ class Task extends Base
// Move a task to another column or to another position
public function move($task_id, $column_id, $position)
{
- return (bool) $this->db
- ->table(self::TABLE)
- ->eq('id', $task_id)
- ->update(array('column_id' => $column_id, 'position' => $position));
+ return $this->update(array(
+ 'id' => $task_id,
+ 'column_id' => $column_id,
+ 'position' => $position,
+ ));
}
public function validateCreation(array $values)
@@ -271,4 +367,19 @@ class Task extends Base
$v->getErrors()
);
}
+
+ public function getTimestampFromDate($value, $format)
+ {
+ $date = \DateTime::createFromFormat($format, $value);
+
+ if ($date !== false) {
+ $errors = \DateTime::getLastErrors();
+ if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
+ $timestamp = $date->getTimestamp();
+ return $timestamp > 0 ? $timestamp : 0;
+ }
+ }
+
+ return 0;
+ }
}
diff --git a/models/user.php b/models/user.php
index 394cf742..21c65b59 100644
--- a/models/user.php
+++ b/models/user.php
@@ -2,6 +2,8 @@
namespace Model;
+require_once __DIR__.'/base.php';
+
use \SimpleValidator\Validator;
use \SimpleValidator\Validators;