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 / 22
CRAP
0.00% covered (danger)
0.00%
0 / 520
GroupService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 22
17822.00
0.00% covered (danger)
0.00%
0 / 520
 __construct
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
 saveGroup
0.00% covered (danger)
0.00%
0 / 1
72.00
0.00% covered (danger)
0.00%
0 / 32
 validateSaveGroupRequest
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 6
 insertGroup
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 15
 updateGroup
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 20
 deleteGroup
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 18
 restoreGroup
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 18
 searchGroup
0.00% covered (danger)
0.00%
0 / 1
380.00
0.00% covered (danger)
0.00%
0 / 52
 getGroupDetails
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 25
 getBatchDetailsByClusterAndBatchGroupId
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 26
 saveBatchGroup
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 26
 saveSubjectStudentGroup
0.00% covered (danger)
0.00%
0 / 1
56.00
0.00% covered (danger)
0.00%
0 / 26
 addStudentsGroup
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 7
 getAssignedSyllabusesFromGroupId
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 15
 getStudentsBatchGroupFromBatchId
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 5
 getAllGroups
0.00% covered (danger)
0.00%
0 / 1
240.00
0.00% covered (danger)
0.00%
0 / 40
 getAllBatchAcademicYears
0.00% covered (danger)
0.00%
0 / 1
42.00
0.00% covered (danger)
0.00%
0 / 31
 findGroupByProperties
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 16
 deleteGroupPermanently
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 18
 updateGroupProperties
