Massive amounts of documentation has been added.

git-svn-id: http://svn.cleancode.org/svn/pickles@55 4d10bc64-7434-11dc-a737-d2d0f8310089
This commit is contained in:
Josh Sherman 2008-09-22 01:43:18 +00:00
parent cbcfc9cc4f
commit 1784514696
20 changed files with 941 additions and 59 deletions

View file

@ -1,23 +1,58 @@
<?php
date_default_timezone_set('America/New_York');
/**
* PICKLES core include file
*
* This is the file that you include on the page you're instantiating the
* controller from (typically index.php). The path to the PICKLES code base is
* established as well as the path that Smarty will use to store the compiled
* pages.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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;
}
?>

View file

@ -1,7 +1,29 @@
<?php
/**
* Small collection of array utilities
*
* A bit too small actually, as there is still only one function in here. Since
* I have built PICKLES based around my own needs, this has been the only
* function I have felt the need to add.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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;
}
}
?>

View file

@ -1,13 +1,45 @@
<?php
/**
* Configuration class
*
* Handles loading and caching of the configuration into a Singleton object.
* Contains logic to determine if the configuration has already been loaded and
* will opt to use a "frozen" object rather than instantiate a new one. Also
* contains logic to reload configurations if the configuration file had been
* modified since it was originally instantiated (smart caching).
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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 {
}
}
}
}
?>

View file

@ -1,12 +1,26 @@
<?php
// @todo Possibly remove the conditionals for the CLI view
/**
* Controller class
*
* The heavy lifter of PICKLES, makes the calls to get the session and
* configuration loaded. Loads models, serves up user authentication when the
* model asks for it, and loads the viewer that the model has requested. Default
* values are present to make things easier on the user.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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 {
}
*/
}
?>

View file

@ -1,19 +1,57 @@
<?php
/**
* Database abstraction layer for MySQL
*
* All database usage inside PICKLES-based sites should be done via the database
* object that is a part of every model ($this->db). Because the database
* object can execute raw SQL, there should be no limitations.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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) {
}

View file

@ -1,10 +1,41 @@
<?php
/**
* Error handling class
*
* Handles (for the most part) all the errors and warnings that are encountered
* by the PICKLES core classes. Unfortunately this was written, but never really
* utilized correctly, so I'm thinking it may be better to remove it entirely or
* add logic to appropriately report the errors, perhaps as a variable in the
* model data array.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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;
}
}
?>

View file

@ -1,7 +1,35 @@
<?php
/**
* Incomplete collection of image manipulation utilities
*
* I'm not entirely sure if this class is being utilized anywhere, especially
* since a lot of the functions are not finished, or var_dump() stuff. The
* functions are (or eventually will be) wrappers for ImageMagick commands. The
* other route would be to code it all in pure PHP as to not have to add another
* dependency to PICKLES. After checking the PHP documentation on image
* processing, it seems there's an ImageMagick module that can utilized, that may
* end up being the route that is taken. Until then, this class is useless shit.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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);
*/
}
?>

View file

@ -1,7 +1,38 @@
<?php
/**
* Small collection of mail utilities
*
* A bit too small actually, as there is still only one function in here. Since
* I have built PICKLES based around my own needs, this has been the only
* function I have felt the need to add.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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');

View file

@ -1,37 +1,91 @@
<?php
/**
* Model class
*
* Every model in PICKLES at both the core and site levels need to extend this
* class. It handles the getting of common model variables (auth, data and view)
* as well as making sure that every model has a database object available.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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() { }
}
?>

View file

@ -1,16 +1,39 @@
<?php
/**
* Object class
*
* Every non-Singleton-based class needs to extend this class. Any models will
* extend the Model class which entends the Object class already. This class
* handles getting an instance of the Config object so that it's available. Also
* provides a getter and setter for variables.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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;
}
}
?>

View file

@ -1,9 +1,25 @@
<?php
/**
* Request class
*
* Another one of those left over classes that seems to have been forgotten.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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;
}
}
?>

View file

@ -1,7 +1,33 @@
<?php
/**
* Security class
*
* Handles authenticating a user via an Apache login box.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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: /');
}
}
?>

View file

@ -1,18 +1,52 @@
<?php
/**
* Session wrapper class
*
* Basic functions to ensure that interaction with the $_SESSION super global is
* done in a consistent manner.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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();
}

View file

@ -1,9 +1,37 @@
<?php
/**
* Singleton class
*
* This is the file that you include on the page you're instantiating the
* controller from (typically index.php). The path to the PICKLES code base is
* established as well as the path that Smarty will use to store the compiled
* pages.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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);
}
}
?>

View file

@ -1,14 +1,39 @@
<?php
/**
* Viewer class
*
* Uses the factory design pattern to create a new Viewer object based on what
* viewer the model says it wants to use.
*
* @package PICKLES
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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);
}
}
?>

View file

@ -1,16 +1,39 @@
<?php
/**
* Common viewer class
*
* This is the class that each viewer class should be extending from.
*
* @package PICKLES
* @subpackage Viewer
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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();
}
?>

View file

@ -1,7 +1,37 @@
<?php
/**
* Debugging viewer
*
* Displays debugging information on the screen.
*
* @package PICKLES
* @subpackage Viewer
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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 '<h1>Debug</h1>' . "\n";
echo '<h2>$_REQUEST</h2>' . "\n";
@ -17,7 +47,6 @@ class Viewer_Debug extends Viewer_Common {
var_dump($_SERVER);
echo '</pre>';
}
}
?>

View file

@ -1,7 +1,21 @@
<?php
/**
* JSON viewer
*
* Displays data in JavaScript Object Notation
*
* @package PICKLES
* @subpackage Viewer
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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());
}
}
}
?>

View file

@ -1,7 +1,30 @@
<?php
/**
* RSS viewer
*
* Displays data in RSS version 2.0 format.
*
* @package PICKLES
* @subpackage Viewer
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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();

View file

@ -1,7 +1,21 @@
<?php
/**
* Smarty viewer
*
* Displays the associated Smarty templates for the Model.
*
* @package PICKLES
* @subpackage Viewer
* @author Joshua Sherman <josh@phpwithpickles.org>
* @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', '&amp;');
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);
}
}
}
?>