AppStateESS/homestead

View on GitHub
class/ResidenceHall.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

namespace Homestead;

use \Homestead\Exception\DatabaseException;
use \PHPWS_Error;
use \PHPWS_DB;

/**
 * HMS Residence Hall class
 *
 * @author Jeremy Booker <jbooker at tux dot appstate dot edu>
 *         Some code copied from:
 * @author Kevin Wilcox <kevin at tux dot appstate dot edu>
 */

class ResidenceHall extends HMS_Item {

    public $hall_name = NULL;
    public $term;
    public $banner_building_code = NULL;
    public $gender_type = 2;
    public $air_conditioned = 0;
    public $is_online = 0;
    public $meal_plan_required = 0;
    public $assignment_notifications = 1;

    // Photo IDs
    public $exterior_image_id;
    public $other_image_id;
    public $map_image_id;
    public $room_plan_image_id;

    // Package desk id
    public $package_desk;

    /**
     * Listing of floors associated with this room
     *
     * @var array
     */
    public $_floors = null;

    /**
     * Temporary values for rh creation
     */
    public $_number_of_floors = 0;
    public $_rooms_per_floor = 0;
    public $_beds_per_room = 0;
    public $_numbering_scheme = 0;

    /**
     * Constructor
     */
    public function __construct($id = 0)
    {
        parent::__construct($id, 'hms_residence_hall');
    }

    public function getDb()
    {
        return new PHPWS_DB('hms_residence_hall');
    }

    /**
     * ******************
     * Instance Methods *
     * *****************
     */

    /*
     * Saves a new or updated residence hall object
    */
    public function save()
    {
        $this->stamp();
        $db = new PHPWS_DB('hms_residence_hall');
        $result = $db->saveObject($this);
        if (!$result || PHPWS_Error::logIfError($result)) {
            throw new DatabaseException($result->toString());
        }
        return true;
    }

    /*
     * Copies this residence hall object to a new term, then calls copy
    * on all 'this' room's floors.
    *
    * Setting $assignments to TRUE causes the copy public function to copy
    * the current assignments as well as the hall structure.
    *
    * @return bool False if unsuccessful.
    */
    public function copy($to_term, $assignments = FALSE, $roles = FALSE)
    {
        if (!$this->id) {
            return false;
        }

        // echo "In hms_residence_hall, copying this hall: $this->id <br>";

        // Create clone of current room object
        // Set id to 0, set term, and save
        $new_hall = clone ($this);
        $new_hall->reset();
        $new_hall->id = 0;
        $new_hall->term = $to_term;

        try {
            $new_hall->save();
        } catch (\Exception $e) {
            // rethrow it to the top level
            throw $e;
        }

        // Copy any roles related to this residence hall.
        if ($roles) {
            // Get memberships by object instance.
            $membs = HMS_Permission::getUserRolesForInstance($this);
            // test($membs,1);
            // Add each user to new hall
            foreach ($membs as $m) {
                // Lookup the username
                $user = new \PHPWS_User($m['user_id']);

                // Load role and add user to new instance
                $role = new HMS_Role();
                $role->id = $m['role'];
                $role->load();
                $role->addUser($user->getUsername(), get_class($new_hall), $new_hall->id);
            }
        }

        // Save successful, create new floors

        // Load all floors for this hall
        if (empty($this->_floors)) {
            try {
                $this->loadFloors();
            } catch (\Exception $e) {
                throw $e;
            }
        }

        // Floors exist, start making copies
        if (!empty($this->_floors)) {
            foreach ($this->_floors as $floor) {
                try {
                    $floor->copy($to_term, $new_hall->id, $assignments, $roles);
                } catch (\Exception $e) {
                    throw $e;
                }
            }
        }
    }

    /**
     * Pulls all the floors associated with this hall and stores them in
     * the _floors variable.
     */
    public function loadFloors()
    {
        if (!$this->id) {
            $this->_floor = null;
            return null;
        }

        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT *
            FROM hms_floor
            WHERE residence_hall_id = :id
            ORDER BY floor_number ASC";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $this->_floors = $sth->fetchAll(\PDO::FETCH_CLASS, '\Homestead\FloorRestored');

        return true;
    }

    /*
     * Creates the floors, rooms, and beds for a new hall
    */
    public function create_child_objects($num_floors, $rooms_per_floor, $beds_per_room)
    {
        if (!$this->id) {
            return false;
        }

        for ($i = 0; $i < $num_floors; $i++) {
            $floor = new Floor();

            $floor->residence_hall_id = $this->id;
            $floor->term = $this->term;
            $floor->gender_type = $this->gender_type;

            if ($floor->save()) {
                $floor->create_child_objects($rooms_per_floor, $beds_per_room);
            } else {
                // Decide on bed result.
            }
        }
    }