0.00% covered (danger)
0.00%
0 / 1
702.00
0.00% covered (danger)
0.00%
0 / 91
 setGroupToGroupRelations
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 17
 haveId
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 14
<?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\request\academic\MapStudentGroupRequest;
use com\linways\core\ams\professional\mapper\academic\GroupServiceMapper;
use com\linways\core\ams\professional\request\academic\SearchGroupRequest;
use com\linways\core\ams\professional\constant\academic\GroupTypeConstant;
use com\linways\core\ams\professional\constant\academic\StatusConstants;
use com\linways\core\ams\professional\dto\academics\BatchProperties as AcademicsBatchProperties;
use com\linways\core\ams\professional\dto\academics\SubjectProperties as AcademicsSubjectProperties;
use com\linways\core\ams\professional\exception\ProfessionalException;
use com\linways\core\ams\professional\dto\api\Group;
use com\linways\core\dto\BatchProperties;
class GroupService extends BaseService
{
    use MakeSingletonTrait;
    private function __construct() {
        $this->mapper = GroupServiceMapper::getInstance()->getMapper();
    }
    /**
     * Save group
     * @param Group $group
     * @return String $id
     */
    public function saveGroup (Group $group)
    {
        $group = $this->realEscapeObject($group);
        $group->createdBy = $GLOBALS['userId'] ?? $group->createdBy;
        $group->updatedBy = $GLOBALS['userId'] ?? $group->updatedBy;
        try{
            $this->validateSaveGroupRequest($group);
            if(!empty($group->id))
            {
                $group->id = $this->updateGroup($group);
            }
            else
            {
                $group->id = $this->insertGroup($group);
            }
        }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 Group! Please try again");
            } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create group.$group->name already exists!");
            } else {
                throw new ProfessionalException ($e->getCode(),$e->getMessage());
            }
        }
        switch ($group->type) {
            case GroupTypeConstant::SUBJECT:
                $this->setGroupToGroupRelations($group,'batchGroupIds');
                break;
            default:
                break;
        }
        return $group->id;
    }
    /**
     * Validate Group Request Before Saving
     * @param Group $group
     * @return NULL
     */
    private function validateSaveGroupRequest(Group $group)
    {
        if(empty($group->name))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group name is empty! Please enter a name for group");
            if(empty($group->type))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group type is empty! Please choose a type for group");
    }
    /**
     * Insert Group
     * @param Group $group
     * @return String $id
     */
    private function insertGroup(Group $group)
    {
        $properties = !empty($group->properties) ? "'" . json_encode($group->properties) . "'" : "NULL";
        $identifyingContext = !empty($group->identifyingContext) ? "'" . json_encode($group->identifyingContext) . "'" : "NULL";
        $id = SecurityUtils::getRandomString();
        $query = "INSERT INTO `groups`
                  (`id`,`identifying_context`,`name`,`type`,`properties`,`created_by`,`updated_by`)
                  VALUES
                  ('$id',$identifyingContext,'$group->name','$group->type',$properties,'$group->createdBy','$group->updatedBy')";
        try {
            $this->executeQuery($query);
            return $id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * Update Group
     * @param Group $group
     * @return NULL
     */
    private function updateGroup(Group $group)
    {
        $properties = !empty($group->properties) ? "'".json_encode($group->properties)."'" : "NULL";
        $identifyingContext = !empty($group->identifying_context) ? "'" . json_encode($group->identifyingContext) . "'" : "NULL";
        $query = "UPDATE
                    `groups`
                SET
                    `identifying_context` = $identifyingContext,
                    `name` = '$group->name',
                    `type` = '$group->type',
                    `properties` = $properties,
                    `updated_by` = '$group->updatedBy'
                WHERE
                    `id` = '$group->id'";
        try {
            $this->executeQuery($query);
            return $group->id;
        } catch (\Exception $e) {
            throw new ProfessionalException($e->getCode(),$e->getMessage());
        }
    }
    /**
     * Delete Group (Soft Delete)
     * @param String $id
     * @return NULL
     */
    public function deleteGroup($id)
    {
        $id = $this->realEscapeString($id);
        $updatedBy = $GLOBALS['userId'];
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group is invalid! Please enter a valid group");
        $query = "UPDATE
                    `groups`
                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 group! Please try again");
        }
    }
    /**
     * Restore Group
     * @param String $id
     * @return NULL
     */
    public function restoreGroup($id)
    {
        $id = $this->realEscapeString($id);
        $updatedBy = $GLOBALS['userId'];
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group is invalid! Please enter a valid group");
        $query = "UPDATE
                    `groups`
                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 SearchGroupRequest $request
     * @return Group
     */
    public function searchGroup(SearchGroupRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $whereQuery = "";
        $limitQuery = "";
        $where = [];
        !empty($request->startYear)?$where [] = " JSON_CONTAINS(g.properties, '{\"startYear\":\"$request->startYear\"}') ":null;
        !empty($request->endYear)?$where [] = " JSON_CONTAINS(g.properties, '{\"endYear\":\"$request->endYear\"}') ":null;
        !empty($request->programId)?$where [] = " JSON_CONTAINS(g.properties, '{\"programId\":\"$request->programId\"}') ":null;
        !empty($request->departmentId)?$where [] = " JSON_CONTAINS(g.properties, '{\"departmentId\":\"$request->departmentId\"}') ":null;
        !empty($request->currentTermId)?$where [] = " JSON_CONTAINS(g.properties, '{\"currentTermId\":\"$request->currentTermId\"}') ":null;
        !empty($request->curriculumId)?$where [] = " JSON_CONTAINS(g.properties, '{\"curriculumId\":\"$request->curriculumId\"}') ":null;
        if(count($request->syllabusIds)){
            $or = [];
            foreach ($request->syllabusIds as $key => $syllabusId) {
                $or [] = " JSON_CONTAINS(g.properties->'$.extraSyllabusId', '\"$syllabusId\"' ,'$') ";
            }
            $where [] = " (".implode(" OR ",$or).") ";
        }
        !empty($request->id)?$where [] = " g.id = '$request->id":null;
        $request->trashed === StatusConstants::ACTIVE ? $where [] = " g.trashed IS NULL ":null;
        $request->trashed === StatusConstants::TRASHED ? $where [] = " g.trashed IS NOT NULL ":null;
        !empty($request->name) ? $where [] = " g.name LIKE '%$request->name%' ":null;
        !empty($request->type) ? $where [] = " g.type LIKE '%$request->type%' ":null;
        if($request->startIndex !== "" && $request->endIndex !== "")
        {
            $limitQuery .= " LIMIT $request->startIndex,$request->endIndex";
        }
        $query = "SELECT
            g.id,
            g.identifying_context,
            g.name,
            g.type,
            g.properties,
            g.trashed,
            g.created_by,
            g.created_date,
            g.updated_by,
            g.updated_date
        FROM
            `groups` g
            ".(count($where)? " WHERE ".implode(' AND ',$where):"");
        try {
            $groups = $this->executeQueryForList($query." ".$limitQuery, $this->mapper[GroupServiceMapper::SEARCH_GROUPS]);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again.");
        }
        if(empty($groups))
        {
            $groups = [];
        }
        return $groups;
    }
    /**
     * get Academic term by id
     * @param String $id
     * @return Group
     */
    public function getGroupDetails($id)
    {
        $id = $this->realEscapeObject($id);
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group is invalid! Please enter a valid group");
            $query = "SELECT
                g.id,
                g.identifying_context,
                g.name,
                g.type,
                g.trashed,
                g.created_by,
                g.created_date,
                g.updated_by,
                g.updated_date
            FROM
                `groups` g
            WHERE
                `id` = $id";
        try {
            $group = $this->executeQueryForObject($query, $this->mapper[GroupServiceMapper::SEARCH_GROUPS]);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again");
        }
        return $group;
    }
    /**
     * get Academic term by id
     * @param String $id
     * @return Group
     */
    public function getBatchDetailsByClusterAndBatchGroupId($request)
    {
        $request = $this->realEscapeObject($request);
        if(empty($request->batchId)||empty($request->clusterId))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Invalid request");
            $query = "SELECT
                g.id,
                g.identifying_context,
                g.name,
                g.type,
                g.trashed,
                g.created_by,
                g.created_date,
                g.updated_by,
                g.updated_date
            FROM
                cluster_groups_relations cgr
            inner join groups_relations gr ON gr.child_groups_id = cgr.groups_id
            inner join `groups` g ON g.id = gr.child_groups_id
            where gr.parent_groups_id = '$request->batchId' and cgr.cluster_id  = '$request->clusterId'";
        try {
            $group = $this->executeQueryForObject($query, $this->mapper[GroupServiceMapper::SEARCH_GROUPS]);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again");
        }
        return $group;
    }
     /**
     * Save a batch
     * @param Group $group
     * @return String $id
     */
    public function saveBatchGroup (Group $group)
    {
        $group = $this->realEscapeObject($group);
        $group->createdBy = $GLOBALS['userId'] ?? $group->createdBy;
        $group->updatedBy = $GLOBALS['userId'] ?? $group->updatedBy;
        $group->type = GroupTypeConstant::BATCH;
        try{
            $this->validateSaveGroupRequest($group);
            if(!empty($group->id))
            {
                $group->id = $this->updateGroup($group);
            }
            else
            {
                $group->id = $this->insertGroup($group);
            }
        }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 Batch! Please try again");
            } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create batch.$group->name already exists!");
            } else {
                throw new ProfessionalException ($e->getCode(),$e->getMessage());
            }
        }
        return $group->id;
    }
    /**
     * Save a subject student group
     * @param Group $group
     * @return String $id
     */
    public function saveSubjectStudentGroup (Group $group)
    {
        $group = $this->realEscapeObject($group);
        $group->createdBy = $GLOBALS['userId'] ?? $group->createdBy;
        $group->updatedBy = $GLOBALS['userId'] ?? $group->updatedBy;
        $group->type = GroupTypeConstant::SUBJECT;
        try{
            $this->validateSaveGroupRequest($group);
            if(!empty($group->id))
            {
                $group->id = $this->updateGroup($group);
            }
            else
            {
                $group->id = $this->insertGroup($group);
            }
        }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 Group! Please try again");
            } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
                throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create subject student group.$group->name already exists!");
            } else {
                throw new ProfessionalException ($e->getCode(),$e->getMessage());
            }
        }
        return $group->id;
    }
    /**
     * Save a subject student group
     * @param MapStudentGroupRequest $mapStudentGroupRequest
     * @return String $id
     */
    public function addStudentsGroup ($mapStudentGroupRequest)
    {
        $mapStudentGroupRequest = $this->realEscapeObject($mapStudentGroupRequest);
        $mapStudentGroupRequest->createdBy = $GLOBALS['userId'] ?? $mapStudentGroupRequest->createdBy;
        $mapStudentGroupRequest->updatedBy = $GLOBALS['userId'] ?? $mapStudentGroupRequest->updatedBy;
        // try{
        //     $this->validateSaveGroupRequest($group);
        //     if(!empty($group->id))
        //     {
        //         $group->id = $this->updateGroup($group);
        //     }
        //     else
        //     {
        //         $group->id = $this->insertGroup($group);
        //     }
        // }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 Group! Please try again");
        //     } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
        //         throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create subject student group.$group->name already exists!");
        //     } else {
        //         throw new ProfessionalException ($e->getCode(),$e->getMessage());
        //     }
        // }
        $group = new Group();
        return $group->id;
    }
    public function getAssignedSyllabusesFromGroupId ($groupId)
    {
        $groupId = $this->realEscapeObject($groupId);
        $this->haveId($groupId,GroupTypeConstant::BATCH);
        $query = "SELECT distinct s.id as `SyllabusId`, s.name AS `SyllabusName`
        FROM `groups` bg
        INNER JOIN `cm_curriculum_syllabus_relation` csr ON csr.cm_curriculum_id = bg.properties->'$.curriculumId'
        INNER JOIN `cm_syllabus` s ON s.id = csr.cm_syllabus_id OR JSON_CONTAINS(bg.properties->'$.extraSyllabusId',concat('\"',s.id,'\"'),'$')
        WHERE bg.type = '".GroupTypeConstant::BATCH."' AND bg.id = '$groupId';";
        try {
            $AssignedSyllabus = $this->executeQueryForList($query);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again");
        }
        return $AssignedSyllabus;
    }
     /**
     * Get a group id of batch
     * @param Integer $batchId
     * @return String $groupId
     */
    public function getStudentsBatchGroupFromBatchId ($batchId)
    {
        $batchId = $this->realEscapeString($batchId);
        // try{
        // TODO: fetch group id of a batch
        $groupId = "q85pNu5563WjsfMBd";
        // }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 Group! Please try again");
        //     } else if ($e->getCode() === ProfessionalException::DUPLICATE_ENTRY) {
        //         throw new ProfessionalException (ProfessionalException::DUPLICATE_ENTRY,"Cannot create subject student group.$group->name already exists!");
        //     } else {
        //         throw new ProfessionalException ($e->getCode(),$e->getMessage());
        //     }
        // }
        return $groupId;
    }
    /**
     * Search Academic term Details
     * @return Group
     */
    public function getAllGroups(SearchGroupRequest $request)
    {
        $request = $this->realEscapeObject($request);
        $where = [];
        $limitQuery = "";
        !empty($request->batchStartYear)?$where [] = "JSON_CONTAINS(g.properties, '{\"batchStartYear\":\"$request->batchStartYear\"}')":null;
        !empty($request->programId)?$where [] = "JSON_CONTAINS(g.properties, '{\"programId\":\"$request->programId\"}')":null;
        !empty($request->courseTypeId)?$where [] = "JSON_CONTAINS(g.properties, '{\"courseTypeId\":\"$request->courseTypeId\"}')":null;
        !empty($request->id)?$where[] = "g.id='$request->id'":null;
        ($request->trashed === StatusConstants::ACTIVE)?$where []= "g.trashed IS NULL":null;
        ($request->trashed === StatusConstants::TRASHED)?$where[]= "g.trashed IS NOT NULL ":null;
        !empty($request->name)?$where []= "g.name LIKE '%$request->name%'":null;
        !empty($request->type)?$where []= "g.type = '$request->type'":null;
        $select = ["g.id","g.identifying_context","g.name","g.type","g.properties","g.trashed","g.created_by","g.created_date","g.updated_by","g.updated_date"];
        if($request->getGroupMembers){
            $where []= " gm.academic_status = '".$request->memberStatus."'";
            $select = array_merge($select,["stdp.id as studentId","std.studentName","stdp.properties->>'$.rollNumber' as rollNo","stdp.properties->>'$.registerNumber' as regNo","gm.properties","gm.groups_id","gm.trashed","gm.id as member_id"]);
            $innerJoin[] = "INNER JOIN `group_members` gm ON gm.groups_id = g.id AND gm.trashed is null";
            $innerJoin[] = "INNER JOIN `student_program_account` stdp ON stdp.id = gm.student_id";
            $innerJoin[] = "INNER JOIN `studentaccount` std ON std.studentID = stdp.student_id";
        }
        if($request->startIndex !== "" && $request->endIndex !== "")
        {
            $limitQuery .= " LIMIT $request->startIndex,$request->endIndex";
        }
        $query = "
            SELECT ".implode(',',$select)." FROM
            `groups` g
            ".implode(' ',$innerJoin)."
            ".(!empty($where)?"WHERE ".implode(' AND ',$where):"").$limitQuery;
        try {
            if($request->getGroupMembers){
                $groups = $this->executeQueryForList($query, $this->mapper[GroupServiceMapper::SEARCH_GROUPS_WITH_GROUP_MEMBERS]);
            }else{
                $groups = $this->executeQueryForList($query, $this->mapper[GroupServiceMapper::SEARCH_GROUPS]);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again.");
        }
        return $groups;
    }
    /**
     * get all batch academic years
     * @param $year START_YEAR, END_YEAR, ACADEMIC_YEAR
     * @return Group
     */
    public function getAllBatchAcademicYears($year="START_YEAR")
    {
        $year = $this->realEscapeString($year);
        $columns = "";
        if ($year === "START_YEAR") {
            $columns = "g.properties->>'$.startYear' AS year";
        }
        if ($year === "END_YEAR") {
            $columns = "g.properties->>'$.batchEndYear' AS year";
        }
        if ($year === "ACADEMIC_YEAR") {
            $columns = "CONCAT(g.properties->>'$.startYear', '-', g.properties->>'\$batchEndYear') AS year";
        }
        $query = "SELECT DISTINCT
            $columns
        FROM
            `groups` g
        WHERE
            g.trashed IS NULL AND g.properties->>'$.startYear' IS NOT NULL";
        try {
            $groups = $this->executeQueryForList($query);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again.");
        }
        usort($groups,function($groupA, $groupB){
            return $groupA->year > $groupB->year;
        });
        $groups = array_values(array_filter($groups, function($g) { return $g->year; }));
        if(empty($groups))
        {
            throw new ProfessionalException(ProfessionalException::EMPTY_SEARCH_ITEMS,"No Batch Groups Found");
        }
        return $groups;
    }
    /**
     * Search group by properties
     * //$request->properties { property : value, property : value }
     * @return Group
     */
    public function findGroupByProperties($request)
    {
        $where = [];
        if(empty($request->properties)){
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Invalid group properties! Please enter a valid properties");
        }
        try {
            $request->type ? $where [] = " type = '$request->type": [];
            foreach ($request->properties as $property => $value) {
                $where [] = " properties->'$.$property' = '$value";
            }
            $query = "SELECT `id`,`identifying_context`,`name`,`type`,`properties`,`trashed`,`created_by`,`created_date`,`updated_by`,`updated_date` FROM `groups` WHERE ".implode(' AND ',$where);
            return $this->executeQueryForList($query, $this->mapper[GroupServiceMapper::SEARCH_GROUPS]);
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_FETCHING,"Cannot fetch group details! Please try again.");
        }
    }
    /**
     * Delete Group (Permanent Delete)
     * @param String $id
     * @return NULL
     */
    public function deleteGroupPermanently($id){
        $id = $this->realEscapeString($id);
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group is invalid! Please enter a valid group");
        GroupMemberService::getInstance()->deleteMembersPermanently($id);
        $query [] = "DELETE FROM `cluster_groups_relations` WHERE `groups_id` = '$id'";
        $query [] = "DELETE FROM `groups_relations` WHERE `parent_groups_id` = '$id'";
        $query [] = "DELETE FROM `groups_relations` WHERE `child_groups_id` = '$id'";
        $query [] = "DELETE FROM `group_members` WHERE `groups_id` = '$id'";
        $query [] = "UPDATE `batches` set `groups_id` = null WHERE `groups_id` = '$id'";
        $query [] = "DELETE FROM `groups` WHERE `id` = '$id'";
        try {
            foreach ($query as $value) {
                $this->executeQuery($value);
            }
        } catch (\Exception $e) {
            throw new ProfessionalException(ProfessionalException::ERROR_DELETING,"Error deleting group! Please try again");
        }
    }
    /**
     * Restore Group
     * @param Object $batch
     * @param Array $properties
     * @param Object $groupProperties
     * @return NULL
     */
    public function updateGroupProperties($group,$properties,$type,$column = 'properties',$appendProperties = false,$removeProperties = false)
    {
        $group = (object)$this->realEscapeObject($group);
        $group->properties = (object)$group->properties;
        switch ($type) {
            case GroupTypeConstant::BATCH:
                $groupProperties = new AcademicsBatchProperties();
                break;
            case GroupTypeConstant::SUBJECT:
                $groupProperties = new AcademicsSubjectProperties();
                break;
            default:
                # code...
                break;
        }
        if(empty($groupProperties))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Invalid properties! Please enter a valid group");
        $updatedBy = $GLOBALS['userId'];
        $id = $group->id;
        if(empty($id))
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Group is invalid! Please enter a valid group");
        $set = [];
        if($appendProperties==true || $removeProperties == true ){
            
            if($appendProperties==true){
                    $externalSyllabusIds =[];
                    foreach ($properties as $key => $property) {
                        foreach ($property->value as $ele) {
                            $externalSyllabusIds [] = $ele;
                        }
                    }
                    $selectQuery = "SELECT g.properties->>'$.extraSyllabusId' as extraSyllabusId FROM `groups` g WHERE g.id= '$id';";
                    $existingSyllabus = $this->executeQueryForObject($selectQuery);
                    $newArray = [];
                    if ($existingSyllabus->extraSyllabusId === null || $existingSyllabus->extraSyllabusId === "" || $existingSyllabus->extraSyllabusId === [""] || $existingSyllabus->extraSyllabusId === `"[""]"` ) {
                        $newArray = $externalSyllabusIds;
    
                    }else{
                        $existingSyllabusArray = [];
                        $existingSyllabusArray = json_decode($existingSyllabus->extraSyllabusId);
    
    
    
                        $newArray = array_merge($existingSyllabusArray,$externalSyllabusIds);
                    }
            }if($removeProperties == true){
                $externalSyllabusIds =[];
                foreach ($properties as $key => $property) {
                    foreach ($property->value as $ele) {
                        $externalSyllabusIds [] = $ele;
                    }
                }
                    $selectQuery = "SELECT g.properties->>'$.extraSyllabusId' as extraSyllabusId FROM `groups` g WHERE g.id= '$id';";
                    $existingSyllabus = $this->executeQueryForObject($selectQuery);
                    $existingSyllabusArray = [];
                    $existingSyllabusArray = json_decode($existingSyllabus->extraSyllabusId);
                    $newArray = array_diff($existingSyllabusArray, $externalSyllabusIds);
            }
            $value = json_encode($newArray);
            try {
                $query = "UPDATE `groups`
                SET `".$column."` = JSON_SET(`".$column."`, '$.".$property->name."', CAST('$value' AS JSON)),
                    updated_by = '$updatedBy',
                    updated_date = utc_timestamp()
                WHERE id = '$id';";
                $this->executeQuery($query);
            }catch (\Exception $e) {
                throw new ProfessionalException(ProfessionalException::ERROR_RESTORING,"Error restoring academic term! Please try again");
            }
        }else{
                try {
                    foreach ($properties as $key => $property) {
                        if(property_exists($groupProperties, $property->name)){
                            if(is_object($property->value)){
        
                            }else if(is_array($property->value)){
                                $value = "JSON_ARRAY(\"".implode('","',$property->value)."\")";
                            }else if(is_string($property->value)){
                                $value = "'".$property->value."'";
                            }else if(is_bool($property->value)){
                                $value = $property->value ? "true":"false";
                            }
                                $query = "UPDATE
                                        `groups`
                                    SET
                                        `".$column."` = JSON_SET(`".$column."`, '$.".$property->name."', $value),
                                        updated_by = '$updatedBy',
                                        updated_date = utc_timestamp()
                                    WHERE
                                        id = '$id'";
        
                                        $this->executeQuery($query);
                            }
        
                        }
                    }
        
                catch (\Exception $e) {
                    throw new ProfessionalException(ProfessionalException::ERROR_RESTORING,"Error restoring academic term! Please try again");
                }
            }
    }
    public function setGroupToGroupRelations($groups,$propertyName){
        $propertyName = $this->realEscapeString($propertyName);
        $groups = $this->realEscapeObject($groups);
        $parentGroupIds = (array)$groups->properties->{$propertyName};
        $createdBy = $GLOBALS['userId'];
        if(empty($groups->id)){
            throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Invalid group! Please try again");
        }
        try{
            $deleteGroupRelations = "DELETE FROM `groups_relations` WHERE `child_groups_id` = '$groups->id' AND properties->'$.".$propertyName."' NOT IN (\"".implode('","',$parentGroupIds)."\");";
            $this->executeQuery($deleteGroupRelations);
            $createGroupRelations = "INSERT IGNORE INTO `groups_relations` (`id`,`parent_groups_id`,`child_groups_id`,`properties`,`created_by`)
            SELECT LEFT(REPLACE(UUID(),'-',''), 17),`id`,'$groups->id',json_object(),'".$createdBy."' FROM `groups` WHERE id IN (\"".implode('","',$parentGroupIds)."\");";
            $this->executeQuery($createGroupRelations);
        }catch(\Exception $e) {
            throw new ProfessionalException ($e->getCode(),$e->getMessage());
        }
    }
    public function haveId($id,$type = ''){
        if(empty($id)){
            switch ($type) {
                case GroupTypeConstant::BATCH:
                    throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Batch is invalid! Please try again");
                    break;
                case GroupTypeConstant::SUBJECT:
                    throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"Subject is invalid! Please try again");
                    break;
                default:
                    throw new ProfessionalException(ProfessionalException::EMPTY_PARAMETERS,"invalid parameters! Please try again");
                    break;
            }
        }
    }
}