synergy/server/controller/SpecificationCtrl.php (338 lines of code) (raw):
<?php
namespace Synergy\Controller;
use Synergy\App\Synergy;
use Synergy\DB\SpecificationDAO;
use Synergy\Extensions\Tribe\TribeSpecificationExtension;
use Synergy\Interfaces\Observer;
use Synergy\Model\Specification;
use Synergy\Model\SpecificationAttachment;
use Synergy\Model\Exception\SpecificationDuplicateException;
use Synergy\Model\SpecificationsSimpleNameList;
use Synergy\Model\Suite;
use Synergy\Extensions\Specification\RemovalRequestExtension;
use Synergy\Misc\Util;
/**
* Description of SpecificationCtrl
*
* @author vriha
*/
class SpecificationCtrl extends ExtensionCtrl implements Observer {
/**
*
* @var SuiteCtrl
*/
private $suiteCtrl;
private $specDao;
private $versionCtrl;
private $userCtrl;
private $runCtrl;
private $tribeCtrl;
private $attachmentCtrl;
private $lockCtrl;
/**
*
* @var CaseCtrl
*/
private $caseCtrl;
function __construct() {
parent::__construct('specification');
$this->specDao = new SpecificationDAO();
}
private function getCaseCtrl() {
if (is_null($this->caseCtrl)) {
$this->caseCtrl = new CaseCtrl();
}
return $this->caseCtrl;
}
private function getTribeCtrl() {
if (is_null($this->tribeCtrl)) {
$this->tribeCtrl = new TribeCtrl();
}
return $this->tribeCtrl;
}
/**
*
* @return SpecificationLockCtrl
*/
public function getLockCtrl() {
if (is_null($this->lockCtrl)) {
$this->lockCtrl = new SpecificationLockCtrl();
}
return $this->lockCtrl;
}
/**
*
* @return AttachmentCtrl
*/
private function getAttachmentCtrl() {
if (is_null($this->attachmentCtrl)) {
$this->attachmentCtrl = new AttachmentCtrl();
}
return $this->attachmentCtrl;
}
private function getSuiteCtrl() {
if (is_null($this->suiteCtrl)) {
$this->suiteCtrl = new SuiteCtrl();
}
return $this->suiteCtrl;
}
private function getVersionCtrl() {
if (is_null($this->versionCtrl)) {
$this->versionCtrl = new VersionCtrl();
}
return $this->versionCtrl;
}
private function getUserCtrl() {
if (is_null($this->userCtrl)) {
$this->userCtrl = new UserCtrl();
}
return $this->userCtrl;
}
private function getRunCtrl() {
if (is_null($this->runCtrl)) {
$this->runCtrl = new RunCtrl();
}
return $this->runCtrl;
}
/**
* Returns all specifications for version given by ID, if versionID is -1, returns all specifications
* @param int $versionID version ID
* @return array
*/
public function getSpecifications($versionID, $userId = -1) {
if ($versionID < 0) {
return parent::get($this->specDao->getAllSpecifications($userId));
}
return parent::get($this->specDao->getSpecifications($versionID, $userId));
}
public function getFavoriteSpecifications($username) {
return parent::get($this->specDao->getFavoriteSpecifications($username));
}
/**
* Returns complete specification with test suites and attachments (but without cases)
* @param type $id
* @param String $label not required, if given, only cases with this label will be counted
* @return \Specification|null
*/
public function getSpecification($id, $label = '', $userId = -1) {
if ($userId === -1) {
$userId = Synergy::getSessionProvider()->getUserId();
}
$spec = $this->specDao->getSpecification($id, $label, $userId);
if (!is_null($spec)) {
$u = $this->getUserCtrl()->getUserById($spec->ownerId);
$spec->owner = $u->username;
$spec->ownerName = $u->firstName . " " . $u->lastName;
$spec->attachments = $this->specDao->getAttachments($id);
$spec->testSuites = $this->specDao->getTestSuites($id);
$spec->estimation = $this->specDao->getEstimatedTime($id, $label);
$spec->similar = $this->getSimilarSpecs($spec->simpleName, $id);
}
return parent::get($spec);
}
/**
* Returns complete specification with test suites and attachments (without cases)
* @param type $simpleName
* @param int $versionID version ID, if < 0, latest version for given specification is used
* @return \Specification|null
*/
private function getSpecificationFromAlias($simpleName, $versionID) {
if ($versionID < 0) {
$spec = $this->specDao->getSpecificationAliasLatest($simpleName);
} else {
$spec = $this->specDao->getSpecificationAlias($simpleName, $versionID);
}
$spec->isFavorite = $this->specDao->isSpecificationFavorite($spec->id, Synergy::getSessionProvider()->getUserId());
if (!is_null($spec)) {
$u = $this->getUserCtrl()->getUserById($spec->ownerId);
$spec->owner = $u->username;
$spec->ownerName = $u->firstName . " " . $u->lastName;
$spec->attachments = $this->specDao->getAttachments($spec->id);
$spec->testSuites = $this->specDao->getTestSuites($spec->id);
$spec->estimation = $this->specDao->getEstimatedTime($spec->id, "");
$spec->similar = $this->getSimilarSpecs($spec->simpleName, $spec->id);
}
return parent::get($spec);
}
/**
* Returns specification with all suites and cases
* @param type $id
* @return Specification|null
*/
public function getSpecificationFull($id) {
$specification = $this->getSpecification(intval($id), '', -1);
$bugTrackingSystem = "other";
if (count($specification->ext["projects"]) > 0) {
$projectCtrl = new ProjectCtrl();
$project = $projectCtrl->getProjectDetailed($specification->ext["projects"][0]->id);
$bugTrackingSystem = $project->bugTrackingSystem;
}
if (is_null($specification)) {
return null;
}
foreach ($specification->testSuites as $ts) {
$ts->testCases = $this->getCaseCtrl()->getTestCasesDetailed($ts->id, '', $bugTrackingSystem);
}
return $specification; // no need to call extensions as it is done in $this->getSpecification()
}
/**
* Returns all attachments for given specification
* @param int $id specification ID
* @return SpecificationAttachment[]
*/
public function getAttachments($id) {
return $this->specDao->getAttachments($id);
}
/**
* Returns sum of duration of all cases for given specification
* @param type $id
* @param String $label not required, if given, only cases with this label will be counted
* @return int
*/
public function getEstimatedTime($id, $label = '') {
return $this->specDao->getEstimatedTime($id, $label);
}
/**
* Updates specification
* @param Specification $specification
* @return boolean
*/
public function updateSpecification($specification, $keepSimpleName = true) {
$versionID = $this->getVersionID($specification->id);
if ($this->simpleNameAndVersionUsed($specification->id, $specification->simpleName, $versionID)) {
throw new SpecificationDuplicateException('attempt to create a duplicate specification', 'Specification with given simple name already exists for given version', '');
}
$originalSimpleName = $specification->simpleName;
$newSimpleName = $specification->stringToSimpleName($specification->title);
if ($originalSimpleName !== $newSimpleName && $keepSimpleName) {
$this->specDao->updateSimpleNames($originalSimpleName, $newSimpleName);
}
$result = $this->specDao->updateSpecification($specification->id, $specification->title, $specification->desc, $specification->ownerId, $newSimpleName);
if ($result) {
parent::edit($specification);
}
return $result;
}
public function getOwnerId($specificationId) {
return $this->specDao->getOwnerId($specificationId);
}
/**
* If user who attempts to remove specification is also owner (or admin/manager), removes specification.
* Otherwise send notification to owner and create removal request
* @param type $id
* @return boolean true if deleted, false if not
*/
public function deleteSpecification($id) {
// TODO check if user is owner, if not, send email to owner
if ($this->specDao->getOwnerId($id) === Synergy::getSessionProvider()->getUserId() || Util::isAuthorized("admin") || Util::isAuthorized("manager")) {
parent::delete($id);
$obsoletes = $this->getSuitesIDs($id);
$this->deleteAttachments($id);
if (count($obsoletes) > 0) {
$this->getSuiteCtrl()->deleteSuitesForSpecification($id, $obsoletes);
}
$this->getUserCtrl()->deleteFavoriteSpecification($id);
// $this->getRunCtrl()->deleteAssignmentsForSpecification($id);
$this->getCaseCtrl()->removeUnusedCases();
return $this->specDao->deleteSpecification($id);
} else {
RemovalRequestExtension::createRemovalRequest($id, Synergy::getSessionProvider()->getUserId());
Mediator::emit("requestedRemoval", $id);
return false;
}
}
/**
* Returns array of IDs of suites that belongs to given specification
* @param type $spec_id
* @return int[]
*/
public function getSuitesIDs($spec_id) {
return $this->specDao->getSuitesIDs($spec_id);
}
/**
* Removes all attachments for given specification
* @param int $id specification ID
*/
public function deleteAttachments($id) {
$attachments = $this->getAttachments($id);
foreach ($attachments as $att) {
$this->getAttachmentCtrl()->deleteSpecificationAttachment($att->id);
}
}
/**
*
* @param type $username
* @return Specification[]
*/
public function getSpecificationsByAuthor($username) {
return parent::get($this->specDao->getSpecificationsByAuthor($username));
}
/**
*
* @param type $username
* @return Specification[]
*/
public function getSpecificationsByOwner($username) {
return parent::get($this->specDao->getSpecificationsByOwner($username));
}
/**
* Returns specifications where given user is owner restricted to given version
* @return Specification[]
*/
public function getSpecificationsByOwnerAndVersion($username, $versionId, $projectId) {
return parent::get($this->specDao->getSpecificationsByOwnerAndVersion($username, $versionId, $projectId));
}
/**
* Returns $limit latest specfications. Age of specification is derived from ID (auto increment in DB)
* @param type $limit
* @return array
*/
public function getLatestSpecifications($limit) {
return parent::get($this->specDao->getLatestSpecifications($limit));
}
/**
* Quazi removes authorship. Because DB constraints have to correct, current user is set as auhtor
* @param type $userId
*/
public function deleteAuthorship($userId) {
return $this->specDao->deleteAuthorship($userId);
}
/**
* Quazi removes authorship. Because DB constraints have to correct, current user is set as auhtor
* @param type $userId
*/
public function deleteOwnership($userId) {
return $this->specDao->deleteOwnership($userId);
}
/**
* Returns specifications with title matching given term
* @param String $title
* @param int $limit maximum number of results to be returned
* @return Specification[]
*/
public function findMatchingSpecifications($title, $limit = 15) {
return parent::get($this->specDao->findMatchingSpecifications($title, $limit));
}
/**
* Clones specification
* @param type $specId ID of specification to be clonned
* @param type $version target version
* @param type $newname name of the created clonned specification
* @return int new specification ID
*/
public function cloneSpecification($specId, $version, $newname) {
$v = $this->getVersionCtrl()->getVersionByName($version);
$versionId = $v->getId();
if (is_null($versionId)) {
return -1;
}
$spec = $this->getSpecification(intval($specId), '', -1);
if ($spec->title !== $newname) {
$newSimpleName = $spec->stringToSimpleName($newname);
if ($this->isUniqueSimpleName($newSimpleName)) {
$oldSimpleName = $spec->simpleName;
$this->specDao->updateSimpleNames($oldSimpleName, $newSimpleName);
}
}
$spec->title = $newname;
$spec->simpleName = $spec->stringToSimpleName($newname);
$spec->version = $version;
$newSpecId = $this->createSpecification($spec, true);
//insert new
if ($newSpecId > 0) {
$this->specDao->cloneSpecificationAttachment($spec, $newSpecId);
for ($i = 0, $max = count($spec->testSuites); $i < $max; $i++) {
/* @var $suite Suite */
$suite = $spec->testSuites[$i];
$newSuiteId = $this->getSuiteCtrl()->cloneSpecificationSuite($newSpecId, $suite);
$cases = $this->getSuiteCtrl()->getTestCasesIds($suite->id);
$this->specDao->cloneSpecificationCases($cases, $newSuiteId);
}
}
Mediator::emit("specificationCreated", $newSpecId);
return $newSpecId;
}
/**
* Creates new specification
* @param Specification $specification
* @return type
*/
public function createSpecification($specification, $isCloning) {
$v = $this->getVersionCtrl()->getVersionByName($specification->version);
if (is_null($v)) {
if (defined('ANONYM')) {
$this->getVersionCtrl()->createVersion($specification->version);
$v = $this->getVersionCtrl()->getVersionByName($specification->version);
} else {
return -1;
}
}
$versionId = $v->getId();
$userId = -1;
$matchedUser = $this->getUserCtrl()->getUser($specification->author);
if (is_null($matchedUser)) {
$userId = $this->getUserCtrl()->getUserIDbyUsername(ANONYM);
} else {
$userId = $matchedUser->id;
}
if ($userId < 0)
return -1;
// error_log(Util::purifyHTML($specfication->desc));
$specification->simpleName = $specification->stringToSimpleName($specification->title);
if ($this->simpleNameAndVersionUsed(-1, $specification->simpleName, $versionId)) {
throw new SpecificationDuplicateException('attempt to create a duplicate specification', 'Specification with given simple name already exists for given version', '');
}
$specification->authorId = $userId;
if ($isCloning) {
$newId = $this->specDao->createSpecification($specification->title, $specification->desc, $versionId, $userId, Synergy::getSessionProvider()->getUserId(), $specification->simpleName);
$specification->ownerId = Synergy::getSessionProvider()->getUserId();
} else {
$newId = $this->specDao->createSpecification($specification->title, $specification->desc, $versionId, $userId, $userId, $specification->simpleName);
$specification->ownerId = $userId;
}
$specification->versionId = $versionId;
$specification->id = $newId;
parent::create($specification, $newId);
return $newId;
}
public static function on($name, $data) {
}
/**
* Returns number of cases in specification with given label
* @param type $specificationId
* @param type $labelId
*/
public function getCasesCount($specificationId, $labelId) {
return $this->specDao->getCasesCount($specificationId, $labelId);
}
/**
* Refreshes specification last update date
* @param type $specificationId
*/
public function refreshSpecification($specificationId) {
date_default_timezone_set('UTC');
$localTime = date('Y-m-d H:i:s');
$this->specDao->setLastUpdatedDate($localTime, $specificationId);
}
/**
* Changes authorship of specification
* @param type $userId new author ID
* @param type $specificationId specification to be updated
*/
public function changeAuthor($userId, $specificationId) {
$this->specDao->setAuthorship($userId, $specificationId);
}
/**
* Returns full specification including test cases based on provided simple name
* @param String $simpleName
* @param int $versionID if < 0, latest version is used
* @return Specification
*/
public function getSpecificationFullByAlias($simpleName, $versionID) {
$specification = $this->getSpecificationFromAlias($simpleName, $versionID);
if (is_null($specification)) {
return null;
}
$bugTrackingSystem = "other";
if (count($specification->ext["projects"]) > 0) {
$projectCtrl = new ProjectCtrl();
$project = $projectCtrl->getProjectDetailed($specification->ext["projects"][0]->id);
$bugTrackingSystem = $project->bugTrackingSystem;
}
foreach ($specification->testSuites as $ts) {
$ts->testCases = $this->getCaseCtrl()->getTestCasesDetailed($ts->id, '', $bugTrackingSystem);
}
return $specification; // no need to call extensions as it is done in $this->getSpecification()
}
/**
* Returns version ID of given specification
* @param type $specificationID
* @return type
*/
public function getVersionID($specificationID) {
return $this->specDao->getSpecificationVersionID($specificationID);
}
/**
* Checks if given simple name is already used for any specification in given version
* @param type $specificationID ID of specification to be excluded from search
* @param type $simpleName
* @param type $versionID
* @return boolean true if simple name is already used in given version
*/
public function simpleNameAndVersionUsed($specificationID, $simpleName, $versionID) {
if ($this->specDao->findMatchingSpecification($specificationID, $simpleName, $versionID) === -1) {
return false;
}
return true;
}
/**
* Returns specifications with the same simple name across versions
* @param type $simpleName
* @param type $excludedId ID of specification to be excluded from search
* @return Specification[]
*/
public function getSimilarSpecs($simpleName, $excludedId) {
return $this->specDao->findSimilar($simpleName, $excludedId);
}
public function getSpecificationsByVersion() {
SpecificationsSimpleNameList::$versions = $this->getVersionCtrl()->getVersions();
return $this->specDao->getAllSpecificationsGroupedBySimpleName();
}
public function createSimpleName($id, $title) {
$this->specDao->setSimpleName($id, $title);
}
public function isUniqueSimpleName($newSimpleName) {
return $this->specDao->isUniqueSimpleName($newSimpleName);
}
public function isSpecificationUsed($specificationId) {
if ($this->getLockCtrl()->isSpecificationLocked($specificationId)) {
return 1;
}
return $this->specDao->isSpecificationUsed($specificationId);
}
public function getSpecificationOverview($specificationId) {
return $this->specDao->getSpecificationOverview($specificationId);
}
public function getSpecificationsForProject($projectId) {
return $this->specDao->getSpecificationsForProject($projectId);
}
}
?>