railpage/railpagecore

View on GitHub
lib/Locos/Correction.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

/**
 * Locomotive suggestions/corrections
 * @since Version 3.8.7
 * @package Railpage
 * @author Michael Greenhill
 */

namespace Railpage\Locos;

use Railpage\AppCore;
use Railpage\Users\User;
use Railpage\Users\Factory as UserFactory;
use Railpage\PrivateMessages\Message;
use Exception;
use DateTime;
use stdClass;

/**
 * Locomotive suggestion or correction
 */

class Correction extends AppCore {
    
    /**
     * Open status
     * @since Version 3.8.7
     * @const int STATUS_OPEN
     */
    
    const STATUS_OPEN = 0;
    
    /**
     * Corrected status
     * @since Version 3.8.7
     * @const int STATUS_CLOSED
     */
    
    const STATUS_CLOSED = 1;
    
    /**
     * Ignored status
     * @since Version 3.8.7
     * @const int STATUS_IGNORED
     */
    
    const STATUS_IGNORED = 2;
    
    /**
     * Correction ID
     * @since Version 3.8.7
     * @var int $id
     */
    
    public $id;
    
    /**
     * Correction text
     * @since Version 3.8.7
     * @var string $text
     */
    
    public $text;
    
    /**
     * Date submitted
     * @since Version 3.8.7
     * @var \DateTime $Date
     */
    
    public $Date;
    
    /**
     * Status
     * @since Version 3.8.7
     * @var int $status
     */
    
    public $status;
    
    /**
     * User object of submitter
     * @since Version 3.8.7
     * @var \Railpage\Users\User $User
     */
    
    public $User;
    
    /**
     * Affected locomotive object
     * @since Version 3.8.7
     * @var object $Object
     */
    
    public $Object;
    
    /**
     * Resolution
     * @since Version 3.8.7
     * @var \stdClass $Resolution
     */
    
    public $Resolution;
    
    /**
     * Constructor
     * @since Version 3.8.7
     * @param int $id
     */
    
    public function __construct($id = NULL) {
        
        parent::__construct(); 
        
        if ($id = filter_var($id, FILTER_VALIDATE_INT)) {
            
            $this->populate($id); 
        }
    }
    
    /**
     * Populate this object
     * @since Version 3.9.1
     * @return void
     */
    
    private function populate($id) {
        
        $query = "SELECT * FROM loco_unit_corrections WHERE correction_id = ?";
        
        $row = $this->db->fetchRow($query, $id);
        
        if (count($row)) {
            $this->id = $id;
            $this->text = $row['text'];
            $this->User = UserFactory::CreateUser($row['user_id']);
            $this->Date = new DateTime($row['date']);
            $this->status = $row['status'];
            $this->Resolution = new stdClass;
            
            if (filter_var($row['resolved_by'], FILTER_VALIDATE_INT)) {
                $this->Resolution->User = UserFactory::CreateUser($row['resolved_by']);
                $this->Resolution->Date = new DateTime($row['resolved_date']);
            }
            
            if ($loco_id = filter_var($row['loco_id'], FILTER_VALIDATE_INT)) {
                $this->Object = new Locomotive($loco_id); 
                return;
            }
            
            if ($class_id = filter_var($row['class_id'], FILTER_VALIDATE_INT)) {
                $this->Object = new LocoClass($class_id); 
                return;
            }
        }
            
        throw new Exception("Unable to determine if this correction belongs to a locomotive or a locomotive class"); 
    }
    
    /**
     * Validate changes to this correction
     * @since Version 3.8.7
     * @return boolean
     * @throws \Exception if $this->text is empty
     * @throws \Exception if $this->Loco is not an instance of \Railpage\Locos\Locomotive
     * @throws \Exception if $this->User is not an instance of \Railpage\Users\User
     */
    
    private function validate() {
        if (empty($this->text)) {
            throw new Exception("Cannot validate changes to this correction: no text provided");
        }
        
        if (!$this->Object instanceof Locomotive && !$this->Object instanceof LocoClass) {
            throw new Exception("Cannot validate changes to this correction: no locomotive or locomotive class provided");
        }
        
        if (!$this->User instanceof User) {
            throw new Exception("Cannot validate changes to this correction: no valid user provided");
        }
        
        if (!$this->Date instanceof DateTime) {
            $this->Date = new DateTime;
        }
        
        if (!filter_var($this->status)) {
            $this->status = self::STATUS_OPEN;
        }
        
        return true;
    }
    
    /**
     * Get the loco ID or class ID for the DB insert
     * @since Version 3.9.1
     * @return null|int
     * @param string $column
     */
    
    private function getObjectIdForSQL($column) {
        
        $return = NULL;
        
        switch ($column) {
            case "class_id" : 
                $return = $this->Object instanceof LocoClass ? $this->Object->id : NULL;
                break;
            
            case "loco_id" : 
                $return = $this->Object instanceof Locomotive ? $this->Object->id : NULL;
                break;
            
        }
        
        return $return;
    }
    
    /**
     * Set the object that this correction applies to
     * @since Version 3.9.1
     * @param \Railpage\Locos\Locomotive | \Railpage\Locos\LocoClass $Object
     * @return \Railpage\Locos\Correction
     */
    
