aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin J Hoerr <kjhoerr@protonmail.com>2017-07-08 13:58:36 -0400
committerKevin J Hoerr <kjhoerr@protonmail.com>2017-07-08 13:58:36 -0400
commit692a4a48d5f8f74a06d0b5890e31887a76a903f3 (patch)
tree9fc39dc20be3b8a442031b85beffc7baa583143b
parent0364d790e9764d91489db21805064ceeb23e3e22 (diff)
downloadaugust-offensive-692a4a48d5f8f74a06d0b5890e31887a76a903f3.tar.gz
august-offensive-692a4a48d5f8f74a06d0b5890e31887a76a903f3.tar.bz2
august-offensive-692a4a48d5f8f74a06d0b5890e31887a76a903f3.zip
Improve exception handling, introduce autoloading
-rw-r--r--index.php43
-rw-r--r--private/Controller/Controller.php44
-rw-r--r--private/Model/Connection.php3
-rw-r--r--private/View/Main.php26
-rw-r--r--private/View/Output.php34
5 files changed, 124 insertions, 26 deletions
diff --git a/index.php b/index.php
index 8c9ef11..f8ef302 100644
--- a/index.php
+++ b/index.php
@@ -4,21 +4,38 @@ declare(strict_types=1);
namespace AugustOffensive;
-// y u no autoload
-include 'private/Model/Connection.php';
-include 'private/Model/Query.php';
-include 'private/Model/Result.php';
-include 'private/View/Main.php';
-include 'private/Controller/Controller.php';
+// Borrowed and modified from PSR-4 Closure Example
+spl_autoload_register(
+ function ($class) {
+ $prefix = 'AugustOffensive\\';
+ $relative_class = substr($class, strlen($prefix));
+
+ // find file in /private/ in respective namespace path
+ $file = __DIR__ . '/private/' . str_replace('\\', '/', $relative_class) . '.php';
+
+ // if the file exists, require it
+ if (file_exists($file)) {
+ require $file;
+ }
+ }
+);
use AugustOffensive\View;
-use AugustOffensive\Model;
+use AugustOffensive\Controller;
+
+try {
+ // initiate connection and build front-end
+ $connection = Controller\Controller::initiateConnection();
+ $view = new View\Main($connection);
-// initiate connection and build front-end
-$connection = new Model\Connection();
-$view = new View\Main($connection);
+ // get results of query from front-end
+ $result = $view->generateResult();
-// get results of query from front-end
-$result = $view->generateResult();
+ echo $result;
+} catch (\Exception $err) {
+ // catch all exceptions and let the controller generate the error
+ $error = Controller\Controller::errorResult($err);
-echo $result;
+ // pass generated error result to output
+ echo View\Main::generateOutput($error);
+}
diff --git a/private/Controller/Controller.php b/private/Controller/Controller.php
index 188345a..586be15 100644
--- a/private/Controller/Controller.php
+++ b/private/Controller/Controller.php
@@ -12,6 +12,20 @@ use AugustOffensive\Model;
class Controller
{
/**
+ * Initiates connection with the database.
+ *
+ * While errors are ideally handled by the controller, this instantiation
+ * will likely throw a \PDOException which should be handled by the front-
+ * end due to this being a fatal error and generally unrecoverable.
+ *
+ * @return Model\Connection
+ */
+ public static function initiateConnection (): Model\Connection
+ {
+ return new Model\Connection();
+ }
+
+ /**
* Creates and returns a Query object.
*
* If the creation results in an error, a different query object is
@@ -29,9 +43,9 @@ class Controller
array $content
): Model\Query {
try {
- return new Model\Query ($path, $request, $content);
+ return new Model\Query($path, $request, $content);
} catch (\Exception $err) {
- return new Model\Query (array(), "", array("ERROR" => $err->getMessage()));
+ return new Model\Query(array(), "", array("ERROR" => $err->getMessage()));
}
}
@@ -48,9 +62,31 @@ class Controller
array $result
): Model\Result {
try {
- return new Model\Result ($resultType, $result);
+ return new Model\Result($resultType, $result);
} catch (\Exception $err) {
- return new Model\Result ("ERROR", array($err->getMessage()));
+ return new Model\Result("ERROR", array($err->getMessage()));
+ }
+ }
+
+ /**
+ * Obtain the error result based on the exception that was thrown.
+ *
+ * @param \Exception $err the error that was thrown.
+ *
+ * @return Model\Result
+ */
+ public static function errorResult (\Exception $err): Model\Result
+ {
+ $errorType = "";
+ // Juggle error: objective is to sort error type
+ try {
+ throw $err;
+ } catch (\PDOException $e) {
+ $errorType = "DATABASE_ERROR";
+ } catch (\Exception $e) {
+ $errorType = "ERROR";
}
+
+ return new Model\Result($errorType, array("error" => $err->getMessage()));
}
}
diff --git a/private/Model/Connection.php b/private/Model/Connection.php
index 48cf4fb..4afa330 100644
--- a/private/Model/Connection.php
+++ b/private/Model/Connection.php
@@ -19,6 +19,7 @@ class Connection
public function __construct ()
{
// Establish connection to db
+ // breaks side-effect rule
include 'creds.php';
try {
@@ -34,7 +35,7 @@ class Connection
} catch (\PDOException $err) {
// we destroy $cred as quickly as possible
$cred = null;
- die(json_encode(array("Result-Type" => "ERROR", "Content" => array($err->getMessage()))));
+ throw $err; // throw for Controller to catch
}
return $this;
}
diff --git a/private/View/Main.php b/private/View/Main.php
index 1dcd760..746c2bb 100644
--- a/private/View/Main.php
+++ b/private/View/Main.php
@@ -18,6 +18,9 @@ class Main
/** @var Model\Result $result the Result object to be sent to the client. */
private $result;
+ /** @var string TYPE The type of output the client should receive. */
+ private const TYPE = "json";
+
/**
* Prepares the output and environment for the front end of the service.
*
@@ -27,8 +30,6 @@ class Main
*/
public function __construct (Model\Connection $connection)
{
- header("Content-Type: application/json");
-
$this->query = Controller\Controller::createQuery(
explode('/', trim($_SERVER['PATH_INFO'] ?? '/api', '/')),
$_SERVER['REQUEST_METHOD'],
@@ -58,7 +59,7 @@ class Main
}
/**
- * Communicates with the controller to generate the JSON result.
+ * Communicates with the controller to generate the output.
*
* @return string
*/
@@ -69,10 +70,19 @@ class Main
array()
);
- // generate result
- return json_encode(array(
- "Result-Type" => $this->result->getResultType(),
- "Content" => $this->result->getResult()
- ));
+ return self::generateOutput($this->result);
+ }
+
+ /**
+ * Creates output of the result based on the defined constant TYPE.
+ *
+ * @param Model\Result $result The result to be sent to the client.
+ *
+ * @return string
+ */
+ public static function generateOutput (Model\Result $result): string
+ {
+ $type = self::TYPE;
+ return Output::$type($result);
}
}
diff --git a/private/View/Output.php b/private/View/Output.php
new file mode 100644
index 0000000..fe42c15
--- /dev/null
+++ b/private/View/Output.php
@@ -0,0 +1,34 @@
+<?php
+
+declare(strict_types=1);
+
+namespace AugustOffensive\View;
+
+use AugustOffensive\Model;
+
+/**
+ * Output formats for Results that are returned to the client.
+ */
+class Output
+{
+ /**
+ * Formats the result into JSON.
+ *
+ * @param Model\Result $result The result to return to the client.
+ * @param bool $prepare Whether to set the content type of the response (default true).
+ *
+ * @return string
+ */
+ public static function json (Model\Result $result, bool $prepare = true): string
+ {
+ // breaks side effect rule?
+ if ($prepare) {
+ header("Content-Type: application/json");
+ }
+
+ return json_encode(array(
+ "Result-Type" => $result->getResultType(),
+ "Content" => $result->getResult()
+ ));
+ }
+}