Open-Source PHP Framework - Designed for rapid development of performance-oriented scalable applications

/webroot/vork

[return to app]
1
<?php error_reporting(E_ALL | E_STRICT);

define('DEBUG_MODE', false); //this is the only line that needs to be adjusted in this file

/**
 * Vork Framework www.Vork.us
 * @version 3.00
 * @author Eric David Benari, Vork Chief Architect
 */
class configInit {
    /**
     * Location of the packages folder (relative to webroot)
     */
    public static function packagesPath() {
         return configDefaults::basepath() . 'packages' . self::DS;
    }

    /**
     * Directory separator, in both Linux and Windows you can just leave this as-is
     */
    const DS = '/';

    /**
     * Creates the ability to access constants within inheriting classes just like properties
     * If there is a naming conflict properties take precedence, but this should never be
     * an issue when following standard Zend Framework/PEAR naming conventions where properties use
     * camel-caps and constants are all-capitals delimited by undersores.
     *
     * get::$config->myProperty
     * get::$config->MY_CONSTANT
     *
     * @param string $key
     * @return mixed
     */
    public function __get($key) {
        $constantName = get_class($this) . '::' . $key;
        if (defined($constantName)) {
            return constant($constantName);
        } else {
            trigger_error('Undefined property: ' . $constantName, E_USER_NOTICE);
        }
    }
}

if (DEBUG_MODE) {
    require configDefaults::basepath() . '.debug';
}

/**
 * Default configuration - these settings will only be used if they are not defined in the config file
 */
class configDefaults extends configInit {
    /**
     * Path to the config file, change only if not using the default file name/location
     * Note: if no DB connections or other configuration settings are needed the .config file can
     * be deleted and this setting will be ignored.
     */
    const CONFIG_PATH = '.config';

    /**
     * Optional, only need to set these if you wish to execute a file that is global to the
     * application before and/or after the page loads. Filename must match the class name and be in the MVC root.
     */
    const APP_CONSTRUCT = null, APP_DESTRUCT = null;

    /**
     * Optional, only need to set these in your config class if you move the folders from the default locations
     *
     * @var string
     */
    public $pathToMvc, $modelsFolder, $viewsFolder, $controllersFolder,
           $layoutsFolder, $elementsFolder, $componentsFolder, $helpersFolder;

    /**
     * Optional, only need to set this in your config class if the webroot folder is not installed in the root of
     * your web site directory
     *
     * @var string
     */
    public $basepath = '/';

    /**
     * Name of controller that is used to handle errors
     *
     * @var string
     */
    public $errorHandler = 'error';

    /**
     * By default no extension is used for MVC files, if you need to use a file extension then
     * it needs to be set it in your config class in order for the files to be found
     * and you need to include the prepended dot
     *
     * @var string
     */
    public $fileExtension = '';

    /**
     * These are the default helperes that will be loaded into every view (and available to every element)
     *
     * Default is 'html' and 'form'; you may wish to add more by overriding this property this
     * property within your config and adding the name of the additional helpers to the parent array.
     *
     * Note: only do this if most of your application needs the helper, otherwise you can load
     * helpers in the __construct of a controller or within any method (action) of a controller
     *
     * @var array
     */
    public $helpers = array('html', 'form');

    /**
     * This sets the objects that will be available to all your models, the default is db and
     * that should suffice for most applications. To add more create the object (class) in your config
     * and then override this property adding the name of your object to the parent array and add a static
     * property with the same name as the object to the config class (this will contain the object later.)
     */
    public static $db, $modelObjects = array('db');

    /**
     * Internal cache of basepath
     * @var string
     */
    protected static $_basepath;