    public function setObject($Object = NULL) {
        
        if ($Object instanceof Locomotive) {
            $this->Object = $Object;
        }
        
        if ($Object instanceof LocoClass) {
            $this->Object = $Object;
        }
        
        return $this;
        
    }
    
    /**
     * Commit changes to this correction
     * @since Version 3.8.7
     * @return \Railpage\Locos\Correction
     */
    
    public function commit() {
        $this->validate();
        
        $data = array(
            "loco_id" => $this->getObjectIdForSQL("loco_id"),
            "class_id" => $this->getObjectIdForSQL("class_id"),
            "user_id" => $this->User->id,
            "date" => $this->Date->format("Y-m-d H:i:s"),
            "status" => $this->status,
            "resolved_by" => (isset($this->Resolution->User) && $this->Resolution->User instanceof User) ? $this->Resolution->User : 0,
            "resolved_date" => (isset($this->Resolution->Date) && $this->Resolution->Date instanceof DateTime) ? $this->Resolution->Date->format("Y-m-d H:i:s") : NULL,
            "text" => $this->text
        );
        
        if (filter_var($this->id, FILTER_VALIDATE_INT)) {
            $where = array(
                "correction_id = ?" => $this->id
            );
            
            $this->db->update("loco_unit_corrections", $data, $where); 
        } else {
            $this->db->insert("loco_unit_corrections", $data);
            $this->id = $this->db->lastInsertId();
        }
        
        return $this;
    }
    
    /**
     * Close this correction
     * @since Version 3.8.7
     * @throws \Exception if $this->Resolution->User is not an instance of \Railpage\Users\User
     * @return \Railpage\Locos\Correction
     * @param string $reason
     */
    
    public function close($reason = NULL) {
        
        $this->closeCorrection("accept", $reason); 
        
        return $this;
        
    }
    
    /**
     * Ignore this correction
     * @since Version 3.8.7
     * @throws \Exception if $this->Resolution->User is not an instance of \Railpage\Users\User
     * @return \Railpage\Locos\Correction
     * @param string $reason
     */
    
    public function ignore($reason = NULL) {
        
        $this->closeCorrection("ignore", $reason); 
        
        return $this;
        
    }
    
    /**
     * close the correction
     * @since Version 3.9.1
     * @param string $type
     * @param string $reason
     * @return void
     */
    
    private function closeCorrection($type, $reason) {
        
        if (!isset($this->Resolution->User) || !$this->Resolution->User instanceof User) {
            throw new Exception("Cannot close correction - User resolving this correction not specified");
        }
        
        $this->Resolution->Date = new DateTime;
        
        $data = array(
            "status" => $type == "accept" ? self::STATUS_CLOSED : self::STATUS_IGNORED,
            "resolved_by" => $this->Resolution->User->id,
            "resolved_date" => $this->Resolution->Date->format("Y-m-d H:i:s")
        );
        
        $where = array(
            "correction_id = ?" => $this->id
        );
        
        $this->db->update("loco_unit_corrections", $data, $where);
        
        /**
         * Send a PM to the author of the correction
         */
        
        $Message = new Message;
        $Message->setAuthor($this->Resolution->User);
        $Message->setRecipient($this->User);
        $Message->subject = $type == "accept" ? "Your Locomotives database correction has been accepted" : "Your Locomotives database correction was not accepted";
        
        $action = $type == "accept" ? "has been accepted" : "was not accepted";
        
        if ($this->Object instanceof Locomotive) {
            $Message->body = "Your suggested correction for [url=" . $this->Object->url->url . "]" . strval($this->Object) . "[/url] in [url=" . $this->Object->Class->url->url . "]" . $this->Object->Class->name . "[/url] " . $action . " by " . $this->Resolution->User->username . ".";
        } else {
            $Message->body = "Your suggested correction for [url=" . $this->Object->url . "]" . strval($this->Object) . "[/url] " . $action . " by " . $this->Resolution->User->username . ".";
        }
        
        if (!empty($this->text)) {
            $Message->body .= "\n\n[quote=Your suggestion]" . $this->text . "[/quote]";
        }
        
        if (!is_null($reason)) {
            $Message->body .= "\n\n" . $reason;
        }
        
        $Message->body .= "\n\nThis is an automated message - there is no need to reply.";
        
        $Message->send();
        
    }
    
    /**
     * Reject - alias of ignore
     * @since Version 3.9.1
     * @throws \Exception if $this->Resolution->User is not an instance of \Railpage\Users\User
     * @return \Railpage\Locos\Correction
     * @param string $reason
     */
    
    public function reject($reason = NULL) {
        
        return $this->ignore($reason); 
        
    }
    
    /**
     * Approve - alias of close
     * @since Version 3.9.1
     * @throws \Exception if $this->Resolution->User is not an instance of \Railpage\Users\User
     * @return \Railpage\Locos\Correction
     * @param string $reason
     */
    
    public function approve($reason = NULL) {
        
        return $this->close($reason); 
        
    }
     
    
    /**
     * Set the user object who has closed or ignored this correction
     * @since Version 3.9.1
     * @param \Railpage\Users\User $Maintainer
     * @return \Railpage\Locos\Correction
     */
    
    public function setMaintainer(User $Maintainer) {
        
        if (!isset($this->Resolution)) {
            $this->Resolution = new stdClass;
        }
        
        $this->Resolution->User = $Maintainer;
        
        return $this;
        
    }
}