Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 321
ClusterService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 16
6162.00
0.00% covered (danger)
0.00%
0 / 321
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
 saveCluster
0.00% covered (danger)
0.00%
0 / 1
132.00
0.00% covered (danger)
0.00%
0 / 39
 validateSaveClusterRequest
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 8
 insertCluster
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 updateCluster
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 deleteCluster
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 18
 restoreCluster
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 18
 searchCluster
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 48
 getClusterDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 26
 saveDeparmentCluster
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 26
 saveSubjectCluster
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 26
 deleteClusterPermanently
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 14
 validateBeforeDeletingDepartment
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 11
 removeGroupIdFromClusterByRequest
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 addGroupIdToClusterByRequest
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 18
 createUpdateClusterGroupRelations
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 17
<?php
namespace com\linways\core\ams\professional\service\academic;
use com\linways\base\util\SecurityUtils;
use com\linways\base\util\MakeSingletonTrait;
use com\linways\core\ams\professional\service\BaseService;
use com\linways\core\ams\professional\mapper\academic\ClusterServiceMapper;
use com\linways\core\ams\professional\request\academic\SearchClusterRequest;
use com\linways\core\ams\professional\constant\academic\ClusterTypeConstant;
use com\linways\core\ams\professional\constant\academic\StatusConstants;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\dto\api\Cluster;
use com\linways\core\ams\professional\service\academic\ClusterMemberService;
class ClusterService extends BaseService
{
    use MakeSingletonTrait;
    private function __construct() {
        $this->mapper = ClusterServiceMapper::getInstance()->getMapper();
    }
    /**
     * Save cluster
     * @param Cluster $cluster
     * @return String $id
     */
    public function saveCluster (Cluster $cluster)
    {
        $cluster = $this->realEscapeObject($cluster);
        $cluster->createdBy = $GLOBALS['userId'] ?? $cluster->createdBy;
        $cluster->updatedBy = $GLOBALS['userId'] ?? $cluster->updatedBy;
        try{
            $this->validateSaveClusterRequest($cluster);
            if(!empty($cluster->id))
            {
                $cluster->id = $this->updateCluster($cluster);
            }
            else
            {
                $cluster->id = $this->insertCluster($cluster);
            }
        }catch(\Exception $e) {
            if($e->getCode() !== ProfessionalException::INVALID_PARAMETER && $e->getCode() !== ProfessionalException::EMPTY_PARAMETERS && $e->getCode() !== ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException($e->getCode(),"Failed to save Cluster! Please try again");
            } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create cluster $cluster->name already exists!");
            } else {
                throw new ProfessionalException ($e->getCode(),$e->getMessage());
            }
        }
        try {
            //code...
            switch ($cluster->type) {
                case 'PSEUDO-SUBJECT':
                case 'SUB-BATCH':
                case 'SUBJECT':
                    ClusterMemberService::getInstance()->createUpdateClusterMembers($cluster->id,'staffId',$cluster->properties->staffIds);
                    $this->createUpdateClusterGroupRelations($cluster);
                    break;
                default:
                    # code...
                    break;
            }
        } catch (\Exception $e) {
            throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Couldn't set cluster members");
        }
        return $cluster->id;
    }
    /**
     * Validate Cluster Request Before Saving
     * @param Cluster $cluster
     * @return NULL
     */
    private function validateSaveClusterRequest(Cluster $cluster)
    {
        if(empty($cluster->name))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Cluster name is empty! Please enter a name for cluster");
        if(empty($cluster->type))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Cluster type is empty! Please choose a type for cluster");
        if(empty($cluster->groupIds) && $cluster->type != ClusterTypeConstant::DEPARTMENT)
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Groups are null! Please choose a groups for cluster");
    }
    /**
     * Insert Cluster
     * @param Cluster $cluster
     * @return String $id
     */
    private function insertCluster(Cluster $cluster)
    {
        $properties = !empty($cluster->properties) ? "'" . json_encode($cluster->properties) . "'" : "NULL";
        $groupIds = !empty($cluster->groupIds) ? "'" . json_encode($cluster->groupIds) . "'" : "'[]'";
        $id = SecurityUtils::getRandomString();
        $query = "INSERT INTO `cluster`
                  (`id`,`name`,`type`,`groups_ids`,`properties`,`created_by`,`updated_by`)
                  VALUES
                  ('$id','$cluster->name','$cluster->type',$groupIds,$properties,'$cluster->createdBy','$cluster->updatedBy')";
        try {
            $this->executeQuery($query);
            return $id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * Update Cluster
     * @param Cluster $cluster
     * @return NULL
     */
    private function updateCluster(Cluster $cluster)
    {
        $properties = !empty($cluster->properties) ? "'".json_encode($cluster->properties)."'" : "NULL";
        $groupIds = !empty($cluster->groupIds) ? "'".json_encode($cluster->groupIds)."'" : "JSON_ARRAY()";
        $query = "UPDATE
                    `cluster`
                SET
                    `name` = '$cluster->name',
                    `type` = '$cluster->type',
                    `groups_ids` = $groupIds,
                    `properties` = $properties,
                    `updated_by` = '$cluster->updatedBy'
                WHERE
                    `id` = '$cluster->id'";
        try {
            $this->executeQuery($query);
            return $cluster->id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * Delete Cluster (Soft Delete)
     * @param String $id
     * @return NULL
     */
    public function deleteCluster($id)
    {
        $id = $this->realEscapeString($id);
        $updatedBy = $GLOBALS['userId'];
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Cluster is invalid! Please enter a valid cluster");
        $query = "UPDATE
                    `cluster`
                SET
                    `trashed` = UTC_TIMESTAMP(),
                    `updated_by` = '$updatedBy'
                WHERE
                    `id` = '$id'";
        try {
            $this->executeQuery($query);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_DELETING,"Error deleting cluster! Please try again");
        }
    }
    /**
     * Restore Cluster
     * @param String $id
     * @return NULL
     */
    public function restoreCluster($id)
    {
        $id = $this->realEscapeString($id);
        $updatedBy = $GLOBALS['userId'];
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Cluster is invalid! Please enter a valid cluster");
        $query = "UPDATE
                    `cluster`
                SET
                    `trashed` = NULL,
                    `updated_by` = '$updatedBy'
                WHERE
                    `id` = '$id'";
        try {
            $this->executeQuery($query);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_RESTORING,"Error restoring academic term! Please try again");
        }
    }
    /**
     * Search Academic term Details
     * @param SearchClusterRequest $request
     * @return Cluster
     */
    public function searchCluster(SearchClusterRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $whereQuery = "";
        $limitQuery = "";
        if(!empty($request->id)) {
            $whereQuery .= " AND c.id='$request->id";
        }
        if($request->trashed === StatusConstants::ACTIVE) {
            $whereQuery .= " AND c.trashed IS NULL ";
        }
        if($request->trashed === StatusConstants::TRASHED) {
            $whereQuery .= " AND c.trashed IS NOT NULL ";
        }
        if(!empty($request->name)) {
            $whereQuery .= " AND  c.name LIKE '%$request->name%' ";
        }
        if(!empty($request->type)) {
            $whereQuery .= " AND  c.type LIKE '%$request->type%' ";
        }
        if(!empty($request->paperSubjectId)) {
            $whereQuery .= " AND  JSON_CONTAINS(c.properties->'$.paperSubjectIds',json_array(".$request->paperSubjectId."),'$') ";
        }
        if($request->startIndex !== "" && $request->endIndex !== "")
        {
            $limitQuery .= " LIMIT $request->startIndex,$request->endIndex";
        }
        $query = "SELECT
            c.id,
            c.name,
            c.type,
            c.groups_ids,
            c.properties,
            c.trashed,
            c.created_by,
            c.created_date,
            c.updated_by,
            c.updated_date
        FROM
            cluster c
        WHERE
            1 = 1";
        try {
            $clusters = $this->executeQueryForList($query.$whereQuery.$limitQuery, $this->mapper[ClusterServiceMapper::SEARCH_CLUSTERS]);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch cluster details! Please try again.");
        }
        return $clusters;
    }
    /**
     * get Academic term by id
     * @param String $id
     * @return Cluster
     */
    public function getClusterDetails($id)
    {
        $id = $this->realEscapeObject($id);
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Cluster is invalid! Please enter a valid cluster");
            $query = "SELECT
                c.id,
                c.name,
                c.type,
                c.groups_ids,
                c.properties,
                c.trashed,
                c.created_by,
                c.created_date,
                c.updated_by,
                c.updated_date
            FROM
                cluster c
            WHERE
                id = '$id'";
        try {
            $cluster = $this->executeQueryForObject($query, $this->mapper[ClusterServiceMapper::SEARCH_CLUSTERS]);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch cluster details! Please try again");
        }
        return $cluster;
    }
     /**
     * Save a batch
     * @param Cluster $cluster
     * @return String $id
     */
    public function saveDeparmentCluster (Cluster $cluster)
    {
        $cluster = $this->realEscapeObject($cluster);
        $cluster->createdBy = $GLOBALS['userId'] ?? $cluster->createdBy;
        $cluster->updatedBy = $GLOBALS['userId'] ?? $cluster->updatedBy;
        $cluster->type = ClusterTypeConstant::DEPARTMENT;
        try{
            $this->validateSaveClusterRequest($cluster);
            if(!empty($cluster->id))
            {
                $cluster->id = $this->updateCluster($cluster);
            }
            else
            {
                $cluster->id = $this->insertCluster($cluster);
            }
        }catch(\Exception $e) {
            if($e->getCode() !== ProfessionalException::INVALID_PARAMETER && $e->getCode() !== ProfessionalException::EMPTY_PARAMETERS && $e->getCode() !== ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException($e->getCode(),"Failed to save Department! Please try again");
            } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create batch.$cluster->name already exists!");
            } else {
                throw new ProfessionalException ($e->getCode(),$e->getMessage());
            }
        }
        return $cluster->id;
    }
    /**
     * Save a subject student cluster
     * @param Cluster $cluster
     * @return String $id
     */
    public function saveSubjectCluster (Cluster $cluster)
    {
        $cluster = $this->realEscapeObject($cluster);
        $cluster->createdBy = $GLOBALS['userId'] ?? $cluster->createdBy;
        $cluster->updatedBy = $GLOBALS['userId'] ?? $cluster->updatedBy;
        $cluster->type = ClusterTypeConstant::SUBJECT;
        try{
            $this->validateSaveClusterRequest($cluster);
            if(!empty($cluster->id))
            {
                $cluster->id = $this->updateCluster($cluster);
            }
            else
            {
                $cluster->id = $this->insertCluster($cluster);
            }
        }catch(\Exception $e) {
            if($e->getCode() !== ProfessionalException::INVALID_PARAMETER && $e->getCode() !== ProfessionalException::EMPTY_PARAMETERS && $e->getCode() !== ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException($e->getCode(),"Failed to save Subject Student Cluster! Please try again");
            } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create subject student cluster.$cluster->name already exists!");
            } else {
                throw new ProfessionalException ($e->getCode(),$e->getMessage());
            }
        }
        return $cluster->id;
    }
    /**
     * Delete Cluster (Permanently Delete)
     * @param String $id
     * @return NULL
     */
    public function deleteClusterPermanently($id)
    {
        $id = $this->realEscapeString($id);
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Cluster is invalid! Please enter a valid cluster");
        $queries [] = "DELETE FROM cluster_members WHERE cluster_id = '$id'";
        $queries [] = "DELETE FROM cluster WHERE id = '$id'";
        try {
            foreach ($queries as $query) {
                $this->executeQuery($query);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_DELETING,"Error deleting cluster! Please try again");
        }
    }
    /**
     * Validate before permanently delete the cluster
     * @param String $id
     * @return NULL
     */
    public function validateBeforeDeletingDepartment($id){
        //checking if current department have dependency with any syllabus
        $sql = "SELECT `id`, `name`, `description`, `type` from `cm_syllabus` WHERE properties->'$.departmentId' = '$id';";
        $syllabus = $this->executeQueryForList($sql);
        if(count($syllabus)){
            throw new ProfessionalException(ProfessionalException::HAVE_RELATIONS,"Found a dependent syllabus, can't delete department! Please try again.");
        }
        //checking if current department have dependency with any curriculum
        $sql = "SELECT `id` from `cm_curriculum_department_relation` WHERE `department_id` = '$id';";
        $program = $this->executeQueryForList($sql);
        if(count($program)){
            throw new ProfessionalException(ProfessionalException::HAVE_RELATIONS,"Found a dependent program, can't delete department! Please try again.");
        }
    }
    /**
     * Remove group Id from cluster
     * @param Object
     * @return Boolean
     * @throws ProfessionalException
     */
    public function removeGroupIdFromClusterByRequest($request){
        if(empty($request->type)){
            throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Should have a cluster type! Please try again.");
        }
        if(empty($request->groupId)){
            throw new ProfessionalException(ProfessionalException::HAVE_RELATIONS,"Should have a group! Please try again.");
        }
        $sql = "UPDATE `cluster` set `groups_ids` = JSON_REMOVE( `groups_ids`, REPLACE(json_search(`groups_ids`, 'one', '$request->groupId'), '\"', '') )
        WHERE JSON_CONTAINS(`groups_ids`,json_array('$request->groupId'),'$') AND type = '$request->type';";
        try {
            $this->executeQuery($sql);
            return true;
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_DELETING,"Error deleting cluster! Please try again");
        }
    }
    /**
     * Add group Id from cluster
     * @param Object
     * @return Boolean
     * @throws ProfessionalException
     */
    public function addGroupIdToClusterByRequest($request){
        if(empty($request->type)){
            throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Should have a cluster type! Please try again.");
        }
        if(empty($request->groupId)){
            throw new ProfessionalException(ProfessionalException::HAVE_RELATIONS,"Should have a group! Please try again.");
        }
        if(empty($request->id)){
            throw new ProfessionalException(ProfessionalException::HAVE_RELATIONS,"Should have a cluster! Please try again.");
        }
        $sql = "UPDATE `cluster` set `groups_ids` = JSON_ARRAY_APPEND(`groups_ids`, '$', '$request->groupId')
        WHERE `type` = '$request->type' AND `id` = '$request->id';";
        try {
            $this->executeQuery($sql);
            return true;
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_DELETING,"Error deleting cluster! Please try again");
        }
    }
    /**
     * Add group Id from cluster
     * @param Object
     * @return Boolean
     * @throws ProfessionalException
     */
    public function createUpdateClusterGroupRelations($cluster){
        if(empty($cluster->id)){
            throw new ProfessionalException(ProfessionalException::INVALID_PARAMETER,"Should have a cluster.");
        }
        $createdBy = $GLOBALS['userId'];
        $deleteClusterGroupRelations = "DELETE FROM `cluster_groups_relations` WHERE `cluster_id` = '$cluster->id' AND `groups_id` NOT IN (\"".implode('","',$cluster->groupIds)."\");";
        $createClusterGroupRelations = "INSERT IGNORE INTO `cluster_groups_relations` (`id`,`cluster_id`,`groups_id`,`properties`,`created_by`)
        SELECT LEFT(REPLACE(UUID(),'-',''), 17),'$cluster->id',`id`,json_object(),'".$createdBy."' FROM `groups` WHERE `id` IN (\"".implode('","',$cluster->groupIds)."\");";
        try {
            if (!($cluster->dontRemoveExistingClusterGroupRelation == '1')) {
                $this->executeQuery($deleteClusterGroupRelations);
            }
            $this->executeQuery($createClusterGroupRelations);
            return true;
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_DELETING,"Error deleting cluster! Please try again");
        }
    }
}