summaryrefslogtreecommitdiff
path: root/app/Model
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2017-02-18 09:42:01 -0500
committerFrederic Guillot <fred@kanboard.net>2017-02-18 09:42:01 -0500
commitde128dbad860478496a0d655b5eb5c1005ebbabe (patch)
tree7fee510e901273472731e8e843981268c593ec40 /app/Model
parent0430a09c069134622c0161dc2fb9ba3718a73c0d (diff)
Remove default swimlane
Diffstat (limited to 'app/Model')
-rw-r--r--app/Model/ProjectDuplicationModel.php10
-rw-r--r--app/Model/ProjectModel.php21
-rw-r--r--app/Model/SwimlaneModel.php308
-rw-r--r--app/Model/TaskCreationModel.php4
-rw-r--r--app/Model/TaskDuplicationModel.php12
-rw-r--r--app/Model/TaskFinderModel.php5
-rw-r--r--app/Model/TaskPositionModel.php4
-rw-r--r--app/Model/TaskStatusModel.php2
8 files changed, 141 insertions, 225 deletions
diff --git a/app/Model/ProjectDuplicationModel.php b/app/Model/ProjectDuplicationModel.php
index d32fa367..1d1eed8e 100644
--- a/app/Model/ProjectDuplicationModel.php
+++ b/app/Model/ProjectDuplicationModel.php
@@ -26,7 +26,6 @@ class ProjectDuplicationModel extends Base
'categoryModel',
'projectPermissionModel',
'actionModel',
- 'swimlaneModel',
'tagDuplicationModel',
'projectMetadataModel',
'projectTaskDuplicationModel',
@@ -42,6 +41,7 @@ class ProjectDuplicationModel extends Base
public function getPossibleSelection()
{
return array(
+ 'swimlaneModel',
'boardModel',
'categoryModel',
'projectPermissionModel',
@@ -94,7 +94,7 @@ class ProjectDuplicationModel extends Base
return false;
}
- // Clone Columns, Categories, Permissions and Actions
+ // Clone Swimlanes, Columns, Categories, Permissions and Actions
foreach ($this->getPossibleSelection() as $model) {
// Skip if optional part has not been selected
@@ -151,11 +151,7 @@ class ProjectDuplicationModel extends Base
'priority_end' => $project['priority_end'],
);
- if (! $this->db->table(ProjectModel::TABLE)->save($values)) {
- return false;
- }
-
- return $this->db->getLastId();
+ return $this->db->table(ProjectModel::TABLE)->persist($values);
}
/**
diff --git a/app/Model/ProjectModel.php b/app/Model/ProjectModel.php
index 7f9cfb9b..a4d75a0b 100644
--- a/app/Model/ProjectModel.php
+++ b/app/Model/ProjectModel.php
@@ -321,19 +321,19 @@ class ProjectModel extends Base
* Create a project
*
* @access public
- * @param array $values Form values
- * @param integer $user_id User who create the project
- * @param bool $add_user Automatically add the user
- * @return integer Project id
+ * @param array $values Form values
+ * @param integer $userId User who create the project
+ * @param bool $addUser Automatically add the user
+ * @return int Project id
*/
- public function create(array $values, $user_id = 0, $add_user = false)
+ public function create(array $values, $userId = 0, $addUser = false)
{
$this->db->startTransaction();
$values['token'] = '';
$values['last_modified'] = time();
$values['is_private'] = empty($values['is_private']) ? 0 : 1;
- $values['owner_id'] = $user_id;
+ $values['owner_id'] = $userId;
if (! empty($values['identifier'])) {
$values['identifier'] = strtoupper($values['identifier']);
@@ -353,8 +353,13 @@ class ProjectModel extends Base
return false;
}
- if ($add_user && $user_id) {
- $this->projectUserRoleModel->addUser($project_id, $user_id, Role::PROJECT_MANAGER);
+ if (! $this->swimlaneModel->create($project_id, t('Default swimlane'))) {
+ $this->db->cancelTransaction();
+ return false;
+ }
+
+ if ($addUser && $userId) {
+ $this->projectUserRoleModel->addUser($project_id, $userId, Role::PROJECT_MANAGER);
}
$this->categoryModel->createDefaultCategories($project_id);
diff --git a/app/Model/SwimlaneModel.php b/app/Model/SwimlaneModel.php
index f20bfa2f..785a1054 100644
--- a/app/Model/SwimlaneModel.php
+++ b/app/Model/SwimlaneModel.php
@@ -37,38 +37,40 @@ class SwimlaneModel extends Base
* Get a swimlane by the id
*
* @access public
- * @param integer $swimlane_id Swimlane id
+ * @param integer $swimlaneId
* @return array
*/
- public function getById($swimlane_id)
+ public function getById($swimlaneId)
{
- return $this->db->table(self::TABLE)->eq('id', $swimlane_id)->findOne();
+ return $this->db->table(self::TABLE)->eq('id', $swimlaneId)->findOne();
}
/**
* Get the swimlane name by the id
*
* @access public
- * @param integer $swimlane_id Swimlane id
+ * @param integer $swimlaneId
* @return string
*/
- public function getNameById($swimlane_id)
+ public function getNameById($swimlaneId)
{
- return $this->db->table(self::TABLE)->eq('id', $swimlane_id)->findOneColumn('name') ?: '';
+ return $this->db->table(self::TABLE)
+ ->eq('id', $swimlaneId)
+ ->findOneColumn('name');
}
/**
* Get a swimlane id by the project and the name
*
* @access public
- * @param integer $project_id Project id
+ * @param integer $projectId Project id
* @param string $name Name
* @return integer
*/
- public function getIdByName($project_id, $name)
+ public function getIdByName($projectId, $name)
{
return (int) $this->db->table(self::TABLE)
- ->eq('project_id', $project_id)
+ ->eq('project_id', $projectId)
->eq('name', $name)
->findOneColumn('id');
}
@@ -77,14 +79,14 @@ class SwimlaneModel extends Base
* Get a swimlane by the project and the name
*
* @access public
- * @param integer $project_id Project id
+ * @param integer $projectId Project id
* @param string $name Swimlane name
* @return array
*/
- public function getByName($project_id, $name)
+ public function getByName($projectId, $name)
{
return $this->db->table(self::TABLE)
- ->eq('project_id', $project_id)
+ ->eq('project_id', $projectId)
->eq('name', $name)
->findOne();
}
@@ -93,54 +95,46 @@ class SwimlaneModel extends Base
* Get first active swimlane for a project
*
* @access public
- * @param integer $project_id
+ * @param integer $projectId
* @return array|null
*/
- public function getFirstActiveSwimlane($project_id)
+ public function getFirstActiveSwimlane($projectId)
{
- $swimlanes = $this->getSwimlanes($project_id);
-
- if (empty($swimlanes)) {
- return null;
- }
-
- return $swimlanes[0];
+ return $this->db->table(self::TABLE)
+ ->eq('project_id', $projectId)
+ ->eq('is_active', 1)
+ ->asc('position')
+ ->findOne();
}
/**
- * Get default swimlane properties
+ * Get first active swimlaneId
*
* @access public
- * @param integer $project_id Project id
- * @return array
+ * @param int $projectId
+ * @return int
*/
- public function getDefault($project_id)
+ public function getFirstActiveSwimlaneId($projectId)
{
- $result = $this->db
- ->table(ProjectModel::TABLE)
- ->eq('id', $project_id)
- ->columns('id', 'default_swimlane', 'show_default_swimlane')
- ->findOne();
-
- if ($result['default_swimlane'] === 'Default swimlane') {
- $result['default_swimlane'] = t($result['default_swimlane']);
- }
-
- return $result;
+ return (int) $this->db->table(self::TABLE)
+ ->eq('project_id', $projectId)
+ ->eq('is_active', 1)
+ ->asc('position')
+ ->findOneColumn('id');
}
/**
* Get all swimlanes for a given project
*
* @access public
- * @param integer $project_id Project id
+ * @param integer $projectId
* @return array
*/
- public function getAll($project_id)
+ public function getAll($projectId)
{
return $this->db
->table(self::TABLE)
- ->eq('project_id', $project_id)
+ ->eq('project_id', $projectId)
->orderBy('position', 'asc')
->findAll();
}
@@ -149,15 +143,15 @@ class SwimlaneModel extends Base
* Get the list of swimlanes by status
*
* @access public
- * @param integer $project_id Project id
- * @param integer $status Status
+ * @param integer $projectId
+ * @param integer $status
* @return array
*/
- public function getAllByStatus($project_id, $status = self::ACTIVE)
+ public function getAllByStatus($projectId, $status = self::ACTIVE)
{
$query = $this->db
->table(self::TABLE)
- ->eq('project_id', $project_id)
+ ->eq('project_id', $projectId)
->eq('is_active', $status);
if ($status == self::ACTIVE) {
@@ -170,65 +164,26 @@ class SwimlaneModel extends Base
}
/**
- * Get active swimlanes
- *
- * @access public
- * @param integer $project_id Project id
- * @return array
- */
- public function getSwimlanes($project_id)
- {
- $swimlanes = $this->db
- ->table(self::TABLE)
- ->columns('id', 'name', 'description')
- ->eq('project_id', $project_id)
- ->eq('is_active', self::ACTIVE)
- ->orderBy('position', 'asc')
- ->findAll();
-
- $defaultSwimlane = $this->db
- ->table(ProjectModel::TABLE)
- ->eq('id', $project_id)
- ->eq('show_default_swimlane', 1)
- ->findOneColumn('default_swimlane');
-
- if ($defaultSwimlane) {
- if ($defaultSwimlane === 'Default swimlane') {
- $defaultSwimlane = t($defaultSwimlane);
- }
-
- array_unshift($swimlanes, array('id' => 0, 'name' => $defaultSwimlane));
- }
-
- return $swimlanes;
- }
-
- /**
* Get list of all swimlanes
*
* @access public
- * @param integer $project_id Project id
- * @param boolean $prepend Prepend default value
- * @param boolean $only_active Return only active swimlanes
+ * @param integer $projectId Project id
+ * @param boolean $prepend Prepend default value
+ * @param boolean $onlyActive Return only active swimlanes
* @return array
*/
- public function getList($project_id, $prepend = false, $only_active = false)
+ public function getList($projectId, $prepend = false, $onlyActive = false)
{
$swimlanes = array();
- $default = $this->db->table(ProjectModel::TABLE)->eq('id', $project_id)->eq('show_default_swimlane', 1)->findOneColumn('default_swimlane');
if ($prepend) {
$swimlanes[-1] = t('All swimlanes');
}
- if (! empty($default)) {
- $swimlanes[0] = $default === 'Default swimlane' ? t($default) : $default;
- }
-
return $swimlanes + $this->db
->hashtable(self::TABLE)
- ->eq('project_id', $project_id)
- ->in('is_active', $only_active ? array(self::ACTIVE) : array(self::ACTIVE, self::INACTIVE))
+ ->eq('project_id', $projectId)
+ ->in('is_active', $onlyActive ? array(self::ACTIVE) : array(self::ACTIVE, self::INACTIVE))
->orderBy('position', 'asc')
->getAll('id', 'name');
}
@@ -237,17 +192,24 @@ class SwimlaneModel extends Base
* Add a new swimlane
*
* @access public
- * @param array $values Form values
- * @return integer|boolean
+ * @param int $projectId
+ * @param string $name
+ * @param string $description
+ * @return bool|int
*/
- public function create($values)
+ public function create($projectId, $name, $description = '')
{
- if (! $this->projectModel->exists($values['project_id'])) {
+ if (! $this->projectModel->exists($projectId)) {
return 0;
}
- $values['position'] = $this->getLastPosition($values['project_id']);
- return $this->db->table(self::TABLE)->persist($values);
+ return $this->db->table(self::TABLE)->persist(array(
+ 'project_id' => $projectId,
+ 'name' => $name,
+ 'description' => $description,
+ 'position' => $this->getLastPosition($projectId),
+ 'is_active' => 1,
+ ));
}
/**
@@ -266,69 +228,17 @@ class SwimlaneModel extends Base
}
/**
- * Update the default swimlane
- *
- * @access public
- * @param array $values Form values
- * @return bool
- */
- public function updateDefault(array $values)
- {
- return $this->db
- ->table(ProjectModel::TABLE)
- ->eq('id', $values['id'])
- ->update(array(
- 'default_swimlane' => $values['default_swimlane'],
- 'show_default_swimlane' => $values['show_default_swimlane'],
- ));
- }
-
- /**
- * Enable the default swimlane
- *
- * @access public
- * @param integer $project_id
- * @return bool
- */
- public function enableDefault($project_id)
- {
- return $this->db
- ->table(ProjectModel::TABLE)
- ->eq('id', $project_id)
- ->update(array(
- 'show_default_swimlane' => 1,
- ));
- }
-
- /**
- * Disable the default swimlane
- *
- * @access public
- * @param integer $project_id
- * @return bool
- */
- public function disableDefault($project_id)
- {
- return $this->db
- ->table(ProjectModel::TABLE)
- ->eq('id', $project_id)
- ->update(array(
- 'show_default_swimlane' => 0,
- ));
- }
-
- /**
* Get the last position of a swimlane
*
* @access public
- * @param integer $project_id
+ * @param integer $projectId
* @return integer
*/
- public function getLastPosition($project_id)
+ public function getLastPosition($projectId)
{
return $this->db
->table(self::TABLE)
- ->eq('project_id', $project_id)
+ ->eq('project_id', $projectId)
->eq('is_active', 1)
->count() + 1;
}
@@ -337,23 +247,23 @@ class SwimlaneModel extends Base
* Disable a swimlane
*
* @access public
- * @param integer $project_id Project id
- * @param integer $swimlane_id Swimlane id
+ * @param integer $projectId
+ * @param integer $swimlaneId
* @return bool
*/
- public function disable($project_id, $swimlane_id)
+ public function disable($projectId, $swimlaneId)
{
$result = $this->db
->table(self::TABLE)
- ->eq('id', $swimlane_id)
+ ->eq('id', $swimlaneId)
+ ->eq('project_id', $projectId)
->update(array(
'is_active' => self::INACTIVE,
'position' => 0,
));
if ($result) {
- // Re-order positions
- $this->updatePositions($project_id);
+ $this->updatePositions($projectId);
}
return $result;
@@ -363,18 +273,19 @@ class SwimlaneModel extends Base
* Enable a swimlane
*
* @access public
- * @param integer $project_id Project id
- * @param integer $swimlane_id Swimlane id
+ * @param integer $projectId
+ * @param integer $swimlaneId
* @return bool
*/
- public function enable($project_id, $swimlane_id)
+ public function enable($projectId, $swimlaneId)
{
return $this->db
->table(self::TABLE)
- ->eq('id', $swimlane_id)
+ ->eq('id', $swimlaneId)
+ ->eq('project_id', $projectId)
->update(array(
'is_active' => self::ACTIVE,
- 'position' => $this->getLastPosition($project_id),
+ 'position' => $this->getLastPosition($projectId),
));
}
@@ -382,25 +293,25 @@ class SwimlaneModel extends Base
* Remove a swimlane
*
* @access public
- * @param integer $project_id Project id
- * @param integer $swimlane_id Swimlane id
+ * @param integer $projecId
+ * @param integer $swimlaneId
* @return bool
*/
- public function remove($project_id, $swimlane_id)
+ public function remove($projecId, $swimlaneId)
{
$this->db->startTransaction();
- // Tasks should not be assigned anymore to this swimlane
- $this->db->table(TaskModel::TABLE)->eq('swimlane_id', $swimlane_id)->update(array('swimlane_id' => 0));
-
- if (! $this->db->table(self::TABLE)->eq('id', $swimlane_id)->remove()) {
+ if ($this->db->table(TaskModel::TABLE)->eq('swimlane_id', $swimlaneId)->exists()) {
$this->db->cancelTransaction();
return false;
}
- // Re-order positions
- $this->updatePositions($project_id);
+ if (! $this->db->table(self::TABLE)->eq('id', $swimlaneId)->remove()) {
+ $this->db->cancelTransaction();
+ return false;
+ }
+ $this->updatePositions($projecId);
$this->db->closeTransaction();
return true;
@@ -410,15 +321,15 @@ class SwimlaneModel extends Base
* Update swimlane positions after disabling or removing a swimlane
*
* @access public
- * @param integer $project_id Project id
+ * @param integer $projectId
* @return boolean
*/
- public function updatePositions($project_id)
+ public function updatePositions($projectId)
{
$position = 0;
$swimlanes = $this->db
->table(self::TABLE)
- ->eq('project_id', $project_id)
+ ->eq('project_id', $projectId)
->eq('is_active', 1)
->asc('position')
->asc('id')
@@ -441,37 +352,37 @@ class SwimlaneModel extends Base
* Change swimlane position
*
* @access public
- * @param integer $project_id
- * @param integer $swimlane_id
+ * @param integer $projectId
+ * @param integer $swimlaneId
* @param integer $position
* @return boolean
*/
- public function changePosition($project_id, $swimlane_id, $position)
+ public function changePosition($projectId, $swimlaneId, $position)
{
- if ($position < 1 || $position > $this->db->table(self::TABLE)->eq('project_id', $project_id)->count()) {
+ if ($position < 1 || $position > $this->db->table(self::TABLE)->eq('project_id', $projectId)->count()) {
return false;
}
- $swimlane_ids = $this->db->table(self::TABLE)
+ $swimlaneIds = $this->db->table(self::TABLE)
->eq('is_active', 1)
- ->eq('project_id', $project_id)
- ->neq('id', $swimlane_id)
+ ->eq('project_id', $projectId)
+ ->neq('id', $swimlaneId)
->asc('position')
->findAllByColumn('id');
$offset = 1;
$results = array();
- foreach ($swimlane_ids as $current_swimlane_id) {
+ foreach ($swimlaneIds as $currentSwimlaneId) {
if ($offset == $position) {
$offset++;
}
- $results[] = $this->db->table(self::TABLE)->eq('id', $current_swimlane_id)->update(array('position' => $offset));
+ $results[] = $this->db->table(self::TABLE)->eq('id', $currentSwimlaneId)->update(array('position' => $offset));
$offset++;
}
- $results[] = $this->db->table(self::TABLE)->eq('id', $swimlane_id)->update(array('position' => $position));
+ $results[] = $this->db->table(self::TABLE)->eq('id', $swimlaneId)->update(array('position' => $position));
return !in_array(false, $results, true);
}
@@ -480,29 +391,30 @@ class SwimlaneModel extends Base
* Duplicate Swimlane to project
*
* @access public
- * @param integer $project_from Project Template
- * @param integer $project_to Project that receives the copy
- * @return integer|boolean
+ * @param integer $projectSrcId
+ * @param integer $projectDstId
+ * @return boolean
*/
-
- public function duplicate($project_from, $project_to)
+ public function duplicate($projectSrcId, $projectDstId)
{
- $swimlanes = $this->getAll($project_from);
+ $swimlanes = $this->getAll($projectSrcId);
foreach ($swimlanes as $swimlane) {
- unset($swimlane['id']);
- $swimlane['project_id'] = $project_to;
-
- if (! $this->db->table(self::TABLE)->save($swimlane)) {
- return false;
+ if (! $this->db->table(self::TABLE)->eq('project_id', $projectDstId)->eq('name', $swimlane['name'])->exists()) {
+ $values = array(
+ 'name' => $swimlane['name'],
+ 'description' => $swimlane['description'],
+ 'position' => $swimlane['position'],
+ 'is_active' => $swimlane['is_active'],
+ 'project_id' => $projectDstId,
+ );
+
+ if (! $this->db->table(self::TABLE)->persist($values)) {
+ return false;
+ }
}
}
- $default_swimlane = $this->getDefault($project_from);
- $default_swimlane['id'] = $project_to;
-
- $this->updateDefault($default_swimlane);
-
return true;
}
}
diff --git a/app/Model/TaskCreationModel.php b/app/Model/TaskCreationModel.php
index bd95c1a4..95f62ee5 100644
--- a/app/Model/TaskCreationModel.php
+++ b/app/Model/TaskCreationModel.php
@@ -62,7 +62,7 @@ class TaskCreationModel extends Base
$values = $this->dateParser->convert($values, array('date_started'), true);
$this->helper->model->removeFields($values, array('another_task', 'duplicate_multiple_projects'));
- $this->helper->model->resetFields($values, array('creator_id', 'owner_id', 'swimlane_id', 'date_due', 'date_started', 'score', 'category_id', 'time_estimated', 'time_spent'));
+ $this->helper->model->resetFields($values, array('creator_id', 'owner_id', 'date_due', 'date_started', 'score', 'category_id', 'time_estimated', 'time_spent'));
if (empty($values['column_id'])) {
$values['column_id'] = $this->columnModel->getFirstColumnId($values['project_id']);
@@ -80,7 +80,7 @@ class TaskCreationModel extends Base
$values['creator_id'] = $this->userSession->getId();
}
- $values['swimlane_id'] = empty($values['swimlane_id']) ? 0 : $values['swimlane_id'];
+ $values['swimlane_id'] = empty($values['swimlane_id']) ? $this->swimlaneModel->getFirstActiveSwimlaneId($values['project_id']) : $values['swimlane_id'];
$values['date_creation'] = time();
$values['date_modification'] = $values['date_creation'];
$values['date_moved'] = $values['date_creation'];
diff --git a/app/Model/TaskDuplicationModel.php b/app/Model/TaskDuplicationModel.php
index c9079653..c07ebca0 100644
--- a/app/Model/TaskDuplicationModel.php
+++ b/app/Model/TaskDuplicationModel.php
@@ -79,11 +79,13 @@ class TaskDuplicationModel extends Base
}
// Check if the swimlane exists for the destination project
- if ($values['swimlane_id'] > 0) {
- $values['swimlane_id'] = $this->swimlaneModel->getIdByName(
- $values['project_id'],
- $this->swimlaneModel->getNameById($values['swimlane_id'])
- );
+ $values['swimlane_id'] = $this->swimlaneModel->getIdByName(
+ $values['project_id'],
+ $this->swimlaneModel->getNameById($values['swimlane_id'])
+ );
+
+ if ($values['swimlane_id'] == 0) {
+ $values['swimlane_id'] = $this->swimlaneModel->getFirstActiveSwimlaneId($values['project_id']);
}
// Check if the column exists for the destination project
diff --git a/app/Model/TaskFinderModel.php b/app/Model/TaskFinderModel.php
index e54a613b..b610a371 100644
--- a/app/Model/TaskFinderModel.php
+++ b/app/Model/TaskFinderModel.php
@@ -142,7 +142,6 @@ class TaskFinderModel extends Base
ColumnModel::TABLE.'.title AS column_name',
ColumnModel::TABLE.'.position AS column_position',
SwimlaneModel::TABLE.'.name AS swimlane_name',
- ProjectModel::TABLE.'.default_swimlane',
ProjectModel::TABLE.'.name AS project_name'
)
->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE)
@@ -304,15 +303,13 @@ class TaskFinderModel extends Base
CategoryModel::TABLE.'.name AS category_name',
SwimlaneModel::TABLE.'.name AS swimlane_name',
ProjectModel::TABLE.'.name AS project_name',
- ProjectModel::TABLE.'.default_swimlane',
ColumnModel::TABLE.'.title AS column_title',
UserModel::TABLE.'.username AS assignee_username',
UserModel::TABLE.'.name AS assignee_name',
'uc.username AS creator_username',
'uc.name AS creator_name',
CategoryModel::TABLE.'.description AS category_description',
- ColumnModel::TABLE.'.position AS column_position',
- ProjectModel::TABLE.'.default_swimlane'
+ ColumnModel::TABLE.'.position AS column_position'
)
->join(UserModel::TABLE, 'id', 'owner_id', TaskModel::TABLE)
->left(UserModel::TABLE, 'uc', 'id', TaskModel::TABLE, 'creator_id')
diff --git a/app/Model/TaskPositionModel.php b/app/Model/TaskPositionModel.php
index aeb7edde..8805d57e 100644
--- a/app/Model/TaskPositionModel.php
+++ b/app/Model/TaskPositionModel.php
@@ -33,6 +33,10 @@ class TaskPositionModel extends Base
$task = $this->taskFinderModel->getById($task_id);
+ if ($swimlane_id == 0) {
+ $swimlane_id = $task['swimlane_id'];
+ }
+
if ($onlyOpen && $task['is_active'] == TaskModel::STATUS_CLOSED) {
return true;
}
diff --git a/app/Model/TaskStatusModel.php b/app/Model/TaskStatusModel.php
index dc114698..bb6725ff 100644
--- a/app/Model/TaskStatusModel.php
+++ b/app/Model/TaskStatusModel.php
@@ -139,6 +139,6 @@ class TaskStatusModel extends Base
->table(TaskModel::TABLE)
->eq('id', $task_id)
->eq('is_active', $status)
- ->count() === 1;
+ ->exists();
}
}