From 1784514696120723718b9c2a1cae07fcc73ac565 Mon Sep 17 00:00:00 2001 From: Josh Sherman Date: Mon, 22 Sep 2008 01:43:18 +0000 Subject: [PATCH] Massive amounts of documentation has been added. git-svn-id: http://svn.cleancode.org/svn/pickles@55 4d10bc64-7434-11dc-a737-d2d0f8310089 --- Pickles.php | 41 ++++++++- classes/ArrayUtils.php | 25 +++++- classes/Config.php | 73 +++++++++++++++- classes/Controller.php | 38 +++++++-- classes/DB.php | 175 ++++++++++++++++++++++++++++++++++++-- classes/Error.php | 82 +++++++++++++++++- classes/ImageUtils.php | 41 ++++++++- classes/Mail.php | 31 +++++++ classes/Model.php | 66 ++++++++++++-- classes/Object.php | 44 +++++++++- classes/Request.php | 25 +++++- classes/Security.php | 35 +++++++- classes/Session.php | 80 ++++++++++++++++- classes/Singleton.php | 54 +++++++++++- classes/Viewer.php | 27 +++++- classes/Viewer/Common.php | 25 +++++- classes/Viewer/Debug.php | 31 ++++++- classes/Viewer/JSON.php | 16 +++- classes/Viewer/RSS.php | 23 +++++ classes/Viewer/Smarty.php | 68 ++++++++++++--- 20 files changed, 941 insertions(+), 59 deletions(-) diff --git a/Pickles.php b/Pickles.php index 9911f88..4d07085 100755 --- a/Pickles.php +++ b/Pickles.php @@ -1,23 +1,58 @@ + * @copyright 2007-2008 Joshua Sherman + * @usage require_once 'Pickles.php'; + */ +/** + * @todo Allow users to override the timezone from their configuration file. + */ +if (ini_get('date.timezone') == '') { + date_default_timezone_set('America/New_York'); +} + +/** + * @todo Change the TEMP_PATH to be named more accordingly (Smarty-centric) + * and ditch sys_get_temp_dir() and point to a directory inside the + * PICKLES path. + */ define('PICKLES_PATH', (phpversion() < 5.3 ? dirname(__FILE__) : __DIR__) . '/'); define('TEMP_PATH', sys_get_temp_dir() . '/pickles/smarty/' . $_SERVER['SERVER_NAME'] . '/'); +/** + * Magic function to automatically load classes + * + * Determines if the system needs to load a PICKLES core class or a PICKLES + * shared model (not to be confused with site level models). + * + * @param string $class Name of the class to be loaded + * @return boolean Return value of require_once() or false (default) + */ function __autoload($class) { $file = PICKLES_PATH . 'classes/' . str_replace('_', '/', $class) . '.php'; if (file_exists($file)) { - require_once $file; + return require_once $file; } else { $file = PICKLES_PATH . 'models/' . str_replace('_', '/', $class) . '.php'; if (file_exists($file)) { - require_once $file; + return require_once $file; } } + + return false; } ?> diff --git a/classes/ArrayUtils.php b/classes/ArrayUtils.php index 3e08580..32bb500 100755 --- a/classes/ArrayUtils.php +++ b/classes/ArrayUtils.php @@ -1,7 +1,29 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Just so it doesn't seem so bare, I need to add a few more common + * array manipulation functions. + */ class ArrayUtils { - + + /** + * Converts an object into an array (recursive) + * + * This only gets used by the Config class because simplexml_load_file() + * returns an object by default, and I prefered having it in an array format. + * + * @param object $object Object to be converted into an array + * @return array Resulting array formed from the passed object + */ public static function object2array($object) { if (is_object($object)) { $object = (array)$object; @@ -15,7 +37,6 @@ class ArrayUtils { return $object; } - } ?> diff --git a/classes/Config.php b/classes/Config.php index d7ab62b..a475793 100755 --- a/classes/Config.php +++ b/classes/Config.php @@ -1,13 +1,45 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Add the ability to load in multiple configuration files. + */ class Config extends Singleton { + /** + * Private instance of the Config class + */ private static $instance; + /** + * Timestamp from when the object was frozen + */ public $timestamp = null; + /** + * Private constructor + */ private function __construct() { } + /** + * Gets an instance of the configuration object + * + * Determines if a Config object has already been instantiated, if so it will + * use it. If not, it will check to see if a frozen copy of the object is + * available. If not, then a new object will be created. + * + * @return An instace of the Config class + */ public static function getInstance() { $session = Session::getInstance(); @@ -23,6 +55,16 @@ class Config extends Singleton { return self::$instance; } + /** + * Loads a configuration file + * + * Handles the potentialy loading of the configuration file, sanitizing the + * boolean values and freezing the instance for later use. + * + * @param string $file File name of the configuration file to be loaded + * @return boolean Based on the success or failure of the file load + * @todo Either get rid of or make better use of the Error object + */ public function load($file) { $load = true; if (isset($this->file)) { @@ -32,7 +74,8 @@ class Config extends Singleton { } } } - + + $load = true; if ($load) { if (file_exists($file)) { $this->file = $file; @@ -42,13 +85,36 @@ class Config extends Singleton { if (is_array($config_array)) { foreach ($config_array as $variable => $value) { if ($value == 'true' || $value == array()) { - $value = (bool) $value; + $value = (bool)$value; } - $this->$variable = $value == array() ? (bool) $value : $value; + $this->$variable = $value == array() ? (bool)$value : $value; } } + /** + * @todo Okay, now if no default section is specified, we'll + * default to the first section listed. But what should be + * done if no sections are specified? Perhaps force just + * the index to load, or perhaps error out? I have to keep + * in mind that single page sites exist where no navigation + * will exist. So yeah, I suppose just specifying the + * default would combat against that, or should I drill + * down further, and see if any site level models exist and + * load the first one, or even better I'm thinking that a + * shared model / template would be good when nothing is + * available. That would in turn tell the user to fix the + * issue to be able to get it all working again. Damn, + * this ended up being a long @todo. + * @todo This may be better suited in the loop above since we're + * already looping through all the values, we could snag it + * in passing. + */ + if (!isset($this->navigation['default']) || $this->navigation['default'] == '') { + $this->navigation['default'] = key($this->navigation['sections']); + + } + $this->freeze(); return true; @@ -59,7 +125,6 @@ class Config extends Singleton { } } } - } ?> diff --git a/classes/Controller.php b/classes/Controller.php index 3f78798..25107da 100755 --- a/classes/Controller.php +++ b/classes/Controller.php @@ -1,12 +1,26 @@ + * @copyright 2007-2008 Joshua Sherman + * @usage new Controller(); or new Controller('/path/to/config.xml'); + * @todo Possibly remove the conditionals for the CLI view + */ class Controller extends Object { - private $model = null; - private $viewer = null; - + /** + * Private objects + */ + private $model = null; + private $viewer = null; private $session = null; /* @@ -14,8 +28,17 @@ class Controller extends Object { private $controller = null; */ + /** + * Constructor + * + * To make life a bit easier when using PICKLES, the Controller logic is + * executed automatically via use of a constructor. + * + * @params string $file File name of the configuration file to be loaded + * @params string $controller Type of controller to create (Web or CLI) + * @todo Need to internally document the process better + */ public function __construct($file = '../config.xml', $controller = 'Web') { - parent::__construct(); // Establish the session @@ -44,7 +67,7 @@ class Controller extends Object { if (strpos($name, '/') === false) { $class = $name; $section = $name; - $event = null; + $event = null; } else { $class = str_replace('/', '_', $name); @@ -111,7 +134,6 @@ class Controller extends Object { } */ - } ?> diff --git a/classes/DB.php b/classes/DB.php index 41c59a0..6f135f1 100755 --- a/classes/DB.php +++ b/classes/DB.php @@ -1,19 +1,57 @@ db). Because the database + * object can execute raw SQL, there should be no limitations. + * + * @package PICKLES + * @author Joshua Sherman + * @copyright 2007-2008 Joshua Sherman + * @todo Internally document the functions better. + * @todo Potentially switch to PDO to be able to easily accomodate different + * database types. + * @todo Eventually finish adding in my ActiveRecord class, even though I + * feel active record dumbs people down since it's a crutch for + * actually being able to write SQL. + */ class DB extends Singleton { + /** + * Private instance of the DB class + */ private static $instance; + /** + * Private database information and login credentials + */ private $hostname; private $username; private $password; private $database; + /** + * Private MySQL resources + */ private $connection; private $results; + /** + * Private constructor + */ private function __construct() { } - + + /** + * Gets an instance of the database object + * + * Determines if a DB object has already been instantiated, if so it will use + * it. If not, it will check to see if a frozen copy of the object is + * available. If not, then a new object will be created. + * + * @return object An instace of the DB class + */ public static function getInstance() { $session = Session::getInstance(); @@ -29,6 +67,15 @@ class DB extends Singleton { return self::$instance; } + /** + * Opens database connection + * + * Establishes a connection to the MySQL database based on the configuration + * options that are available in the Config object. + * + * @return boolean Based on the success or failure of mysql_connect() + * @todo Remove the error supressing @ from mysql_connect() + */ public function open() { if (!is_resource($this->connection)) { $config = Config::getInstance(); @@ -66,6 +113,13 @@ class DB extends Singleton { return true; } + /** + * Closes database connection + * + * Checks to see if the connection is available, and if so, closes it out. + * + * @return boolean Returns the status of mysql_close() or false (default) + */ public function close() { if (is_resource($this->connection)) { return mysql_close($this->connection); @@ -74,6 +128,17 @@ class DB extends Singleton { return false; } + /** + * Executes SQL + * + * Executes the passed SQL without any manipulation. If no SQL is passed in + * the function will return false (why return true if it didn't actually do + * something?) + * + * @param string $sql SQL statement to be executed + * @return boolean Returns the status of the execution + * @todo Need to get rid of the error suppressing @ symbol. + */ public function execute($sql) { $this->open(); @@ -94,6 +159,25 @@ class DB extends Singleton { return false; } + /** + * Gets a field from a result set + * + * Returns the value of a single field from either a previously executed + * query, or from the passed SQL. This function assumes your query results + * only contain a single field. If multiple fields are returned, this + * function will only return the first one. + * + * @param string $sql SQL statement to be executed (optional) + * @return string Returns the value of the field or null if none + * @todo Need to remove the error supression + * @todo Right now it assumes your query only returns a single field, that + * probably should be changed to allow someone to specify what field + * they want from a row of data. Actually, this is still debatable + * as someone could use getRow and reference the field they want to + * accomplish the same goal. + * @todo Another debate point, should it return false instead of null, or + * perhaps have some sort of error indicator in the result set? + */ public function getField($sql = null) { if (isset($sql)) { $this->execute($sql); @@ -114,7 +198,31 @@ class DB extends Singleton { return null; } - + + /** + * Gets a row from a result set + * + * Returns a row in an associative array from either a previously executed + * query, or from the passed SQL. This function assumes your query results + * only contain a single row. If multiple rows are returned, this function + * will only return the first one. + * + * @param string $sql SQL statement to be executed (optional) + * @return string Returns the row in an associative array or null if none + * @todo Need to remove the error supression + * @todo Right now it assumes your query only returns a single row, that + * probably should be changed to allow someone to specify what row + * they want from a set of data. Actually, this is still debatable + * as someone could use getArray and reference the row they want to + * accomplish the same goal. + * @todo Another debate point, should it return false instead of null, or + * perhaps have some sort of error indicator in the result set? + * @todo Calling bullshit on my own code, apparently this should only be + * returning a single row, but returns all the rows instead of just + * the first one. So basically, this function is functioning exactly + * the same as DB::getArray(). Just goes to show how often I + * actually use this function. + */ public function getRow($sql = null) { if (isset($sql)) { $this->execute($sql); @@ -135,7 +243,19 @@ class DB extends Singleton { return null; } - + + /** + * Gets all the rows from a result set + * + * Returns all the rows (each row in an associative array) from either a + * previously executed query, or from the passed SQL. + * + * @param string $sql SQL statement to be executed (optional) + * @return string Returns the rows in an array or null if none + * @todo Need to remove the error supression + * @todo Another debate point, should it return false instead of null, or + * perhaps have some sort of error indicator in the result set? + */ public function getArray($sql = null) { if (isset($sql)) { $this->execute($sql); @@ -160,12 +280,23 @@ class DB extends Singleton { return null; } + /** + * Inserts a row into a table + * + * Easy insertion of a row into a table without being too savvy with SQL. + * + * @param string $table Name of the table you want to insert to + * @param array $columnValues Associative array of name value pairs + * (Corresponds with the column names for the table) + * @return boolean Returns the status of the execution + * @todo Convert from camel case to underscores + * @todo Check that the table exists, and possibly check that the columns + * exist as well + */ public function insert($table, $columnValues) { $this->open(); if (trim($table) != '') { - // @todo Check that the table exists, and possibly check that the columns exist as well - if (is_array($columnValues)) { foreach ($columnValues as $key => $value) { $columnValues[$key] = $value == null ? 'NULL' : "'" . mysql_real_escape_string(stripslashes($value), $this->connection) . "'"; @@ -192,12 +323,26 @@ class DB extends Singleton { return false; } + /** + * Updates an existing row row in a table + * + * Easy update of an existing row or rows (depending on the passed + * conditions) in a table without being too savvy with SQL. + * + * @params string $table Name of the table you want to insert to + * @params array $columnValues Associative array of name value pairs + * (Corresponds with the column names for the table) + * @params array $conditions Associative array of name value pairs that will + * be used to create a WHERE clause in the SQL. + * @return boolean Returns the status of the execution + * @todo Convert from camel case to underscores + * @todo Check that the table exists, and possibly check that the columns + * exist and conditional columns exist as well + */ public function update($table, $columnValues, $conditions) { $this->open(); if (trim($table) != '') { - // @todo Check that the table exists, and possibly check that the columns exist as well - $fields = $where = null; if (is_array($columnValues)) { foreach ($columnValues as $key => $value) { @@ -236,6 +381,22 @@ class DB extends Singleton { return false; } + /** + * Deletes an existing row row in a table + * + * Easy deletion of an existing row or rows (depending on the passed + * conditions) in a table without being too savvy with SQL. + * + * @access private + * @params string $table Name of the table you want to insert to + * @params array $columnValues Associative array of name value pairs + * (Corresponds with the column names for the table) + * @params array $conditions Associative array of name value pairs that will + * be used to create a WHERE clause in the SQL. + * @return boolean Returns the status of the execution + * @todo This function doesn't exist yet + * @todo Convert from camel case to underscores + */ public function delete($table, $columnValues, $conditions) { } diff --git a/classes/Error.php b/classes/Error.php index c4aa548..0725ba7 100755 --- a/classes/Error.php +++ b/classes/Error.php @@ -1,10 +1,41 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Internally document the functions better. + * @todo Convert the class to extend Singleton. + * @todo Quite possibly revamp the class entirely as it is still left over + * from the previous iteration of PICKLES (the system received a kick + * in the ass Q2 of 2008 to move in a more object-oriented direction, + * previously models were procedural files and not instantiated + * classes. I want to thank Joe Stump for the direction I took. + */ class Error { + /** + * Private message arrays + */ private static $errors; private static $warnings; - + + /** + * Gets an instance of the object + * + * Determines if the Error object has been instantiated, and if not, it will + * go ahead and instantiate it. + * + * @return object An instance of the Error class + */ public static function instance() { static $object; @@ -15,24 +46,63 @@ class Error { return $object; } + /** + * Adds an error message + * + * Takes the passed error message and loads it into the private array of + * error messages. + * + * @return boolean true + */ public static function addError($message) { self::$errors[] = $message; return true; } + /** + * Adds a warning message + * + * Takes the passed warning message and loads it into the private array of + * warning messages. + * + * @return boolean true + */ public static function addWarning($message) { self::$warnings[] = $message; return true; } + /** + * Gets the stored errors + * + * Returns the errors that have been stored in the private array of error + * messages. + * + * @return array Error messages indexed by the order they were stored + */ public static function getError() { return self::$errors; } + /** + * Gets the stored warnings + * + * Returns the warnings that have been stored in the private array of warning + * messages. + * + * @return array Warning messages indexed by the order they were stored + */ public static function getWarning() { return self::$warnings; } + /** + * Determines if there are any stored errors or warnings + * + * Checks the private error and warning arrays and returns the status. + * + * @return boolean Whether or not there are any errors or warnings. + */ public static function isError() { if (is_array(self::getError()) || is_array(self::getWarning())) { return true; @@ -41,6 +111,15 @@ class Error { return false; } + /** + * Display errors and warnings + * + * If any errors or warnings are set they are echo'd out separated by XHTML + * compliant line breaks. Also clears out the private arrays upon displaying + * their contents. + * + * @return boolean Whether or not there are any errors or warnings. + */ public function display() { if (self::isError()) { if (self::getError()) { @@ -61,7 +140,6 @@ class Error { return false; } - } ?> diff --git a/classes/ImageUtils.php b/classes/ImageUtils.php index e779008..5217405 100755 --- a/classes/ImageUtils.php +++ b/classes/ImageUtils.php @@ -1,7 +1,35 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Make the class usable. + */ class ImageUtils { + /** + * Checks an image format + * + * This is basically just a wrapper for in_array(). The passed image type is + * checked against the passed array of types (else it will use the default + * list). + * + * @param string $type The type of being being checked + * @param array $types An array of valid image types, defaults to the common + * web formats of jpg, gif and png + * @return boolean If the passed type is in the list of valid types + */ static function check($type, $types = array('image/jpeg', 'image/gif', 'image/png')) { if (!is_array($types)) { $types[0] = $types; @@ -10,6 +38,18 @@ class ImageUtils { return in_array($type, $types); } + /** + * Moves an uploaded file + * + * Handles not only moving an uploaded file to another location, but removes + * the original file once it's been moved. It's ashame that the function + * move_uploaded_file() just copies a file, and doesn't actually move it. + * + * @param string $origin The uploaded file that is to be moved + * @param string $destination The destination for the origin file + * @todo This function needs to return the status of the move + * @todo Currently if the move fails, the origin file will still be removed. + */ static function move($origin, $destination) { move_uploaded_file($origin, $destination); imagedestroy($origin); @@ -45,7 +85,6 @@ class ImageUtils { imagedestroy($source); */ - } ?> diff --git a/classes/Mail.php b/classes/Mail.php index 444aaa2..4c885bd 100755 --- a/classes/Mail.php +++ b/classes/Mail.php @@ -1,7 +1,38 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Just so it doesn't seem so bare, I need to come up and implement a + * few more mail functions. + * @todo Still thinking about making this an instantiated object instead of + * a static class. Perhaps I should add a mail (rename it to mailer + * maybe) object to each model so it's ready to be loaded, and if it + * is loaded, then go ahead and automatically send it?!? Loves it. + */ class Mail { + /** + * Sends an email message + * + * Creates and sends an email message. Relies heavily on a certain set of + * circumstances specifically, the sender information, subject and message + * are all assumed to be in the $_REQUEST variable and named a certain way. + * This isn't that bad assuming you're using the PICKLES canned contact form + * or adhere to the naming conventions. Recipient, subject line and subject + * line prefix can all be loaded in from the configuration file. + * + * @param array $recipients An array of recipients (optional) + * @param string $prefix Prefix to use on the subject line (optional) + * @return array An associative array with a status type and message + */ static function send($recipients = null, $prefix = null) { $config = Config::getInstance(); $defaults = $config->get('contact'); diff --git a/classes/Model.php b/classes/Model.php index c1f956a..1988069 100644 --- a/classes/Model.php +++ b/classes/Model.php @@ -1,37 +1,91 @@ + * @copyright 2007-2008 Joshua Sherman + */ class Model extends Object { - - protected $db = null; + + /** + * Data array used by the viewer + */ protected $data = array(); + + /** + * Database object + */ + protected $db = null; + + /** + * Name of the model + */ protected $name = null; + /** + * Constructor + * + * Handles calling the parent constructor and sets up the model's internal + * database object + */ public function __construct() { parent::__construct(); $this->db = DB::getInstance(); } + /** + * Gets the auth variable + * + * @return boolean Whether or not the model requires authorization to use + */ public function getAuth() { return $this->get('auth'); } + /** + * Gets the data variable + * + * @return array Associative array of data that was set by the model + */ public function getData() { return $this->get('data'); } + /** + * Gets the view type + * + * @return string The viewer that the model has requested to be used + */ public function getView() { return $this->get('view'); } + /** + * Destructor + * + * Handles calling the parent's constructor, nothing else. + */ public function __destruct() { parent::__destruct(); } - public function __default() { - - } - + /** + * Default function + * + * This function is overloaded by the model. The __default() function is + * where any code that needs to be executed at run time needs to be placed. + * It's not in the constructor as the model needs to be instantiated first + * so that the authorization requirements can be checked without running + * code it's potentially not supposed to have run. + */ + public function __default() { } } ?> diff --git a/classes/Object.php b/classes/Object.php index 6305ade..98d8219 100644 --- a/classes/Object.php +++ b/classes/Object.php @@ -1,16 +1,39 @@ + * @copyright 2007-2008 Joshua Sherman + */ class Object { + /** + * Protected instance of the Config class + * + * @todo Perhaps this should be private? + */ protected $config = null; + /** + * Constructor + * + * Handles getting an instance of the Config class. + */ public function __construct() { $this->config = Config::getInstance(); } - public function __destruct() { - - } + /** + * Destructor + */ + public function __destruct() { } /* // @todo maybe later @@ -23,6 +46,14 @@ class Object { } */ + /** + * Gets a variable + * + * @return Returns either the variable value or false if no variable. + * @todo Returning false could be misleading, especially if you're + * expecting a boolean value to begin with. Perhaps an error should + * be thrown? + */ public function get($variable, $array_element = null) { if (isset($this->$variable)) { if (isset($array_element)) { @@ -40,10 +71,15 @@ class Object { return false; } + /** + * Sets a variable + * + * @param string $variable Name of the variable to be set + * @param mixed $value Value to be assigned to the passed variable + */ public function set($variable, $value) { $this->$variable = $value; } - } ?> diff --git a/classes/Request.php b/classes/Request.php index 729c5f6..d8893dd 100755 --- a/classes/Request.php +++ b/classes/Request.php @@ -1,9 +1,25 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Phase out entirely or make use of it. + */ class Request { + /** + * Private request array + */ private static $request; + /** + * Loads the $_REQUEST super global into the object's array + */ public static function load() { if (is_array($_REQUEST)) { foreach ($_REQUEST as $key => $value) { @@ -15,6 +31,14 @@ class Request { return true; } + /** + * Gets a variable + * + * @return Returns either the variable value or false if no variable. + * @todo Returning false could be misleading, especially if you're + * expecting a boolean value to begin with. Perhaps an error should + * be thrown? + */ public static function get($variable) { if (isset(self::$request[$variable])) { return self::$request[$variable]; @@ -22,7 +46,6 @@ class Request { return false; } - } ?> diff --git a/classes/Security.php b/classes/Security.php index 8446dc8..eab7c95 100644 --- a/classes/Security.php +++ b/classes/Security.php @@ -1,7 +1,33 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Make the SQL less specific, right now you have to use a table + * named users, and use the email as the username. I will need to + * move this to the configuration and allow the user to specify which + * table to authenticate against, and what column names to use for the + * username and password. + */ class Security extends Object { - + + /** + * Authenticates the user + * + * Checks for the authentication variables to be passed in the $_SERVER super + * global and attempts to authenticate the user against MySQL. If the user + * cannot successfully they will be presented with a 401 Unauthorized page. + * + * @todo I'm sure someone will find the access denied message offensive, so + * this will need to be made more generic. May also want to add in the + * ability for someone to add a custom message and/or landing page in + * the configuration as well. + */ static function authenticate() { $db = DB::getInstance(); $session = Session::getInstance(); @@ -36,6 +62,12 @@ class Security extends Object { } } + /** + * Logs the user out + * + * Destroys the session, clears out the authentication variables in the + * $_SERVER super global and redirects the user to the root of the site. + */ static function logout() { $session = Session::getInstance(); $session->destroy(); @@ -45,7 +77,6 @@ class Security extends Object { header('Location: /'); } - } ?> diff --git a/classes/Session.php b/classes/Session.php index e5e71df..ab3b048 100755 --- a/classes/Session.php +++ b/classes/Session.php @@ -1,18 +1,52 @@ + * @copyright 2007-2008 Joshua Sherman + * @todo Make the SQL less specific, right now you have to use a table + * named users, and use the email as the username. I will need to + * move this to the configuration and allow the user to specify which + * table to authenticate against, and what column names to use for the + * username and password. + */ class Session extends Singleton { + /** + * Private instance of the Session class + */ private static $instance; + /** + * Session ID + */ public static $id = null; + /** + * Private constructor + * + * Checks if session.auto_start is not enabled and if not, it will start the + * session and then grabs the session ID. + * + * @todo Need to look into whether or not sessions can be disabled + * indefinately. If so, this may need to be rethought. + */ private function __construct() { if (ini_get('session.auto_start') == 0) { session_start(); - $this->id = session_id(); } + + $this->id = session_id(); } + /** + * Gets an instance of the Session class + */ public static function getInstance() { if (!self::$instance instanceof Session) { self::$instance = new Session(); @@ -21,6 +55,12 @@ class Session extends Singleton { return self::$instance; } + /** + * Destroys the session + * + * Loops through all the $_SESSION variables and session_unregister()s them. + * After the unregistering session_destory() is called + */ public function destroy() { // foreach ($_SESSION as $variable => $value) foreach (array_keys($_SESSION) as $variable) { @@ -30,10 +70,30 @@ class Session extends Singleton { session_destroy(); } + /** + * Clone function + * + * Triggers a PHP error as the Session class cannot be cloned because it + * extends the Singleton class. + * + * @todo The Config and Session (and any other Singleton classes) need to + * have this function. I think it can be added to the Singleton class + * directly, then the child classes will have it via inheritance. Wait + * just remembered that class inheritance with static classes is a bit + * screwy so every class may need the function directly. + */ public function __clone() { trigger_error('Clone is not allowed for ' . __CLASS__, E_USER_ERROR); } + /** + * Gets a session variable + * + * @param string $var Name of the variable to be returned + * @return Value of the requested variable + * @todo Returns null if the variable isn't set. Not sure if this is as + * drastic as returning false, we'll see. + */ public function __get($var) { if (!isset($_SESSION[$var])) { $_SESSION[$var] = null; @@ -42,14 +102,32 @@ class Session extends Singleton { return $_SESSION[$var]; } + /** + * Sets a session variable + * + * @param string $var Name of the variable to set + * @param mixed $val Value to be assigned to the passed variable + * @return boolean The returned status of assigning the variable. + */ function __set($var, $val) { return ($_SESSION[$var] = $val); } + /** + * Checks if a session variable is set + * + * @param string $var Name of the variable to be checked + * @return boolean Whether or not the passed variable is set + */ public function __isset($var) { return isset($_SESSION[$var]) || isset($this->$var); } + /** + * Destructor + * + * Closes out the session. + */ public function __destruct() { session_write_close(); } diff --git a/classes/Singleton.php b/classes/Singleton.php index 9e96095..0ad1238 100644 --- a/classes/Singleton.php +++ b/classes/Singleton.php @@ -1,9 +1,37 @@ + * @copyright 2007-2008 Joshua Sherman + */ class Singleton { + /** + * Private constructor + */ private function __construct() { } + /** + * Gets a variable + * + * @param string $variable Name of the variable to be returned + * @param string $array_element Name of the array element that's part of the + * requested variable (optional) + * @return Returns either the variable value or false if no variable. + * @todo Need better checking if the passed variable is an array when the + * array element value is present + * @todo Returning false could be misleading, especially if you're + * expecting a boolean value to begin with. Perhaps an error should + * be thrown? + */ public function get($variable, $array_element = null) { if (isset($this->$variable)) { if (isset($array_element)) { @@ -21,10 +49,24 @@ class Singleton { return false; } + /** + * Sets a variable + * + * @param string $variable Name of the variable to be set + * @param mixed $value Value to be assigned to the passed variable + */ public function set($variable, $value) { $this->$$variable = $value; } + /** + * Freezes (caches) an object + * + * Takes the object and serializes it and then stores it and the name and the + * timestamp that it was serialized in the session. + * + * @todo Needs to return the status for error tracking. + */ public function freeze() { $session = Session::getInstance(); $this->timestamp = time(); @@ -32,13 +74,23 @@ class Singleton { $session->$class = serialize($this); } + /** + * Thaws out a frozen object + * + * Forces an __autoload on the passed class name because if a serialized + * object is unserialized and then you attempt to use it, it will error out + * due to the class not being loaded. __autoload() doesn't occur + * automatically in this scenario, that's why it must be forced. + * + * @param string $class The name of the class to be thawed out + * @return object The unserialized object for the passed class name + */ public static function thaw($class) { __autoload($class); $session = Session::getInstance(); return unserialize($session->$class); } - } ?> diff --git a/classes/Viewer.php b/classes/Viewer.php index b5baee9..69f303e 100644 --- a/classes/Viewer.php +++ b/classes/Viewer.php @@ -1,14 +1,39 @@ + * @copyright 2007-2008 Joshua Sherman + */ class Viewer { + /** + * Private constructor + */ private function __construct() { } + /** + * Viewer factory + * + * Creates an instance of the Viewer type that the model requests. + * + * @param object $model The model to be displayed + * @return object An instance of the viewer, loaded with the passed model + * @todo Add some checking to determine if the passed object is really a + * valid instance of Model. + * @todo Create constants to correspond with each viewer type so it's + * potentially easier to reference from the model (since the + * constants would each be uppercase instead of mixedcase. + */ public static function factory(Model $model) { $class = 'Viewer_' . $model->getView(); return new $class($model); } - } ?> diff --git a/classes/Viewer/Common.php b/classes/Viewer/Common.php index 4f0637b..7894bab 100644 --- a/classes/Viewer/Common.php +++ b/classes/Viewer/Common.php @@ -1,16 +1,39 @@ + * @copyright 2007-2008 Joshua Sherman + */ abstract class Viewer_Common extends Object { + /** + * Protected model object + */ protected $model = null; + /** + * Constructor + * + * Runs the parent's constructor and adds the model to the object. + * + * @param object $model Object for the model we're loading + * @todo Need better validation of the passed model. + */ public function __construct(Model $model) { parent::__construct(); $this->model = $model; } + /** + * Abstract display function that is overloaded within the loaded viewer + */ abstract public function display(); - } ?> diff --git a/classes/Viewer/Debug.php b/classes/Viewer/Debug.php index 6dfc782..f34f1a8 100644 --- a/classes/Viewer/Debug.php +++ b/classes/Viewer/Debug.php @@ -1,7 +1,37 @@ + * @copyright 2007-2008 Joshua Sherman + */ class Viewer_Debug extends Viewer_Common { + /** + * Display the debugging information + * + * var_dump()s a few important super globals to aid in debugging. + * + * @todo May want to use contrib/dBug as it has better output. + * @todo Just a thought, perhaps instead of a debug viewer, the debug mode + * would be better served as an option in the model and then the + * regular viewer would be executed as well as displaying the debug + * data. + * @todo May also be cool to add in logic to check for the vi swap file, and + * if that's present, force the model into a debug state, as it will + * indicate it's being worked on. + * @todo Even cooler still, perhaps a debug console should be available when + * the model is marked debug or when a file is open. It would be + * activated with a hot key, would be legendary. + * @todo Perhaps it could be a configuration option to say that if a file is + * open, to now allow the end user to see the page, give them a generic + * "hey we're working on it" message. + */ public function display() { echo '