    /**
     * Set the base working path
     * @return string
     */
    public static function basepath() {
        if (self::$_basepath === null) {
            if (isset($_SERVER['DOCUMENT_ROOT']) && $_SERVER['DOCUMENT_ROOT']) {
                $_SERVER['DOCUMENT_ROOT'] = rtrim($_SERVER['DOCUMENT_ROOT'], self::DS);
                self::$_basepath = (substr($_SERVER['DOCUMENT_ROOT'], -7) == 'webroot'
                                    ? substr($_SERVER['DOCUMENT_ROOT'], 0, -8) : $_SERVER['DOCUMENT_ROOT']) .
 
self::DS; } else { //cli self::$_basepath = substr($_SERVER['SCRIPT_FILENAME'], 0, -12); //remove webroot/vork } } return self::$_basepath; } /** * Establishes MVC folder locations automatically and sets default title/meta-data (if defaults exist) */ public function __construct() { if (!get::$title) { get::$title = (isset($this->title) && $this->title ? $this->title : $this->SITE_NAME); } if (!get::$meta && isset($this->meta) && is_array($this->meta)) { get::$meta = $this->meta; } if ($this->pathToMvc === null) { $this->pathToMvc = configDefaults::basepath() . 'mvc' . self::DS; if (isset($_SERVER['SCRIPT_NAME']) && $_SERVER['SCRIPT_NAME'] == '/webroot/vork') { $this->pathToMvc = $_SERVER['DOCUMENT_ROOT'] . self::DS . 'mvc' . self::DS; } } else { if (substr($this->pathToMvc, -1) != self::DS) { //append trailing slash if needed $this->pathToMvc .= self::DS; } } $mvcFolders = array('models', 'views', 'controllers', 'layouts', 'elements', 'components', 'helpers'); foreach ($mvcFolders as $mvcFolder) { if ($this->{$mvcFolder . 'Folder'} === null) { $this->{$mvcFolder . 'Folder'} = $mvcFolder; } } } } /** * The internal MVC logic - essentially the brain of the framework */ class mvc { /** * Override these within your application to change controller, action, layout or view * You can also modify the params array as needed. * mvc::$controller = 'cart'; * mvc::$action = 'logout'; * mvc::$layout = 'mobile'; * mvc::$view = 'confirmation'; * * Changes to the above will only take affect after the current action returns, to make the affect * immediate (to redirect before completing the current action) simply add a return; statement right after. * * These properties have defaults set: * If no controller is defined in the URL then the index controller is used * If no action is defined in the URL then the index action is used * If no layout is defined in the controller then the default layout is used * * Views will always default to a file with the same name as the action and will first look within a * folder in the views directory that has the same name as the controller. If using the index action or * in the case that a controller is not found (usually for a page of semi-static content) and the folder * or the file within it is not found it will then look for a file in the root of the views * directory with the name of the controller. * * Acceptable locations are: * /mvc/views/controllerName/actionName * /mvc/views/controllerName * * To use a view from a different controller you can simply override the view setting within * your application and include the path: * mvc::$view = 'someOtherController' . get::$config->DS . 'newView'; */ public static $controller = 'index', $action = 'index', $layout = 'default', $view, $params = array(); /** * This is a safety to prevent redirecting in infinite loops (eg. a redirects to b, then b redirects * back to a.) The default maximum redirects is 10 within one request, if you need more you could * increase this but keep in mind that any app that needs to redirect over 10 times per request * likely has some serious flaw in the architecture. */ protected $_maxActionRedirects = 10, $_redirectHistory = array(); /** * Buffer used to contain view params * @var array */ protected static $_viewParams = array(); /** * Indicator as to the current processing-state of Vork internals */ protected static $_state = '__construct'; /** * Set the $_state property */ public static function setState($state) { if (DEBUG_MODE) { debug::log('Vork internal state: ' . $state); } self::$_state = $state; } /** * Read-only public access to the $_state property * @return string */ public static function state() { return self::$_state; } /** * Replaces characters that are not valid within the name of a PHP object * * @param string $objName * @return string */ public static function getValidObjectName($objName) { $objName = preg_replace('/\W/', '_', $objName); if (is_numeric($objName[0])) { //cannot start with a number $objName = '_' . $objName; } return $objName; } /** * Load config, open a DB connection & cache (if they are defined,) parse the URL to determine
 
controller/action * and then load the page */ public function __construct() { if (is_file(configDefaults::basepath() . configDefaults::CONFIG_PATH)) { require configDefaults::basepath() . configDefaults::CONFIG_PATH; get::$config = new config; } else { get::$config = new configDefaults; } if (DEBUG_MODE) { debug::log('Config loaded'); } if (get::$config->CACHE_CONNECT) { get::dbConnection('cache'); if (DEBUG_MODE) { debug::log('Cache loaded'); } } $this->_parseUrl(); if (get::$config->APP_CONSTRUCT && is_file(get::$config->pathToMvc . get::$config->APP_CONSTRUCT)) { require get::$config->pathToMvc . get::$config->APP_CONSTRUCT; get::$config->{get::$config->APP_CONSTRUCT} = new get::$config->APP_CONSTRUCT; if (DEBUG_MODE) { debug::log('APP_CONSTRUCT loaded'); } } $this->_loadAction(); if (get::$config->APP_DESTRUCT && is_file(get::$config->pathToMvc . get::$config->APP_DESTRUCT)) { require get::$config->pathToMvc . get::$config->APP_DESTRUCT; get::$config->{get::$config->APP_DESTRUCT} = new get::$config->APP_DESTRUCT; if (DEBUG_MODE) { debug::log('APP_DESTRUCT loaded'); } } } /** * Loads an element. Elements can access the view params plus the params sent to them as an argument as if * they are local variables. If there is a naming conflict the variable in the argument takes precedence. * * @param string $outputType * @param string $elementName * @param array $elementParams * @return mixed */ protected static function _loadElement($outputType, $elementName, $elementParams) { $elementFile = get::mvcFilePath('elements', $elementName); if (is_file($elementFile)) { if (is_array(self::$_viewParams)) { extract(self::$_viewParams); } if (is_array($elementParams)) { extract($elementParams); } if (DEBUG_MODE) { $logMsg = 'element ' . $elementName . ' loaded'; if ($elementParams) { $logMsg .= ' with ' . json_encode($elementParams); } } if ($outputType == 'return') { ob_start(); require $elementFile; $element = ob_get_contents(); ob_end_clean(); if (DEBUG_MODE) { debug::log($logMsg); } return $element; } else { $return = require $elementFile; if (DEBUG_MODE) { debug::log($logMsg); } return $return; } } else { trigger_error('File for element ' . $elementName . ' could not be found', E_USER_WARNING); } } /** * Returns the output of an element as a string * * @param string $elementName * @param array $elementParams * @return string */ public static function getElement($elementName, $elementParams = array()) { return self::_loadElement('return', $elementName, $elementParams); } /** * Loads an element, any output goes directly to stdout (echos to the screen) * * @param string $elementName * @param array $elementParams */ public static function loadElement($elementName, $elementParams = array()) { return self::_loadElement('echo', $elementName, $elementParams); } /** * Loads the default helpers defined in the config at every page instance */ protected function _loadDefaultHelpers() { foreach (get::$config->helpers as $helper) { if (!isset(self::$_viewParams[$helper])) { $helperFile = get::mvcFilePath('helpers', $helper); if (is_file($helperFile)) { if (!class_exists($helper . 'Helper')) { require $helperFile; } $helperClassName = $helper . 'Helper'; get::$loadedObjects['helper'][$helper][null] = self::$_viewParams[$helper] = new
 
$helperClassName; } else { trigger_error('File for ' . $helperFile . ' helper could not be found', E_USER_WARNING); } } } if (DEBUG_MODE) { debug::log('Default helpers loaded: ' . implode(', ', get::$config->helpers)); } } /** * Loads a view, if a layout exists then the view will be loaded into the layout * * @param string $controllerName * @param string $action * @return mixed */ protected function _loadView($controllerName, $action) { if (!load::$loadView || self::$view === false) { return; } self::setState('view'); if (self::$view == null) { //try: /mvc/views/controllerName/actionName $viewFile = get::mvcFilePath('views', $controllerName . get::$config->DS . $action); if (!is_file($viewFile) && $action == 'index') { //try: /mvc/views/controllerName $viewFile = get::mvcFilePath('views', $controllerName); } } else { $viewFile = get::mvcFilePath('views', $controllerName . get::$config->DS . self::$view); if (!is_file($viewFile)) { //local path failed, try absolute path $viewFile = get::mvcFilePath('views', self::$view); } } if (!is_file($viewFile) && $controllerName != get::$config->errorHandler) { return $this->_loadAction(get::$config->errorHandler, 'missingView'); } if (is_array(self::$_viewParams)) { extract(self::$_viewParams); } if (is::ajax() && get::$config->ajaxEnabled && (!is_array(get::$config->ajaxEnabled) //ajax=true || (isset(get::$config->ajaxEnabled[$controllerName]) && (get::$config->ajaxEnabled[$controllerName] === true //ajax[controllerName]=true || get::$config->ajaxEnabled[$controllerName] == $action //ajax[controllerName]=action || (is_array(get::$config->ajaxEnabled[$controllerName])
 //ajax[controllerName]=array(action)
&& in_array($action, get::$config->ajaxEnabled[$controllerName])))))) { self::$layout = false; //AJAX request } $layoutFile = get::mvcFilePath('layouts', self::$layout); if (self::$layout && is_file($layoutFile)) { ob_start(); require $viewFile; $view = ob_get_contents(); ob_end_clean(); if (DEBUG_MODE) { debug::log('View loaded'); } self::setState('layout'); require $layoutFile; if (DEBUG_MODE) { debug::log('Layout loaded'); } } else { require $viewFile; if (DEBUG_MODE) { debug::log('View loaded'); } } } /** * Redirects controllers and/or action * * @param string $originalController * @param string $originalAction */ protected function _redirectAction($originalController, $originalAction) { if (count($this->_redirectHistory) < $this->_maxActionRedirects) { $this->_redirectHistory[] = array('oldController' => $originalController, 'newController' => self::$controller, 'oldAction' => $originalAction, 'newAction' => self::$action); $this->_loadAction(); } else { self::$params['redirectHistory'] = $this->_redirectHistory; $this->_loadAction(get::$config->errorHandler, 'redirectEndlessLooping'); } } /** * Loads an action * * @param string $controllerName Optional, if omitted then self::$controller is used * @param string $action Optional, if omitted then self::$action is used * @return null */ protected function _loadAction($controllerName = null, $action = null) { if (is_null($controllerName)) { $controllerName = self::$controller; } if (is_null($action)) { $action = self::getValidObjectName(self::$action); } if (strpos($controllerName, '..') !== false || strpos($controllerName, ':') !== false) { return $this->_loadAction(get::$config->errorHandler, 'invalidControllerName'); } if (!is_file(get::mvcFilePath('controllers', $controllerName))) { //no controller, attempt to load view
 directly
$this->_loadDefaultHelpers(); return $this->_loadView($controllerName, $action); } $originalController = $controllerName; $controllerClassName = $controllerName . 'Controller'; if (!class_exists($controllerClassName)) { require get::mvcFilePath('controllers', $controllerName); } if (!class_exists($controllerClassName) && $controllerName != get::$config->errorHandler) { return $this->_loadAction(get::$config->errorHandler, 'controllerNotDefined'); } $originalAction = self::$action; $controller = new $controllerClassName; if ($controllerName != self::$controller && $controllerName != get::$config->errorHandler) { return $this->_redirectAction($originalController, $action); //controller was changed in
 __construct()
} if ($originalAction != self::$action) { //action was changed in __construct() $action = self::$action; } $optionalAction = (defined($controllerName . 'Controller::optionalAction') && constant($controllerName . 'Controller::optionalAction')); if (!$optionalAction) { //updates self::$action in instances where _loadAction() was called with $action
 arg
self::$action = $action; } if (!method_exists($controller, $action) && $controllerName != get::$config->errorHandler) { if ($optionalAction && self::$action != 'index') { array_unshift(self::$params, self::$action); self::$action = 'index'; return $this->_loadAction($controllerName, 'index'); } else { return $this->_loadAction(get::$config->errorHandler, 'missingAction'); } } $this->_loadDefaultHelpers(); self::setState('controller::action'); $viewParams = $controller->$action(); if (is_array($viewParams)) { self::$_viewParams = array_merge(self::$_viewParams, $viewParams); } if (DEBUG_MODE) { debug::log('Controller:action loaded'); } if ($controllerName != get::$config->errorHandler) { if (self::$controller != $originalController || self::$action != $action) { return $this->_redirectAction($originalController, $action); } } $this->_loadView($controllerName, $action); } /** * Parse URL string to extract controller name, action name and params */ protected function _parseUrl() { $basepathLen = strlen(get::$config->basepath); if (isset($_SERVER['REDIRECT_URL'])) { $_SERVER['REQUEST_URI'] = $_SERVER['REDIRECT_URL']; } if (isset($_SERVER['REQUEST_URI'])) { $path = substr($_SERVER['REQUEST_URI'], $basepathLen); $positionOfGet = strpos($path, '?'); if ($positionOfGet !== false) { $path = substr($path, 0, $positionOfGet); } $pathParts = explode('/', $path); $fileName = (strrpos($_SERVER['SCRIPT_FILENAME'], get::$config->DS) + 1); if (isset($pathParts[0]) && $pathParts[0] == substr($_SERVER['SCRIPT_FILENAME'], $fileName)) { $firstSegment = array_shift($pathParts); //remove the current filename from the path parts; if ($firstSegment == 'vork' && is::superuser()) { require configDefaults::basepath() . '.installer'; } } foreach ($pathParts as $pathSegment) { $pathSegment = trim($pathSegment); if ($pathSegment != '') { $pathSegments[] = $pathSegment; } } } else if (isset($_SERVER['argv'])) { //cli-mode $pathSegments = $_SERVER['argv']; array_shift($pathSegments); } if (isset($pathSegments) && $pathSegments) { self::$controller = self::getValidObjectName(array_shift($pathSegments)); if (isset($pathSegments[0])) { self::$action = array_shift($pathSegments); if (!empty($pathSegments)) { self::$params = $pathSegments; } } } if (DEBUG_MODE) { debug::log('URL parsed'); } } } /** * Blackhole object used when catching a database exception to avoid fatal errors being thrown before reaching * the error-handler controller & view. * Note: static database methods will still fatal-error in pre-5.3 versions of PHP as __callStatic was not yet
 
supported */ class blackhole implements Iterator, ArrayAccess { public static function __callStatic($method, array $args) { return new blackhole; } public function __call($method, array $args) { return $this; } public function __get($name) { return $this; } public function __set($name, $val) {} public function __isset($name) { return false; } public function __unset($name) {} public function __toString() { return ''; } public function rewind() {} public function current() {} public function key() {} public function next() {} public function valid() { return false; } public function offsetExists($offset) { return false; } public function offsetGet($offset) {} public function offsetSet($offset, $value) {} public function offsetUnset($offset) {} } /** * Public interface to determine Boolean properties */ class is { /** * If instance is requested via AJAX * @return Boolean */ public static function ajax() { return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] ==
 
'XMLHttpRequest'); } /** * If instance is requested via HTTPS * @return Boolean */ public static function ssl() { return (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'); } /** * Internal cache for the is::bot() and is::mobile() methods * @var Boolean or null */ protected static $_bot, $_mobile; /** * Identifies a spider/bot/crawler * @return Boolean */ public static function bot() { if (is_null(self::$_bot)) { self::$_bot = false; if (isset($_SERVER['HTTP_USER_AGENT'])) { $spiders = array('search', 'spider', 'crawler', 'archiver', 'indexer', 'webbot', 'robot', 'nagios', 'Googlebot', 'MSNbot', 'Jeeves', 'Slurp', 'Scooter', 'InfoSeek',
 
'Lycos', 'seoprofiler', 'Feedfetcher', 'facebookexternalhit'); self::$_bot = (preg_match('/' . implode('|', $spiders) . '/i', $_SERVER['HTTP_USER_AGENT'])); } } return self::$_bot; } /** * Identifies a mobile user * @return Boolean */ public static function mobile() { if (is_null(self::$_mobile)) { self::$_mobile = false; if (isset($_SERVER['HTTP_USER_AGENT'])) { $mobile = array('Android', 'AvantGo', 'BlackBerry', 'DoCoMo', 'Fennec', 'iPod', 'iPhone', 'J2ME', 'MIDP', 'NetFront', 'Nokia', 'Opera Mini', 'PalmOS', 'PalmSource', 'portalmmm', 'Plucker', 'ReqwirelessWeb', 'SonyEricsson', 'Symbian', 'UP\.Browser', 'webOS', 'Windows CE', 'Xiino'); self::$_mobile = (preg_match('/' . implode('|', $mobile) . '/i', $_SERVER['HTTP_USER_AGENT'])); } } return self::$_mobile; } /** * If instance is requested from Flash * @return Boolean */ public static function flash() { return (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/^(Shockwave|Adobe) Flash/i', $_SERVER['HTTP_USER_AGENT'])); } /** * Wrapper for get::$config->isSuperuser() to unify syntax * @return Boolean */ public static function superuser() { return get::$config->isSuperuser(); } } /** * Public interface to retrieve rendered elements and other objects */ class get { /** * Opens up public access to config constants and variables and the cache object * @var object */ public static $config, $cache; /** * Used to store the page title and meta data for layout usage * * You can set properties for "title" and "meta" in the .config to act as default values (setting in the view
 
or * controller will always override the defaults) * public $title = 'My Default Title'; * public $meta = array('keyowords' => 'apples, bananas, kiwis', 'description' => 'My site is about...'); * * @var string $title * @var array $meta valid keys are description and keywords */ public static $title, $meta = array(); /** * Index of objects loaded, used to maintain uniqueness of singletons * @var array */ public static $loadedObjects = array(); /** * Index of names of database-objects that have a connection open * @var array Keys are DB names, vals are always Bool true */ protected static $_dbConnected = array(); /** * Returns fully qualified path to an MVC file * * @param string $type * @param string $mvcName * @return string */ public static function mvcFilePath($type, $mvcName) { return self::$config->pathToMvc . self::$config->{$type . 'Folder'} . self::$config->DS . $mvcName . self::$config->fileExtension; } /** * Gets the current URL * * @param array Optional, keys: * get - Boolean Default: false - include GET URL if it exists * abs - Boolean Default: false - true=absolute URL (aka. FQDN), false=just the path for relative
 
links * ssl - Boolean Default: null - true=https, false=http, unset/null=auto-selects the current
 
protocol * a true or false value implies abs=true * @return string */ public static function url(array $args = array()) { $ssl = null; $get = false; $abs = false; extract($args); if (!isset($_SERVER['HTTP_HOST']) && PHP_SAPI == 'cli') { $_SERVER['HTTP_HOST'] = trim(`hostname`); $argv = $_SERVER['argv']; array_shift($argv); $_SERVER['REDIRECT_URL'] = '/' . implode('/', $argv); $get = false; // command-line has no GET } $url = (isset($_SERVER['REDIRECT_URL']) ? $_SERVER['REDIRECT_URL'] : $_SERVER['SCRIPT_NAME']); if (substr($url, -1) == '/') { //strip trailing slash for URL consistency $url = substr($url, 0, -1); } if (is_null($ssl) && $abs == true) { $ssl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on'); } if ($abs || !is_null($ssl)) { $url = (!$ssl ? 'http://' : 'https://') . $_SERVER['HTTP_HOST'] . $url; } if ($get && isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING']) { $url .= '?' . $_SERVER['QUERY_STRING']; } return ($url ? $url : '/'); } /** * Initializes a database connection * @param string $db */ public static function dbConnection($db) { if (!isset(self::$_dbConnected[$db]) && method_exists(self::$config, 'dbConnect')) { try { self::$config->dbConnect($db); self::$_dbConnected[$db] = true; } catch (Exception $e) { mvc::$params = $e; mvc::$controller = get::$config->errorHandler; mvc::$action = 'DatasourceError'; config::$$db = new blackhole; } } } /** * Loads an object as a singleton * * @param string $objectType * @param string $objectName * @param mixed $args Optional, default is null - this is sent as an argument to the constructor and used as
 
part * of the criteria to determine a unique singleton object - differing args return new
 
objects * @return object */ protected static function _loadObject($objectType, $objectName, $args = null) { if ($objectName == null) { $objectName = mvc::$controller; } $argsSerialized = serialize($args); if (isset(self::$loadedObjects[$objectType][$objectName][$argsSerialized])) { return self::$loadedObjects[$objectType][$objectName][$argsSerialized]; } $objectFile = self::mvcFilePath($objectType . 's', $objectName); if (is_file($objectFile)) { if (strpos($objectName, '/')) { //objects within folders $segments = explode('/', $objectName); $objectName = array_shift($segments); foreach ($segments as $segment) { $objectName .= ucfirst($segment); } } $objectClassName = mvc::getValidObjectName($objectName) . ucfirst($objectType); if (!class_exists($objectClassName)) { require $objectFile; } if (class_exists($objectClassName)) { try { $objectObject = new $objectClassName($args); } catch (Exception $e) { trigger_error($e->getMessage(), E_USER_WARNING); return new blackhole; } if ($objectType == 'model' && config::MODEL_AUTOCONNECT) { foreach (config::$modelObjects as $modelObject) { self::dbConnection($modelObject); $objectObject->$modelObject = config::$$modelObject; } } self::$loadedObjects[$objectType][$objectName][$argsSerialized] = $objectObject; if (DEBUG_MODE) { debug::log($objectType . ' ' . $objectName . ' loaded'); } return $objectObject; } else { $errorMsg = 'Class for ' . $objectType . ' ' . $objectName . ' could not be found'; } } else { $errorMsg = 'File for ' . $objectType . ' ' . $objectName . ' could not be found'; } trigger_error($errorMsg, E_USER_WARNING); } /** * Returns a model object * * @param string $model * @param mixed $args Optional - arguments to be passed to the model-object constructor * @return object */ public static function model($model = null, $args = null) { return self::_loadObject('model', $model, $args); } /** * Returns a component object * * @param string $component * @param mixed $args Optional - arguments to be passed to the component-object constructor * @return object */ public static function component($component = null, $args = null) { return self::_loadObject('component', $component, $args); } /** * Returns a helper object * * @param string $helper * @param mixed $args Optional - arguments to be passed to the helper-object constructor * @return object */ public static function helper($helper, $args = null) { if (is_array($helper)) { array_walk($helper, array('self', __METHOD__)); return; } if (!in_array($helper, self::$config->helpers)) { self::$config->helpers[] = $helper; } return self::_loadObject('helper', $helper, $args); } /** * Renders an element and returns the results as a string * * @param string $element * @param array $params */ public static function element($element, $params = array()) { $elementId = $element . $paramsString = serialize($params); if (!isset(self::$loadedObjects['element'][$elementId])) { self::$loadedObjects['element'][$elementId] = mvc::getElement($element, $params); } return self::$loadedObjects['element'][$elementId]; } /** * Overloads the php function htmlentities and changes the default charset to UTF-8 and the default value for
 
the * fourth parameter $doubleEncode to false. Also adds ability to pass a null value to get the default
 
$quoteStyle * and $charset (removes need to repeatedly define ENT_COMPAT, 'UTF-8', just to access the $doubleEncode
 
argument) * * If you are using a PHP version prior to 5.2.3 the $doubleEncode parameter is not available so you will
 
need * to comment out the last parameter in the return clause (including the preceding comma) * * @param string $string * @param int $quoteStyle Uses ENT_COMPAT if null or omitted * @param string $charset Uses UTF-8 if null or omitted * @param boolean $doubleEncode * @return string */ public static function htmlentities($string, $quoteStyle = ENT_COMPAT, $charset = 'UTF-8', $doubleEncode =
 
false) { return htmlentities($string, (!is_null($quoteStyle) ? $quoteStyle : ENT_COMPAT), (!is_null($charset) ? $charset : 'UTF-8'), $doubleEncode); } /** * Initialize the character maps needed for the xhtmlentities() method and verifies the argument values * passed to it are valid. * * @param int $quoteStyle * @param string $charset Only valid options are UTF-8 and ISO-8859-1 (Latin-1) * @param boolean $doubleEncode */ protected static function initXhtmlentities($quoteStyle, $charset, $doubleEncode) { $chars = get_html_translation_table(HTML_ENTITIES, $quoteStyle); if (isset($chars)) { unset($chars['<'], $chars['>'], $chars['&']); $charMaps[$quoteStyle]['ISO-8859-1'][true] = $chars; $charMaps[$quoteStyle]['ISO-8859-1'][false] = array_combine(array_values($chars), $chars); $charMaps[$quoteStyle]['UTF-8'][true] = array_combine(array_map('utf8_encode', array_keys($chars)),
 
$chars); $charMaps[$quoteStyle]['UTF-8'][false] = array_merge($charMaps[$quoteStyle]['ISO-8859-1'][false], $charMaps[$quoteStyle]['UTF-8'][true]); self::$loadedObjects['xhtmlEntities'] = $charMaps; } if (!isset($charMaps[$quoteStyle][$charset][$doubleEncode])) { if (!isset($chars)) { $invalidArgument = 'quoteStyle = ' . $quoteStyle; } else if (!isset($charMaps[$quoteStyle][$charset])) { $invalidArgument = 'charset = ' . $charset; } else { $invalidArgument = 'doubleEncode = ' . (string) $doubleEncode; } trigger_error('Undefined argument sent to xhtmlentities() method: ' . $invalidArgument,
 
E_USER_NOTICE); } } /** * Converts special characters in a string to XHTML-valid ASCII encoding the same as htmlentities except * this method allows the use of HTML tags and ASCII-code within your string. Signature is the same as
 
htmlentities * except that the only character sets available (third argument) are UTF-8 (default) and ISO-8859-1
 
(Latin-1). * * @param string $string * @param int $quoteStyle Constants available are ENT_NOQUOTES (default), ENT_QUOTES, ENT_COMPAT * @param string $charset Only valid options are UTF-8 (default) and ISO-8859-1 (Latin-1) * @param boolean $doubleEncode Default is false * @return string */ public static function xhtmlentities($string, $quoteStyle = ENT_NOQUOTES, $charset = 'UTF-8', $doubleEncode = false) { $quoteStyles = array(ENT_NOQUOTES, ENT_QUOTES, ENT_COMPAT); $quoteStyle = (!in_array($quoteStyle, $quoteStyles) ? current($quoteStyles) : $quoteStyle); $charset = ($charset != 'ISO-8859-1' ? 'UTF-8' : $charset); $doubleEncode = (Boolean) $doubleEncode; if (!isset(self::$loadedObjects['xhtmlEntities'][$quoteStyle][$charset][$doubleEncode])) { self::initXhtmlentities($quoteStyle, $charset, $doubleEncode); } $string = strtr($string, self::$loadedObjects['xhtmlEntities'][$quoteStyle][$charset][$doubleEncode]); return preg_replace('/\&(?!([a-zA-Z]{3}[a-zA-Z0-9]{0,3}|#\d{1,8}|#x[a-zA-Z0-9]{2,8});)/', '&amp;',
 
$string); } } /** * Abstract class to extend model functionality (usage is optional, model functionality is not dependent on this) */ abstract class model { /** * Enables true lazy-loading of database connections when config::MODEL_AUTOCONNECT is set to false and each * model extends this class * * @param string $var * @return object */ public function __GET($var) { get::dbConnection($var); return $this->$var = config::$$var; } } class cache { /** * Public access to the cache object * @return obj */ public function __construct() { return get::$cache; } /** * Static wrapper for the caching methods * * @param str $method * @param array $args * @return mixed */ public static function __callStatic($method, array $args) { return call_user_func_array(array(get::$cache, $method), $args); } /** * Automates caching of a function or method result * * @param str $id * @param mixed $method * @param array $args * @param int $expires * @return mixed */ public static function method($id, $method, array $args = array(), $flag = null, $expires = null) { $return = get::$cache->get($id); if ($return === false) { $return = call_user_func_array($method, $args); get::$cache->set($id, $return, $flag, $expires); } return $return; } /** * The next bunch of methods are workarounds for lack of __callStatic(), they can be safely removed in PHP
 
5.3+ * @deprecated */ public static function get() { $args = func_get_args(); return call_user_func_array(array(get::$cache, __FUNCTION__), $args); } public static function set() { $args = func_get_args(); return call_user_func_array(array(get::$cache, __FUNCTION__), $args); } public static function delete() { $args = func_get_args(); return call_user_func_array(array(get::$cache, __FUNCTION__), $args); } public static function flush() { $args = func_get_args(); return call_user_func_array(array(get::$cache, __FUNCTION__), $args); } } /** * Public interface to load elements and cause redirects */ class load { /** * Flag set to false to supress loading a view; used when the user is redirected * @var boolean */ public static $loadView = true; /** * Sends a redirects header and disables view rendering * This redirects via a browser command, this is not the same as changing controllers which is handled within
 
MVC * * @param string $url Optional, if undefined this will refresh the page (mostly useful for dumping post
 
values) * @param boolean $exit Optional, defaults to true - if false then the instance will be allowed to continue
 
after */ public static function redirect($url = null, $exit = true) { self::$loadView = false; header('Location: ' . ($url ? $url : get::url(array('get' => true)))); if ($exit) { exit(0); } } /** * Loads the 404 Not Found error page * * During controller execution this takes effect only upon completion of the current controller-action * During view/layout execution this uses a browser-redirect * * For immediate redirection without further code-execution, "return" immediately via: return
 
load::error404(); */ public static function error404() { mvc::$controller = get::$config->errorHandler; mvc::$action = 'notFound'; $state = mvc::state(); if ($state == 'layout' || $state == 'view') { self::redirect('/' . mvc::$controller . '/' . mvc::$action); } } /** * Loads an element to STDOUT * * @param string $element * @param array $params */ public static function element($element, $params = array()) { return mvc::loadElement($element, $params); } /** * Loads JavaScript library; any output goes directly to stdout (echos to the screen) * Simplified-access wrapper to htmlHelper::jsLoad() * * @param mixed $args Same args as htmlHelper::jsLoad() */ public static function js($args) { echo get::helper('html')->jsLoad($args); } } if (!defined('DONT_AUTOSTART_VORK')) { new mvc; }