From d7387adc04b4814cbe607e1a06aef08a7dcb9b15 Mon Sep 17 00:00:00 2001 From: Marcel Folaron Date: Fri, 30 Aug 2024 19:15:20 -0400 Subject: [PATCH] update comments --- .idea/leantime-oss.iml | 3 +- .idea/php.xml | 1 + .idea/phpspec.xml | 3 + .idea/symfony2.xml | 5 +- .idea/vcs.xml | 1 + .phpdoc/template/api-md/index.api-md.twig | 2 +- app/Domain/Projects/Services/Projects.php | 2864 +++++++++++---------- app/Domain/Tickets/Services/Tickets.php | 135 +- app/Domain/Users/Controllers/EditOwn.php | 2 +- composer.json | 6 +- composer.lock | 190 +- dev-php.ini | 0 makefile | 6 +- phpstan.neon | 21 +- 14 files changed, 1731 insertions(+), 1508 deletions(-) delete mode 100644 dev-php.ini diff --git a/.idea/leantime-oss.iml b/.idea/leantime-oss.iml index 48bede271..e937d8139 100644 --- a/.idea/leantime-oss.iml +++ b/.idea/leantime-oss.iml @@ -6,8 +6,6 @@ - - @@ -207,6 +205,7 @@ + diff --git a/.idea/php.xml b/.idea/php.xml index 79c0374ca..ae1b7f75c 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -268,6 +268,7 @@ + diff --git a/.idea/phpspec.xml b/.idea/phpspec.xml index 1ee8efc6e..e91012819 100644 --- a/.idea/phpspec.xml +++ b/.idea/phpspec.xml @@ -74,6 +74,9 @@ + + \ No newline at end of file diff --git a/.idea/symfony2.xml b/.idea/symfony2.xml index 15d4d3f50..2f212cfe3 100644 --- a/.idea/symfony2.xml +++ b/.idea/symfony2.xml @@ -1,7 +1,8 @@ - - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index bd69c239c..a3835b65e 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -3,5 +3,6 @@ + \ No newline at end of file diff --git a/.phpdoc/template/api-md/index.api-md.twig b/.phpdoc/template/api-md/index.api-md.twig index 2c4bb4d6b..f678d0452 100644 --- a/.phpdoc/template/api-md/index.api-md.twig +++ b/.phpdoc/template/api-md/index.api-md.twig @@ -5,7 +5,7 @@ title: {{project.name}} {% include 'config/frontmatter.twig' %} --- -# {{ project.name|raw }} jsonRPC method namespaces +# {{ project.name|raw }} JsonRPC 2.0 namespaces For an introduction into connecting to the Leantime API please see [Api Usage](https://docs.leantime.io/#/api/usage) diff --git a/app/Domain/Projects/Services/Projects.php b/app/Domain/Projects/Services/Projects.php index 79ed84401..31a598e8a 100644 --- a/app/Domain/Projects/Services/Projects.php +++ b/app/Domain/Projects/Services/Projects.php @@ -1,1753 +1,1833 @@ tpl = $tpl; + $this->projectRepository = $projectRepository; + $this->ticketRepository = $ticketRepository; + $this->settingsRepo = $settingsRepo; + $this->filesRepository = $filesRepository; + $this->language = $language; + $this->messengerService = $messengerService; + $this->notificationService = $notificationService; + } + + /** + * Gets the project types. + * + * @return mixed * * @api */ - class Projects + public function getProjectTypes(): mixed { - use DispatchesEvents; - - private TemplateCore $tpl; - private ProjectRepository $projectRepository; - private TicketRepository $ticketRepository; - private SettingRepository $settingsRepo; - private LanguageCore $language; - private Messengers $messengerService; - private NotificationService $notificationService; - private FileRepository $filesRepository; - - /** - * @param TemplateCore $tpl - * @param ProjectRepository $projectRepository - * @param TicketRepository $ticketRepository - * @param SettingRepository $settingsRepo - * @param FileRepository $filesRepository - * @param LanguageCore $language - * @param Messengers $messengerService - * @param NotificationService $notificationService - * - * @api - */ - public function __construct( - TemplateCore $tpl, - ProjectRepository $projectRepository, - TicketRepository $ticketRepository, - SettingRepository $settingsRepo, - FileRepository $filesRepository, - LanguageCore $language, - Messengers $messengerService, - NotificationService $notificationService - ) { - $this->tpl = $tpl; - $this->projectRepository = $projectRepository; - $this->ticketRepository = $ticketRepository; - $this->settingsRepo = $settingsRepo; - $this->filesRepository = $filesRepository; - $this->language = $language; - $this->messengerService = $messengerService; - $this->notificationService = $notificationService; - } - - /** - * @return mixed - * - * @api - */ - public function getProjectTypes(): mixed - { - - $types = array("project" => "label.project"); - $filtered = static::dispatch_filter("filterProjectType", $types); - - //Strategy & Program are protected types - if (isset($filtered["strategy"])) { - unset($filtered["strategy"]); - } + $types = array("project" => "label.project"); - if (isset($filtered["program"])) { - unset($filtered["program"]); - } + $filtered = static::dispatch_filter("filterProjectType", $types); - return $filtered; + //Strategy & Program are protected types + if (isset($filtered["strategy"])) { + unset($filtered["strategy"]); } - /** - * @param int $id - * @return array|bool - * - * @api - */ - public function getProject(int $id): bool|array - { - return $this->projectRepository->getProject($id); + if (isset($filtered["program"])) { + unset($filtered["program"]); } - //Gets project progress + return $filtered; + } - /** - * @param $projectId - * @return array - * @throws \Exception - * + /** + * Gets the project with the given ID. + * + * @param int $id The ID of the project to retrieve. + * @return bool|array Returns the project data as an associative array if the project exists, otherwise returns false. + * * @api */ - public function getProjectProgress($projectId): array - { - $returnValue = array("percent" => 0, "estimatedCompletionDate" => "We need more data to determine that.", "plannedCompletionDate" => ""); + public function getProject(int $id): bool|array + { + return $this->projectRepository->getProject($id); + } - $averageStorySize = $this->ticketRepository->getAverageTodoSize($projectId); + //Gets project progress - //We'll use this as the start date of the project - $firstTicket = $this->ticketRepository->getFirstTicket($projectId); + /** + * Gets the progress of a project. + * Calculates the completion percentage, estimated completion date, + * and planned completion date of the project. + * + * @param int $projectId The ID of the project. + * @return array The progress of the project. + * + * @api + */ + public function getProjectProgress($projectId): array + { + $returnValue = array("percent" => 0, "estimatedCompletionDate" => "We need more data to determine that.", "plannedCompletionDate" => ""); - if (is_object($firstTicket) === false) { - return $returnValue; - } + $averageStorySize = $this->ticketRepository->getAverageTodoSize($projectId); - $dateOfFirstTicket = new DateTime($firstTicket->date); - $today = new DateTime(); - $totalprojectDays = $today->diff($dateOfFirstTicket)->format("%a"); + //We'll use this as the start date of the project + $firstTicket = $this->ticketRepository->getFirstTicket($projectId); + if (is_object($firstTicket) === false) { + return $returnValue; + } - //Calculate percent + $dateOfFirstTicket = new DateTime($firstTicket->date); + $today = new DateTime(); + $totalprojectDays = $today->diff($dateOfFirstTicket)->format("%a"); - $numberOfClosedTickets = $this->ticketRepository->getNumberOfClosedTickets($projectId); - $numberOfTotalTickets = $this->ticketRepository->getNumberOfAllTickets($projectId); + //Calculate percent - if ($numberOfTotalTickets == 0) { - $percentNum = 0; - } else { - $percentNum = ($numberOfClosedTickets / $numberOfTotalTickets) * 100; - } + $numberOfClosedTickets = $this->ticketRepository->getNumberOfClosedTickets($projectId); - $effortOfClosedTickets = $this->ticketRepository->getEffortOfClosedTickets($projectId, $averageStorySize); - $effortOfTotalTickets = $this->ticketRepository->getEffortOfAllTickets($projectId, $averageStorySize); + $numberOfTotalTickets = $this->ticketRepository->getNumberOfAllTickets($projectId); - if ($effortOfTotalTickets == 0) { - $percentEffort = $percentNum; //This needs to be set to percentNum in case users choose to not use efforts - } else { - $percentEffort = ($effortOfClosedTickets / $effortOfTotalTickets) * 100; - } + if ($numberOfTotalTickets == 0) { + $percentNum = 0; + } else { + $percentNum = ($numberOfClosedTickets / $numberOfTotalTickets) * 100; + } - $finalPercent = $percentEffort; + $effortOfClosedTickets = $this->ticketRepository->getEffortOfClosedTickets($projectId, $averageStorySize); + $effortOfTotalTickets = $this->ticketRepository->getEffortOfAllTickets($projectId, $averageStorySize); - if ($totalprojectDays > 0) { - $dailyPercent = $finalPercent / $totalprojectDays; - } else { - $dailyPercent = 0; - } + if ($effortOfTotalTickets == 0) { + $percentEffort = $percentNum; //This needs to be set to percentNum in case users choose to not use efforts + } else { + $percentEffort = ($effortOfClosedTickets / $effortOfTotalTickets) * 100; + } - $percentLeft = 100 - $finalPercent; + $finalPercent = $percentEffort; - if ($dailyPercent == 0) { - $estDaysLeftInProject = 10000; - } else { - $estDaysLeftInProject = ceil($percentLeft / $dailyPercent); - } + if ($totalprojectDays > 0) { + $dailyPercent = $finalPercent / $totalprojectDays; + } else { + $dailyPercent = 0; + } - $today->add(new DateInterval('P' . $estDaysLeftInProject . 'D')); + $percentLeft = 100 - $finalPercent; + if ($dailyPercent == 0) { + $estDaysLeftInProject = 10000; + } else { + $estDaysLeftInProject = ceil($percentLeft / $dailyPercent); + } - //Fix this - $currentDate = new DateTime(); - $inFiveYears = intval($currentDate->format("Y")) + 5; + $today->add(new DateInterval('P' . $estDaysLeftInProject . 'D')); - if (intval($today->format("Y")) >= $inFiveYears) { - $completionDate = "Past " . $inFiveYears; - } else { - $completionDate = $today->format($this->language->__('language.dateformat')); - } + //Fix this + $currentDate = new DateTime(); + $inFiveYears = intval($currentDate->format("Y")) + 5; - $returnValue = array("percent" => $finalPercent, "estimatedCompletionDate" => $completionDate, "plannedCompletionDate" => ''); - if ($numberOfClosedTickets < 10) { - $returnValue['estimatedCompletionDate'] = " Complete more To-Dos to see that!"; - } elseif ($finalPercent == 100) { - $returnValue['estimatedCompletionDate'] = " This project is complete, onto the next!"; - } - return $returnValue; + if (intval($today->format("Y")) >= $inFiveYears) { + $completionDate = "Past " . $inFiveYears; + } else { + $completionDate = $today->format($this->language->__('language.dateformat')); } - /** - * @param $projectId - * @return array - * - * @api - */ - public function getUsersToNotify($projectId): array - { - - $users = $this->projectRepository->getUsersAssignedToProject($projectId); - - $to = array(); - //Only users that actually want to be notified and are active - foreach ($users as $user) { - if ($user["notifications"] != 0 && strtolower($user["status"]) == 'a') { - $to[] = $user["id"]; - } - } - - return $to; + $returnValue = array("percent" => $finalPercent, "estimatedCompletionDate" => $completionDate, "plannedCompletionDate" => ''); + if ($numberOfClosedTickets < 10) { + $returnValue['estimatedCompletionDate'] = " Complete more To-Dos to see that!"; + } elseif ($finalPercent == 100) { + $returnValue['estimatedCompletionDate'] = " This project is complete, onto the next!"; } + return $returnValue; + } - /** - * @param $projectId - * @return array - * + /** + * Gets an array of user IDs to notify for a given project. + * + * @param int $projectId The ID of the project to get users to notify for. + * @return array An array of user IDs. + * * @api */ - public function getAllUserInfoToNotify($projectId): array - { + public function getUsersToNotify($projectId): array + { - $users = $this->projectRepository->getUsersAssignedToProject($projectId); + $users = $this->projectRepository->getUsersAssignedToProject($projectId); - $to = array(); + $to = array(); - //Only users that actually want to be notified - foreach ($users as $user) { - if ($user["notifications"] != 0 && ($user['username'] != session("userdata.mail"))) { - $to[] = $user; - } + //Only users that actually want to be notified and are active + foreach ($users as $user) { + if ($user["notifications"] != 0 && strtolower($user["status"]) == 'a') { + $to[] = $user["id"]; } - - return $to; } - //TODO Split and move to notifications + return $to; + } - /** - * @param Notification $notification - * @return void - * @throws BindingResolutionException - * + /** + * Gets all the users who need to be notified for a given project. + * + * @param int $projectId The ID of the project. + * @return array An array of users to notify. + * * @api */ - public function notifyProjectUsers(Notification $notification): void - { + public function getAllUserInfoToNotify($projectId): array + { - //Filter notifications - $notification = EventCore::dispatch_filter("notificationFilter", $notification); + $users = $this->projectRepository->getUsersAssignedToProject($projectId); - //Email - $users = $this->getUsersToNotify($notification->projectId); - $projectName = $this->getProjectName($notification->projectId); + $to = array(); - $users = array_filter($users, function ($user) use ($notification) { - return $user != $notification->authorId; - }, ARRAY_FILTER_USE_BOTH); + //Only users that actually want to be notified + foreach ($users as $user) { + if ($user["notifications"] != 0 && ($user['username'] != session("userdata.mail"))) { + $to[] = $user; + } + } - /* - $mailer = app()->make(MailerCore::class); - $mailer->setContext('notify_project_users'); - $mailer->setSubject($notification->subject); + return $to; + } + //TODO Split and move to notifications - $mailer->setHtml($emailMessage); - //$mailer->sendMail($users, session("userdata.name")); - * + /** + * Notifies the users associated with a project about a notification. + * + * @param Notification $notification The notification object to send. + * @return void + * * @api */ + public function notifyProjectUsers(Notification $notification): void + { - $emailMessage = $notification->message; - if ($notification->url !== false) { - $emailMessage .= " " . $notification->url['text'] . ""; - } + //Filter notifications + $notification = EventCore::dispatch_filter("notificationFilter", $notification); - // NEW Queuing messaging system - $queue = app()->make(QueueRepository::class); - $queue->queueMessageToUsers($users, $emailMessage, $notification->subject, $notification->projectId); + //Email + $users = $this->getUsersToNotify($notification->projectId); + $projectName = $this->getProjectName($notification->projectId); - //Send to messengers - $this->messengerService->sendNotificationToMessengers($notification, $projectName); + $users = array_filter($users, function ($user) use ($notification) { + return $user != $notification->authorId; + }, ARRAY_FILTER_USE_BOTH); + + /* + $mailer = app()->make(MailerCore::class); + $mailer->setContext('notify_project_users'); + $mailer->setSubject($notification->subject); - //Notify users about mentions - //Fields that should be parsed for mentions - $mentionFields = array( - "comments" => array("text"), - "projects" => array("details"), - "tickets" => array("description"), - "canvas" => array("description", "data", "conclusion", "assumptions"), - ); - $contentToCheck = ''; - //Find entity ID & content - //Todo once all entities are models this if statement can be reduced - if (isset($notification->entity) && is_array($notification->entity) && isset($notification->entity["id"])) { - $entityId = $notification->entity["id"]; + $mailer->setHtml($emailMessage); + //$mailer->sendMail($users, session("userdata.name")); + * + * @api + */ - if (isset($mentionFields[$notification->module])) { - $fields = $mentionFields[$notification->module]; + $emailMessage = $notification->message; + if ($notification->url !== false) { + $emailMessage .= " " . $notification->url['text'] . ""; + } - foreach ($fields as $field) { - if (isset($notification->entity[$field])) { - $contentToCheck .= $notification->entity[$field]; - } + // NEW Queuing messaging system + $queue = app()->make(QueueRepository::class); + $queue->queueMessageToUsers($users, $emailMessage, $notification->subject, $notification->projectId); + + //Send to messengers + $this->messengerService->sendNotificationToMessengers($notification, $projectName); + + //Notify users about mentions + //Fields that should be parsed for mentions + $mentionFields = array( + "comments" => array("text"), + "projects" => array("details"), + "tickets" => array("description"), + "canvas" => array("description", "data", "conclusion", "assumptions"), + ); + + $contentToCheck = ''; + //Find entity ID & content + //Todo once all entities are models this if statement can be reduced + if (isset($notification->entity) && is_array($notification->entity) && isset($notification->entity["id"])) { + $entityId = $notification->entity["id"]; + + if (isset($mentionFields[$notification->module])) { + $fields = $mentionFields[$notification->module]; + + foreach ($fields as $field) { + if (isset($notification->entity[$field])) { + $contentToCheck .= $notification->entity[$field]; } } - } elseif (isset($notification->entity) && is_object($notification->entity) && isset($notification->entity->id)) { - $entityId = $notification->entity->id; + } + } elseif (isset($notification->entity) && is_object($notification->entity) && isset($notification->entity->id)) { + $entityId = $notification->entity->id; - if (isset($mentionFields[$notification->module])) { - $fields = $mentionFields[$notification->module]; + if (isset($mentionFields[$notification->module])) { + $fields = $mentionFields[$notification->module]; - foreach ($fields as $field) { - if (isset($notification->entity->$field)) { - $contentToCheck .= $notification->entity->$field; - } + foreach ($fields as $field) { + if (isset($notification->entity->$field)) { + $contentToCheck .= $notification->entity->$field; } } - } else { - //Entity id not set use project id - $entityId = $notification->projectId; - } - - if ($contentToCheck != '') { - $this->notificationService->processMentions( - $contentToCheck, - $notification->module, - (int)$entityId, - $notification->authorId, - $notification->url["url"] - ); } + } else { + //Entity id not set use project id + $entityId = $notification->projectId; + } - EventCore::dispatch_event("notifyProjectUsers", array("type" => "projectUpdate", "module" => $notification->module, "moduleId" => $entityId, "message" => $notification->message, "subject" => $notification->subject, "users" => $this->getAllUserInfoToNotify($notification->projectId), "url" => $notification->url['url']), "domain.services.projects"); + if ($contentToCheck != '') { + $this->notificationService->processMentions( + $contentToCheck, + $notification->module, + (int)$entityId, + $notification->authorId, + $notification->url["url"] + ); } /** - * @param $projectId - * @return mixed|void + * This event is fired to notify project users of important updates. + * An event "notifyProjectUsers" is dispatched with an array of variables required for the notification. + * These variables include the type of update, module affected, entity ID, message and subject of notification, + * users to be notified, and url if present. This event belongs to the "domain.services.projects" context. * + * @event notifyProjectUsers + * + * @param string $type The type of update. E.g., "projectUpdate" + * @param string $module The name of the module affected by the update. + * @param int $moduleId The ID of the entity affected by the update. + * @param string $message The content of the notification message. + * @param string $subject The subject of the notification message. + * @param array $users The users to be notified about this update. Retrieved by the 'getAllUserInfoToNotify' method. + * @param string|null $url The url leading to the update if any. + * @context domain.services.projects + */ + EventCore::dispatch_event("notifyProjectUsers", array("type" => "projectUpdate", "module" => $notification->module, "moduleId" => $entityId, "message" => $notification->message, "subject" => $notification->subject, "users" => $this->getAllUserInfoToNotify($notification->projectId), "url" => $notification->url['url']), "domain.services.projects"); + } + + /** + * Retrieves the name of a project based on its ID. + * + * @param int $projectId The ID of the project. + * @return string|null The name of the project, or null if the project does not exist. + * * @api */ - public function getProjectName($projectId) - { + public function getProjectName($projectId) + { - $project = $this->projectRepository->getProject($projectId); - if ($project) { - return $project["name"]; - } + $project = $this->projectRepository->getProject($projectId); + if ($project) { + return $project["name"]; } + } - /** - * @param $userId - * @return array|false - * + /** + * Gets the project IDs assigned to a specified user. + * + * @param int $userId The ID of the user. + * @return false|array The project IDs assigned to the user, or false if no projects are found. + * * @api */ - public function getProjectIdAssignedToUser($userId): false|array - { + public function getProjectIdAssignedToUser($userId): false|array + { - $projects = $this->projectRepository->getUserProjectRelation($userId); + $projects = $this->projectRepository->getUserProjectRelation($userId); - if ($projects) { - return $projects; - } else { - return false; - } + if ($projects) { + return $projects; + } else { + return false; } + } - /** - * @param $userId - * @param string $projectStatus - * @param $clientId - * @return array - * + /** + * Gets projects assigned to a user. + * + * @param int $userId The ID of the user. + * @param string $projectStatus The status of the projects. Defaults to "open". + * @param int|null $clientId The ID of the client. Defaults to null. + * @return array The projects assigned to the user. + * * @api */ - public function getProjectsAssignedToUser($userId, string $projectStatus = "open", $clientId = null): array - { - $projects = $this->projectRepository->getUserProjects($userId, $projectStatus, $clientId); + public function getProjectsAssignedToUser($userId, string $projectStatus = "open", $clientId = null): array + { + $projects = $this->projectRepository->getUserProjects($userId, $projectStatus, $clientId); - if ($projects) { - return $projects; - } else { - return []; - } + if ($projects) { + return $projects; + } else { + return []; } + } - /** - * @param $currentParentId - * @param array $projects - * @return array - * + /** + * Finds all children projects for a given parent project. + * + * @param mixed $currentParentId The ID of the current parent project. + * @param array $projects An array of projects to search for children. + * @return array An array of children projects found. + * * @api */ - public function findMyChildren($currentParentId, array $projects): array - { + public function findMyChildren($currentParentId, array $projects): array + { - $branch = []; + $branch = []; - foreach ($projects as $project) { - if ($project['parent'] == $currentParentId) { - $children = $this->findMyChildren($project['id'], $projects); - if ($children) { - $project['children'] = $children; - } - $branch[] = $project; + foreach ($projects as $project) { + if ($project['parent'] == $currentParentId) { + $children = $this->findMyChildren($project['id'], $projects); + if ($children) { + $project['children'] = $children; } + $branch[] = $project; } - return $branch; } + return $branch; + } - /** - * Ensures all projects have a valid parent. If not the parent is removed. - * This way a user can still access a project even if they don't have access to the child. - * - * @param array $projects - * @return array - * + /** + * Cleans the parent relationship in the given array of projects. + * Removes projects that have a parent project that does not exist in the array. + * Assigns a parent id of 0 to projects that have no parent. + * + * @param array $projects An array of projects + * @return array The cleaned array of projects + * * @api */ - public function cleanParentRelationship(array $projects): array - { + public function cleanParentRelationship(array $projects): array + { - $parents = []; - foreach ($projects as $project) { - $parents[$project['id']] = $project; - } + $parents = []; + foreach ($projects as $project) { + $parents[$project['id']] = $project; + } - $cleanList = []; - foreach ($projects as $project) { - if (isset($parents[$project['parent']])) { - $cleanList[] = $project; - } else { - $project['parent'] = 0; - $cleanList[] = $project; - } + $cleanList = []; + foreach ($projects as $project) { + if (isset($parents[$project['parent']])) { + $cleanList[] = $project; + } else { + $project['parent'] = 0; + $cleanList[] = $project; } - - return $cleanList; } - /** - * @param $userId - * @param string $projectStatus - * @param $clientId - * @return array - * + return $cleanList; + } + + /** + * Gets the hierarchy of projects assigned to a user. + * + * @param int $userId The ID of the user. + * @param string $projectStatus The project status. Default is "open". + * @param int|null $clientId The ID of the client. Default is null. + * + * @return array An array containing the assigned projects, the project hierarchy, and the favorite projects. + * * @api */ - public function getProjectHierarchyAssignedToUser($userId, string $projectStatus = "open", $clientId = null): array - { - - //Load all projects user is assigned to - $projects = $this->projectRepository->getUserProjects( - userId: $userId, - projectStatus: $projectStatus, - clientId: (int)$clientId, - accessStatus: "assigned" - ); - $projects = self::dispatch_filter('afterLoadingProjects', $projects); - - - //Build project hierarchy - $projectsClean = $this->cleanParentRelationship($projects); - $projectHierarchy = $this->findMyChildren(0, $projectsClean); - $projectHierarchy = self::dispatch_filter('afterPopulatingProjectHierarchy', $projectHierarchy, array("projects" => $projects)); + public function getProjectHierarchyAssignedToUser($userId, string $projectStatus = "open", $clientId = null): array + { - //Get favorite projects - $favorites = []; - foreach ($projects as $project) { - if (isset($project["isFavorite"]) && $project["isFavorite"] == 1) { - $favorites[] = $project; - } + //Load all projects user is assigned to + $projects = $this->projectRepository->getUserProjects( + userId: $userId, + projectStatus: $projectStatus, + clientId: (int)$clientId, + accessStatus: "assigned" + ); + $projects = self::dispatch_filter('afterLoadingProjects', $projects); + + + //Build project hierarchy + $projectsClean = $this->cleanParentRelationship($projects); + $projectHierarchy = $this->findMyChildren(0, $projectsClean); + $projectHierarchy = self::dispatch_filter('afterPopulatingProjectHierarchy', $projectHierarchy, array("projects" => $projects)); + + //Get favorite projects + $favorites = []; + foreach ($projects as $project) { + if (isset($project["isFavorite"]) && $project["isFavorite"] == 1) { + $favorites[] = $project; } - $favorites = self::dispatch_filter('afterPopulatingProjectFavorites', $favorites, array("projects" => $projects)); - - return [ - "allAssignedProjects" => $projects, - "allAssignedProjectsHierarchy" => $projectHierarchy, - "favoriteProjects" => $favorites, - ]; } + $favorites = self::dispatch_filter('afterPopulatingProjectFavorites', $favorites, array("projects" => $projects)); - /** - * @param $userId - * @param string $projectStatus - * @param $clientId - * @return array - * + return [ + "allAssignedProjects" => $projects, + "allAssignedProjectsHierarchy" => $projectHierarchy, + "favoriteProjects" => $favorites, + ]; + } + + /** + * Gets the project hierarchy available to a user. + * + * @param int $userId The ID of the user. + * @param string $projectStatus The status of the projects to retrieve. Defaults to "open". + * @param int|null $clientId The ID of the client. Defaults to null. + * @return array Returns an array containing the following keys: + * - "allAvailableProjects": An array of all projects available to the user. + * - "allAvailableProjectsHierarchy": An array representing the project hierarchy available to the user. + * - "clients": An array of clients associated with the projects available to the user. + * * @api */ - public function getProjectHierarchyAvailableToUser($userId, string $projectStatus = "open", $clientId = null): array - { - - //Load all projects user is assigned to - $projects = $this->projectRepository->getUserProjects( - userId: $userId, - projectStatus: $projectStatus, - clientId: (int)$clientId, - accessStatus: "all" - ); - $projects = self::dispatch_filter('afterLoadingProjects', $projects); + public function getProjectHierarchyAvailableToUser($userId, string $projectStatus = "open", $clientId = null): array + { + //Load all projects user is assigned to + $projects = $this->projectRepository->getUserProjects( + userId: $userId, + projectStatus: $projectStatus, + clientId: (int)$clientId, + accessStatus: "all" + ); + $projects = self::dispatch_filter('afterLoadingProjects', $projects); - //Build project hierarchy - $projectsClean = $this->cleanParentRelationship($projects); - $projectHierarchy = $this->findMyChildren(0, $projectsClean); - $projectHierarchy = self::dispatch_filter('afterPopulatingProjectHierarchy', $projectHierarchy, array("projects" => $projects)); - $clients = $this->getClientsFromProjectList($projects); + //Build project hierarchy + $projectsClean = $this->cleanParentRelationship($projects); + $projectHierarchy = $this->findMyChildren(0, $projectsClean); + $projectHierarchy = self::dispatch_filter('afterPopulatingProjectHierarchy', $projectHierarchy, array("projects" => $projects)); - return [ - "allAvailableProjects" => $projects, - "allAvailableProjectsHierarchy" => $projectHierarchy, - "clients" => $clients, - ]; - } + $clients = $this->getClientsFromProjectList($projects); + return [ + "allAvailableProjects" => $projects, + "allAvailableProjectsHierarchy" => $projectHierarchy, + "clients" => $clients, + ]; + } - /** - * Gets all the clients available to a user. - * Clients are determined by the projects - * the user is assigned to. - * - * @param int $userId The ID of the user. - * @param string $projectStatus (optional) The status of the projects to consider. Defaults to "open". - * @return array An array of client objects. - * + + /** + * Gets all the clients available to a user. + * + * @param int $userId The ID of the user. + * @param string $projectStatus The status of the projects to be considered. Defaults to "open". + * @return array An array of clients available to the user. + * * @api */ - public function getAllClientsAvailableToUser($userId, string $projectStatus = "open"): array - { - - //Load all projects user is assigned to - $projects = $this->projectRepository->getUserProjects( - userId: $userId, - projectStatus: $projectStatus, - clientId: null, - accessStatus: "all" - ); - $projects = self::dispatch_filter('afterLoadingProjects', $projects); + public function getAllClientsAvailableToUser($userId, string $projectStatus = "open"): array + { + //Load all projects user is assigned to + $projects = $this->projectRepository->getUserProjects( + userId: $userId, + projectStatus: $projectStatus, + clientId: null, + accessStatus: "all" + ); + $projects = self::dispatch_filter('afterLoadingProjects', $projects); - $clients = $this->getClientsFromProjectList($projects); - return $clients; - } + $clients = $this->getClientsFromProjectList($projects); - /** - * @param array $projects - * @return array - * - * @api + return $clients; + } + + /** + * */ - public function getClientsFromProjectList(array $projects): array - { - - $clients = []; - foreach ($projects as $project) { - if (!array_key_exists($project["clientId"], $clients)) { - $clients[$project["clientId"]] = array( - "name" => $project['clientName'], - "id" => $project["clientId"], - ); - } - } + public function getClientsFromProjectList(array $projects): array + { - return $clients; + $clients = []; + foreach ($projects as $project) { + if (!array_key_exists($project["clientId"], $clients)) { + $clients[$project["clientId"]] = array( + "name" => $project['clientName'], + "id" => $project["clientId"], + ); + } } - /** - * @param $userId - * @param $projectId - * @return mixed|string - * + return $clients; + } + + /** + * Gets the role of a user in a specific project. + * + * @param mixed $userId The user ID. + * @param mixed $projectId The project ID. + * @return mixed The role of the user in the project (string) or an empty string if the user is not assigned to the project or if the project role is not defined. + * * @api */ - public function getProjectRole($userId, $projectId): mixed - { + public function getProjectRole($userId, $projectId): mixed + { - $project = $this->projectRepository->getUserProjectRelation($userId, $projectId); + $project = $this->projectRepository->getUserProjectRelation($userId, $projectId); - if (is_array($project)) { - if (isset($project[0]['projectRole']) && $project[0]['projectRole'] != '') { - return $project[0]['projectRole']; - } else { - return ""; - } + if (is_array($project)) { + if (isset($project[0]['projectRole']) && $project[0]['projectRole'] != '') { + return $project[0]['projectRole']; } else { return ""; } + } else { + return ""; } + } - /** - * @param $userId - * @return array|false - * + /** + * Gets the projects that a user has access to. + * + * @param int $userId The ID of the user. + * @return array|false The array of projects if the user has access, false otherwise. + * * @api */ - public function getProjectsUserHasAccessTo($userId): false|array - { - $projects = $this->projectRepository->getUserProjects(userId: $userId, accessStatus: "all"); + public function getProjectsUserHasAccessTo($userId): false|array + { + $projects = $this->projectRepository->getUserProjects(userId: $userId, accessStatus: "all"); - if ($projects) { - return $projects; - } else { - return false; - } + if ($projects) { + return $projects; + } else { + return false; } + } - /** - * Sets the current project in the session. - * If a project ID is provided in the query string, it is used to set the current project. - * If no project ID is provided, the last visited project or the first assigned project is set as the current project. - * If no project is found, an exception is thrown. - * - * @return void - * @throws \Exception when unable to set the current project - * - * @api + /** + * Sets the current project for the user. + * If projectId is present in the query string, it sets the project based on that. + * If projectId is not present, it checks if the currentProject is set in the session and sets the project based on that. + * If currentProject is not set, it sets the currentProject to 0. + * If lastProject setting is set in the user's settings, it sets the project based on that. + * If lastProject setting is not set, it sets the currentProject to the first project assigned to the user. + * If no projects are assigned to the user, it throws an Exception. + * + * @return void + * + * @throws \Exception */ - public function setCurrentProject(): void - { - - if (isset($_GET['projectId']) === true) { - $projectId = filter_var($_GET['projectId'], FILTER_SANITIZE_NUMBER_INT); + public function setCurrentProject(): void + { - if ($this->changeCurrentSessionProject($projectId) === true) { - return; - } - } + if (isset($_GET['projectId']) === true) { + $projectId = filter_var($_GET['projectId'], FILTER_SANITIZE_NUMBER_INT); - if ( - session()->has("currentProject") - && $this->changeCurrentSessionProject(session("currentProject")) - ) { + if ($this->changeCurrentSessionProject($projectId) === true) { return; } + } - session(["currentProject" => 0]); + if ( + session()->has("currentProject") + && $this->changeCurrentSessionProject(session("currentProject")) + ) { + return; + } - //If last project setting is set use that - $lastProject = $this->settingsRepo->getSetting("usersettings." . session("userdata.id") . ".lastProject"); - if ( - !empty($lastProject) - && $this->changeCurrentSessionProject($lastProject) - ) { - return; - } + session(["currentProject" => 0]); - $allProjects = $this->getProjectsAssignedToUser(session("userdata.id")); - if (empty($allProjects)) { - return; - } + //If last project setting is set use that + $lastProject = $this->settingsRepo->getSetting("usersettings." . session("userdata.id") . ".lastProject"); + if ( + !empty($lastProject) + && $this->changeCurrentSessionProject($lastProject) + ) { + return; + } - if ($this->changeCurrentSessionProject($allProjects[0]['id']) === true) { - return; - } + $allProjects = $this->getProjectsAssignedToUser(session("userdata.id")); + if (empty($allProjects)) { + return; + } - throw new \Exception("Error trying to set a project"); + if ($this->changeCurrentSessionProject($allProjects[0]['id']) === true) { + return; } - /** - * Get current project id or 0 if no current project is set. - * - * @return int - * - * @api + throw new \Exception("Error trying to set a project"); + } + + /** + * Gets the current project ID. + * If the session variable "currentProject" is set, it returns its integer value. + * Otherwise, it returns 0. + * + * @return int The current project ID. + * */ - public function getCurrentProjectId(): int - { - // Make sure that we never return a value less than 0. - return max(0, (int) (session("currentProject") ?? 0)); - } + public function getCurrentProjectId(): int + { + // Make sure that we never return a value less than 0. + return max(0, (int) (session("currentProject") ?? 0)); + } - /** - * @param $projectId - * @return bool - * @throws BindingResolutionException - * + /** + * Change the current session project to the specified projectId. + * + * @param mixed $projectId The ID of the project to set as current. + * + * @return bool Returns true if the current project is successfully changed, false otherwise. + * * @api */ - public function changeCurrentSessionProject($projectId): bool - { - if (!is_numeric($projectId)) { - return false; - } + public function changeCurrentSessionProject($projectId): bool + { + if (!is_numeric($projectId)) { + return false; + } - $projectId = (int)$projectId; + $projectId = (int)$projectId; - if ( - session()->exists("currentProject") && - session("currentProject") == $projectId - ) { - return true; - } + if ( + session()->exists("currentProject") && + session("currentProject") == $projectId + ) { + return true; + } - session(["currentProjectName" => '']); + session(["currentProjectName" => '']); - if ($this->isUserAssignedToProject(session("userdata.id"), $projectId) === true) { - //Get user project role + if ($this->isUserAssignedToProject(session("userdata.id"), $projectId) === true) { + //Get user project role - $project = $this->getProject($projectId); + $project = $this->getProject($projectId); - if ($project) { - if ( - session()->exists("currentProject") && - session("currentProject") == $project['id'] - ) { - return true; - } + if ($project) { + if ( + session()->exists("currentProject") && + session("currentProject") == $project['id'] + ) { + return true; + } - $projectRole = $this->getProjectRole(session("userdata.id"), $projectId); + $projectRole = $this->getProjectRole(session("userdata.id"), $projectId); - session(["currentProject" => $projectId]); + session(["currentProject" => $projectId]); - if (mb_strlen($project['name']) > 25) { - session(["currentProjectName" => mb_substr($project['name'], 0, 25) . " (...)"]); - } else { - session(["currentProjectName" => $project['name']]); - } + if (mb_strlen($project['name']) > 25) { + session(["currentProjectName" => mb_substr($project['name'], 0, 25) . " (...)"]); + } else { + session(["currentProjectName" => $project['name']]); + } - session(["currentProjectClient" => $project['clientName']]); + session(["currentProjectClient" => $project['clientName']]); - session(["userdata.projectRole" => '']); - if ($projectRole != '') { - session(["userdata.projectRole" => Roles::getRoleString($projectRole)]); - } + session(["userdata.projectRole" => '']); + if ($projectRole != '') { + session(["userdata.projectRole" => Roles::getRoleString($projectRole)]); + } - session(["currentSprint" => ""]); - session(["currentIdeaCanvas" => ""]); - session(["lastTicketView" => ""]); - session(["lastFilterdTicketTableView" => ""]); - session(["lastFilterdTicketKanbanView" => ""]); - session(["currentWiki" => '']); - session(["lastArticle" => ""]); - - session(["currentSWOTCanvas" => ""]); - session(["currentLEANCanvas" => ""]); - session(["currentEMCanvas" => ""]); - session(["currentINSIGHTSCanvas" => ""]); - session(["currentSBCanvas" => ""]); - session(["currentRISKSCanvas" => ""]); - session(["currentEACanvas" => ""]); - session(["currentLBMCanvas" => ""]); - session(["currentOBMCanvas" => ""]); - session(["currentDBMCanvas" => ""]); - session(["currentSQCanvas" => ""]); - session(["currentCPCanvas" => ""]); - session(["currentSMCanvas" => ""]); - session(["currentRETROSCanvas" => ""]); - $this->settingsRepo->saveSetting("usersettings." . session("userdata.id") . ".lastProject", session("currentProject")); - - - $recentProjects = $this->settingsRepo->getSetting("usersettings." . session("userdata.id") . ".recentProjects"); - $recent = unserialize($recentProjects); - - if (is_array($recent) === false) { - $recent = array(); - } - $key = array_search(session("currentProject"), $recent); - if ($key !== false) { - unset($recent[$key]); - } - array_unshift($recent, session("currentProject")); + session(["currentSprint" => ""]); + session(["currentIdeaCanvas" => ""]); + session(["lastTicketView" => ""]); + session(["lastFilterdTicketTableView" => ""]); + session(["lastFilterdTicketKanbanView" => ""]); + session(["currentWiki" => '']); + session(["lastArticle" => ""]); + + session(["currentSWOTCanvas" => ""]); + session(["currentLEANCanvas" => ""]); + session(["currentEMCanvas" => ""]); + session(["currentINSIGHTSCanvas" => ""]); + session(["currentSBCanvas" => ""]); + session(["currentRISKSCanvas" => ""]); + session(["currentEACanvas" => ""]); + session(["currentLBMCanvas" => ""]); + session(["currentOBMCanvas" => ""]); + session(["currentDBMCanvas" => ""]); + session(["currentSQCanvas" => ""]); + session(["currentCPCanvas" => ""]); + session(["currentSMCanvas" => ""]); + session(["currentRETROSCanvas" => ""]); + $this->settingsRepo->saveSetting("usersettings." . session("userdata.id") . ".lastProject", session("currentProject")); + + + $recentProjects = $this->settingsRepo->getSetting("usersettings." . session("userdata.id") . ".recentProjects"); + $recent = unserialize($recentProjects); + + if (is_array($recent) === false) { + $recent = array(); + } + $key = array_search(session("currentProject"), $recent); + if ($key !== false) { + unset($recent[$key]); + } + array_unshift($recent, session("currentProject")); - $recent = array_slice($recent, 0, 20); + $recent = array_slice($recent, 0, 20); - $this->settingsRepo->saveSetting("usersettings." . session("userdata.id") . ".recentProjects", serialize($recent)); + $this->settingsRepo->saveSetting("usersettings." . session("userdata.id") . ".recentProjects", serialize($recent)); - session()->forget("projectsettings"); + session()->forget("projectsettings"); - self::dispatch_event("projects.setCurrentProject", $project); + self::dispatch_event("projects.setCurrentProject", $project); - return true; - } else { - return false; - } + return true; } else { return false; } + } else { + return false; } + } - /** - * @return void - * @throws BindingResolutionException - * - * @api + /** + * Resets the current project by clearing all session data related to the project. + * + * @return void + * */ - public function resetCurrentProject(): void - { - - session(["currentProject" => ""]); - session(["currentProjectClient" => ""]); - session(["currentProjectName" => ""]); - - session(["currentSprint" => ""]); - session(["currentIdeaCanvas" => ""]); - - session(["currentSWOTCanvas" => ""]); - session(["currentLEANCanvas" => ""]); - session(["currentEMCanvas" => ""]); - session(["currentINSIGHTSCanvas" => ""]); - session(["currentSBCanvas" => ""]); - session(["currentRISKSCanvas" => ""]); - session(["currentEACanvas" => ""]); - session(["currentLBMCanvas" => ""]); - session(["currentOBMCanvas" => ""]); - session(["currentDBMCanvas" => ""]); - session(["currentSQCanvas" => ""]); - session(["currentCPCanvas" => ""]); - session(["currentSMCanvas" => ""]); - session(["currentRETROSCanvas" => ""]); - session()->forget("projectsettings"); - - $this->settingsRepo->saveSetting("usersettings." . session("userdata.id") . ".lastProject", session("currentProject")); - - $this->setCurrentProject(); - } + public function resetCurrentProject(): void + { + session(["currentProject" => ""]); + session(["currentProjectClient" => ""]); + session(["currentProjectName" => ""]); + + session(["currentSprint" => ""]); + session(["currentIdeaCanvas" => ""]); + + session(["currentSWOTCanvas" => ""]); + session(["currentLEANCanvas" => ""]); + session(["currentEMCanvas" => ""]); + session(["currentINSIGHTSCanvas" => ""]); + session(["currentSBCanvas" => ""]); + session(["currentRISKSCanvas" => ""]); + session(["currentEACanvas" => ""]); + session(["currentLBMCanvas" => ""]); + session(["currentOBMCanvas" => ""]); + session(["currentDBMCanvas" => ""]); + session(["currentSQCanvas" => ""]); + session(["currentCPCanvas" => ""]); + session(["currentSMCanvas" => ""]); + session(["currentRETROSCanvas" => ""]); + session()->forget("projectsettings"); + + $this->settingsRepo->saveSetting("usersettings." . session("userdata.id") . ".lastProject", session("currentProject")); + + $this->setCurrentProject(); + } - /** - * @param $projectId - * @return array - * - * @api - */ - public function getUsersAssignedToProject($projectId): array - { - $users = $this->projectRepository->getUsersAssignedToProject($projectId); - - foreach ($users as $key => $user) { - - if(dtHelper()->isValidDateString($user['modified'])) { - $users[$key]['modified'] = dtHelper()->parseDbDateTime($user['modified'])->toIso8601ZuluString(); - }else{ - $users[$key]['modified'] = null; - } - } - if ($users) { - return $users; - } + /** + * Gets all the users assigned to a specific project. + * + * @param int $projectId The ID of the project. + * @return array An array of users assigned to the project. + * + * @api + */ + public function getUsersAssignedToProject($projectId): array + { + $users = $this->projectRepository->getUsersAssignedToProject($projectId); + + foreach ($users as $key => $user) { - return array(); + if(dtHelper()->isValidDateString($user['modified'])) { + $users[$key]['modified'] = dtHelper()->parseDbDateTime($user['modified'])->toIso8601ZuluString(); + }else{ + $users[$key]['modified'] = null; + } } - /* - * Checks if a user has access to a project. Either via direct assignment. Via client assignment or in case projects are available to all - * - * @param int $userId - * @param int $projectId - * @return bool - * @throws BindingResolutionException - * + if ($users) { + return $users; + } + + return array(); + } + + /** + * Checks if a user is assigned to a particular project. + * + * @param int $userId The ID of the user being checked. + * @param int $projectId The ID of the project being checked. + * @return bool Returns true if the user is assigned to the project, false otherwise. + * * @api */ - public function isUserAssignedToProject(int $userId, int $projectId): bool - { + public function isUserAssignedToProject(int $userId, int $projectId): bool + { - return $this->projectRepository->isUserAssignedToProject($userId, $projectId); - } + return $this->projectRepository->isUserAssignedToProject($userId, $projectId); + } - /** - * Checks if a user is directly assigned to a project. - * Client assignments or projects available to entire organization are not considered true. - * - * @param int $userId - * @param int $projectId - * @return bool - * @throws BindingResolutionException - * + /** + * Checks if a user is a member of a specific project. + * + * @param int $userId - The ID of the user. + * @param int $projectId - The ID of the project. + * @return bool - Returns true if the user is a member of the project, otherwise false. + * * @api */ - public function isUserMemberOfProject(int $userId, int $projectId): bool - { - return $this->projectRepository->isUserMemberOfProject($userId, $projectId); - } + public function isUserMemberOfProject(int $userId, int $projectId): bool + { + return $this->projectRepository->isUserMemberOfProject($userId, $projectId); + } - /** - * Adds a new project to the system. - * - * @param array $values An associative array containing the project details. - * - name: The name of the project. - * - details: Additional details of the project (optional, default: ''). - * - clientId: The ID of the client associated with the project. - * - hourBudget: The hour budget for the project (optional, default: 0). - * - assignedUsers: Comma-separated list of user IDs assigned to the project (optional, default: ''). - * - dollarBudget: The dollar budget for the project (optional, default: 0). - * - psettings: The settings for the project (optional, default: 'restricted'). - * - type: The type of the project (optional, default: 'project'). - * - start: The start date of the project in user format (YYYY-MM-DD). - * - end: The end date of the project in user format (YYYY-MM-DD). - * @return int|false The ID of the newly added project - * + /** + * Adds a new project. + * + * @param array $values The project data. + * - name: string (required) The name of the project. + * - details: string (optional) Additional details about the project. + * - clientId: int (required) The ID of the client associated with the project. + * - hourBudget: int (optional) The hour budget for the project (defaults to 0). + * - assignedUsers: string (optional) The list of assigned users (defaults to an empty string). + * - dollarBudget: int (optional) The dollar budget for the project (defaults to 0). + * - psettings: string (optional) The project settings (defaults to 'restricted'). + * - type: string (fixed value 'project') The type of the project. + * - start: string|null The start date of the project in user format or null. + * - end: string|null The end date of the project in user format or null. + * @return int|false The ID of the added project, or false if the project could not be added. + * * @api */ - public function addProject(array $values): int|false - { - $values = array( - "name" => $values['name'], - 'details' => $values['details'] ?? '', - 'clientId' => $values['clientId'], - 'hourBudget' => $values['hourBudget'] ?? 0, - 'assignedUsers' => $values['assignedUsers'] ?? '', - 'dollarBudget' => $values['dollarBudget'] ?? 0, - 'psettings' => $values['psettings'] ?? 'restricted', - 'type' => "project", - 'start' => $values['start'], - 'end' => $values['end'], - ); - if ($values['start'] != null) { - $values['start'] = format(value: $values['start'], fromFormat: FromFormat::UserDateStartOfDay)->isoDateTime(); - } - if ($values['end'] != null) { - $values['end'] = format($values['end'], fromFormat: FromFormat::UserDateEndOfDay)->isoDateTime(); - } - return $this->projectRepository->addProject($values); + public function addProject(array $values): int|false + { + $values = array( + "name" => $values['name'], + 'details' => $values['details'] ?? '', + 'clientId' => $values['clientId'], + 'hourBudget' => $values['hourBudget'] ?? 0, + 'assignedUsers' => $values['assignedUsers'] ?? '', + 'dollarBudget' => $values['dollarBudget'] ?? 0, + 'psettings' => $values['psettings'] ?? 'restricted', + 'type' => "project", + 'start' => $values['start'], + 'end' => $values['end'], + ); + if ($values['start'] != null) { + $values['start'] = format(value: $values['start'], fromFormat: FromFormat::UserDateStartOfDay)->isoDateTime(); } + if ($values['end'] != null) { + $values['end'] = format($values['end'], fromFormat: FromFormat::UserDateEndOfDay)->isoDateTime(); + } + return $this->projectRepository->addProject($values); + } - /** - * @param int $projectId - * @param int $clientId - * @param string $projectName - * @param string $userStartDate - * @param bool $assignSameUsers - * @return bool|int - * @throws BindingResolutionException - * + /** + * Duplicates a project with the specified details. + * + * @param int $projectId The ID of the project to duplicate. + * @param int $clientId The ID of the client for the duplicate project. + * @param string $projectName The name of the duplicate project. + * @param string $userStartDate The start date of the duplicate project in the format specified by the language setting. + * @param bool $assignSameUsers Whether to assign the same users as the original project. + * @return bool|int Returns true if the project was successfully duplicated, or the ID of the new project if successful. + * * @api */ - public function duplicateProject(int $projectId, int $clientId, string $projectName, string $userStartDate, bool $assignSameUsers): bool|int - { - - $startDate = datetime::createFromFormat($this->language->__("language.dateformat"), $userStartDate); - - //Ignoring - //Comments, files, timesheets, personalCalendar EventDispatcher - $oldProjectId = $projectId; - - //Copy project Entry - $projectValues = $this->getProject($projectId); - - $copyProject = array( - "name" => $projectName, - "clientId" => $clientId, - "details" => $projectValues['details'], - "state" => $projectValues['state'], - "hourBudget" => $projectValues['hourBudget'], - "dollarBudget" => $projectValues['dollarBudget'], - "menuType" => $projectValues['menuType'], - 'psettings' => $projectValues['psettings'], - 'assignedUsers' => array(), - ); + public function duplicateProject(int $projectId, int $clientId, string $projectName, string $userStartDate, bool $assignSameUsers): bool|int + { - if ($assignSameUsers) { - $projectUsers = $this->projectRepository->getUsersAssignedToProject($projectId); + $startDate = datetime::createFromFormat($this->language->__("language.dateformat"), $userStartDate); - foreach ($projectUsers as $user) { - $copyProject['assignedUsers'][] = array("id" => $user['id'], "projectRole" => $user['projectRole']); - } + //Ignoring + //Comments, files, timesheets, personalCalendar EventDispatcher + $oldProjectId = $projectId; + + //Copy project Entry + $projectValues = $this->getProject($projectId); + + $copyProject = array( + "name" => $projectName, + "clientId" => $clientId, + "details" => $projectValues['details'], + "state" => $projectValues['state'], + "hourBudget" => $projectValues['hourBudget'], + "dollarBudget" => $projectValues['dollarBudget'], + "menuType" => $projectValues['menuType'], + 'psettings' => $projectValues['psettings'], + 'assignedUsers' => array(), + ); + + if ($assignSameUsers) { + $projectUsers = $this->projectRepository->getUsersAssignedToProject($projectId); + + foreach ($projectUsers as $user) { + $copyProject['assignedUsers'][] = array("id" => $user['id'], "projectRole" => $user['projectRole']); } + } - $projectSettingsKeys = array("retrolabels", "ticketlabels", "idealabels"); - $newProjectId = $this->projectRepository->addProject($copyProject); + $projectSettingsKeys = array("retrolabels", "ticketlabels", "idealabels"); + $newProjectId = $this->projectRepository->addProject($copyProject); - //ProjectSettings - foreach ($projectSettingsKeys as $key) { - $setting = $this->settingsRepo->getSetting("projectsettings." . $projectId . "." . $key); + //ProjectSettings + foreach ($projectSettingsKeys as $key) { + $setting = $this->settingsRepo->getSetting("projectsettings." . $projectId . "." . $key); - if ($setting !== false) { - $this->settingsRepo->saveSetting("projectsettings." . $newProjectId . "." . $key, $setting); - } + if ($setting !== false) { + $this->settingsRepo->saveSetting("projectsettings." . $newProjectId . "." . $key, $setting); } + } - //Duplicate all todos without dependent Ticket set - $allTickets = $this->ticketRepository->getAllByProjectId($projectId); + //Duplicate all todos without dependent Ticket set + $allTickets = $this->ticketRepository->getAllByProjectId($projectId); - //Checks the oldest editFrom date and makes this the start date - $oldestTicket = new DateTime(); + //Checks the oldest editFrom date and makes this the start date + $oldestTicket = new DateTime(); - foreach ($allTickets as $ticket) { - if ($ticket->editFrom != null && $ticket->editFrom != "" && $ticket->editFrom != "0000-00-00 00:00:00" && $ticket->editFrom != "1969-12-31 00:00:00") { - $ticketDateTimeObject = datetime::createFromFormat("Y-m-d H:i:s", $ticket->editFrom); - if ($oldestTicket > $ticketDateTimeObject) { - $oldestTicket = $ticketDateTimeObject; - } + foreach ($allTickets as $ticket) { + if ($ticket->editFrom != null && $ticket->editFrom != "" && $ticket->editFrom != "0000-00-00 00:00:00" && $ticket->editFrom != "1969-12-31 00:00:00") { + $ticketDateTimeObject = datetime::createFromFormat("Y-m-d H:i:s", $ticket->editFrom); + if ($oldestTicket > $ticketDateTimeObject) { + $oldestTicket = $ticketDateTimeObject; } + } - if ($ticket->dateToFinish != null && $ticket->dateToFinish != "" && $ticket->dateToFinish != "0000-00-00 00:00:00" && $ticket->dateToFinish != "1969-12-31 00:00:00") { - $ticketDateTimeObject = datetime::createFromFormat("Y-m-d H:i:s", $ticket->dateToFinish); - if ($oldestTicket > $ticketDateTimeObject) { - $oldestTicket = $ticketDateTimeObject; - } + if ($ticket->dateToFinish != null && $ticket->dateToFinish != "" && $ticket->dateToFinish != "0000-00-00 00:00:00" && $ticket->dateToFinish != "1969-12-31 00:00:00") { + $ticketDateTimeObject = datetime::createFromFormat("Y-m-d H:i:s", $ticket->dateToFinish); + if ($oldestTicket > $ticketDateTimeObject) { + $oldestTicket = $ticketDateTimeObject; } } + } - $projectStart = new DateTime($startDate); - $interval = $oldestTicket->diff($projectStart); + $projectStart = new DateTime($startDate); + $interval = $oldestTicket->diff($projectStart); - //oldId = > newId - $ticketIdList = array(); + //oldId = > newId + $ticketIdList = array(); - //Iterate through root tickets first - foreach ($allTickets as $ticket) { - if ($ticket->milestoneid == 0 || $ticket->milestoneid == "" || $ticket->milestoneid == null) { - $dateToFinishValue = ""; - if ($ticket->dateToFinish != null && $ticket->dateToFinish != "" && $ticket->dateToFinish != "0000-00-00 00:00:00" && $ticket->dateToFinish != "1969-12-31 00:00:00") { - $dateToFinish = new DateTime($ticket->dateToFinish); - $dateToFinish->add($interval); - $dateToFinishValue = $dateToFinish->format('Y-m-d H:i:s'); - } + //Iterate through root tickets first + foreach ($allTickets as $ticket) { + if ($ticket->milestoneid == 0 || $ticket->milestoneid == "" || $ticket->milestoneid == null) { + $dateToFinishValue = ""; + if ($ticket->dateToFinish != null && $ticket->dateToFinish != "" && $ticket->dateToFinish != "0000-00-00 00:00:00" && $ticket->dateToFinish != "1969-12-31 00:00:00") { + $dateToFinish = new DateTime($ticket->dateToFinish); + $dateToFinish->add($interval); + $dateToFinishValue = $dateToFinish->format('Y-m-d H:i:s'); + } - $editFromValue = ""; - if ($ticket->editFrom != null && $ticket->editFrom != "" && $ticket->editFrom != "0000-00-00 00:00:00" && $ticket->editFrom != "1969-12-31 00:00:00") { - $editFrom = new DateTime($ticket->editFrom); - $editFrom->add($interval); - $editFromValue = $editFrom->format('Y-m-d H:i:s'); - } + $editFromValue = ""; + if ($ticket->editFrom != null && $ticket->editFrom != "" && $ticket->editFrom != "0000-00-00 00:00:00" && $ticket->editFrom != "1969-12-31 00:00:00") { + $editFrom = new DateTime($ticket->editFrom); + $editFrom->add($interval); + $editFromValue = $editFrom->format('Y-m-d H:i:s'); + } - $editToValue = ""; - if ($ticket->editTo != null && $ticket->editTo != "" && $ticket->editTo != "0000-00-00 00:00:00" && $ticket->editTo != "1969-12-31 00:00:00") { - $editTo = new DateTime($ticket->editTo); - $editTo->add($interval); - $editToValue = $editTo->format('Y-m-d H:i:s'); - } + $editToValue = ""; + if ($ticket->editTo != null && $ticket->editTo != "" && $ticket->editTo != "0000-00-00 00:00:00" && $ticket->editTo != "1969-12-31 00:00:00") { + $editTo = new DateTime($ticket->editTo); + $editTo->add($interval); + $editToValue = $editTo->format('Y-m-d H:i:s'); + } - $ticketValues = array( - 'headline' => $ticket->headline, - 'type' => $ticket->type, - 'description' => $ticket->description, - 'projectId' => $newProjectId, - 'editorId' => $ticket->editorId, - 'userId' => session("userdata.id"), - 'date' => date("Y-m-d H:i:s"), - 'dateToFinish' => $dateToFinishValue, - 'status' => $ticket->status, - 'storypoints' => $ticket->storypoints, - 'hourRemaining' => $ticket->hourRemaining, - 'planHours' => $ticket->planHours, - 'priority' => $ticket->priority, - 'sprint' => "", - 'acceptanceCriteria' => $ticket->acceptanceCriteria, - 'tags' => $ticket->tags, - 'editFrom' => $editFromValue, - 'editTo' => $editToValue, - 'dependingTicketId' => "", - 'milestoneid' => '', - ); + $ticketValues = array( + 'headline' => $ticket->headline, + 'type' => $ticket->type, + 'description' => $ticket->description, + 'projectId' => $newProjectId, + 'editorId' => $ticket->editorId, + 'userId' => session("userdata.id"), + 'date' => date("Y-m-d H:i:s"), + 'dateToFinish' => $dateToFinishValue, + 'status' => $ticket->status, + 'storypoints' => $ticket->storypoints, + 'hourRemaining' => $ticket->hourRemaining, + 'planHours' => $ticket->planHours, + 'priority' => $ticket->priority, + 'sprint' => "", + 'acceptanceCriteria' => $ticket->acceptanceCriteria, + 'tags' => $ticket->tags, + 'editFrom' => $editFromValue, + 'editTo' => $editToValue, + 'dependingTicketId' => "", + 'milestoneid' => '', + ); - $newTicketId = $this->ticketRepository->addTicket($ticketValues); + $newTicketId = $this->ticketRepository->addTicket($ticketValues); - $ticketIdList[$ticket->id] = $newTicketId; - } + $ticketIdList[$ticket->id] = $newTicketId; } + } - //Iterate through childObjects - foreach ($allTickets as $ticket) { - if ($ticket->milestoneid != "" && $ticket->milestoneid > 0) { - $dateToFinishValue = ""; - if ($ticket->dateToFinish != null && $ticket->dateToFinish != "" && $ticket->dateToFinish != "0000-00-00 00:00:00" && $ticket->dateToFinish != "1969-12-31 00:00:00") { - $dateToFinish = new DateTime($ticket->dateToFinish); - $dateToFinish->add($interval); - $dateToFinishValue = $dateToFinish->format('Y-m-d H:i:s'); - } + //Iterate through childObjects + foreach ($allTickets as $ticket) { + if ($ticket->milestoneid != "" && $ticket->milestoneid > 0) { + $dateToFinishValue = ""; + if ($ticket->dateToFinish != null && $ticket->dateToFinish != "" && $ticket->dateToFinish != "0000-00-00 00:00:00" && $ticket->dateToFinish != "1969-12-31 00:00:00") { + $dateToFinish = new DateTime($ticket->dateToFinish); + $dateToFinish->add($interval); + $dateToFinishValue = $dateToFinish->format('Y-m-d H:i:s'); + } - $editFromValue = ""; - if ($ticket->editFrom != null && $ticket->editFrom != "" && $ticket->editFrom != "0000-00-00 00:00:00" && $ticket->editFrom != "1969-12-31 00:00:00") { - $editFrom = new DateTime($ticket->editFrom); - $editFrom->add($interval); - $editFromValue = $editFrom->format('Y-m-d H:i:s'); - } + $editFromValue = ""; + if ($ticket->editFrom != null && $ticket->editFrom != "" && $ticket->editFrom != "0000-00-00 00:00:00" && $ticket->editFrom != "1969-12-31 00:00:00") { + $editFrom = new DateTime($ticket->editFrom); + $editFrom->add($interval); + $editFromValue = $editFrom->format('Y-m-d H:i:s'); + } - $editToValue = ""; - if ($ticket->editTo != null && $ticket->editTo != "" && $ticket->editTo != "0000-00-00 00:00:00" && $ticket->editTo != "1969-12-31 00:00:00") { - $editTo = new DateTime($ticket->editTo); - $editTo->add($interval); - $editToValue = $editTo->format('Y-m-d H:i:s'); - } + $editToValue = ""; + if ($ticket->editTo != null && $ticket->editTo != "" && $ticket->editTo != "0000-00-00 00:00:00" && $ticket->editTo != "1969-12-31 00:00:00") { + $editTo = new DateTime($ticket->editTo); + $editTo->add($interval); + $editToValue = $editTo->format('Y-m-d H:i:s'); + } - $ticketValues = array( - 'headline' => $ticket->headline, - 'type' => $ticket->type, - 'description' => $ticket->description, - 'projectId' => $newProjectId, - 'editorId' => $ticket->editorId, - 'userId' => session("userdata.id"), - 'date' => date("Y-m-d H:i:s"), - 'dateToFinish' => $dateToFinishValue, - 'status' => $ticket->status, - 'storypoints' => $ticket->storypoints, - 'hourRemaining' => $ticket->hourRemaining, - 'planHours' => $ticket->planHours, - 'priority' => $ticket->priority, - 'sprint' => "", - 'acceptanceCriteria' => $ticket->acceptanceCriteria, - 'tags' => $ticket->tags, - 'editFrom' => $editFromValue, - 'editTo' => $editToValue, - 'milestoneid' => $ticketIdList[$ticket->milestoneid], - ); + $ticketValues = array( + 'headline' => $ticket->headline, + 'type' => $ticket->type, + 'description' => $ticket->description, + 'projectId' => $newProjectId, + 'editorId' => $ticket->editorId, + 'userId' => session("userdata.id"), + 'date' => date("Y-m-d H:i:s"), + 'dateToFinish' => $dateToFinishValue, + 'status' => $ticket->status, + 'storypoints' => $ticket->storypoints, + 'hourRemaining' => $ticket->hourRemaining, + 'planHours' => $ticket->planHours, + 'priority' => $ticket->priority, + 'sprint' => "", + 'acceptanceCriteria' => $ticket->acceptanceCriteria, + 'tags' => $ticket->tags, + 'editFrom' => $editFromValue, + 'editTo' => $editToValue, + 'milestoneid' => $ticketIdList[$ticket->milestoneid], + ); - $newTicketId = $this->ticketRepository->addTicket($ticketValues); + $newTicketId = $this->ticketRepository->addTicket($ticketValues); - $ticketIdList[$ticket->id] = $newTicketId; - } + $ticketIdList[$ticket->id] = $newTicketId; } + } - //Ideas - $this->duplicateCanvas( - repository: IdeaRepository::class, - originalProjectId: $projectId, - newProjectId: $newProjectId - ); + //Ideas + $this->duplicateCanvas( + repository: IdeaRepository::class, + originalProjectId: $projectId, + newProjectId: $newProjectId + ); + + $this->duplicateCanvas( + repository: GoalcanvaRepository::class, + originalProjectId: $projectId, + newProjectId: $newProjectId + ); + + $this->duplicateCanvas( + repository: Wiki::class, + originalProjectId: $projectId, + newProjectId: $newProjectId, + canvasTypeName: "wiki" + ); + + $this->duplicateCanvas( + repository: LeancanvaRepository::class, + originalProjectId: $projectId, + newProjectId: $newProjectId + ); + + return $newProjectId; + } - $this->duplicateCanvas( - repository: GoalcanvaRepository::class, - originalProjectId: $projectId, - newProjectId: $newProjectId - ); + /** + * Duplicate a canvas from one project to another. + * + * @param string $repository The repository class to use for CRUD operations + * @param int $originalProjectId The ID of the original project + * @param int $newProjectId The ID of the new project + * @param string $canvasTypeName The canvas type name (optional) + * @return bool True if the canvas is duplicated successfully, false otherwise + * + * @api + */ + private function duplicateCanvas(string $repository, int $originalProjectId, int $newProjectId, string $canvasTypeName = ''): bool + { - $this->duplicateCanvas( - repository: Wiki::class, - originalProjectId: $projectId, - newProjectId: $newProjectId, - canvasTypeName: "wiki" - ); + $canvasIdList = []; + $canvasRepo = app()->make($repository); + $canvasBoards = $canvasRepo->getAllCanvas($originalProjectId, $canvasTypeName); - $this->duplicateCanvas( - repository: LeancanvaRepository::class, - originalProjectId: $projectId, - newProjectId: $newProjectId + foreach ($canvasBoards as $canvas) { + $canvasValues = array( + "title" => $canvas['title'], + "author" => session("userdata.id"), + "projectId" => $newProjectId, + "description" => $canvas['description'] ?? '', ); - return $newProjectId; - } + $newCanvasId = $canvasRepo->addCanvas($canvasValues, $canvasTypeName); + $canvasIdList[$canvas['id']] = $newCanvasId; - /** - * @param string $repository - * @param int $originalProjectId - * @param int $newProjectId - * @param string $canvasTypeName - * @return bool - * @throws BindingResolutionException - * - * @api - */ - private function duplicateCanvas(string $repository, int $originalProjectId, int $newProjectId, string $canvasTypeName = ''): bool - { - - $canvasIdList = []; - $canvasRepo = app()->make($repository); - $canvasBoards = $canvasRepo->getAllCanvas($originalProjectId, $canvasTypeName); - - foreach ($canvasBoards as $canvas) { - $canvasValues = array( - "title" => $canvas['title'], - "author" => session("userdata.id"), - "projectId" => $newProjectId, - "description" => $canvas['description'] ?? '', - ); + $canvasItems = $canvasRepo->getCanvasItemsById($canvas['id']); - $newCanvasId = $canvasRepo->addCanvas($canvasValues, $canvasTypeName); - $canvasIdList[$canvas['id']] = $newCanvasId; - - $canvasItems = $canvasRepo->getCanvasItemsById($canvas['id']); - - if ($canvasItems && count($canvasItems) > 0) { - //Build parent Array - //oldId => newId - $idMap = array(); - - foreach ($canvasItems as $item) { - - $milestoneId = ""; - if (isset($idMap[$item['milestoneId']])) { - $milestoneId = $idMap[$item['milestoneId']]; - } - - $canvasItemValues = array( - "description" => $item['description'] ?? '', - "assumptions" => $item['assumptions'] ?? '', - "data" => $item['data'] ?? '', - "conclusion" => $item['conclusion'] ?? '', - "box" => $item['box'] ?? '', - "author" => $item['author'] ?? '', - - "canvasId" => $newCanvasId, - "sortindex" => $item['sortindex'] ?? '', - "status" => $item['status'] ?? '', - "relates" => $item['relates'] ?? '', - "milestoneId" => $milestoneId, - "title" => $item['title'] ?? '', - "parent" => $item['parent'] ?? '', - "featured" => $item['featured'] ?? '', - "tags" => $item['tags'] ?? '', - "kpi" => $item['kpi'] ?? '', - "data1" => $item['data1'] ?? '', - "data2" => $item['data2'] ?? '', - "data3" => $item['data3'] ?? '', - "data4" => $item['data4'] ?? '', - "data5" => $item['data5'] ?? '', - "startDate" => '', - "endDate" => '', - "setting" => $item['setting'] ?? '', - "metricType" => $item['metricType'] ?? '', - "startValue" => '', - "currentValue" => '', - "endValue" => $item['endValue'] ?? '', - "impact" => $item['impact'] ?? '', - "effort" => $item['effort'] ?? '', - "probability" => $item['probability'] ?? '', - "action" => $item['action'] ?? '', - "assignedTo" => $item['assignedTo'] ?? '', - ); - - $newId = $canvasRepo->addCanvasItem($canvasItemValues); - $idMap[$item['id']] = $newId; - } + if ($canvasItems && count($canvasItems) > 0) { + //Build parent Array + //oldId => newId + $idMap = array(); - //Now fix relates to and parent relationships - $newCanvasItems = $canvasRepo->getCanvasItemsById($newCanvasId); - foreach ($canvasItems as $newItem) { - $newCanvasItemValues = array( - "relates" => $idMap[$newItem['relates']] ?? '', - "parent" => $idMap[$newItem['parent']] ?? '', - ); + foreach ($canvasItems as $item) { - $canvasRepo->patchCanvasItem($newItem['id'], $newCanvasItemValues); + $milestoneId = ""; + if (isset($idMap[$item['milestoneId']])) { + $milestoneId = $idMap[$item['milestoneId']]; } + + $canvasItemValues = array( + "description" => $item['description'] ?? '', + "assumptions" => $item['assumptions'] ?? '', + "data" => $item['data'] ?? '', + "conclusion" => $item['conclusion'] ?? '', + "box" => $item['box'] ?? '', + "author" => $item['author'] ?? '', + + "canvasId" => $newCanvasId, + "sortindex" => $item['sortindex'] ?? '', + "status" => $item['status'] ?? '', + "relates" => $item['relates'] ?? '', + "milestoneId" => $milestoneId, + "title" => $item['title'] ?? '', + "parent" => $item['parent'] ?? '', + "featured" => $item['featured'] ?? '', + "tags" => $item['tags'] ?? '', + "kpi" => $item['kpi'] ?? '', + "data1" => $item['data1'] ?? '', + "data2" => $item['data2'] ?? '', + "data3" => $item['data3'] ?? '', + "data4" => $item['data4'] ?? '', + "data5" => $item['data5'] ?? '', + "startDate" => '', + "endDate" => '', + "setting" => $item['setting'] ?? '', + "metricType" => $item['metricType'] ?? '', + "startValue" => '', + "currentValue" => '', + "endValue" => $item['endValue'] ?? '', + "impact" => $item['impact'] ?? '', + "effort" => $item['effort'] ?? '', + "probability" => $item['probability'] ?? '', + "action" => $item['action'] ?? '', + "assignedTo" => $item['assignedTo'] ?? '', + ); + + $newId = $canvasRepo->addCanvasItem($canvasItemValues); + $idMap[$item['id']] = $newId; } - } - return true; - } + //Now fix relates to and parent relationships + $newCanvasItems = $canvasRepo->getCanvasItemsById($newCanvasId); + foreach ($canvasItems as $newItem) { + $newCanvasItemValues = array( + "relates" => $idMap[$newItem['relates']] ?? '', + "parent" => $idMap[$newItem['parent']] ?? '', + ); - /** - * @param $id - * @return array - * - * @api - */ - public function getProjectUserRelation($id): array - { - return $this->projectRepository->getProjectUserRelation($id); + $canvasRepo->patchCanvasItem($newItem['id'], $newCanvasItemValues); + } + } } - /** - * @param $id - * @param $params - * @return bool - * + return true; + } + + /** + * Retrieves the relation between a project and its users. + * + * @param int $id The ID of the project. + * @return array The relation between the project and its users. + * * @api */ - public function patch($id, $params): bool - { - return $this->projectRepository->patch($id, $params); - } + public function getProjectUserRelation($id): array + { + return $this->projectRepository->getProjectUserRelation($id); + } - /** - * @param $id - * @return mixed - * @throws BindingResolutionException - * + /** + * Updates a project with the given parameters. + * + * @param int $id The ID of the project. + * @param array $params The parameters to update the project. + * @return bool Returns true if the project was successfully updated, false otherwise. + * * @api */ - public function getProjectAvatar($id): mixed - { - $avatar = $this->projectRepository->getProjectAvatar($id); - $avatar = self::dispatch_filter("afterGettingAvatar", $avatar, array("projectId" => $id)); - return $avatar; - } + public function patch($id, $params): bool + { + return $this->projectRepository->patch($id, $params); + } - /** - * @param $file - * @param $project - * @return null - * @throws BindingResolutionException - * + /** + * Retrieves the avatar for a project. + * + * @param mixed $id The ID of the project. + * @return mixed The avatar for the project. + * * @api */ - public function setProjectAvatar($file, $project): bool - { - return $this->projectRepository->setPicture($file, $project); - } + public function getProjectAvatar($id): mixed + { + $avatar = $this->projectRepository->getProjectAvatar($id); + $avatar = self::dispatch_filter("afterGettingAvatar", $avatar, array("projectId" => $id)); + return $avatar; + } - public function getAllProjects() - { - return $this->projectRepository->getAll(); - } + /** + * Sets the avatar for a project. + * + * @param mixed $file The file containing the avatar. + * @param mixed $project The project object. + * @return bool Indicates whether the avatar was successfully set. + * + * @api + */ + public function setProjectAvatar($file, $project): bool + { + return $this->projectRepository->setPicture($file, $project); + } - /** - * @param $projectId - * @return array - * @throws BindingResolutionException - * + /** + * Retrieves all projects. + * + * @return array The projects. * @api */ - public function getProjectSetupChecklist($projectId): array - { - $progressSteps = array( - "define" => array( - "title" => "label.define", - "description" => "checklist.define.description", - "tasks" => array( - "description" => array( - "title" => "label.projectDescription", - "status" => "", - "link" => BASE_URL . "/projects/showProject/" . session("currentProject") . "", - "description" => "checklist.define.tasks.description", - ), - "defineTeam" => array( - "title" => "label.defineTeam", - "status" => "", - "link" => BASE_URL . "/projects/showProject/" . session("currentProject") . "#team", - "description" => "checklist.define.tasks.defineTeam", - ), - "createBlueprint" => array( - "title" => "label.createBlueprint", - "status" => "", - "link" => BASE_URL . "/strategy/showBoards/", - "description" => "checklist.define.tasks.createBlueprint", - ), + public function getAllProjects() + { + return $this->projectRepository->getAll(); + } + + /** + * Retrieves the setup checklist for a project. + * + * @param int $projectId The ID of the project. + * @return array The setup checklist for the project. + * + */ + public function getProjectSetupChecklist($projectId): array + { + $progressSteps = array( + "define" => array( + "title" => "label.define", + "description" => "checklist.define.description", + "tasks" => array( + "description" => array( + "title" => "label.projectDescription", + "status" => "", + "link" => BASE_URL . "/projects/showProject/" . session("currentProject") . "", + "description" => "checklist.define.tasks.description", + ), + "defineTeam" => array( + "title" => "label.defineTeam", + "status" => "", + "link" => BASE_URL . "/projects/showProject/" . session("currentProject") . "#team", + "description" => "checklist.define.tasks.defineTeam", + ), + "createBlueprint" => array( + "title" => "label.createBlueprint", + "status" => "", + "link" => BASE_URL . "/strategy/showBoards/", + "description" => "checklist.define.tasks.createBlueprint", ), - "status" => '', ), - "goals" => array( - "title" => "label.setGoals", - "description" => "checklist.goals.description", - "tasks" => array( - "setGoals" => array( - "title" => "label.setGoals", - "status" => "", - "link" => BASE_URL . "/goalcanvas/dashboard", - "description" => "checklist.goals.tasks.setGoals", - ), + "status" => '', + ), + "goals" => array( + "title" => "label.setGoals", + "description" => "checklist.goals.description", + "tasks" => array( + "setGoals" => array( + "title" => "label.setGoals", + "status" => "", + "link" => BASE_URL . "/goalcanvas/dashboard", + "description" => "checklist.goals.tasks.setGoals", ), - "status" => '', ), - "timeline" => array( - "title" => "label.setTimeline", - "description" => "checklist.timeline.description", - "tasks" => array( - "createMilestones" => array( - "title" => "label.createMilestones", - "status" => "", - "link" => BASE_URL . "/tickets/roadmap", - "description" => "checklist.timeline.tasks.createMilestones", - ), - + "status" => '', + ), + "timeline" => array( + "title" => "label.setTimeline", + "description" => "checklist.timeline.description", + "tasks" => array( + "createMilestones" => array( + "title" => "label.createMilestones", + "status" => "", + "link" => BASE_URL . "/tickets/roadmap", + "description" => "checklist.timeline.tasks.createMilestones", ), - "status" => '', + ), - "implementation" => array( - "title" => "label.implement", - "description" => "checklist.implementation.description", - "tasks" => array( - "createTasks" => array( - "title" => "label.createTasks", - "status" => "", "link" => BASE_URL . "/tickets/showAll", - "description" => "checklist.implementation.tasks.createTasks ", - ), - "finish80percent" => array( - "title" => "label.finish80percent", - "status" => "", - "link" => BASE_URL . "/reports/show", - "description" => "checklist.implementation.tasks.finish80percent", - ), + "status" => '', + ), + "implementation" => array( + "title" => "label.implement", + "description" => "checklist.implementation.description", + "tasks" => array( + "createTasks" => array( + "title" => "label.createTasks", + "status" => "", "link" => BASE_URL . "/tickets/showAll", + "description" => "checklist.implementation.tasks.createTasks ", + ), + "finish80percent" => array( + "title" => "label.finish80percent", + "status" => "", + "link" => BASE_URL . "/reports/show", + "description" => "checklist.implementation.tasks.finish80percent", ), - "status" => '', ), - ); - - //Todo determine tasks that are done. - $project = $this->getProject($projectId); - //Project Description - if ($project['details'] != '') { - $progressSteps["define"]["tasks"]["description"]["status"] = "done"; - } + "status" => '', + ), + ); + + //Todo determine tasks that are done. + $project = $this->getProject($projectId); + //Project Description + if ($project['details'] != '') { + $progressSteps["define"]["tasks"]["description"]["status"] = "done"; + } - /* - if ($project['numUsers'] > 1) { - $progressSteps["define"]["tasks"]["defineTeam"]["status"] = "done"; - } + /* + if ($project['numUsers'] > 1) { + $progressSteps["define"]["tasks"]["defineTeam"]["status"] = "done"; + } - if ($project['numDefinitionCanvas'] >= 1) { - $progressSteps["define"]["tasks"]["createBlueprint"]["status"] = "done"; - }*/ + if ($project['numDefinitionCanvas'] >= 1) { + $progressSteps["define"]["tasks"]["createBlueprint"]["status"] = "done"; + }*/ - $goals = app()->make(GoalcanvaRepository::class); - $allCanvas = $goals->getAllCanvas($projectId); + $goals = app()->make(GoalcanvaRepository::class); + $allCanvas = $goals->getAllCanvas($projectId); - $totalGoals = 0; - foreach ($allCanvas as $goalsCanvas) { - $totalGoals = $totalGoals + $goalsCanvas['boxItems']; - } - if ($totalGoals > 0) { - $progressSteps["define"]["goals"]["setGoals"]["status"] = "done"; - } + $totalGoals = 0; + foreach ($allCanvas as $goalsCanvas) { + $totalGoals = $totalGoals + $goalsCanvas['boxItems']; + } + if ($totalGoals > 0) { + $progressSteps["define"]["goals"]["setGoals"]["status"] = "done"; + } - /* - if ($project['numberMilestones'] >= 1) { - $progressSteps["timeline"]["tasks"]["createMilestones"]["status"] = "done"; - } + /* + if ($project['numberMilestones'] >= 1) { + $progressSteps["timeline"]["tasks"]["createMilestones"]["status"] = "done"; + } - if ($project['numberOfTickets'] >= 1) { - $progressSteps["implementation"]["tasks"]["createTasks"]["status"] = "done"; - }*/ + if ($project['numberOfTickets'] >= 1) { + $progressSteps["implementation"]["tasks"]["createTasks"]["status"] = "done"; + }*/ - $percentDone = $this->getProjectProgress($projectId); - if ($percentDone['percent'] >= 80) { - $progressSteps["implementation"]["tasks"]["finish80percent"]["status"] = "done"; - } + $percentDone = $this->getProjectProgress($projectId); + if ($percentDone['percent'] >= 80) { + $progressSteps["implementation"]["tasks"]["finish80percent"]["status"] = "done"; + } - //Add overrides - if (!$stepsCompleted = $this->settingsRepo->getSetting("projectsettings.$projectId.stepsComplete")) { - $stepsCompleted = []; - } else { - $stepsCompleted = unserialize($stepsCompleted); - } + //Add overrides + if (!$stepsCompleted = $this->settingsRepo->getSetting("projectsettings.$projectId.stepsComplete")) { + $stepsCompleted = []; + } else { + $stepsCompleted = unserialize($stepsCompleted); + } - $stepsCompleted = array_map(fn ($status) => 'done', $stepsCompleted); - - $halfStep = (1 / count($progressSteps)) / 2 * 100; - $position = 0; - $debug = []; - foreach ($progressSteps as $name => $step) { - // set the "left" css position for the step on the progress bar - $progressSteps[$name]['positionLeft'] = ($position++ / count($progressSteps) * 100) + $halfStep; - - // set the status based on the stepsCompleted setting - data_set( - $progressSteps, - "$name.tasks", - collect(data_get($progressSteps, "$name.tasks")) - ->map(function ($task, $key) use ($stepsCompleted) { - $task['status'] = $stepsCompleted[$key] ?? ''; - return $task; - }) - ->toArray() - ); + $stepsCompleted = array_map(fn ($status) => 'done', $stepsCompleted); - // check for any open tasks - if (in_array('', data_get($progressSteps, "$name.tasks.*.status"))) { - if ( - $name == array_key_first($progressSteps) - || ($previousValue['stepType'] ?? '') == 'complete' - ) { - $progressSteps[$name]['stepType'] = 'current'; - } else { - $progressSteps[$name]['stepType'] = ''; - } + $halfStep = (1 / count($progressSteps)) / 2 * 100; + $position = 0; + $debug = []; + foreach ($progressSteps as $name => $step) { + // set the "left" css position for the step on the progress bar + $progressSteps[$name]['positionLeft'] = ($position++ / count($progressSteps) * 100) + $halfStep; - $progressSteps[$name]['status'] = ''; - $previousValue = $progressSteps[$name]; - continue; - } + // set the status based on the stepsCompleted setting + data_set( + $progressSteps, + "$name.tasks", + collect(data_get($progressSteps, "$name.tasks")) + ->map(function ($task, $key) use ($stepsCompleted) { + $task['status'] = $stepsCompleted[$key] ?? ''; + return $task; + }) + ->toArray() + ); - // otherwise, set the step as completed - $progressSteps[$name]['status'] = 'done'; + // check for any open tasks + if (in_array('', data_get($progressSteps, "$name.tasks.*.status"))) { if ( - !in_array($previousValue['stepType'] ?? null, ['current', '']) - || $name == array_key_first($progressSteps) + $name == array_key_first($progressSteps) + || ($previousValue['stepType'] ?? '') == 'complete' ) { - $progressSteps[$name]['stepType'] = 'complete'; + $progressSteps[$name]['stepType'] = 'current'; } else { $progressSteps[$name]['stepType'] = ''; } + + $progressSteps[$name]['status'] = ''; $previousValue = $progressSteps[$name]; + continue; } - // Set the Percentage done of the progress Bar - $numberDone = count(array_filter(data_get($progressSteps, '*.stepType'), fn ($status) => $status == 'complete')); - $stepsTotal = count($progressSteps); - $percentDone = $numberDone == $stepsTotal ? 100 : $numberDone / $stepsTotal * 100 + $halfStep; - - return [ - $progressSteps, - $percentDone, - ]; + // otherwise, set the step as completed + $progressSteps[$name]['status'] = 'done'; + if ( + !in_array($previousValue['stepType'] ?? null, ['current', '']) + || $name == array_key_first($progressSteps) + ) { + $progressSteps[$name]['stepType'] = 'complete'; + } else { + $progressSteps[$name]['stepType'] = ''; + } + $previousValue = $progressSteps[$name]; } + // Set the Percentage done of the progress Bar + $numberDone = count(array_filter(data_get($progressSteps, '*.stepType'), fn ($status) => $status == 'complete')); + $stepsTotal = count($progressSteps); + $percentDone = $numberDone == $stepsTotal ? 100 : $numberDone / $stepsTotal * 100 + $halfStep; - /** - * @param $stepsComplete - * @param $projectId - * @return void - * - * @api - */ - public function updateProjectProgress($stepsComplete, $projectId): void - { - if (empty($stepsComplete)) { - return; - } + return [ + $progressSteps, + $percentDone, + ]; + } - $stepsDoneArray = []; - if (is_string($stepsComplete)) { - parse_str($stepsComplete, $stepsDoneArray); - } else { - $stepsDoneArray = $stepsComplete; - } - $this->settingsRepo->saveSetting( - "projectsettings.$projectId.stepsComplete", - serialize($stepsDoneArray) - ); + /** + * Updates the progress of a project. + * + * @param string|array $stepsComplete The steps completed for the project. + * @param int $projectId The ID of the project. + * @return void + */ + public function updateProjectProgress($stepsComplete, $projectId): void + { + if (empty($stepsComplete)) { + return; } - /** - * Edits the project relations of a user. - * - * @param int $id The ID of the user. - * @param array $projects An array of project IDs to be assigned to the user. - * @return bool Returns true if the project relations were successfully edited, false otherwise. - * - * @api - */ - public function editUserProjectRelations($id, $projects): bool - { - return $this->projectRepository->editUserProjectRelations($id, $projects); + $stepsDoneArray = []; + if (is_string($stepsComplete)) { + parse_str($stepsComplete, $stepsDoneArray); + } else { + $stepsDoneArray = $stepsComplete; } - /** - * Returns the project ID by its name from the given array of projects. - * - * @param array $allProjects An array of projects. - * @param string $projectName The name of the project to search for. - * @return int|bool The ID of the project if found, or false if not found. - * - * @api + $this->settingsRepo->saveSetting( + "projectsettings.$projectId.stepsComplete", + serialize($stepsDoneArray) + ); + } + + /** + * Edits the project relations of a user. + * + * @param int $id The ID of the user. + * @param array $projects The projects to be edited. + * @return bool True if the project relations were successfully edited, false otherwise. */ - public function getProjectIdbyName($allProjects, $projectName) - { - foreach ($allProjects as $project) { - if (strtolower(trim($project['name'])) == strtolower(trim($projectName))) { - return $project['id']; - } + public function editUserProjectRelations($id, $projects): bool + { + return $this->projectRepository->editUserProjectRelations($id, $projects); + } + + /** + * Retrieves the ID of a project by its name. + * + * @param array $allProjects The array of all projects. + * @param string $projectName The name of the project to retrieve the ID for. + * @return mixed The ID of the project if found, or false if not found. + */ + public function getProjectIdbyName($allProjects, $projectName) + { + foreach ($allProjects as $project) { + if (strtolower(trim($project['name'])) == strtolower(trim($projectName))) { + return $project['id']; } - return false; } + return false; + } - /** - * @param $params - * @return false|void - * - * @api + /** + * Updates the sorting of multiple projects. + * + * @param array $params The array containing the project IDs as keys and their corresponding sort index as values (ticketId: sortIndex). + * @return bool Returns true if the sorting update was successful, false otherwise. */ - public function updateProjectSorting($params) - { - //ticketId: sortIndex - foreach ($params as $id => $sortKey) { - if ($this->projectRepository->patch($id, ["sortIndex" => $sortKey * 100]) === false) { - return false; - } + public function updateProjectSorting($params): bool + { + //ticketId: sortIndex + foreach ($params as $id => $sortKey) { + if ($this->projectRepository->patch($id, ["sortIndex" => $sortKey * 100]) === false) { + return false; } } - /** - * Edits a project with the given values. - * - * @param mixed $values The values to update the project with. - * @param int $id The ID of the project to edit. - * - * @return void - * - * @api + return true; + } + + /** + * Edits a project. + * + * @param mixed $values The values to be updated in the project. + * @param int $id The ID of the project to be edited. + * @return void */ - public function editProject($values, $id) - { - $this->projectRepository->editProject($values, $id); - } + public function editProject($values, $id) + { + $this->projectRepository->editProject($values, $id); + } - /** - * @param $params - * @param $handler - * @return bool - * - * @api + /** + * Updates the status and sorting of projects. + * + * @param array $params An associative array representing the project status and sorting. + * The key is the status and the value is the serialized project list. + * @param null $handler Optional parameter for handling the project update process. + * @return bool Returns true if the update process is successful, false otherwise. */ - public function updateProjectStatusAndSorting($params, $handler = null): bool - { - - //Jquery sortable serializes the array for kanban in format - //statusKey: item[]=X&item[]=X2..., - //statusKey2: item[]=X&item[]=X2..., - //This represents status & kanban sorting - foreach ($params as $status => $projectList) { - if (is_numeric($status) && !empty($projectList)) { - $projects = explode("&", $projectList); - - if (is_array($projects) === true) { - foreach ($projects as $key => $projectString) { - $id = substr($projectString, 7); - - $this->projectRepository->patch($id, ["sortIndex" => $key * 100, "state" => $status]); - } + public function updateProjectStatusAndSorting($params, $handler = null): bool + { + + //Jquery sortable serializes the array for kanban in format + //statusKey: item[]=X&item[]=X2..., + //statusKey2: item[]=X&item[]=X2..., + //This represents status & kanban sorting + foreach ($params as $status => $projectList) { + if (is_numeric($status) && !empty($projectList)) { + $projects = explode("&", $projectList); + + if (is_array($projects) === true) { + foreach ($projects as $key => $projectString) { + $id = substr($projectString, 7); + + $this->projectRepository->patch($id, ["sortIndex" => $key * 100, "state" => $status]); } } } - - return true; } - /** - * Gets all the projects a company manager has access to. - * Includes all projects within a client + all assigned projects - * - * @param int $userId - * @param int $clientId - * @return array - * - * @api + return true; + } + + /** + * Retrieves the projects for a client manager. + * + * @param int $userId The ID of the user. + * @param int $clientId The ID of the client. + * @return array The projects for the client manager. */ - public function getClientManagerProjects(int $userId, int $clientId): array - { + public function getClientManagerProjects(int $userId, int $clientId): array + { - $clientProjects = $this->projectRepository->getClientProjects($clientId); - $userProjects = $this->projectRepository->getUserProjects($userId); + $clientProjects = $this->projectRepository->getClientProjects($clientId); + $userProjects = $this->projectRepository->getUserProjects($userId); - $allProjects = []; + $allProjects = []; - foreach ($clientProjects as $project) { - if (isset($allProjects[$project['id']]) === false) { - $allProjects[$project['id']] = $project; - } + foreach ($clientProjects as $project) { + if (isset($allProjects[$project['id']]) === false) { + $allProjects[$project['id']] = $project; } + } - foreach ($userProjects as $project) { - if (isset($allProjects[$project['id']]) === false) { - $allProjects[$project['id']] = $project; - } + foreach ($userProjects as $project) { + if (isset($allProjects[$project['id']]) === false) { + $allProjects[$project['id']] = $project; } - - return $userProjects; } - /** - * @param bool $showClosedProjects - * @return array - * + return $userProjects; + } + + /** + * Gets all the projects for the current user. + * By default, closed projects are not included. + * + * @param bool $showClosedProjects (optional) Set to true to include closed projects. + * @return array Returns an array of projects. + * * @api */ - public function getAll(bool $showClosedProjects = false): array - { - return $this->projectRepository->getUserProjects( userId: session('userdata.id'), - accessStatus: "all", - projectTypes: "project"); - } + public function getAll(bool $showClosedProjects = false): array + { + return $this->projectRepository->getUserProjects( userId: session('userdata.id'), + accessStatus: "all", + projectTypes: "project"); + } - /** - * @param string $term - * @return array - * - * @api - */ - public function findProject(string $term = "") - { - $projects = $this->projectRepository->getUserProjects( - userId: session('userdata.id'), - accessStatus: "all", - projectTypes: "project"); + /** + * Finds projects based on a search term. + * + * @param string $term The search term (optional) + * @return array The filtered projects that match the search term + * + * @api + */ + public function findProject(string $term = "") + { + $projects = $this->projectRepository->getUserProjects( + userId: session('userdata.id'), + accessStatus: "all", + projectTypes: "project"); - $filteredProjects = []; - foreach ($projects as $key => $project) { + $filteredProjects = []; + foreach ($projects as $key => $project) { - if(Str::contains($projects[$key]['name'], $term, ignoreCase: true) || $term =='') { - $projects[$key] = $this->prepareDatesForApiResponse($project); - $projects[$key]['id'] = $project['id'] . '-' . $project['modified']; + if(Str::contains($projects[$key]['name'], $term, ignoreCase: true) || $term =='') { + $projects[$key] = $this->prepareDatesForApiResponse($project); + $projects[$key]['id'] = $project['id'] . '-' . $project['modified']; - $filteredProjects[] = $projects[$key]; - } + $filteredProjects[] = $projects[$key]; } - - return $filteredProjects; } - /** - * @return array - * - * @api - */ - public function pollForNewProjects() { - - $projects = $this->projectRepository->getUserProjects(userId: session('userdata.id'), accessStatus: "all"); + return $filteredProjects; + } - foreach ($projects as $key => $project) { - $projects[$key] = $this->prepareDatesForApiResponse($project); - } + /** + * Polls for new projects for the current user session. + * Retrieves all projects for the current user and prepares the dates for API response. + * + * @return array An array of projects with prepared dates for API response. + * + * @api + */ + public function pollForNewProjects() { - return $projects; + $projects = $this->projectRepository->getUserProjects(userId: session('userdata.id'), accessStatus: "all"); + foreach ($projects as $key => $project) { + $projects[$key] = $this->prepareDatesForApiResponse($project); } + return $projects; - /** - * @return array - * - * @api - */ - public function pollForUpdatedProjects(): array - { - $projects = $this->projectRepository->getUserProjects(userId: session('userdata.id'), accessStatus: "all"); + } - foreach ($projects as $key => $project) { - $projects[$key] = $this->prepareDatesForApiResponse($project); - $projects[$key]['id'] = $project['id'] . '-' . $project['modified']; - } + /** + * Polls for updated projects. + * Retrieves all the projects the current user has access to and prepares them for API response. + * Adds the modified timestamp to the project ID for tracking updates. + * + * @return array + * + * @api + */ + public function pollForUpdatedProjects(): array + { + $projects = $this->projectRepository->getUserProjects(userId: session('userdata.id'), accessStatus: "all"); - return $projects; - } + foreach ($projects as $key => $project) { + $projects[$key] = $this->prepareDatesForApiResponse($project); + $projects[$key]['id'] = $project['id'] . '-' . $project['modified']; + } - private function prepareDatesForApiResponse($project) { + return $projects; + } - if(dtHelper()->isValidDateString($project['modified'])) { - $project['modified'] = dtHelper()->parseDbDateTime($project['modified'])->toIso8601ZuluString(); - }else{ - $project['modified'] = null; - } - if(dtHelper()->isValidDateString($project['start'])) { - $project['start'] = dtHelper()->parseDbDateTime($project['start'])->toIso8601ZuluString(); - }else{ - $project['start'] = null; - } + /** + * Prepares date values in a project for API response. + * + * The method takes a project array and converts the 'modified', 'start', + * and 'end' date values into ISO 8601 Zulu string format. If a date value + * is not a valid string, it sets it to null. + * + * @param array $project The project array to be modified. + * @return array The modified project array with formatted date values. + * + * @internal + */ + private function prepareDatesForApiResponse($project) { - if(dtHelper()->isValidDateString($project['end'])) { - $project['end'] = dtHelper()->parseDbDateTime($project['end'])->toIso8601ZuluString(); - }else{ - $project['end'] = null; - } + if(dtHelper()->isValidDateString($project['modified'])) { + $project['modified'] = dtHelper()->parseDbDateTime($project['modified'])->toIso8601ZuluString(); + }else{ + $project['modified'] = null; + } - return $project; + if(dtHelper()->isValidDateString($project['start'])) { + $project['start'] = dtHelper()->parseDbDateTime($project['start'])->toIso8601ZuluString(); + }else{ + $project['start'] = null; + } + if(dtHelper()->isValidDateString($project['end'])) { + $project['end'] = dtHelper()->parseDbDateTime($project['end'])->toIso8601ZuluString(); + }else{ + $project['end'] = null; } + + return $project; + } } + diff --git a/app/Domain/Tickets/Services/Tickets.php b/app/Domain/Tickets/Services/Tickets.php index ba0267e56..0015dbd65 100644 --- a/app/Domain/Tickets/Services/Tickets.php +++ b/app/Domain/Tickets/Services/Tickets.php @@ -1196,11 +1196,9 @@ public function getAllSubtasks(int $ticketId): false|array /** * @param $params - * @return bool|string[] - * @throws BindingResolutionException + * @return array|bool * @api -* -*/ + */ public function quickAddTicket($params): array|bool { @@ -1307,13 +1305,40 @@ public function quickAddMilestone($params): array|bool|int } /** - * @param $values - * @return bool|string[]|void - * @throws BindingResolutionException + * Adds a ticket to the system. + * + * @param array $values An array of ticket data. + * - id (optional): The ID of the ticket. + * - headline (optional): The headline of the ticket. + * - type (optional): The type of the ticket. Default is "task". + * - description (optional): The description of the ticket. + * - projectId (optional): The ID of the project the ticket belongs to. Default is the current project. + * - editorId (optional): The ID of the editor of the ticket. + * - userId: The ID of the user creating the ticket. + * - date: The date when the ticket is created. + * - dateToFinish (optional): The date to finish the ticket. + * - timeToFinish (optional): The time to finish the ticket. + * - status (optional): The status of the ticket. Default is 3. + * - planHours (optional): The planned hours for the ticket. + * - tags (optional): The tags associated with the ticket. + * - sprint (optional): The sprint the ticket belongs to. + * - storypoints (optional): The story points assigned to the ticket. + * - hourRemaining (optional): The remaining hours for the ticket. + * - priority (optional): The priority of the ticket. + * - acceptanceCriteria (optional): The acceptance criteria of the ticket. + * - editFrom (optional): The edit from date of the ticket. + * - timeFrom (optional): The edit from time of the ticket. + * - editTo (optional): The edit to date of the ticket. + * - timeTo (optional): The edit to time of the ticket. + * - dependingTicketId (optional): The ID of the depending ticket. + * - milestoneid (optional): The ID of the milestone the ticket belongs to. + * @return array|int|bool If the ticket is successfully added, returns the ID of the ticket. + * If the user does not have access to the project, returns an error message and type array. + * If the headline is missing, returns an error message and type array. + * * @api -* -*/ - public function addTicket($values) + */ + public function addTicket($values): array|int|bool { $values = array( 'id' => '', @@ -1376,6 +1401,8 @@ public function addTicket($values) return $addTicketResponse; } } + + return false; } //Update @@ -1403,9 +1430,10 @@ public function addTicket($values) * - 'priority' => The ticket priority. (optional) * - 'acceptanceCriteria' => The ticket acceptance criteria. (optional) * - 'editFrom' => The ticket edit 'from' date-time. (optional) - * - 'time* @api -* -*/ + * - 'time* + * + * @api + */ public function updateTicket($values): array|bool { if (!isset($values["headline"])) { @@ -2070,6 +2098,26 @@ public function getTicketTemplateAssignments($params): array ); } + /** + * Retrieves the assignments for the ToDoWidget. + * + * @param array $params The parameters for filtering the assignments. + * - projectFilter (optional): The project filter for the assignments. + * - groupBy (optional): The grouping for the assignments (time, project, priority, or sprint). + * + * @return array An array containing the assignments for the ToDoWidget. + * - tickets: The open user tickets based on the groupBy parameter. + * - onTheClock: Indicates whether the user is currently clocked in. + * - efforts: The labels for the effort values. + * - priorities: The labels for the priority values. + * - ticketTypes: The available ticket types. + * - statusLabels: The labels for the ticket status values. + * - milestones: The milestones for each project. + * - allAssignedprojects: The projects assigned to the user. + * - projectFilter: The current project filter. + * - groupBy: The current grouping for the assignments. + * + */ public function getToDoWidgetAssignments($params) { @@ -2143,6 +2191,15 @@ public function getToDoWidgetAssignments($params) ); } + /** + * Prepare ticket dates for database. + * + * @param array $values The values of the ticket fields. + * + * @return array The values of the ticket fields after preparing the dates. + * + * @api + */ public function prepareTicketDates(&$values) { //Prepare dates for db @@ -2176,6 +2233,14 @@ public function prepareTicketDates(&$values) return $values; } + /** + * Find milestones that contain a specific term in their headline. + * + * @param string $term The term to search for in the headline. + * @param int $projectId The ID of the project to search milestones in. + * @return array The array of milestones that match the search term. + * @api + */ public function findMilestone(string $term, int $projectId) { @@ -2192,6 +2257,15 @@ public function findMilestone(string $term, int $projectId) return $milestones; } + /** + * Finds tickets based on search term, project ID, and optional user ID. + * + * @param string $term The search term to match against ticket headlines. + * @param int $projectId The ID of the project to search within. + * @param int|null $userId (Optional) The ID of the user to limit the search to. + * @return array An array of tickets matching the search criteria. + * @api + */ public function findTicket(string $term, int $projectId, ?int $userId) { @@ -2209,10 +2283,11 @@ public function findTicket(string $term, int $projectId, ?int $userId) } /** - * @param ?int $projectId - * @param ?int $userId - * @return array + * Retrieve milestones for a specific project and user. * + * @param int|null $projectId The ID of the project (optional) + * @param int|null $userId The ID of the user (optional) + * @return array|false An array of milestones or false if an error occurred * @api */ public function pollForNewAccountMilestones(?int $projectId = null, ?int $userId = null): array | false @@ -2234,10 +2309,13 @@ public function pollForNewAccountMilestones(?int $projectId = null, ?int $userId } /** - * @param ?int $projectId - * @param ?int $userId - * @return array + * Polls for updated account milestones. + * + * Retrieves all milestones based on the provided search criteria and prepares the dates for API response. * + * @param int|null $projectId (optional) The ID of the project to filter milestones by. + * @param int|null $userId (optional) The ID of the user to filter milestones by. + * @return array|false An array of milestones with prepared dates for API response, or false if an error occurs. * @api */ public function pollForUpdatedAccountMilestones(?int $projectId = null, ?int $userId = null): array|false @@ -2260,10 +2338,16 @@ public function pollForUpdatedAccountMilestones(?int $projectId = null, ?int $us } /** - * @param ?int $projectId - * @param ?int $userId - * @return array + * Polls for new account todos. * + * Retrieves all account todos based on the provided search criteria. If no criteria are provided, + * it will return all todos. Optionally, a project ID and a user ID can be specified to filter the todos. + * It excludes todos of type "milestone". + * + * @param int|null $projectId The ID of the project to filter the todos (optional). + * @param int|null $userId The ID of the user to filter the todos (optional). + * @return array|false The retrieved todos as an array of associative arrays. + * Returns false if an error occurs during retrieval. * @api */ public function pollForNewAccountTodos(?int $projectId = null, ?int $userId = null): array|false @@ -2285,10 +2369,11 @@ public function pollForNewAccountTodos(?int $projectId = null, ?int $userId = nu } /** - * @param ?int $projectId - * @param ?int $userId - * @return array + * Polls for updated account todos. * + * @param int|null $projectId The ID of the project (optional) + * @param int|null $userId The ID of the user (optional) + * @return array|false An array of updated account todos or false if there was an error * @api */ public function pollForUpdatedAccountTodos(?int $projectId = null, ?int $userId = null): array|false diff --git a/app/Domain/Users/Controllers/EditOwn.php b/app/Domain/Users/Controllers/EditOwn.php index 9aafcbc39..cc7fc93b0 100644 --- a/app/Domain/Users/Controllers/EditOwn.php +++ b/app/Domain/Users/Controllers/EditOwn.php @@ -327,7 +327,7 @@ public function post(): Response * Returns list of supported varying date-time formats. * @link https://www.php.net/manual/en/class.datetimeinterface.php#datetimeinterface.constants.types * - * @return [] Format of ID => date-time string + * @return array Format of ID => date-time string */ private function getSupportedDateTimeFormats(): array { diff --git a/composer.json b/composer.json index c448df504..a99d6e9cc 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true, "metasyntactical/composer-plugin-license-check": true, - "php-http/discovery": true + "php-http/discovery": true, + "phpstan/extension-installer": true } }, "authors": [ @@ -94,7 +95,8 @@ "phpcsstandards/phpcsextra": "^1.2.1", "zebra-north/phpcs-short-types": "^1.0", "phpstan/phpstan": "^1.10", - "leantime/leantime-documentor": "@dev" + "leantime/leantime-documentor": "@dev", + "phpstan/extension-installer": "^1.4" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 6a2155041..740e1e9b1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "ae748f666309b4d97857665e23aaec25", + "content-hash": "4fa35896fd99b71b706fc9032106d7fe", "packages": [ { "name": "aws/aws-crt-php", @@ -62,16 +62,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.321.1", + "version": "3.321.2", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "f4ad64dffc2665dde6275e6dcc3f653f15c6e57f" + "reference": "c04f8f30891cee8480c132778cd4cc486467e77a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/f4ad64dffc2665dde6275e6dcc3f653f15c6e57f", - "reference": "f4ad64dffc2665dde6275e6dcc3f653f15c6e57f", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/c04f8f30891cee8480c132778cd4cc486467e77a", + "reference": "c04f8f30891cee8480c132778cd4cc486467e77a", "shasum": "" }, "require": { @@ -154,9 +154,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.321.1" + "source": "https://github.com/aws/aws-sdk-php/tree/3.321.2" }, - "time": "2024-08-29T19:10:23+00:00" + "time": "2024-08-30T18:14:40+00:00" }, { "name": "bacon/bacon-qr-code", @@ -5582,16 +5582,16 @@ }, { "name": "symfony/cache", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "6702d2d777260e6ff3451fee2d7d78ab5f715cdc" + "reference": "36daef8fce88fe0b9a4f8cf4c342ced5c05616dc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/6702d2d777260e6ff3451fee2d7d78ab5f715cdc", - "reference": "6702d2d777260e6ff3451fee2d7d78ab5f715cdc", + "url": "https://api.github.com/repos/symfony/cache/zipball/36daef8fce88fe0b9a4f8cf4c342ced5c05616dc", + "reference": "36daef8fce88fe0b9a4f8cf4c342ced5c05616dc", "shasum": "" }, "require": { @@ -5658,7 +5658,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.10" + "source": "https://github.com/symfony/cache/tree/v6.4.11" }, "funding": [ { @@ -5674,7 +5674,7 @@ "type": "tidelift" } ], - "time": "2024-07-17T06:05:49+00:00" + "time": "2024-08-05T07:40:31+00:00" }, { "name": "symfony/cache-contracts", @@ -5754,16 +5754,16 @@ }, { "name": "symfony/console", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc" + "reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/504974cbe43d05f83b201d6498c206f16fc0cdbc", - "reference": "504974cbe43d05f83b201d6498c206f16fc0cdbc", + "url": "https://api.github.com/repos/symfony/console/zipball/42686880adaacdad1835ee8fc2a9ec5b7bd63998", + "reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998", "shasum": "" }, "require": { @@ -5828,7 +5828,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.10" + "source": "https://github.com/symfony/console/tree/v6.4.11" }, "funding": [ { @@ -5844,7 +5844,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:30:32+00:00" + "time": "2024-08-15T22:48:29+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6146,16 +6146,16 @@ }, { "name": "symfony/finder", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "af29198d87112bebdd397bd7735fbd115997824c" + "reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/af29198d87112bebdd397bd7735fbd115997824c", - "reference": "af29198d87112bebdd397bd7735fbd115997824c", + "url": "https://api.github.com/repos/symfony/finder/zipball/d7eb6daf8cd7e9ac4976e9576b32042ef7253453", + "reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453", "shasum": "" }, "require": { @@ -6190,7 +6190,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.10" + "source": "https://github.com/symfony/finder/tree/v6.4.11" }, "funding": [ { @@ -6206,20 +6206,20 @@ "type": "tidelift" } ], - "time": "2024-07-24T07:06:38+00:00" + "time": "2024-08-13T14:27:37+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "b5e498f763e0bf5eed8dcd946e50a3b3f71d4ded" + "reference": "4c92046bb788648ff1098cc66da69aa7eac8cb65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/b5e498f763e0bf5eed8dcd946e50a3b3f71d4ded", - "reference": "b5e498f763e0bf5eed8dcd946e50a3b3f71d4ded", + "url": "https://api.github.com/repos/symfony/http-client/zipball/4c92046bb788648ff1098cc66da69aa7eac8cb65", + "reference": "4c92046bb788648ff1098cc66da69aa7eac8cb65", "shasum": "" }, "require": { @@ -6283,7 +6283,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.10" + "source": "https://github.com/symfony/http-client/tree/v6.4.11" }, "funding": [ { @@ -6299,7 +6299,7 @@ "type": "tidelift" } ], - "time": "2024-07-15T09:26:24+00:00" + "time": "2024-08-26T06:30:21+00:00" }, { "name": "symfony/http-client-contracts", @@ -6458,16 +6458,16 @@ }, { "name": "symfony/http-kernel", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "147e0daf618d7575b5007055340d09aece5cf068" + "reference": "1ba6b89d781cb47448155cc70dd2e0f1b0584c79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/147e0daf618d7575b5007055340d09aece5cf068", - "reference": "147e0daf618d7575b5007055340d09aece5cf068", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1ba6b89d781cb47448155cc70dd2e0f1b0584c79", + "reference": "1ba6b89d781cb47448155cc70dd2e0f1b0584c79", "shasum": "" }, "require": { @@ -6552,7 +6552,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.10" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.11" }, "funding": [ { @@ -6568,20 +6568,20 @@ "type": "tidelift" } ], - "time": "2024-07-26T14:52:04+00:00" + "time": "2024-08-30T16:57:20+00:00" }, { "name": "symfony/mime", - "version": "v6.4.9", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "7d048964877324debdcb4e0549becfa064a20d43" + "reference": "dba5d5f6073baf7a3576b580cc4a208b4ca00553" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/7d048964877324debdcb4e0549becfa064a20d43", - "reference": "7d048964877324debdcb4e0549becfa064a20d43", + "url": "https://api.github.com/repos/symfony/mime/zipball/dba5d5f6073baf7a3576b580cc4a208b4ca00553", + "reference": "dba5d5f6073baf7a3576b580cc4a208b4ca00553", "shasum": "" }, "require": { @@ -6637,7 +6637,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.9" + "source": "https://github.com/symfony/mime/tree/v6.4.11" }, "funding": [ { @@ -6653,7 +6653,7 @@ "type": "tidelift" } ], - "time": "2024-06-28T09:49:33+00:00" + "time": "2024-08-13T12:15:02+00:00" }, { "name": "symfony/options-resolver", @@ -7494,16 +7494,16 @@ }, { "name": "symfony/property-access", - "version": "v5.4.40", + "version": "v5.4.43", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "6e4834145c2231b34eafabe440aaac478a95b456" + "reference": "2d751866b976a02e22743359733edc55cd20e9fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/6e4834145c2231b34eafabe440aaac478a95b456", - "reference": "6e4834145c2231b34eafabe440aaac478a95b456", + "url": "https://api.github.com/repos/symfony/property-access/zipball/2d751866b976a02e22743359733edc55cd20e9fd", + "reference": "2d751866b976a02e22743359733edc55cd20e9fd", "shasum": "" }, "require": { @@ -7555,7 +7555,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v5.4.40" + "source": "https://github.com/symfony/property-access/tree/v5.4.43" }, "funding": [ { @@ -7571,7 +7571,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2024-08-29T08:50:14+00:00" }, { "name": "symfony/property-info", @@ -7741,16 +7741,16 @@ }, { "name": "symfony/string", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "ccf9b30251719567bfd46494138327522b9a9446" + "reference": "5bc3eb632cf9c8dbfd6529d89be9950d1518883b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/ccf9b30251719567bfd46494138327522b9a9446", - "reference": "ccf9b30251719567bfd46494138327522b9a9446", + "url": "https://api.github.com/repos/symfony/string/zipball/5bc3eb632cf9c8dbfd6529d89be9950d1518883b", + "reference": "5bc3eb632cf9c8dbfd6529d89be9950d1518883b", "shasum": "" }, "require": { @@ -7807,7 +7807,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.10" + "source": "https://github.com/symfony/string/tree/v6.4.11" }, "funding": [ { @@ -7823,7 +7823,7 @@ "type": "tidelift" } ], - "time": "2024-07-22T10:21:14+00:00" + "time": "2024-08-12T09:55:28+00:00" }, { "name": "symfony/translation", @@ -8000,16 +8000,16 @@ }, { "name": "symfony/var-dumper", - "version": "v6.4.10", + "version": "v6.4.11", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "a71cc3374f5fb9759da1961d28c452373b343dd4" + "reference": "ee14c8254a480913268b1e3b1cba8045ed122694" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/a71cc3374f5fb9759da1961d28c452373b343dd4", - "reference": "a71cc3374f5fb9759da1961d28c452373b343dd4", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ee14c8254a480913268b1e3b1cba8045ed122694", + "reference": "ee14c8254a480913268b1e3b1cba8045ed122694", "shasum": "" }, "require": { @@ -8065,7 +8065,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.10" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.11" }, "funding": [ { @@ -8081,7 +8081,7 @@ "type": "tidelift" } ], - "time": "2024-07-26T12:30:32+00:00" + "time": "2024-08-30T16:03:21+00:00" }, { "name": "symfony/var-exporter", @@ -8162,16 +8162,16 @@ }, { "name": "symfony/yaml", - "version": "v5.4.40", + "version": "v5.4.43", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "81cad0ceab3d61fe14fe941ff18a230ac9c80f83" + "reference": "62f96e1cfd4cf518882a36bfedcf1fe4093c1299" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/81cad0ceab3d61fe14fe941ff18a230ac9c80f83", - "reference": "81cad0ceab3d61fe14fe941ff18a230ac9c80f83", + "url": "https://api.github.com/repos/symfony/yaml/zipball/62f96e1cfd4cf518882a36bfedcf1fe4093c1299", + "reference": "62f96e1cfd4cf518882a36bfedcf1fe4093c1299", "shasum": "" }, "require": { @@ -8217,7 +8217,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.40" + "source": "https://github.com/symfony/yaml/tree/v5.4.43" }, "funding": [ { @@ -8233,7 +8233,7 @@ "type": "tidelift" } ], - "time": "2024-05-31T14:33:22+00:00" + "time": "2024-08-11T17:40:32+00:00" }, { "name": "vedmant/laravel-feed-reader", @@ -9342,12 +9342,12 @@ "source": { "type": "git", "url": "https://github.com/Leantime/leantime-documentor.git", - "reference": "1a35535003aa1e5cf9e7bb9ef5fff16cd417c136" + "reference": "2d3a300544672642349e9ea0cb259559397d7505" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Leantime/leantime-documentor/zipball/1a35535003aa1e5cf9e7bb9ef5fff16cd417c136", - "reference": "1a35535003aa1e5cf9e7bb9ef5fff16cd417c136", + "url": "https://api.github.com/repos/Leantime/leantime-documentor/zipball/2d3a300544672642349e9ea0cb259559397d7505", + "reference": "2d3a300544672642349e9ea0cb259559397d7505", "shasum": "" }, "require": { @@ -9417,7 +9417,7 @@ "support": { "source": "https://github.com/Leantime/leantime-documentor/tree/main" }, - "time": "2024-08-30T02:12:38+00:00" + "time": "2024-08-30T15:33:39+00:00" }, { "name": "masterminds/html5", @@ -10138,6 +10138,54 @@ }, "time": "2024-02-23T11:10:43+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "46c8219b3fb0deb3fc08301e8f0797d321d17dcd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/46c8219b3fb0deb3fc08301e8f0797d321d17dcd", + "reference": "46c8219b3fb0deb3fc08301e8f0797d321d17dcd", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.2" + }, + "time": "2024-08-26T07:38:00+00:00" + }, { "name": "phpstan/phpdoc-parser", "version": "1.30.0", diff --git a/dev-php.ini b/dev-php.ini deleted file mode 100644 index e69de29bb..000000000 diff --git a/makefile b/makefile index 43767e488..fa527f980 100644 --- a/makefile +++ b/makefile @@ -122,15 +122,15 @@ acceptance-test-ci: build-dev docker compose --file .dev/docker-compose.yaml --file .dev/docker-compose.tests.yaml exec leantime-dev php vendor/bin/codecept run Acceptance --steps codesniffer: - ./vendor/squizlabs/php_codesniffer/bin/phpcs app + ./vendor/squizlabs/php_codesniffer/bin/phpcs app -d memory_limit=1048M codesniffer-fix: - ./vendor/squizlabs/php_codesniffer/bin/phpcbf app + ./vendor/squizlabs/php_codesniffer/bin/phpcbf app -d memory_limit=1048M get-version: @echo $(VERSION) -phpstan: build-dev +phpstan: ./vendor/bin/phpstan analyse --memory-limit 512M update-carbon-macros: diff --git a/phpstan.neon b/phpstan.neon index 4071f13c9..16027fec1 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -21,15 +21,16 @@ parameters: - messages: - '#Attribute class Leantime\\Domain\\Connector\\Models\\DbColumn does not exist\.#' - # - '#Variable \$__data might not be defined\.#' - # - '#Constant BASE_URL not found\.#' - # - '#Constant CURRENT_URL not found\.#' - # - '#Variable \$login might not be defined\.#' - # - '#Variable \$roles might not be defined\.#' - # paths: - # - app/Domain/*/Templates/*.tpl.php - # - app/Domain/*/Templates/*.inc.php - # - app/Domain/*/Templates/submodules/*.sub.php + - '#Variable \$__data might not be defined\.#' + - '#Variable \$tpl might not be defined\.#' + - '#Constant BASE_URL not found\.#' + - '#Constant CURRENT_URL not found\.#' + - '#Variable \$login might not be defined\.#' + - '#Variable \$roles might not be defined\.#' + paths: + - app/Domain/*/Templates/*.tpl.php + - app/Domain/*/Templates/*.inc.php + - app/Domain/*/Templates/submodules/*.sub.php universalObjectCratesClasses: - Leantime\Core\Environment earlyTerminatingMethodCalls: @@ -37,3 +38,5 @@ parameters: - redirect - display - displayPartial + +