Debug

' . "\n"; echo '

$_REQUEST

' . "\n"; @@ -17,7 +47,6 @@ class Viewer_Debug extends Viewer_Common { var_dump($_SERVER); echo ''; } - } ?> diff --git a/classes/Viewer/JSON.php b/classes/Viewer/JSON.php index 07b0f0c..7a508f8 100644 --- a/classes/Viewer/JSON.php +++ b/classes/Viewer/JSON.php @@ -1,7 +1,21 @@ + * @copyright 2007-2008 Joshua Sherman + * @link http://json.org/ + */ class Viewer_JSON extends Viewer_Common { + /** + * Displays the data in JSON format + */ public function display() { header('Content-type: application/json; charset=utf-8'); @@ -10,9 +24,7 @@ class Viewer_JSON extends Viewer_Common { } else { echo json_encode($this->model->getData()); } - } - } ?> diff --git a/classes/Viewer/RSS.php b/classes/Viewer/RSS.php index c37d1db..ff996ed 100644 --- a/classes/Viewer/RSS.php +++ b/classes/Viewer/RSS.php @@ -1,7 +1,30 @@ + * @copyright 2007-2008 Joshua Sherman + * @link http://cyber.law.harvard.edu/rss/rss.html + * @todo Need to add support for RSS v1.0 as well as ATOM feeds. This may + * result in my abstracting out these classes a bit more (Probably a + * Feed viewer that would take a parameter to determine which type of + * of feed to use). + */ class Viewer_RSS extends Viewer_Common { + /** + * Displays the RSS feed data + * + * Uses a combination of configuration options and a properly formatted data + * array to create an RSS v2.0 feed. + * + * @todo Error handling is non-existant. + */ public function display() { $config = Config::getInstance(); $data = $this->model->getData(); diff --git a/classes/Viewer/Smarty.php b/classes/Viewer/Smarty.php index 2de266d..5124c40 100644 --- a/classes/Viewer/Smarty.php +++ b/classes/Viewer/Smarty.php @@ -1,7 +1,21 @@ + * @copyright 2007-2008 Joshua Sherman + * @link http://smart.net/ + */ class Viewer_Smarty extends Viewer_Common { + /** + * Displays the Smarty generated pages + */ public function display() { // Obliterates any passed in PHPSESSID (thanks Google) if (stripos($_SERVER['REQUEST_URI'], '?PHPSESSID=') !== false) { @@ -15,12 +29,17 @@ class Viewer_Smarty extends Viewer_Common { ini_set('arg_separator.output', '&'); ini_set('url_rewriter.tags', 'a=href,area=href,frame=src,input=src,fieldset='); - // @todo Create a wrapper so that we can auto load this + /** + * @todo Create a wrapper so that we can auto load this + */ require_once 'contrib/smarty/libs/Smarty.class.php'; $smarty = new Smarty(); - // @todo Perhaps the templates directory would be better suited as a config variable? + /** + * @todo Perhaps the templates directory would be better suited as a + * config variable? + */ $smarty->template_dir = '../templates/'; $cache_dir = TEMP_PATH . 'cache'; @@ -53,13 +72,19 @@ class Viewer_Smarty extends Viewer_Common { $navigation = $this->config->get('navigation', 'sections'); // Add the admin section if we're authenticated - // @todo add code to check if the user is logged in + /** + * @todo Add logic to check if the user is already logged in. Currently + * it is always assumed that they are not. + */ if (false) { if ($this->config->get('admin', 'menu') == true) { $navigation['admin'] = 'Admin'; } } + /** + * @todo Maybe the template path should be part of the configuration? + */ $template = '../templates/' . $this->model->get('name') . '.tpl'; $shared_template = str_replace('../', '../../pickles/', $template); @@ -73,15 +98,23 @@ class Viewer_Smarty extends Viewer_Common { $smarty->assign('navigation', $navigation); $smarty->assign('section', $this->model->get('section')); $smarty->assign('model', $this->model->get('name')); - $smarty->assign('action', $this->model->get('action')); // @todo rename me to event... - $smarty->assign('event', $this->model->get('action')); // but it almost seems like we don't need these anymore at all + /** + * @todo Rename action to event + * @todo I'm not entirely sure that these values are necessary at all due + * to new naming conventions. + */ + $smarty->assign('action', $this->model->get('action')); + $smarty->assign('event', $this->model->get('action')); // Thanks to new naming conventions $smarty->assign('admin', $this->config->get('admin', 'sections')); $smarty->assign('template', $template); // Only load the session if it's available - // @todo not entirely sure that the view needs full access to the session (seems insecure at best) + /** + * @todo Not entirely sure that the view needs full access to the session + * (seems insecure at best) + */ /* if (isset($_SESSION)) { $smarty->assign('session', $_SESSION); @@ -96,11 +129,12 @@ class Viewer_Smarty extends Viewer_Common { } } + /** + * @todo There's no error checking for the index... should it be shared, + * and should the error checking occur anyway since any shit could + * happen? + */ /* - @todo there's no error checking for the index... should it be - shared, and should the error checking occur anyway since - any shit could happen? - $template = '../templates/index.tpl'; $shared_template = str_replace('../', '../../pickles/', $template); @@ -113,9 +147,19 @@ class Viewer_Smarty extends Viewer_Common { // Load it up! header('Content-type: text/html; charset=UTF-8'); - $smarty->display('index.tpl'); - } + // If the index.tpl file is present, load it, else load the template directly + /** + * @todo Should there be additional logic to allow the model or the + * template to determine whether or not the index should be loaded? + */ + if ($smarty->template_exists('index.tpl')) { + $smarty->display('index.tpl'); + } + else { + $smarty->display($template); + } + } } ?>