    /*
     * Returns TRUE or FALSE. The gender of a building can only be
    * changed to the target gender if all floors can be changed
    * to the target gender.
    *
    * This public function checks to make sure all floors can be changed,
    * those floors in tern check all thier rooms, and so on.
    */
    // TODO: rewrite this becase the behavior changed
    public function can_change_gender($target_gender)
    {
        // You can always change to a COED gender.
        if ($target_gender == COED) {
            return true;
        }

        // We must be changing to either male or female if we make it here

        // If there are any COED floors, then return false
        if ($this->check_for_floors_of_gender(COED)) {
            return false;
        }

        // Can only change gender if there are no floors of the opposite sex
        if ($target_gender == MALE) {
            $check_for_gender = FEMALE;
        } else {
            $check_for_gender = MALE;
        }

        // If a check for rooms of the opposite gender returns true, then return false
        if ($this->check_for_floors_of_gender($check_for_gender)) {
            return false;
        }

        return true;
    }

    public function check_for_floors_of_gender($gender_type)
    {
        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_floor.id
            FROM hms_floor
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id AND hms_floor.gender_type = :gender";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id, 'gender' => $gender_type));
        $result = $sth->rowCount();

        if ($result == 0) {
            return false;
        }
        return true;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getTerm()
    {
        return $this->term;
    }

    public function getHallName()
    {
        return $this->hall_name;
    }

    public function isOnline()
    {
        if($this->is_online){
            return true;
        }

        return false;
    }

    public function getLink()
    {
        $editHallCmd = CommandFactory::getCommand('EditResidenceHallView');
        $editHallCmd->setHallId($this->getId());
        return $editHallCmd->getLink($this->getHallName());
    }

    /*
     * Returns the number of floors in the current hall
    */
    public function get_number_of_floors()
    {
        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_floor.id
            FROM hms_floor
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $result = $sth->rowCount();

        return $result;
    }

    /*
     * Returns the number of rooms in the current hall
    */
    public function get_number_of_rooms()
    {
        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_room.id
            FROM hms_room
            JOIN hms_floor
            ON floor_id = hms_floor.id
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $result = $sth->rowCount();

        return $result;
    }

    /*
     * Returns the number of beds in the current hall
    */
    public function get_number_of_beds()
    {
        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_bed.id
            FROM hms_bed
            JOIN hms_room
            ON room_id = hms_room.id
            JOIN hms_floor
            ON floor_id = hms_floor.id
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $result = $sth->rowCount();

        return $result;
    }

    /**
     * @deprecated
     * @see countNominalBeds()
     */
    public function get_number_of_online_nonoverflow_beds()
    {
        return $this->countNominalBeds();
    }

    public function countNominalBeds()
    {
        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_bed.id
            FROM hms_bed
            JOIN hms_room
            ON room_id = hms_room.id
            JOIN hms_floor
            ON floor_id = hms_floor.id
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id AND hms_room.offline = 0 AND hms_room.overflow = 0 AND hms_room.parlor = 0";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $result = $sth->rowCount();

        return $result;
    }

    /*
     * Returns the number of students currently assigned to the current hall
    */
    public function get_number_of_assignees()
    {
        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_assignment.id
            FROM hms_assignment
            JOIN hms_bed
            ON bed_id = hms_bed.id
            JOIN hms_room
            ON room_id = hms_room.id
            JOIN hms_floor
            ON floor_id = hms_floor.id
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $result = $sth->rowCount();

        return $result;
    }

    /*
     * Returns an array of floor objects which are within the current hall.
    */
    public function &get_floors()
    {
        if (!$this->loadFloors()) {
            return false;
        }

        return $this->_floors;
    }

    public function getFloors()
    {
        $this->loadFloors();
        return $this->_floors;
    }

    /*
     * Returns an array with the keys being floor ID's and the value being the floor number
    */
    public function get_floors_array()
    {
        if (!$this->loadFloors()) {
            return false;
        }

        $floors = array();

        foreach ($this->_floors as $floor) {
            $floors[$floor->id] = $floor->floor_number;
        }

        return $floors;
    }

    /*
     * Returns an array of room objects which are in the current hall
    */
    public function &get_rooms()
    {
        if (!$this->loadFloors()) {
            return false;
        }

        $rooms = array();

        foreach ($this->_floors as $floor) {
            $floor_rooms = $floor->get_rooms();
            if(!empty($floor_rooms))
            {
              $rooms = array_merge($rooms, $floor_rooms);
            }
        }
        return $rooms;
    }

    /*
     * Returns an array of the bed objects which are in the current hall
    */
    public function &get_beds()
    {
        if (!$this->loadFloors()) {
            return false;
        }

        $beds = array();

        foreach ($this->_floors as $floor) {
            $floor_beds = $floor->get_beds();
            $beds = array_merge($rooms, $floor_beds);
        }
        return $beds;
    }

    /**
     * Determines the number of beds per room in a hall.  If the count varies for some rooms,
     * then return the count that applies to the majority of the rooms.
     * @deprecated -- Unused as far as I can tell
     *
     */
    public function count_beds_per_room()
    {
        $total = array(); // stores the number of rooms with that many beds

        $db = PdoFactory::getPdoInstance();
        $sql = "SELECT hms_room.*
            FROM hms_room
            JOIN hms_floor
            ON floor_id = hms_floor.id
            JOIN hms_residence_hall
            ON residence_hall_id = hms_residence_hall.id
            WHERE hms_residence_hall.id = :id";
        $sth = $db->prepare($sql);
        $sth->execute(array('id' => $this->id));
        $result = $sth->fetchAll(\PDO::FETCH_ASSOC);

        // and for each room get a list of the beds
        foreach ($result as $room) {
            $db = PdoFactory::getPdoInstance();
            $sql = "SELECT hms_bed.id
                FROM hms_bed
                JOIN hms_room
                ON room_id = hms_room.id
                WHERE hms_room.id = :id";
            $sth = $db->prepare($sql);
            $sth->execute(array('id' => $room['id']));
            $result = $sth->rowCount();

            // and increment the count of the number of rooms with that many
            // beds in this hall
            if ($result) {
                $total[$result] = empty($total[$result]) ? 1 : $total[$result] + 1;
            }
        }

        asort($total); // Sort the bed totals by the number of rooms that have each total

        if(!end($total)){  // Jump to the end of the array, return false if array is empty
            return key($total); // return the last key (the greatest number of beds)
        } else {
            return null; // There aren't any beds, so we can't find the max
        }
    }

    /*
     * Returns an array of the student objects which are currently assigned to the current hall
    */
    public function get_assignees()
    {
        if (!$this->loadFloors()) {
            return false;
        }

        $assignees = array();

        foreach ($this->_floors as $floor) {
            $floor_assignees = $floor->get_assignees();
            $assignees = array_merge($assignees, $floor_assignees);
        }
        return $assignees;
    }

    /*
     * Returns TRUE if the hall has vacant beds, false otherwise
    */
    public function has_vacancy()
    {
        /*
         if($this->get_number_of_assignees() < $this->get_number_of_beds()) {
        return TRUE;
        }
        */
        $floors = $this->getFloorsWithVacancies();

        if (sizeof($floors) > 0) {
            return true;
        }

        return FALSE;
    }

    /**
     * Returns an array of floor objects in this hall that have vacancies
     */
    public function getFloorsWithVacancies()
    {
        if (!$this->loadFloors()) {
            return false;
        }

        $vacant_floors = array();

        foreach ($this->_floors as $floor) {
            if ($floor->has_vacancy()) {
                $vacant_floors[] = $floor;
            }
        }

        return $vacant_floors;
    }

    public function count_avail_lottery_rooms($gender, $rlcId = null)
    {
        $now = time();

        $db = PdoFactory::getPdoInstance();
        // Calculate the number of non-full male/female rooms in this hall
        $query = "SELECT DISTINCT hms_room.id FROM hms_room
                    JOIN hms_bed ON hms_bed.room_id = hms_room.id
                    JOIN hms_floor ON hms_room.floor_id = hms_floor.id
                    JOIN hms_residence_hall ON hms_floor.residence_hall_id = hms_residence_hall.id
                    WHERE (hms_bed.id NOT IN (SELECT bed_id FROM hms_lottery_reservation WHERE term = :term AND expires_on > :now)
                    AND hms_bed.id NOT IN (SELECT bed_id FROM hms_assignment WHERE term = :term))
                    AND hms_residence_hall.id = :id
                    AND hms_residence_hall.is_online = 1
                    AND hms_floor.is_online = 1
                    AND hms_floor.rlc_id IS NULL
                    AND hms_room.gender_type IN (:gender,3)
                    AND hms_room.reserved = 0
                    AND hms_room.offline = 0
                    AND hms_room.private = 0
                    AND hms_room.overflow = 0
                    AND hms_room.parlor = 0 ";

        $params = array('id' => $this->id, 'term' => $this->term, 'now' => $now, 'gender' => $gender);

        if($rlcId != null) {
            $query .= "AND hms_room.reserved_rlc_id = :rlc ";
            $params += ['rlc' => $rlcId];
        }else {
            $query .= "AND hms_room.reserved_rlc_id IS NULL ";
        }

        $query .= "AND hms_bed.international_reserved = 0
                    AND hms_bed.ra = 0
                    AND hms_bed.ra_roommate = 0";

        $sth = $db->prepare($query);
        $sth->execute($params);
        $avail_rooms = $sth->rowCount();

        return $avail_rooms;
    }

    /**
     * Returns an array where each element is an associative sub-array of info for
     * the coordinators of this halll. Returns null if there is no coordinator.
     * NB: There may be multiple people with the coordinator role. This will return
     * the array of all of them.
     */
    public function getCoordinators()
    {
        return HMS_Permission::getUsersInRoleForInstance('Coordinator', $this);
    }

    /**
     * *******************
     * Getters & Setters *
     */
    public function getBannerBuildingCode()
    {
        return $this->banner_building_code;
    }

    /**
     * Returns the ID of this hall's package desk
     *
     * @return int
     */
    public function getPackageDeskId()
    {
        return $this->package_desk;
    }

    /**
     * Sets the package desk ID for this hall.
     * Id must appear in
     * the 'hms_package_desk' table.
     *
     * @param int $id
     */
    public function setPackageDeskId($id)
    {
        $this->package_desk = $id;
    }

    /**
     * Returns whether a meal plan is required for this residence hall.
     * @return int Integer value 1 if a meal plan is required, 0 if a meal plan is optional
     */
    public function mealPlanRequired(){
        return $this->meal_plan_required;
    }

    /**
     * ****************
     * Static Methods *
     * ***************
     */

    /**
     * Returns an array of hall objects for the given term.
     * If no
     * term is provided, then the current term is used.
     *
     * @deprecated
     *
     * @see ResidenceHallFactory
     */
    public static function get_halls($term)
    {
        $db = PdoFactory::getPdoInstance();
        $params = array();
        $sql = "SELECT id FROM hms_residence_hall ";
        if (isset($term)) {
            $sql .= 'WHERE term = :term ORDER BY hall_name ASC';
            $params += ['term' => $term];
        }else{
            $sql .= 'ORDER BY hall_name ASC';
        }
        $sth = $db->prepare($sql);
        $sth->execute($params);
        $results = $sth->fetchAll(\PDO::FETCH_ASSOC);

        foreach ($results as $result) {
            $halls[] = new ResidenceHall($result['id']);
        }

        return $halls;
    }

    /**
     * Returns an array with the hall id as the key and the hall name as the value
     *
     * @deprecated
     *
     * @see ResidenceHallFactory
     */
    public static function get_halls_array($term = NULL)
    {
        $hall_array = array();

        $halls = ResidenceHallFactory::getHallsForTerm($term);

        foreach ($halls as $hall) {
            $hall_array[$hall->id] = $hall->hall_name;
        }

        return $hall_array;
    }

    public static function getHallsDropDownValues($term)
    {
        $hall_array = array();

        $halls = ResidenceHallFactory::getHallsForTerm($term);

        $hall_array[0] = 'Select...';

        foreach ($halls as $hall) {
            $hall_array[$hall->id] = $hall->hall_name;
        }

        return $hall_array;
    }

    /**
     * Returns an array of only the halls with vacancies
     */
    public static function getHallsWithVacancies($term)
    {
        $vacant_halls = array();

        $halls = ResidenceHallFactory::getHallsForTerm($term);

        foreach ($halls as $hall) {
            if ($hall->has_vacancy()) {
                $vacant_halls[] = $hall;
            }
        }

        return $vacant_halls;
    }

    /**
     * Returns an array with a key of the hall ID and a value of the hall name
     * for halls which have vacancies
     */
    public static function getHallsWithVacanciesArray($term)
    {
        $hallArray = array();
        $hallArray[0] = 'Select...';

        $halls = ResidenceHall::getHallsWithVacancies($term);

        foreach ($halls as $hall) {
            $hallArray[$hall->id] = $hall->hall_name;
        }

        return $hallArray;
    }

    /**
     * Returns an associate array (key = hall id, value = hall name) of halls
     * which have an available lottery bed (based on the term, gender, the number
     * of lottery rooms allotted in the hall, the number of used lottery rooms, and
     * any pending lottery bed reservations.
     */
    public static function get_lottery_avail_hall_list($term)
    {
        $halls = ResidenceHall::get_halls($term);

        $output_list = array();

        foreach ($halls as $hall) {

            // Make sure we have a room of the specified gender available in the hall (or a co-ed room)
            if ($hall->count_avail_lottery_rooms($gender) <= 0 && $hall->count_avail_lottery_rooms(COED) <= 0) {
                continue;
            }

            $output_list[] = $hall;
        }

        return $output_list;
    }
}