AppStateESS/InternshipInventory

View on GitHub
class/Command/SaveInternship.php

Summary

Maintainability
F
3 days
Test Coverage
<?php

/**
 * This file is part of Internship Inventory.
 *
 * Internship Inventory is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * Internship Inventory is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License version 3
 * along with Internship Inventory.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2011-2018 Appalachian State University
 */

namespace Intern\Command;

use \Intern\WorkflowStateFactory;
use \Intern\ChangeHistory;
use \Intern\DatabaseStorage;
use \Intern\DataProvider\Student\StudentDataProviderFactory;
use \Intern\TermFactory;
use \Intern\SupervisorFactory;
use \Intern\SubHostFactory;
use \Intern\Exception\StudentNotFoundException;

/**
 * Controller class to save changes (on create or update) to an Internship
 *
 * @author jbooker
 * @package intern
 */
class SaveInternship {

    public function __construct(){}

    private function rerouteWithError($url, $errorMessage)
    {
        // Restore the values in the fields the user already entered
        foreach ($_POST as $key => $val) {
            $url .= "&$key=$val";
        }

        \NQ::simple('intern', \Intern\UI\NotifyUI::ERROR, $errorMessage);
        \NQ::close();

        return \PHPWS_Core::reroute($url);
    }

    public function execute() {
        // We don't want to do certain things like state change or error checks if this is an ajax request.
        $isAjax = false;
        if(\Canopy\Request::isAjax()){
            $isAjax = true;
        }
        /**************
         * Sanity Checks
         */
        // Required fields check
        $missing = self::checkRequest();
        if (!is_null($missing) && !empty($missing)) {
            // checkRequest returned some missing fields.
            $url = 'index.php?module=intern&action=ShowInternship';
            $url .= '&missing=' . implode('+', $missing);

            $this->rerouteWithError($url, 'Please fill in the highlighted fields.');
        }

        // Course start date must be before end date
        if (!empty($_REQUEST['start_date']) && !empty($_REQUEST['end_date'])) {
            $start = strtotime($_REQUEST['start_date']);
            $end = strtotime($_REQUEST['end_date']);

            if ($start >= $end) {
                if(!$isAjax){
                    $url = 'index.php?module=intern&action=ShowInternship&missing=start_date+end_date';
                    // Restore the values in the fields the user already entered
                    unset($_POST['start_date']);
                    unset($_POST['end_date']);
                    $this->rerouteWithError($url,
                            'The internship start date must be before the end date.');
                }
            }
        }

        // Sanity check internship supervisor zip, allows a-z or A-Z if international
        if ((isset($_REQUEST['supervisor_zip']) && $_REQUEST['supervisor_zip'] != "") && !is_numeric($_REQUEST['supervisor_zip'])) {
            if (!($_REQUEST['location'] == 'international' && preg_match('/[\w]/',
                            $_REQUEST['supervisor_zip']))) {
                $url = 'index.php?module=intern&action=ShowInternship&missing=supervisor_zip';
                $this->rerouteWithError($url,
                        "The supervisor's zip code is invalid. No changes were saved. Zip codes should be 5 digits only (no letters, spaces, or punctuation).");
            }
        }

        // Sanity check course number
        if ((isset($_REQUEST['course_no']) && $_REQUEST['course_no'] != '') && (strlen($_REQUEST['course_no']) > 20 || !is_numeric($_REQUEST['course_no']))) {
            $url = 'index.php?module=intern&action=ShowInternship&missing=course_no';
            $this->rerouteWithError($url,
                    "The course number provided is invalid. No changes were saved. Course numbers should be less than 20 digits (no letters, spaces, or punctuation).");
        }

        \PHPWS_DB::begin();

        /********************************
         * Load the existing internship *
         */
        try {
            $i = \Intern\InternshipFactory::getInternshipById($_REQUEST['internship_id']);
        } catch (\Exception $e) {
            // Rollback and re-throw the exception so that admins gets an email
            \PHPWS_DB::rollback();
            throw $e;
        }

        // Check that the form token matched before we save anything
        if ($i->form_token == $_REQUEST['form_token']) {
            // Generate a new form token
            $i->form_token = uniqid();
        } else {
            // Form token doesn't match, so show a nice error message
            $this->rerouteWithError('index.php?module=intern&action=ShowInternship',
                    'Someone else has modified this internship while you were working. In order to not overwrite their changes, your changes were not saved.');
        }

        // Load the student object
        try {
            $student = StudentDataProviderFactory::getProvider()->getStudent($i->getBannerId());
        } catch (StudentNotFoundException $e) {
            $student = null;
            \NQ::simple('intern', \Intern\UI\NotifyUI::WARNING, "We couldn't find a matching student in Banner. Your changes were saved, but this student probably needs to contact the Registrar's Office to re-enroll.");
            \NQ::close();
        }

        $i->faculty_id = $_REQUEST['faculty_id'] > 0 ? $_REQUEST['faculty_id'] : null;
        $i->department_id = $_REQUEST['department'];
        $i->start_date = !empty($_REQUEST['start_date']) ? strtotime($_REQUEST['start_date']) : 0;
        $i->end_date = !empty($_REQUEST['end_date']) ? strtotime($_REQUEST['end_date']) : 0;
        $i->credits = isset($_POST['multipart']) && isset($_POST['secondary_part']) ? null : (int) $_REQUEST['credits'];
        $avg_hours_week = (int) $_REQUEST['avg_hours_week'];
        $i->avg_hours_week = $avg_hours_week ? $avg_hours_week : null;
        $i->paid = $_REQUEST['payment'] == 'paid';
        $i->stipend = isset($_REQUEST['stipend']) && $i->paid;
        $i->pay_rate = self::trimField($_REQUEST['pay_rate']);
        $i->loc_phone = self::trimField($_REQUEST['host_phone']);
        if (isset($_POST['remote'])){
            $i->remote = 1;
            $i->remote_state = $_POST['remote_state'];
        } else{
            $i->remote = 0;
            $i->remote_state = NULL;
        }

        if (\Current_User::allow('intern', 'change_term')) {
            $i->term = $_REQUEST['term'];
        }

        $term = TermFactory::getTermByTermCode($i->term);

        // Internship experience type
        if (isset($_REQUEST['experience_type'])) {
            $i->setExperienceType($_REQUEST['experience_type']);
        }

        //Location Data
        if(isset($_REQUEST['SUB_NAME'])){
            $i->host_sub_id = $_REQUEST['SUB_NAME'];
        }

        // Save State/Country if deity changing host
        if (\Current_User::isDeity()) {
            $i->host_id = $_REQUEST['main_host'];
            $i->host_sub_id = $_REQUEST['sub_host'];

            $subInfo = SubHostFactory::getSubById($_REQUEST['sub_host']);
            if($i->isDomestic()) {
                $i->loc_state = $subInfo->state;
            } else{
                $i->loc_country = $subInfo->country;
                $i->loc_province = $subInfo->province;
            }
        }

        if (isset($_POST['course_subj']) && $_POST['course_subj'] != '-1') {
            $i->course_subj = strip_tags($_POST['course_subj']);
        } else {
            $i->course_subj = null;
        }

        // Course info
        $i->course_no = !isset($_POST['course_no']) ? null : self::trimField(strip_tags($_POST['course_no']));
        $i->course_sect = !isset($_POST['course_sect']) ? null : self::trimField(strip_tags($_POST['course_sect']));
        $i->course_title = !isset($_POST['course_title']) ? null : self::trimField(strip_tags($_POST['course_title']));

        // Multipart course
        if (isset($_POST['multipart'])) {
            $i->multi_part = 1;
        } else {
            $i->multi_part = 0;
        }

        if (isset($_POST['multipart']) && isset($_POST['secondary_part'])) {
            $i->secondary_part = 1;
        } else {
            $i->secondary_part = 0;
        }

        // Corequisite Course Info
        if (isset($_POST['corequisite_course_num'])) {
            $i->corequisite_number = $_POST['corequisite_course_num'];
        }

        if (isset($_POST['corequisite_course_sect'])) {
            $i->corequisite_section = $_POST['corequisite_course_sect'];
        }

        // Student Information
        $i->preferred_name = self::trimField($_REQUEST['student_preferred_name']);
        $i->setPreferredNameMetaphone(self::trimField($_REQUEST['student_preferred_name']));
        $i->phone = self::trimField($_REQUEST['student_phone']);

        if (\Current_User::isDeity()) {
            $i->campus = $_REQUEST['campus'];
        }
        if (\Current_User::isDeity()) {
            $i->level = $_REQUEST['level'];
        }

        // Student major handling, if more than one major
        // Make sure we have a student object, since it could be null if the Banner lookup failed
        if (isset($student) && $student != null) {
            $majors = $student->getMajors();
        } else {
            $majors = array();
        }

        if (sizeof($majors) > 1) {

            if (!isset($_POST['major_code'])) {
                // Student has multiple majors, but user didn't choose one, so just take the first one
                $i->major_code = $majors[0]->getCode();
                $i->major_description = $majors[0]->getDescription();
            } else {
                // User choose a major, so loop over the set of majors until we find the matching major code
                $code = $_POST['major_code'];
                foreach ($majors as $m) {
                    if ($m->getCode() == $code) {
                        $major = $m;
                        break;
                    }
                }

                $i->major_code = $major->getCode();
                $i->major_description = $major->getDescription();
            }
        } else if (sizeof($majors) == 1) {
            // Student has exactly one major
            $i->major_code = $majors[0]->getCode();
            $i->major_description = $majors[0]->getDescription();
        }

        /************
         * OIED Certification
         */
        // Check if this has changed from non-certified->certified so we can log it later
        if ($i->oied_certified == 0 && $_POST['oied_certified_hidden'] == 'true') {
            // note the change for later
            $oiedCertified = true;
        } else {
            $oiedCertified = false;
        }

        if ($_POST['oied_certified_hidden'] == 'true') {
            $i->oied_certified = 1;
        } else if ($_POST['oied_certified_hidden'] == 'false') {
            $i->oied_certified = 0;
        } else {
            $i->oied_certified = 0;
        }

        /************
         * Background and Drug checks
         * mainly handled in otherGoodies.js
         */
        //var_dump('here');
        $i->bgcheck = isset($_POST['bgcheck']) ? 1 : 0;
        $i->dcheck = isset($_POST['dcheck']) ? 1 : 0;


        // If we don't have a state and this is a new internship,
        // then set an initial state
        if ($i->id == 0 && is_null($i->state)) {
            $state = WorkflowStateFactory::getState('CreationState');
            $i->setState($state); // Set this initial value
        }

        try {
            $i->save();
        } catch (\Exception $e) {
            // Rollback and re-throw the exception so that admins gets an email
            \PHPWS_DB::rollback();
            throw $e;
        }

        try {
            $supervisor = SupervisorFactory::getSupervisorById($_REQUEST['supervisor_id']);
        } catch (\Exception $e) {
            // Rollback and re-throw the exception so that admins gets an email
            \PHPWS_DB::rollback();
            throw $e;
        }

        //Supervisor Info
        $supervisor->supervisor_first_name = self::trimField($_REQUEST['supervisor_first_name']);
        $supervisor->supervisor_last_name = self::trimField($_REQUEST['supervisor_last_name']);
        $supervisor->supervisor_title = self::trimField($_REQUEST['supervisor_title']);
        $supervisor->supervisor_phone = self::trimField($_REQUEST['supervisor_phone']);
        $supervisor->supervisor_email = self::trimField($_REQUEST['supervisor_email']);
        $supervisor->supervisor_fax = self::trimField($_REQUEST['supervisor_fax']);
        $supervisor->supervisor_address = self::trimField($_REQUEST['supervisor_address']);
        $supervisor->supervisor_city = self::trimField($_REQUEST['supervisor_city']);
        $supervisor->supervisor_zip = $_REQUEST['supervisor_zip'];
        if ($i->isDomestic()) {
            $supervisor->supervisor_state = $_REQUEST['supervisor_state'] == '-1' ? null : $_REQUEST['supervisor_state'];
        } else {
            $supervisor->supervisor_province = self::trimField($_REQUEST['supervisor_province']);
            $supervisor->supervisor_country = $_REQUEST['supervisor_country'] == '-1' ? null : $_REQUEST['supervisor_country'];
        }
        $supervisor->address_same_flag = isset($_REQUEST['copy_address']) ? 't' : 'f';

        try {
            DatabaseStorage::save($supervisor);
        } catch (\Exception $e) {
            // Rollback and re-throw the exception so that admins gets an email
            \PHPWS_DB::rollback();
            throw $e;
        }

        //Commit to save changes in case of workflow error
        \PHPWS_DB::commit();
        \PHPWS_DB::begin();

        /** *************************
         * State/Workflow Handling *
         * ************************* */
        if(!$isAjax){
            if(!isset($_POST['workflow_action'])){
                $this->rerouteWithError('index.php?module=intern&action=ShowInternship',
                        'The saving of the current workflow status is unknown.');
            }
            $t = \Intern\WorkflowTransitionFactory::getTransitionByName($_POST['workflow_action']);
            $workflow = new \Intern\WorkflowController($i, $t);
            try {
                $workflow->doTransition(isset($_POST['notes']) ? $_POST['notes'] : null);
            } catch (\Intern\Exception\MissingDataException $e) {
                \NQ::simple('intern', \Intern\UI\NotifyUI::ERROR, $e->getMessage());
                \NQ::close();
                return \PHPWS_Core::reroute('index.php?module=intern&action=ShowInternship&internship_id=' . $i->id);
            }

            // Create a ChangeHisotry for the OIED certification.
            if ($oiedCertified) {
                $currState = WorkflowStateFactory::getState($i->getStateName());
                $ch = new ChangeHistory($i, \Current_User::getUserObj(), time(),
                        $currState, $currState, 'Certified by OIED');
                $ch->save();

                // Notify the faculty member that OIED has certified the internship
                if ($i->getFaculty() != null) {
                    $email = new \Intern\Email\OIEDCertifiedEmail(\Intern\InternSettings::getInstance(), $i, $term);
                    $email->send();
                }
            }

            \PHPWS_DB::commit();

            $workflow->doNotification(isset($_POST['notes']) ? $_POST['notes'] : null);
        }

        // If the user clicked the 'Generate Contract' button, then redirect to the PDF view
        if (isset($_POST['generateContract']) && $_POST['generateContract'] == 'true') {
            //return \PHPWS_Core::reroute('index.php?module=intern&action=pdf&internship_id=' . $i->id);
            echo json_encode($i);
            exit;
        } else {
            // Otherwise, redirect to the internship edit view
            // Show message if user edited internship
            \NQ::simple('intern', \Intern\UI\NotifyUI::SUCCESS, 'Saved internship for ' . $i->getFullName());
            \NQ::close();

            return \PHPWS_Core::reroute('index.php?module=intern&action=ShowInternship&internship_id=' . $i->id);
        }
    }

    /**
     * Check that required fields are in the REQUEST.
     */
    private static function checkRequest() {
        $vals = null;

        foreach (\Intern\InternshipView::$requiredFields as $field) {
            /* If not set or is empty (For text fields) */
            if (!isset($_REQUEST[$field]) || $_REQUEST[$field] == '') {
                $vals[] = $field;
            }
        }

        /* Required select boxes should not equal -1 */
        if (!isset($_REQUEST['department']) || $_REQUEST['department'] == -1) {
            $vals[] = 'department';
        }

        return $vals;
    }

    /**
     *  Trim fields for all user input text fields
     */
    private static function trimField(string $info)
    {
        //trims whitespaces from beginning and end of string
        $info = trim($info);
        //trims extra spaces from middle of two words
        $info = preg_replace('!\s+!', ' ', $info);
        return $info;
    }

}