Merge branch '98-implement-hybrid-router' into 'master'

Implemented renewed Routing and Output system.

Everything is in accordance with issue #89 and #90.

> Closes #89 

> Closes #90

> Closes #98 

See merge request !47
This commit is contained in:
Abel Hoogeveen 2016-06-26 16:41:10 +02:00
commit 625e7ffa2b
42 changed files with 1190 additions and 1011 deletions

1
.gitignore vendored
View File

@ -24,3 +24,4 @@ Modules/admin/themes/adminlte2.1/bootstrap/
doc
nbproject
Application/Cache
Application/Logs

View File

@ -2,6 +2,7 @@
return array(
'cache_file_path' => '',
'cache_query_string' => false,
'memcached' => array(
'default' => array(
'hostname' => '127.0.0.1',

View File

@ -11,12 +11,13 @@ return array(
'username' => '',
'password' => '',
'database' => '',
'dbdriver' => 'mysqli',
'dbdriver' => '',
'subdriver'=> '',
'dbprefix' => '',
'pconnect' => FALSE,
'db_debug' => FALSE,
'cache_on' => FALSE,
'cachedir' => '',
'cachedir' => 'Application/Cache',
'char_set' => 'utf8',
'dbcollat' => 'utf8_general_ci',
'swap_pre' => '',
@ -24,7 +25,6 @@ return array(
'compress' => FALSE,
'stricton' => FALSE,
'failover' => array(),
'save_queries' => TRUE
),

View File

@ -1,5 +1,4 @@
<?php return array (
'debug' => false,
'error_reporting' => true,
'log_to_file' => false,
'logger_template' => 'logger_default',

View File

@ -1,10 +1,9 @@
<?php
return array(
'SITE_URL' => '',
'SITE_DOMAIN' => '',
'SERVER_NAME' => '',
'SITE_LOGO_URL' => '',
'base_url' => '',
'index_page' => 'index.php',
'server_name' => '',
'administrator_mail' => '',

View File

@ -1,9 +1,4 @@
<?php
return array(
// '/^alias(|\-(?P<function>.*?))$/' => array(
// 'controller' => 'home'
// ),
'/^(?P<controller>.*?)(|\/(?P<function>.*?)(|\/(?P<parameters>.*?)))$/',
);

View File

@ -84,4 +84,7 @@ return array(
*/
'url_suffix' => '',
'default_controller' => 'standard',
'default_function' => 'index',
);

View File

@ -54,6 +54,7 @@ class Standard extends ControllerAbstract
*/
public function index($path = null)
{
$this->output->cache(60);
$this->layout->view('home');
}
}

View File

View File

@ -32,6 +32,7 @@
use FuzeWorks\Logger;
use Fuzeworks\Factory;
use FuzeWorks\Core;
/**
* Database Cache Class
@ -43,17 +44,9 @@ use Fuzeworks\Factory;
* @author EllisLab Dev Team
* @link https://codeigniter.com/user_guide/database/
* @license http://opensource.org/licenses/MIT MIT License
* @todo Fix URI
*/
class FW_DB_Cache {
/**
* CI Singleton
*
* @var object
*/
public $CI;
/**
* Database object
*
@ -81,7 +74,7 @@ class FW_DB_Cache {
*/
public function __construct(&$db)
{
// Assign the main CI object to $this->CI and load the file helper since we use it a lot
$this->db =& $db;
$this->factory = Factory::getInstance();
$this->factory->helpers->load('file');
@ -121,7 +114,7 @@ class FW_DB_Cache {
return $this->db->cache_off();
}
if ( ! is_really_writable($path))
if ( ! Core::isReallyWritable($path))
{
Logger::logDebug('DB cache dir not writable: '.$path);
@ -146,8 +139,8 @@ class FW_DB_Cache {
*/
public function read($sql)
{
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$segment_one = ($this->factory->uri->segment(1) == FALSE) ? 'default' : $this->factory->uri->segment(1);
$segment_two = ($this->factory->uri->segment(2) == FALSE) ? 'index' : $this->factory->uri->segment(2);
$filepath = $this->db->cachedir.$segment_one.'+'.$segment_two.'/'.md5($sql);
if (FALSE === ($cachedata = @file_get_contents($filepath)))
@ -169,8 +162,8 @@ class FW_DB_Cache {
*/
public function write($sql, $object)
{
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$segment_one = ($this->factory->uri->segment(1) == FALSE) ? 'default' : $this->factory->uri->segment(1);
$segment_two = ($this->factory->uri->segment(2) == FALSE) ? 'index' : $this->factory->uri->segment(2);
$dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/';
$filename = md5($sql);
@ -201,12 +194,12 @@ class FW_DB_Cache {
{
if ($segment_one === '')
{
$segment_one = ($this->CI->uri->segment(1) == FALSE) ? 'default' : $this->CI->uri->segment(1);
$segment_one = ($this->factory->uri->segment(1) == FALSE) ? 'default' : $this->factory->uri->segment(1);
}
if ($segment_two === '')
{
$segment_two = ($this->CI->uri->segment(2) == FALSE) ? 'index' : $this->CI->uri->segment(2);
$segment_two = ($this->factory->uri->segment(2) == FALSE) ? 'index' : $this->factory->uri->segment(2);
}
$dir_path = $this->db->cachedir.$segment_one.'+'.$segment_two.'/';

View File

@ -30,6 +30,7 @@
* @version Version 0.0.1
*/
use FuzeWorks\Factory;
use FuzeWorks\Logger;
use FuzeWorks\DatabaseException;
use FuzeWorks\Utf8;
@ -375,7 +376,7 @@ abstract class FW_DB_driver {
$this->factory = Factory::getInstance();
Logger::log('Database Driver Class Initialized');
Logger::log('Database Driver ' . get_class($this) . ' Initialized');
}
// --------------------------------------------------------------------
@ -1739,14 +1740,13 @@ abstract class FW_DB_driver {
* @param string any "swap" values
* @param bool whether to localize the message
* @return string sends the application/views/errors/error_db.php template
* @todo FIX THIS
*/
public function display_error($error = '', $swap = '', $native = FALSE)
{
// First load the language
$LANG = Language::get('db');
Language::get('db');
$heading = $LANG->line('db_error_heading');
$heading = Language::line('db_error_heading');
if ($native === TRUE)
{
@ -1754,7 +1754,7 @@ abstract class FW_DB_driver {
}
else
{
$message = is_array($error) ? $error : array(str_replace('%s', $swap, $LANG->line($error)));
$message = is_array($error) ? $error : array(str_replace('%s', $swap, Language::line($error)));
}
// Find the most likely culprit of the error by going through
@ -1774,14 +1774,17 @@ abstract class FW_DB_driver {
if (strpos($call['file'], 'Core'.DS.'Database') === FALSE && strpos($call['class'], 'Loader') === FALSE)
{
// Found it - use a relative path for safety
$message[] = 'Filename: '.str_replace(array(APPPATH, BASEPATH), '', $call['file']);
$message[] = 'Filename: '.str_replace(array('Application', 'Core'), '', $call['file']);
$message[] = 'Line Number: '.$call['line'];
break;
}
}
}
Logger::logError($heading . ' || ' . $message);
Logger::logError($heading);
foreach ($message as $message) {
Logger::logError($message);
}
Logger::http_error(500);
exit(8); // EXIT_DATABASE
}

View File

@ -54,7 +54,14 @@ class routerRouteEvent extends Event
/**
* @var bool Whether the callable will be loaded directly after or not
*/
public $loadCallable;
public $performLoading;
/**
* Whether a cached page should be ignored or not
*
* @var bool true if cache should not be used
*/
public $cacheOverride = false;
/**
* The current path input to FuzeWorks.
@ -63,10 +70,20 @@ class routerRouteEvent extends Event
*/
public $path;
public function init($routes, $loadCallable, $path)
public function init($routes, $performLoading, $path)
{
$this->routes = $routes;
$this->loadCallable = $loadCallable;
$this->performLoading = $performLoading;
$this->path = $path;
}
/**
* Whether a cached page should be ignored or not
*
* @param bool $overrideCache true if cache should not be used
*/
public function overrideCache($bool = true)
{
$this->cacheOverride = $bool;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
namespace FuzeWorks\Event;
use FuzeWorks\Event;
/**
* Class routerSetPathEvent.
*
* Fired when the router's path is changing
*
* @author Abel Hoogeveen <abel@techfuze.net>
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
*/
class routerSetPathEvent extends Event
{
/**
* The path to be set to the router.
*
* @var string The new path
*/
public $path;
public function init($path)
{
$this->path = $path;
}
}

View File

@ -34,7 +34,7 @@ namespace FuzeWorks\Library;
use FuzeWorks\Config;
use FuzeWorks\Logger;
use FuzeWorks\LibraryException;
use FuzeWorks\Libraries;
use FuzeWorks\Factory;
use ReflectionObject;
/**
@ -117,7 +117,7 @@ class FW_Driver_Library {
}
// Get package paths and filename case variations to search
$paths = Libraries::getLibraryPaths();
$paths = Factory::getInstance()->libraries->getLibraryPaths();
// Is there an extension?
$class_name = str_replace('{prefix}', $prefix, $child_name);

View File

@ -132,7 +132,7 @@ class FW_Email {
/**
* Number of characters to wrap at.
*
* @see CI_Email::$wordwrap
* @see Email::$wordwrap
* @var int
*/
public $wrapchars = 76;
@ -227,7 +227,7 @@ class FW_Email {
/**
* BCC Batch max number size.
*
* @see CI_Email::$bcc_batch_mode
* @see Email::$bcc_batch_mode
* @var int
*/
public $bcc_batch_size = 200;
@ -314,7 +314,7 @@ class FW_Email {
/**
* Debug messages
*
* @see CI_Email::print_debugger()
* @see Email::print_debugger()
* @var string
*/
protected $_debug_msg = array();
@ -357,7 +357,7 @@ class FW_Email {
/**
* Valid $protocol values
*
* @see CI_Email::$protocol
* @see Email::$protocol
* @var string[]
*/
protected $_protocols = array('mail', 'sendmail', 'smtp');
@ -377,7 +377,7 @@ class FW_Email {
*
* Valid mail encodings
*
* @see CI_Email::$_encoding
* @see Email::$_encoding
* @var string[]
*/
protected $_bit_depths = array('7bit', '8bit');
@ -447,7 +447,7 @@ class FW_Email {
* Initialize preferences
*
* @param array
* @return CI_Email
* @return Email
*/
public function initialize($config = array())
{
@ -480,7 +480,7 @@ class FW_Email {
* Initialize the Email Data
*
* @param bool
* @return CI_Email
* @return Email
*/
public function clear($clear_attachments = FALSE)
{
@ -514,7 +514,7 @@ class FW_Email {
* @param string $from
* @param string $name
* @param string $return_path = NULL Return-Path
* @return CI_Email
* @return Email
*/
public function from($from, $name = '', $return_path = NULL)
{
@ -562,7 +562,7 @@ class FW_Email {
*
* @param string
* @param string
* @return CI_Email
* @return Email
*/
public function reply_to($replyto, $name = '')
{
@ -602,7 +602,7 @@ class FW_Email {
* Set Recipients
*
* @param string
* @return CI_Email
* @return Email
*/
public function to($to)
{
@ -630,7 +630,7 @@ class FW_Email {
* Set CC
*
* @param string
* @return CI_Email
* @return Email
*/
public function cc($cc)
{
@ -658,7 +658,7 @@ class FW_Email {
*
* @param string
* @param string
* @return CI_Email
* @return Email
*/
public function bcc($bcc, $limit = '')
{
@ -693,7 +693,7 @@ class FW_Email {
* Set Email Subject
*
* @param string
* @return CI_Email
* @return Email
*/
public function subject($subject)
{
@ -708,7 +708,7 @@ class FW_Email {
* Set Body
*
* @param string
* @return CI_Email
* @return Email
*/
public function message($body)
{
@ -737,7 +737,7 @@ class FW_Email {
* @param string $disposition = 'attachment'
* @param string $newname = NULL
* @param string $mime = ''
* @return CI_Email
* @return Email
*/
public function attach($file, $disposition = '', $newname = NULL, $mime = '')
{
@ -810,7 +810,7 @@ class FW_Email {
*
* @param string
* @param string
* @return CI_Email
* @return Email
*/
public function set_header($header, $value)
{
@ -844,7 +844,7 @@ class FW_Email {
* Set Multipart Value
*
* @param string
* @return CI_Email
* @return Email
*/
public function set_alt_message($str)
{
@ -858,7 +858,7 @@ class FW_Email {
* Set Mailtype
*
* @param string
* @return CI_Email
* @return Email
*/
public function set_mailtype($type = 'text')
{
@ -872,7 +872,7 @@ class FW_Email {
* Set Wordwrap
*
* @param bool
* @return CI_Email
* @return Email
*/
public function set_wordwrap($wordwrap = TRUE)
{
@ -886,7 +886,7 @@ class FW_Email {
* Set Protocol
*
* @param string
* @return CI_Email
* @return Email
*/
public function set_protocol($protocol = 'mail')
{
@ -900,7 +900,7 @@ class FW_Email {
* Set Priority
*
* @param int
* @return CI_Email
* @return Email
*/
public function set_priority($n = 3)
{
@ -914,7 +914,7 @@ class FW_Email {
* Set Newline Character
*
* @param string
* @return CI_Email
* @return Email
*/
public function set_newline($newline = "\n")
{
@ -928,7 +928,7 @@ class FW_Email {
* Set CRLF
*
* @param string
* @return CI_Email
* @return Email
*/
public function set_crlf($crlf = "\n")
{

View File

@ -184,7 +184,7 @@ class FW_Encryption {
* Initialize
*
* @param array $params Configuration parameters
* @return CI_Encryption
* @return Encryption
*/
public function initialize(array $params)
{

View File

@ -96,6 +96,11 @@ class Config
return $this->cfg[$configName];
}
public function __get($configName)
{
return $this->getConfig($configName);
}
/**
* Determine whether the file exists and, if so, load the ConfigORM
*

View File

@ -70,6 +70,15 @@ class Core
*/
public static function init()
{
// Set the CWD for usage in the shutdown function+
self::$cwd = getcwd();
// If the environment is not yet defined, use production settings
if (!defined('ENVIRONMENT'))
{
define('ENVIRONMENT', 'PRODUCTION');
}
// Defines the time the framework starts. Used for timing functions in the framework
if (!defined('STARTTIME')) {
define('STARTTIME', microtime(true));
@ -112,9 +121,6 @@ class Core
if ($event->isCancelled()) {
return true;
}
// Set the CWD for usage in the shutdown function+
self::$cwd = getcwd();
}
/**
@ -172,10 +178,15 @@ class Core
chdir(self::$cwd);
// Fire the Shutdown event
Events::fireEvent('coreShutdownEvent');
$event = Events::fireEvent('coreShutdownEvent');
// And end the logger
Logger::shutdown();
if ($event->isCancelled() === false)
{
// If the output should be displayed, send the final render and parse the logger
Logger::shutdownError();
Factory::getInstance()->output->_display();
Logger::shutdown();
}
}
/**
@ -190,6 +201,7 @@ class Core
if (file_exists($file)) {
include $file;
Logger::log('Loaded Composer');
Logger::loadComposer();
return true;
}
@ -216,4 +228,170 @@ class Core
return $_is_php[$version];
}
public static function isCli()
{
return (PHP_SAPI === 'cli' OR defined('STDIN'));
}
/**
* Is HTTPS?
*
* Determines if the application is accessed via an encrypted
* (HTTPS) connection.
*
* @return bool
*/
public static function isHttps()
{
if ( ! empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off')
{
return TRUE;
}
elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
{
return TRUE;
}
elseif ( ! empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off')
{
return TRUE;
}
return FALSE;
}
/**
* Tests for file writability
*
* is_writable() returns TRUE on Windows servers when you really can't write to
* the file, based on the read-only attribute. is_writable() is also unreliable
* on Unix servers if safe_mode is on.
*
* @link https://bugs.php.net/bug.php?id=54709
* @param string
* @return bool
*/
public static function isReallyWritable($file)
{
// If we're on a Unix server with safe_mode off we call is_writable
if (DIRECTORY_SEPARATOR === '/' && (self::isPHP('5.4') OR ! ini_get('safe_mode')))
{
return is_writable($file);
}
/* For Windows servers and safe_mode "on" installations we'll actually
* write a file then read it. Bah...
*/
if (is_dir($file))
{
$file = rtrim($file, '/').'/'.md5(mt_rand());
if (($fp = @fopen($file, 'ab')) === FALSE)
{
return FALSE;
}
fclose($fp);
@chmod($file, 0777);
@unlink($file);
return TRUE;
}
elseif ( ! is_file($file) OR ($fp = @fopen($file, 'ab')) === FALSE)
{
return FALSE;
}
fclose($fp);
return TRUE;
}
/**
* Set HTTP Status Header
*
* @param int the status code
* @param string
* @return void
*/
public static function setStatusHeader($code = 200, $text = '')
{
if (self::isCli())
{
return;
}
if (empty($code) OR ! is_numeric($code))
{
throw new Exception('Status codes must be numeric', 1);
}
if (empty($text))
{
is_int($code) OR $code = (int) $code;
$stati = array(
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
422 => 'Unprocessable Entity',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported'
);
if (isset($stati[$code]))
{
$text = $stati[$code];
}
else
{
throw new CoreException('No status text available. Please check your status code number or supply your own message text.', 1);
}
}
if (strpos(PHP_SAPI, 'cgi') === 0)
{
header('Status: '.$code.' '.$text, TRUE);
}
else
{
$server_protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1';
header($server_protocol.' '.$code.' '.$text, TRUE, $code);
}
}
}

View File

@ -98,11 +98,11 @@ class Factory
$this->instances['Database'] = new Database();
$this->instances['Language'] = new Language();
$this->instances['Utf8'] = new Utf8();
$this->instances['URI'] = new URI();
$this->instances['Uri'] = new URI();
$this->instances['Security'] = new Security();
$this->instances['Input'] = new Input();
$this->instances['Router'] = new Router();
$this->instances['Output'] = new Output();
$this->instances['Router'] = new Router();
return true;
}

View File

@ -110,7 +110,7 @@ class Input {
*
* Parsed from php://input at runtime
*
* @see CI_Input::input_stream()
* @see Input::input_stream()
* @var array
*/
protected $_input_stream;
@ -685,7 +685,7 @@ class Input {
// Clean UTF-8 if supported
if (UTF8_ENABLED === TRUE)
{
$str = UTF8::clean_string($str);
$str = $this->factory->utf8->clean_string($str);
}
// Remove control characters
@ -734,7 +734,7 @@ class Input {
// Clean UTF-8 if supported
if (UTF8_ENABLED === TRUE)
{
return UTF8::clean_string($str);
return $this->factory->utf8->clean_string($str);
}
return $str;

View File

@ -95,23 +95,33 @@ class Layout
private static $current_engine;
/**
* Retrieve a template file using a string and a directory and immediatly echo it.
* Retrieve a template file using a string and a directory and immediatly parse it to the output class.
*
* What template file gets loaded depends on the template engine that is being used.
* PHP for example uses .php files. Providing this function with 'home/dashboard' will load the home/view.dashboard.php file.
* You can also provide no particular engine, and the manager will decide what template to load.
* Remember that doing so will result in a LayoutException when multiple compatible files are found.
*
* @param string $file File to load
* @param string $directory Directory to load it from
* @param string $file File to load
* @param string $directory Directory to load it from
* @param bool $directOutput Whether to directly output the result with an echo or send it to the output class. True if echo
*
* @throws LayoutException On error
*/
public static function view($file, $directory = null)
public static function view($file, $directory = null, $directOutput = false)
{
$output = Factory::getInstance()->output;
$directory = (is_null($directory) ? self::$directory : $directory);
echo self::get($file, $directory);
if ($directOutput === true)
{
echo self::get($file, $directory);
}
else
{
$output->append_output(self::get($file, $directory));
}
return;
}
@ -146,11 +156,9 @@ class Layout
}
// Then assign some basic variables for the template
self::$assigned_variables['viewDir'] = Config::get('main')->SITE_URL.preg_replace('#/+#', '/', substr(self::$directory.'/', -strlen(self::$directory.'/')));
self::$assigned_variables['siteURL'] = Config::get('main')->SITE_URL;
self::$assigned_variables['siteLogo'] = Config::get('main')->SITE_LOGO_URL;
self::$assigned_variables['serverName'] = Config::get('main')->SERVER_NAME;
self::$assigned_variables['siteDomain'] = Config::get('main')->SITE_DOMAIN;
self::$assigned_variables['viewDir'] = Config::get('main')->base_url.preg_replace('#/+#', '/', substr(self::$directory.'/', -strlen(self::$directory.'/')));
self::$assigned_variables['siteURL'] = Config::get('main')->base_url;
self::$assigned_variables['serverName'] = Config::get('main')->server_name;
self::$assigned_variables['adminMail'] = Config::get('main')->administrator_mail;
self::$assigned_variables['contact'] = Config::get('contact')->toArray();
@ -469,8 +477,8 @@ class Layout
// Load the engines provided in this file
self::registerEngine(new PHPEngine(), 'PHP', array('php'));
self::registerEngine(new SmartyEngine(), 'Smarty', array('tpl'));
self::registerEngine(new JsonEngine(), 'JSON', array('json'));
self::registerEngine(new SmartyEngine(), 'Smarty', array('tpl'));
self::$engines_loaded = true;
}
}

View File

@ -32,6 +32,7 @@
*/
namespace FuzeWorks;
use Tracy\Debugger;
/**
* Logger Class.
@ -115,6 +116,13 @@ class Logger {
*/
public static $markPoints = array();
/**
* Whether to use the Tracy debugger instead of FuzeWorks Logger
*
* @var bool
*/
public static $useTracy = false;
/**
* Initiates the Logger.
*
@ -127,18 +135,60 @@ class Logger {
set_Exception_handler(array('\FuzeWorks\Logger', 'exceptionHandler'));
error_reporting(false);
}
self::$debug = Config::get('error')->debug;
self::$debug = (ENVIRONMENT === 'DEVELOPMENT');
self::$log_to_file = Config::get('error')->log_to_file;
self::$logger_template = Config::get('error')->logger_template;
self::newLevel('Logger Initiated');
}
/**
* Try to load Trace Debugger when available
*
* @return void
*/
public static function loadComposer()
{
if (class_exists('\Tracy\Debugger', true))
{
if (ENVIRONMENT === 'DEVELOPMENT')
{
Debugger::enable(Debugger::DEVELOPMENT, realpath('Application'.DS.'Logs'));
}
else
{
Debugger::enable(Debugger::PRODUCTION, realpath('Application'.DS.'Logs'));
}
self::$useTracy = true;
}
}
/**
* Function to be run upon FuzeWorks shutdown.
*
* Logs data to screen when requested to do so
*/
public static function shutdown() {
// And finally stop the Logging
self::stopLevel();
if (self::$debug === true || self::$print_to_screen) {
self::log('Parsing debug log');
self::logToScreen();
}
if (self::$log_to_file == true)
{
self::logToFile();
}
}
/**
* Function to be run upon FuzeWorks shutdown.
*
* Logs a fatal error and outputs the log when configured or requested to do so
*/
public static function shutdown() {
public static function shutdownError()
{
// Load last error if thrown
$errfile = 'Unknown file';
$errstr = 'shutdown';
@ -153,20 +203,13 @@ class Logger {
$errstr = $error['message'];
// Log it!
Factory::getInstance()->output->set_output('');
self::errorHandler($errno, $errstr, $errfile, $errline);
}
// And finally stop the Logging
self::stopLevel();
if (self::$debug == true || self::$print_to_screen) {
self::log('Parsing debug log');
self::logToScreen();
}
if (self::$log_to_file == true)
{
self::logToFile();
if (self::$useTracy === false)
{
self::http_error('500');
}
}
}
@ -232,7 +275,7 @@ class Logger {
Layout::reset();
Layout::assign('Logs', self::$Logs);
Layout::view(self::$logger_template, 'Core'.DS.'Views');
Layout::view(self::$logger_template, 'Core'.DS.'Views', true);
}
public static function logToFile()
@ -314,6 +357,12 @@ class Logger {
self::$infoErrors[] = $LOG;
self::$Logs[] = $LOG;
// Use Tracy when we can
if (self::$useTracy === true)
{
Debugger::log($msg, 'info');
}
}
/**
@ -334,6 +383,12 @@ class Logger {
self::$debugErrors[] = $LOG;
self::$Logs[] = $LOG;
// Use Tracy when we can
if (self::$useTracy === true)
{
Debugger::log($msg, 'debug');
}
}
/**
@ -354,6 +409,12 @@ class Logger {
self::$criticalErrors[] = $LOG;
self::$Logs[] = $LOG;
// Use Tracy when we can
if (self::$useTracy === true)
{
Debugger::log($msg, 'error');
}
}
/**
@ -374,6 +435,12 @@ class Logger {
self::$warningErrors[] = $LOG;
self::$Logs[] = $LOG;
// Use Tracy when we can
if (self::$useTracy === true)
{
Debugger::log($msg, 'warning');
}
}
/**
@ -393,6 +460,12 @@ class Logger {
'runtime' => round(self::getRelativeTime(), 4),);
self::$Logs[] = $LOG;
// Use Tracy when we can
if (self::$useTracy === true)
{
Debugger::log($msg, 'info');
}
}
/**

View File

@ -385,7 +385,7 @@ class Modules
if ($cache)
{
// Retrieve the cache if possible
$cache = Libraries::getDriver('cache');
$cache = Factory::getInstance()->libraries->getDriver('cache');
$cacheData = $cache->$cachingMethod->get('moduleRegisters');
if ( ! is_bool($cacheData) )
@ -403,7 +403,7 @@ class Modules
self::$advertiseRegister = $advertiseRegister;
self::$module_routes = $routeRegister;
foreach ($routeRegister as $route => $name) {
Router::addRoute($route, array('\FuzeWorks\Modules', 'moduleCallable'), true);
Factory::getInstance()->router->addRoute($route, array('callable' => array('\FuzeWorks\Modules', 'moduleCallable')), true);
}
Logger::stopLevel();
return true;
@ -489,7 +489,7 @@ class Modules
foreach ($cfg->routes as $route) {
// Create the route and callable and parse them
$callable = array('\FuzeWorks\Modules', 'moduleCallable');
Router::addRoute($route, $callable, true);
Factory::getInstance()->router->addRoute($route, array('callable' => $callable), true);
self::$module_routes[$route] = $name;
}
}

View File

@ -115,6 +115,10 @@ class Output {
*/
public $parse_exec_vars = TRUE;
protected $config;
protected $uri;
protected $router;
/**
* Class constructor
*
@ -124,15 +128,20 @@ class Output {
*/
public function __construct()
{
$factory = Factory::getInstance();
$this->config = $factory->config;
$this->uri = $factory->uri;
$this->router = $factory->router;
$this->_zlib_oc = (bool) ini_get('zlib.output_compression');
$this->_compress_output = (
$this->_zlib_oc === FALSE
&& Config::get('main')->compress_output === TRUE
&& $this->config->main->compress_output === TRUE
&& extension_loaded('zlib')
);
// Get mime types for later
$this->mimes = Config::get('mimes')->toArray();
$this->mimes = $this->config->mimes->toArray();
}
// --------------------------------------------------------------------
@ -157,7 +166,7 @@ class Output {
* Sets the output string.
*
* @param string $output Output data
* @return CI_Output
* @return Output
*/
public function set_output($output)
{
@ -173,7 +182,7 @@ class Output {
* Appends data onto the output string.
*
* @param string $output Data to append
* @return CI_Output
* @return Output
*/
public function append_output($output)
{
@ -193,7 +202,7 @@ class Output {
*
* @param string $header Header
* @param bool $replace Whether to replace the old header value, if already set
* @return CI_Output
* @return Output
*/
public function set_header($header, $replace = TRUE)
{
@ -217,7 +226,7 @@ class Output {
*
* @param string $mime_type Extension of the file we're outputting
* @param string $charset Character set (default: NULL)
* @return CI_Output
* @return Output
*/
public function set_content_type($mime_type, $charset = NULL)
{
@ -314,13 +323,11 @@ class Output {
*
* @param int $code Status code (default: 200)
* @param string $text Optional message
* @todo Fix this
* @return CI_Output
* @return Output
*/
public function set_status_header($code = 200, $text = '')
{
return $this;
set_status_header($code, $text);
Core::setStatusHeader($code, $text);
return $this;
}
@ -330,7 +337,7 @@ class Output {
* Enable/disable Profiler
*
* @param bool $val TRUE to enable or FALSE to disable
* @return CI_Output
* @return Output
*/
public function enable_profiler($val = TRUE)
{
@ -347,7 +354,7 @@ class Output {
* Profiler section display.
*
* @param array $sections Profiler sections
* @return CI_Output
* @return Output
*/
public function set_profiler_sections($sections)
{
@ -371,7 +378,7 @@ class Output {
* Set Cache
*
* @param int $time Cache expiration time in minutes
* @return CI_Output
* @return Output
*/
public function cache($time)
{
@ -391,23 +398,21 @@ class Output {
* Note: All "view" data is automatically put into $this->final_output
* by controller class.
*
* @uses CI_Output::$final_output
* @uses Output::$final_output
* @param string $output Output data override
* @return void
* @todo Implement cache
*/
public function _display($output = '')
{
// Note: We use load_class() because we can't use $CI =& get_instance()
// since this function is sometimes called by the caching mechanism,
// which happens before the CI super object is available.
$BM =& load_class('Benchmark', 'core');
$CFG =& load_class('Config', 'core');
$router = Factory::getInstance()->router;
// Grab the super object if we can.
if (class_exists('CI_Controller', FALSE))
if ($router->getCallable() === null)
{
$CI =& get_instance();
$use_cache = true;
}
else
{
$use_cache = false;
}
// --------------------------------------------------------------------
@ -423,10 +428,10 @@ class Output {
// Do we need to write a cache file? Only if the controller does not have its
// own _output() method and we are not dealing with a cache file, which we
// can determine by the existence of the $CI object above
//if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
//{
// $this->_write_cache($output);
//}
if ($this->cache_expiration > 0 && $use_cache === false)
{
$this->_write_cache($output);
}
// --------------------------------------------------------------------
@ -444,12 +449,12 @@ class Output {
// --------------------------------------------------------------------
// Is compression requested?
//if (isset($CI) // This means that we're not serving a cache file, if we were, it would already be compressed
// && $this->_compress_output === TRUE
// && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
//{
// ob_start('ob_gzhandler');
//}
if ($use_cache === false // This means that we're not serving a cache file, if we were, it would already be compressed
&& $this->_compress_output === TRUE
&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
{
ob_start('ob_gzhandler');
}
// --------------------------------------------------------------------
@ -464,10 +469,7 @@ class Output {
// --------------------------------------------------------------------
// Does the $CI object exist?
// If not we know we are dealing with a cache file so we'll
// simply echo out the data and exit.
if ( ! isset($CI))
if ( $use_cache === true)
{
if ($this->_compress_output === TRUE)
{
@ -494,8 +496,11 @@ class Output {
// Do we need to generate profile data?
// If so, load the Profile class and run it.
/*if ($this->enable_profiler === TRUE)
if ($this->enable_profiler === TRUE)
{
Logger::logWarning("Profiler not yet implemented");
return;
$CI->load->library('profiler');
if ( ! empty($this->_profiler_sections))
{
@ -511,16 +516,7 @@ class Output {
}
}
// Does the controller contain a function named _output()?
// If so send the output there. Otherwise, echo it.
if (method_exists($CI, '_output'))
{
$CI->_output($output);
}
else
{
echo $output; // Send it to the browser!
}*/
echo $output;
Logger::log('Final output sent to browser');
Logger::logDebug('Total execution time: '.$elapsed);
@ -532,30 +528,24 @@ class Output {
* Write Cache
*
* @param string $output Output data to cache
* @todo Implement cache
* @return void
*/
public function _write_cache($output)
{
Logger::logWarning("Cache is not implemented as of yet");
return;
$path = $this->config->cache->cache_file_path;
$cache_path = ($path === '') ? 'Application'.DS.'Cache'.DS : $path;
$CI =& get_instance();
$path = $CI->config->item('cache_path');
$cache_path = ($path === '') ? APPPATH.'cache/' : $path;
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
if ( ! is_dir($cache_path) OR ! Core::isReallyWritable($cache_path))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
Logger::logError('Unable to write cache file: '.$cache_path);
return;
}
$uri = $CI->config->item('base_url')
.$CI->config->item('index_page')
.$CI->uri->uri_string();
$uri = $this->config->main->base_url
.$this->config->main->index_page
.$this->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
if (($cache_query_string = $this->config->cache->cache_query_string) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
@ -571,7 +561,7 @@ class Output {
if ( ! $fp = @fopen($cache_path, 'w+b'))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
Logger::logError('Unable to write cache file: '.$cache_path);
return;
}
@ -612,7 +602,7 @@ class Output {
}
else
{
log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
Logger::logError('Unable to secure a file lock for file at: '.$cache_path);
return;
}
@ -621,7 +611,7 @@ class Output {
if (is_int($result))
{
chmod($cache_path, 0640);
log_message('debug', 'Cache file written: '.$cache_path);
Logger::logDebug('Cache file written: '.$cache_path);
// Send HTTP cache-control headers to browser to match file cache settings.
$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
@ -629,7 +619,7 @@ class Output {
else
{
@unlink($cache_path);
log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
Logger::logError('Unable to write the complete cache content at: '.$cache_path);
}
}
@ -638,26 +628,20 @@ class Output {
/**
* Update/serve cached output
*
* @uses CI_Config
* @uses CI_URI
* @todo Implement
* @uses Config
* @uses URI
*
* @param object &$CFG CI_Config class instance
* @param object &$URI CI_URI class instance
* @return bool TRUE on success or FALSE on failure
*/
public function _display_cache(&$CFG, &$URI)
public function _display_cache()
{
Logger::logWarning("Cache is not implemented as of yet");
return false;
$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
$cache_path = ($this->config->cache->cache_file_path === '') ? 'Application'.DS.'Cache'.DS : $this->config->cache->cache_file_path;
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
$main = $this->config->main;
$uri = $main->base_url.$main->index_page.$this->uri->uri_string;
if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
if (($cache_query_string = $this->config->cache->cache_query_string) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
@ -673,6 +657,7 @@ class Output {
if ( ! file_exists($filepath) OR ! $fp = @fopen($filepath, 'rb'))
{
Logger::logDebug("No cache file for $uri found");
return FALSE;
}
@ -695,11 +680,11 @@ class Output {
$last_modified = filemtime($filepath);
// Has the file expired?
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
if ($_SERVER['REQUEST_TIME'] >= $expire && Core::isReallyWritable($cache_path))
{
// If so we'll delete it.
@unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
Logger::logDebug('Cache file has expired. File deleted.');
return FALSE;
}
else
@ -716,7 +701,7 @@ class Output {
// Display the cache
$this->_display(substr($cache, strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
Logger::logDebug('Cache file is current. Sending it to browser.');
return TRUE;
}
@ -727,31 +712,26 @@ class Output {
*
* @param string $uri URI string
* @return bool
* @todo Implement
*/
public function delete_cache($uri = '')
{
Logger::logWarning("Caching is not implemented as of yet");
return false;
$CI =& get_instance();
$cache_path = $CI->config->item('cache_path');
$cache_path = $this->config->cache->cache_file_path;
if ($cache_path === '')
{
$cache_path = APPPATH.'cache/';
$cache_path = 'Application'.DS.'Cache'.DS;
}
if ( ! is_dir($cache_path))
{
log_message('error', 'Unable to find cache path: '.$cache_path);
Logger::logError('Unable to find cache path: '.$cache_path);
return FALSE;
}
if (empty($uri))
{
$uri = $CI->uri->uri_string();
$uri = $this->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
if (($cache_query_string = $this->config->cache->cache_query_string) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
@ -764,11 +744,11 @@ class Output {
}
}
$cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
$cache_path .= md5($this->config->mainbase_url.$this->config->main->index_page.ltrim($uri, '/'));
if ( ! @unlink($cache_path))
{
log_message('error', 'Unable to delete cache file for '.$uri);
Logger::logError('Unable to delete cache file for '.$uri);
return FALSE;
}

View File

@ -41,12 +41,14 @@ use Application\Init;
* The overall structure of the routing is as follows:
*
* The routes-array will hold a list of RegEx-strings. When the route-method is called, the framework will try
* to match the current path against all the RegEx's. When a RegEx matches, the linked callable will be called.
* to match the current path found in the URI class against all the RegEx's. When a RegEx matches,
* it will try and load what the route is related to. This can be a callable or a translator. A translator will
* convert the values of a route into a callable. In the end a callable will always be loaded.
*
* Every module can register routes and add their own callables. By default, two callables are used:
* The defaultCallable and the moduleCallable.
* Every module can register routes and add their own callables. By default, two callables are available:
* The defaultCallable and the moduleCallable of which the last one is found in the Modules class.
*
* The defaultCallable is a traditional MVC controller loader. Loading an URL using a default route works as follows:
* The defaultCallable is a traditional MVC controller loader. Loading an URL when no route matches works as follows:
*
* Let's say the visitor requests /A/B/C
*
@ -54,7 +56,7 @@ use Application\Init;
* B would be the function to be called in the 'controller' (default: index)
* C would be the first parameter
*
* All controllers are to be placed in the /Application/controller-directory.
* All controllers are to be placed in the /Application/Controller - directory.
*
* This is the default behaviour by adding routes to the config.routes.php. It is also possible to load Modules using routes.
* To load a Module using a route, add the route to the moduleInfo.php in a routes array.
@ -69,63 +71,143 @@ use Application\Init;
* Callables are NO controllers!! By default, the 'defaultCallable' will load the correct controller from
* the default controller directory. When you make custom routes, the callable will need to call your own
* controllers. This means that the one callable you provide with your RegEx will be called for EVERYTHING
* the RegEx matches. The names groups 'controller' and 'function' will be passed as first two arguments,
* the RegEx matches. Only the regex matches will be provided to the callable,
* if no names groups are available; you will need to extract them yourself from the path.
*
* After the core has been loaded, the method setPath will be called with the request URI (e.g. obtained via .htaccess).
* That method will then call the route-method, which will call the right controller and it's method.
* After the core has been loaded, the URI class will generate the URI which is currently being used.
* The index file will then call the route-method, which will call the right controller and it's associated method.
*
* @see Router::setPath
* @see Router::route
* @see Router::addRoute
*
* @author Abel Hoogeveen <abel@techfuze.net>
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
*
* @todo Implement Query Strings
* @todo Implement Unit tests
*/
class Router
{
/**
* @var null|string The provided path
*/
private static $path = null;
/**
* @var array Routes
*/
private static $routes = array();
protected $routes = array();
/**
* @var null|mixed The callable
*/
private static $callable = null;
protected $callable = null;
/**
* @var null|array The extracted matches from the regex
*/
private static $matches = null;
protected $matches = null;
/**
* The constructor adds the default route to the routing table.
* Translate URI dashes
*
* Determines whether dashes in controller & method segments
* should be automatically replaced by underscores.
*
* @var bool
*/
protected $translate_uri_dashes = false;
/**
* The Config class used to get configurations
*
* @var Config FuzeWorks config class
*/
protected $config;
/**
* The Uri class used to get paths
*
* @var Uri FuzeWorks uri class
*/
protected $uri;
/**
* The Logger class used to log information
*
* @var Logger FuzeWorks logger class
*/
protected $logger;
/**
* The Events class used to fire events
*
* @var Events FuzeWorks events class
*/
protected $events;
/**
* The Output class used to parse cache data
*
* @var Output FuzeWorks output class
*/
protected $output;
/**
* Constructor of the Router
*
* Loads all required classes and adds all the routes to the routingTable
*
* @return void
*/
public function __construct()
{
foreach (Config::get('routes') as $route => $callable) {
if (is_int($route)) {
$route = $callable;
$callable = array('\FuzeWorks\Router', 'defaultCallable');
}
// Load related classes
$factory = Factory::getInstance();
$this->config = $factory->config;
$this->uri = $factory->uri;
$this->logger = $factory->logger;
$this->events = $factory->events;
$this->output = $factory->output;
self::addRoute($route, $callable, false);
}
// Start parsing the routing
$this->parseRouting();
}
/**
* Returns the current routing path.
*
* @return bool|string
* Route Parser
*
* This method parses all the routes in the routes table config file
* and adds them to the Router. It converts some routes which use wildcards
*
* @return void
*/
public static function getPath()
protected function parseRouting()
{
return self::$path;
// Get routing routes
$routes = $this->config->routes;
$routing = $this->config->routing;
// If no query strings are used, we will add all routes in the config.routes.php file.
// We modify these routes to be an array of a regex string and a callable
$http_verb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';
foreach ($routes as $route => $value)
{
// Check if the route format is using HTTP verbs
if (is_array($value))
{
$value = array_change_key_case($value, CASE_LOWER);
if (isset($value[$http_verb]))
{
$value = $value['http_verb'];
}
else
{
continue;
}
}
// Convert wildcards to Regex
$route = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $route);
$this->addRoute($route, $value, false);
}
}
/**
@ -133,19 +215,19 @@ class Router
*
* @return array
*/
public static function getRoutes()
public function getRoutes()
{
return self::$routes;
return $this->routes;
}
/**
* Returns the currently loaded callable.
* Returns the currently loaded or selected callable.
*
* @return null|callable
*/
public static function getCallable()
public function getCallable()
{
return self::$callable;
return $this->callable;
}
/**
@ -153,99 +235,39 @@ class Router
*
* @return null|array
*/
public static function getMatches()
public function getMatches()
{
return self::$matches;
return $this->matches;
}
/**
* Set the current routing path.
* Add a route to the Router's routing table
*
* The route consists of 2 parts: the route and data.
*
* The route is a regex string which will later be matched upon Router::route().
*
* The data can be multiple things. First it can be a string, which will later be processed and turned into
* a callable. If the string is like 'controller/method' then the contoller 'Controller' will be loaded and the
* method 'method' will be called. The data can also be a callable. That callable will be called with all the regex
* that match the route. The callable is expected to return a string just like above. You can also provide an array.
* If you have an array like this: array('callable' => array('Class', 'method')) then your callable shall be used
* instead of the defaultCallabele.
*
* @param string $path The routing path (e.g. a/b/c/d/e)
*
* @return bool|string
*/
public static function setPath($path)
{
// Fire the event to notify our modules
$event = Events::fireEvent('routerSetPathEvent', $path);
// The event has been cancelled
if ($event->isCancelled()) {
return false;
}
// Remove double slashes
$path = preg_replace('@[/]+@', '/', $event->path);
// Remove first slash
if (substr($path, 0, 1) == '/') {
$path = substr($path, 1);
}
// Remove trailing slash
if (substr($path, -1, 1) == '/') {
$path = substr($path, 0, strlen($path) - 1);
}
return self::$path = $path;
}
/**
* Add a route.
*
* The path will be checked before custom routes before the default route(/controller/function/param1/param2/etc)
* When the given RegEx matches the current routing-path, the callable will be called.
*
* The callable will be called with three arguments:
*
* Callable($regex_matches = array())
*
* The variables in the array will be the named groups of your RegEx. When one or more named groups are
* not matched, they will be set to NULL. The default RegEx is:
*
* /^(?P<controller>.*?)(|\/(?P<function>.*?)(|\/(?P<parameters>.*?)))$/
*
* ^ Named group 1 ^ Named group 2 ^ Named group 3
*
* Named group 1 is named 'controller' and thus will become $controller
* Named group 2 is named 'function' and thus will become $function
* Named group 3 is named 'parameters' and thus will become $parameters
*
* You can also add aliases with the following:
*
* '/^this-is-an-alias$/' => array(
* 'controller' => 'home',
* 'function' => 'index',
* 'parameters' => array()
* ),
*
* This will link '/this-is-an-alias/ to /home/index. It is also possible to use the three named capture groups
* for the function, parameters or controllers. Like this:
*
* '/^alias(|\-(?P<function>.*?))$/' => array(
* 'controller' => 'home'
* ),
*
* This will mask '/alias' to '/home' and '/alias-test' to 'home/test'.
*
* You do not *have* to use named groups, but when you don't the arguments will be left NULL; and you will need to
* extract the information from the routing-path yourself.
*
* @param string $route This is a RegEx of the route, Every capture group will be a parameter
* @param callable $callable The callable to execute
* @param string $route This is a RegEx of the route, Every capture group will be a match, passed on to a callable
* @param mixed $data Can be multiple things. See description above
* @param bool $prepend Whether or not to insert at the beginning of the routing table
* @return void
*/
public static function addRoute($route, $callable, $prepend = true)
public function addRoute($route, $callable, $prepend = true)
{
if ($prepend) {
self::$routes = array($route => $callable) + self::$routes;
$this->routes = array($route => $callable) + $this->routes;
} else {
self::$routes[$route] = $callable;
$this->routes[$route] = $callable;
}
Logger::log('Route added at '.($prepend ? 'top' : 'bottom').': "'.$route.'"');
$this->logger->log('Route added at '.($prepend ? 'top' : 'bottom').': "'.$route.'"');
}
/**
@ -253,59 +275,154 @@ class Router
*
* @param $route string The route to remove
*/
public static function removeRoute($route)
public function removeRoute($route)
{
unset(self::$routes[$route]);
unset($this->routes[$route]);
Logger::log('Route removed: '.$route);
$this->logger->log('Route removed: '.$route);
}
/**
* Extracts the routing path from the URL using the routing table.
*
* Determines what callable should be loaded and what data matches the route regex.
* Determines what should be loaded and what data matches the route regex.
*
* @param bool $loadCallable Immediate load the callable when it's route matches
* @param bool $performLoading Immediate process the route after it has been determined
*/
public static function route($loadCallable = true)
public function route($performLoading = true)
{
// Turn the segment array into a URI string
$uri = implode('/', $this->uri->segments);
// Fire the event to notify our modules
$event = Events::fireEvent('routerRouteEvent', self::$routes, $loadCallable, self::$path);
$event = Events::fireEvent('routerRouteEvent', $this->routes, $performLoading, $uri);
// The event has been cancelled
if ($event->isCancelled()) {
if ($event->isCancelled())
{
return;
}
// Assign everything to the object to make it accessible, but let modules check it first
$routes = $event->routes;
$loadCallable = $event->loadCallable;
$performLoading = $event->performLoading;
//Check the custom routes
foreach ($routes as $r => $c) {
//A custom route is found
if (preg_match($r, $event->path, $matches)) {
Logger::log('Route matched: '.$r);
// If a cached page should be loaded, do so and stop loading a routed page
if ($performLoading === true && $event->cacheOverride === false && $this->output->_display_cache() === true)
{
return true;
}
// Add the matches to the current class
self::$matches = $matches;
// Check the custom routes
foreach ($routes as $route => $value)
{
// Match the path against the routes
if (preg_match('#^'.$route.'$#', $event->path, $matches))
{
$this->logger->log('Route matched: '.$route);
// Save the matches
$this->matches = $matches;
self::$callable = $c;
if (!$loadCallable || !self::loadCallable($matches, $r)) {
break;
// Are we using callbacks or another method?
if ( is_array($value))
{
// Maybe there is a real callable which should be called in the future
if ( isset($value['callable']) )
{
$this->callable = $value['callable'];
}
// If the callable is satisfied, break away
if (!$performLoading || !$this->loadCallable($matches, $route))
{
return;
}
// Otherwise try other routes
continue;
}
elseif ( ! is_string($value) && is_callable($value))
{
// Prepare the callable
array_shift($matches);
// Retrieve the path that should be loaded
$value = call_user_func_array($value, $matches);
}
elseif (strpos($value, '$') !== FALSE && strpos($route, '(') !== FALSE)
{
$value = preg_replace('#^'.$route.'$#', $value, $event->path);
}
// Now run the defaultRouter for when something is not a callable
$this->routeDefault(explode('/', $value), $route);
return;
}
}
// Check if we found a callable anyway
if (self::$callable === null) {
Logger::log('No routes found for given path: "'.$event->path.'"', E_WARNING);
Logger::http_error(404);
return;
// If we got this far it means we didn't encounter a
// matching route so we'll set the site default route
$this->matches = array();
if ($performLoading === true)
{
$this->routeDefault(array_values($this->uri->segments), '.*$');
}
}
/**
* @todo Implement validateRequest
*/
protected function validateRequest($segments)
{
$c = count($segments);
}
/**
* Converts a routing string into parameters for the defaultCallable.
*
* @param array $segments Segments of the controller,method,parameters to open
* @param string @route The route which was matched
* @return void
*/
protected function routeDefault($segments = array(), $route)
{
// If we don't have any segments left - try the default controller;
// WARNING: Directories get shifted out of the segments array!
if (empty($segments))
{
$segments[0] = $this->config->routing->default_controller;
}
if ($this->translate_uri_dashes === true)
{
$segments[0] = str_replace('-', '_', $segments[0]);
if (isset($segments[1]))
{
$segments[1] = str_replace('-', '_', $segments[1]);
}
}
// Prepare the values for loading
$controller = $segments[0];
$function = (isset($segments[1]) ? $segments[1] : $this->config->routing->default_function);
// And prepare the Router URI
array_unshift($segments, null);
unset($segments[0]);
$this->uri->rsegments = $segments;
// Now create a matches array
$matches = array(
'controller' => $controller,
'function' => $function,
'parameters' => array_slice($this->uri->rsegments, 2)
);
// And finally load the callable
$this->callable = array('\FuzeWorks\Router', 'defaultCallable');
$this->loadCallable($matches, $route);
}
/**
* Load the callable to which the route matched.
*
@ -318,12 +435,12 @@ class Router
*
* @return bool Whether or not the callable was satisfied
*/
public static function loadCallable($matches = array(), $route)
public function loadCallable($matches = array(), $route)
{
Logger::newLevel('Loading callable');
$this->logger->newLevel('Loading callable');
// Fire the event to notify our modules
$event = Events::fireEvent('routerLoadCallableEvent', self::$callable, $matches, $route);
$event = Events::fireEvent('routerLoadCallableEvent', $this->callable, $matches, $route);
// The event has been cancelled
if ($event->isCancelled()) {
@ -335,39 +452,39 @@ class Router
$args['route'] = $event->route;
if (!is_callable($event->callable)) {
if (isset(self::$callable['controller'])) {
if (isset($this->callable['controller'])) {
// Reset the arguments and fetch from custom callable
$args = array();
$args['controller'] = isset(self::$callable['controller']) ? self::$callable['controller'] : (isset($matches['controller']) ? $matches['controller'] : null);
$args['function'] = isset(self::$callable['function']) ? self::$callable['function'] : (isset($matches['function']) ? $matches['function'] : null);
$args['parameters'] = isset(self::$callable['parameters']) ? self::$callable['parameters'] : (isset($matches['parameters']) ? explode('/', $matches['parameters']) : null);
$args['controller'] = isset($this->callable['controller']) ? $this->callable['controller'] : (isset($matches['controller']) ? $matches['controller'] : null);
$args['function'] = isset($this->callable['function']) ? $this->callable['function'] : (isset($matches['function']) ? $matches['function'] : null);
$args['parameters'] = isset($this->callable['parameters']) ? $this->callable['parameters'] : (isset($matches['parameters']) ? explode('/', $matches['parameters']) : null);
self::$callable = array('\FuzeWorks\Router', 'defaultCallable');
$this->callable = array('\FuzeWorks\Router', 'defaultCallable');
} else {
Logger::log('The given callable is not callable!', E_ERROR);
Logger::http_error(500);
Logger::stopLevel();
$this->logger->log('The given callable is not callable!', E_ERROR);
$this->logger->http_error(500);
$this->logger->stopLevel();
return true;
}
} else {
self::$callable = $event->callable;
$this->callable = $event->callable;
}
// And log the input to the logger
Logger::newLevel('Calling callable');
$this->logger->newLevel('Calling callable');
foreach ($args as $key => $value) {
Logger::log($key.': '.var_export($value, true).'');
$this->logger->log($key.': '.var_export($value, true).'');
}
Logger::stopLevel();
$this->logger->stopLevel();
$skip = call_user_func_array(self::$callable, array($args)) === false;
$skip = call_user_func_array($this->callable, array($args)) === false;
if ($skip) {
Logger::log('Callable not satisfied, skipping to next callable');
$this->logger->log('Callable not satisfied, skipping to next callable');
}
Logger::stopLevel();
$this->logger->stopLevel();
return $skip;
}
@ -378,12 +495,12 @@ class Router
* This callable will do the 'old skool' routing. It will load the controllers from the controller-directory
* in the application-directory.
*/
public static function defaultCallable($arguments = array())
public function defaultCallable($arguments = array())
{
Logger::log('Default callable called!');
$this->logger->log('Default callable called!');
$controller = empty($arguments['controller']) ? Config::get('main')->default_controller : $arguments['controller'];
$function = empty($arguments['function']) ? Config::get('main')->default_function : $arguments['function'];
$controller = $arguments['controller'];
$function = $arguments['function'];
$parameters = empty($arguments['parameters']) ? null : $arguments['parameters'];
// Construct file paths and classes
@ -405,38 +522,37 @@ class Router
return;
}
Logger::log('Loading controller '.$event->className.' from file: '.$event->file);
// Check if the file exists
if (file_exists($event->file)) {
if (!class_exists($event->className)) {
$this->logger->log('Loading controller '.$event->className.' from file: '.$event->file);
include $event->file;
}
// Get the path the controller should know about
$path = substr(self::getPath(), ($pos = strpos(self::getPath(), '/')) !== false ? $pos + 1 : 0);
$path = implode('/', $this->uri->rsegments);
// And create the controller
self::$callable = new $event->className($path);
$this->callable = new $event->className($path);
// If the controller does not want a function to be loaded, provide a halt parameter.
if (isset(self::$callable->halt)) {
if (isset($this->callable->halt)) {
return;
}
// Check if method exists or if there is a caller function
if (method_exists(self::$callable, $event->function) || method_exists(self::$callable, '__call')) {
if (method_exists($this->callable, $event->function) || method_exists($this->callable, '__call')) {
// Execute the function on the controller
echo self::$callable->{$event->function}($event->parameters);
echo $this->callable->{$event->function}($event->parameters);
} else {
// Function could not be found
Logger::log('Could not find function '.$event->function.' on controller '.$event->className);
Logger::http_error(404);
$this->logger->log('Could not find function '.$event->function.' on controller '.$event->className);
$this->logger->http_error(404);
}
} else {
// Controller could not be found
Logger::log('Could not find controller '.$event->className);
Logger::http_error(404);
$this->logger->log('Could not find controller '.$event->className);
$this->logger->http_error(404);
}
}
}

View File

@ -48,14 +48,14 @@ class URI {
*
* @var array
*/
public static $keyval = array();
public $keyval = array();
/**
* Current URI string
*
* @var string
*/
public static $uri_string = '';
public $uri_string = '';
/**
* List of URI segments
@ -64,7 +64,7 @@ class URI {
*
* @var array
*/
public static $segments = array();
public $segments = array();
/**
* List of routed URI segments
@ -73,7 +73,7 @@ class URI {
*
* @var array
*/
public static $rsegments = array();
public $rsegments = array();
/**
* Permitted URI chars
@ -82,14 +82,14 @@ class URI {
*
* @var string
*/
protected static $_permitted_uri_chars;
protected $_permitted_uri_chars;
/**
* The configuration of this class
*
* @var ConfigORM
*/
private static $config;
private $config;
/**
* Class constructor
@ -98,43 +98,69 @@ class URI {
*/
public function __construct()
{
self::$config = Config::get('routing');
$this->config = Config::get('routing');
// If query strings are enabled, we don't need to parse any segments.
// However, they don't make sense under CLI.
if ((PHP_SAPI === 'cli' OR defined('STDIN')) OR self::$config->enable_query_strings !== TRUE)
// Determine the base_url
if (empty(Config::get('main')->base_url))
{
self::$_permitted_uri_chars = self::$config->permitted_uri_chars;
// If it's a CLI request, ignore the configuration
if ( (PHP_SAPI === 'cli' OR defined('STDIN')) )
if (isset($_SERVER['SERVER_ADDR']))
{
$uri = self::_parse_argv();
if (strpos($_SERVER['SERVER_ADDR'], ':') !== FALSE)
{
$server_addr = '['.$_SERVER['SERVER_ADDR'].']';
}
else
{
$server_addr = $_SERVER['SERVER_ADDR'];
}
$base_url = (Core::isHttps() ? 'https' : 'http').'://'.$server_addr
.substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
}
else
{
$protocol = self::$config->uri_protocol;
$base_url = 'http://localhost/';
}
Config::get('main')->base_url = $base_url;
}
// If query strings are enabled, we don't need to parse any segments.
// However, they don't make sense under CLI.
if (Core::isCli() OR $this->config->enable_query_strings !== TRUE)
{
$this->_permitted_uri_chars = $this->config->permitted_uri_chars;
// If it's a CLI request, ignore the configuration
if ( Core::isCli() )
{
$uri = $this->_parse_argv();
}
else
{
$protocol = $this->config->uri_protocol;
empty($protocol) && $protocol = 'REQUEST_URI';
switch ($protocol)
{
case 'AUTO': // For BC purposes only
case 'REQUEST_URI':
$uri = self::_parse_request_uri();
$uri = $this->_parse_request_uri();
break;
case 'QUERY_STRING':
$uri = self::_parse_query_string();
$uri = $this->_parse_query_string();
break;
case 'PATH_INFO':
default:
$uri = isset($_SERVER[$protocol])
? $_SERVER[$protocol]
: self::_parse_request_uri();
: $this->_parse_request_uri();
break;
}
}
self::_set_uri_string($uri);
$this->_set_uri_string($uri);
}
}
@ -146,39 +172,39 @@ class URI {
* @param string $str
* @return void
*/
protected static function _set_uri_string($str)
protected function _set_uri_string($str)
{
// Filter out control characters and trim slashes
self::$uri_string = trim(Utf8::remove_invisible_characters($str, FALSE), '/');
$this->uri_string = trim(Utf8::remove_invisible_characters($str, FALSE), '/');
if (self::$uri_string !== '')
if ($this->uri_string !== '')
{
// Remove the URL suffix, if present
if (($suffix = (string) self::$config->url_suffix) !== '')
if (($suffix = (string) $this->config->url_suffix) !== '')
{
$slen = strlen($suffix);
if (substr(self::$uri_string, -$slen) === $suffix)
if (substr($this->uri_string, -$slen) === $suffix)
{
self::$uri_string = substr(self::$uri_string, 0, -$slen);
$this->uri_string = substr($this->uri_string, 0, -$slen);
}
}
self::$segments[0] = NULL;
$this->segments[0] = NULL;
// Populate the segments array
foreach (explode('/', trim(self::$uri_string, '/')) as $val)
foreach (explode('/', trim($this->uri_string, '/')) as $val)
{
$val = trim($val);
// Filter segments for security
self::filter_uri($val);
$this->filter_uri($val);
if ($val !== '')
{
self::$segments[] = $val;
$this->segments[] = $val;
}
}
unset(self::$segments[0]);
unset($this->segments[0]);
}
}
@ -192,7 +218,7 @@ class URI {
*
* @return string
*/
protected static function _parse_request_uri()
protected function _parse_request_uri()
{
if ( ! isset($_SERVER['REQUEST_URI'], $_SERVER['SCRIPT_NAME']))
{
@ -240,7 +266,7 @@ class URI {
// Do some final cleaning of the URI and return it
return self::_remove_relative_directory($uri);
return $this->_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
@ -252,7 +278,7 @@ class URI {
*
* @return string
*/
protected static function _parse_query_string()
protected function _parse_query_string()
{
$uri = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : @getenv('QUERY_STRING');
@ -269,7 +295,7 @@ class URI {
parse_str($_SERVER['QUERY_STRING'], $_GET);
return self::_remove_relative_directory($uri);
return $this->_remove_relative_directory($uri);
}
// --------------------------------------------------------------------
@ -281,7 +307,7 @@ class URI {
*
* @return string
*/
protected static function _parse_argv()
protected function _parse_argv()
{
$args = array_slice($_SERVER['argv'], 1);
return $args ? implode('/', $args) : '';
@ -292,12 +318,12 @@ class URI {
/**
* Remove relative directory (../) and multi slashes (///)
*
* Do some final cleaning of the URI and return it, currently only used in self::_parse_request_uri()
* Do some final cleaning of the URI and return it, currently only used in $this->_parse_request_uri()
*
* @param string $uri
* @return string
*/
protected static function _remove_relative_directory($uri)
protected function _remove_relative_directory($uri)
{
$uris = array();
$tok = strtok($uri, '/');
@ -323,9 +349,9 @@ class URI {
* @param string $str
* @return void
*/
public static function filter_uri(&$str)
public function filter_uri(&$str)
{
if ( ! empty($str) && ! empty(self::$_permitted_uri_chars) && ! preg_match('/^['.self::$_permitted_uri_chars.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $str))
if ( ! empty($str) && ! empty($this->_permitted_uri_chars) && ! preg_match('/^['.$this->_permitted_uri_chars.']+$/i'.(UTF8_ENABLED ? 'u' : ''), $str))
{
throw new UriException('The URI you submitted has disallowed characters.', 1);
}
@ -336,14 +362,14 @@ class URI {
/**
* Fetch URI Segment
*
* @see CI_URI::$segments
* @see URI::$segments
* @param int $n Index
* @param mixed $no_result What to return if the segment index is not found
* @return mixed
*/
public static function segment($n, $no_result = NULL)
public function segment($n, $no_result = NULL)
{
return isset(self::$segments[$n]) ? self::$segments[$n] : $no_result;
return isset($this->segments[$n]) ? $this->segments[$n] : $no_result;
}
// --------------------------------------------------------------------
@ -353,17 +379,17 @@ class URI {
*
* Returns the re-routed URI segment (assuming routing rules are used)
* based on the index provided. If there is no routing, will return
* the same result as CI_URI::segment().
* the same result as URI::segment().
*
* @see CI_URI::$rsegments
* @see CI_URI::segment()
* @see URI::$rsegments
* @see URI::segment()
* @param int $n Index
* @param mixed $no_result What to return if the segment index is not found
* @return mixed
*/
public static function rsegment($n, $no_result = NULL)
public function rsegment($n, $no_result = NULL)
{
return isset(self::$rsegments[$n]) ? self::$rsegments[$n] : $no_result;
return isset($this->rsegments[$n]) ? $this->rsegments[$n] : $no_result;
}
// --------------------------------------------------------------------
@ -388,9 +414,9 @@ class URI {
* @param array $default Default values
* @return array
*/
public static function uri_to_assoc($n = 3, $default = array())
public function uri_to_assoc($n = 3, $default = array())
{
return self::_uri_to_assoc($n, $default, 'segment');
return $this->_uri_to_assoc($n, $default, 'segment');
}
// --------------------------------------------------------------------
@ -398,17 +424,17 @@ class URI {
/**
* Routed URI to assoc
*
* Identical to CI_URI::uri_to_assoc(), only it uses the re-routed
* Identical to URI::uri_to_assoc(), only it uses the re-routed
* segment array.
*
* @see CI_URI::uri_to_assoc()
* @see URI::uri_to_assoc()
* @param int $n Index (default: 3)
* @param array $default Default values
* @return array
*/
public static function ruri_to_assoc($n = 3, $default = array())
public function ruri_to_assoc($n = 3, $default = array())
{
return self::_uri_to_assoc($n, $default, 'rsegment');
return $this->_uri_to_assoc($n, $default, 'rsegment');
}
// --------------------------------------------------------------------
@ -418,36 +444,36 @@ class URI {
*
* Generates a key/value pair from the URI string or re-routed URI string.
*
* @used-by CI_URI::uri_to_assoc()
* @used-by CI_URI::ruri_to_assoc()
* @used-by URI::uri_to_assoc()
* @used-by URI::ruri_to_assoc()
* @param int $n Index (default: 3)
* @param array $default Default values
* @param string $which Array name ('segment' or 'rsegment')
* @return array
*/
protected static function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
protected function _uri_to_assoc($n = 3, $default = array(), $which = 'segment')
{
if ( ! is_numeric($n))
{
return $default;
}
if (isset(self::$keyval[$which], self::$keyval[$which][$n]))
if (isset($this->keyval[$which], $this->keyval[$which][$n]))
{
return self::$keyval[$which][$n];
return $this->keyval[$which][$n];
}
$total_segments = "total_{$which}s";
$segment_array = "{$which}_array";
if (self::$total_segments() < $n)
if ($this->$total_segments() < $n)
{
return (count($default) === 0)
? array()
: array_fill_keys($default, NULL);
}
$segments = array_slice(self::$segment_array(), ($n - 1));
$segments = array_slice($this->$segment_array(), ($n - 1));
$i = 0;
$lastval = '';
$retval = array();
@ -478,8 +504,8 @@ class URI {
}
// Cache the array for reuse
isset(self::$keyval[$which]) OR self::$keyval[$which] = array();
self::$keyval[$which][$n] = $retval;
isset($this->keyval[$which]) OR $this->keyval[$which] = array();
$this->keyval[$which][$n] = $retval;
return $retval;
}
@ -493,7 +519,7 @@ class URI {
* @param array $array Input array of key/value pairs
* @return string URI string
*/
public static function assoc_to_uri($array)
public function assoc_to_uri($array)
{
$temp = array();
foreach ((array) $array as $key => $val)
@ -516,9 +542,9 @@ class URI {
* @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public static function slash_segment($n, $where = 'trailing')
public function slash_segment($n, $where = 'trailing')
{
return self::_slash_segment($n, $where, 'segment');
return $this->_slash_segment($n, $where, 'segment');
}
// --------------------------------------------------------------------
@ -532,9 +558,9 @@ class URI {
* @param string $where Where to add the slash ('trailing' or 'leading')
* @return string
*/
public static function slash_rsegment($n, $where = 'trailing')
public function slash_rsegment($n, $where = 'trailing')
{
return self::_slash_segment($n, $where, 'rsegment');
return $this->_slash_segment($n, $where, 'rsegment');
}
// --------------------------------------------------------------------
@ -544,15 +570,15 @@ class URI {
*
* Fetches an URI Segment and adds a slash to it.
*
* @used-by CI_URI::slash_segment()
* @used-by CI_URI::slash_rsegment()
* @used-by URI::slash_segment()
* @used-by URI::slash_rsegment()
*
* @param int $n Index
* @param string $where Where to add the slash ('trailing' or 'leading')
* @param string $which Array name ('segment' or 'rsegment')
* @return string
*/
protected static function _slash_segment($n, $where = 'trailing', $which = 'segment')
protected function _slash_segment($n, $where = 'trailing', $which = 'segment')
{
$leading = $trailing = '/';
@ -565,7 +591,7 @@ class URI {
$trailing = '';
}
return $leading.self::$which($n).$trailing;
return $leading.$this->$which($n).$trailing;
}
// --------------------------------------------------------------------
@ -573,11 +599,11 @@ class URI {
/**
* Segment Array
*
* @return array CI_URI::$segments
* @return array URI::$segments
*/
public static function segment_array()
public function segment_array()
{
return self::$segments;
return $this->segments;
}
// --------------------------------------------------------------------
@ -585,11 +611,11 @@ class URI {
/**
* Routed Segment Array
*
* @return array CI_URI::$rsegments
* @return array URI::$rsegments
*/
public static function rsegment_array()
public function rsegment_array()
{
return self::$rsegments;
return $this->rsegments;
}
// --------------------------------------------------------------------
@ -599,9 +625,9 @@ class URI {
*
* @return int
*/
public static function total_segments()
public function total_segments()
{
return count(self::$segments);
return count($this->segments);
}
// --------------------------------------------------------------------
@ -611,9 +637,9 @@ class URI {
*
* @return int
*/
public static function total_rsegments()
public function total_rsegments()
{
return count(self::$rsegments);
return count($this->rsegments);
}
// --------------------------------------------------------------------
@ -621,24 +647,10 @@ class URI {
/**
* Fetch URI string
*
* @return string CI_URI::$uri_string
* @return string URI::$uri_string
*/
public static function uri_string()
public function uri_string()
{
return self::$uri_string;
return $this->uri_string;
}
// --------------------------------------------------------------------
/**
* Fetch Re-routed URI string
*
* @return string
* @todo Implement router
*/
public static function ruri_string()
{
return ltrim(load_class('Router', 'core')->directory, '/').implode('/', self::$rsegments);
}
}

View File

@ -75,7 +75,7 @@ class Utf8 {
mb_internal_encoding($charset);
}
// This is required for mb_convert_encoding() to strip invalid characters.
// That's utilized by CI_Utf8, but it's also done for consistency with iconv.
// That's utilized by Utf8, but it's also done for consistency with iconv.
mb_substitute_character('none');
}
else
@ -135,9 +135,9 @@ class Utf8 {
* @param string $str String to clean
* @return string
*/
public static function clean_string($str)
public function clean_string($str)
{
if (self::is_ascii($str) === FALSE)
if ($this->is_ascii($str) === FALSE)
{
if (MB_ENABLED)
{
@ -164,9 +164,9 @@ class Utf8 {
* @param string $str String to clean
* @return string
*/
public static function safe_ascii_for_xml($str)
public function safe_ascii_for_xml($str)
{
return self::remove_invisible_characters($str, FALSE);
return $this->remove_invisible_characters($str, FALSE);
}
// --------------------------------------------------------------------
@ -180,7 +180,7 @@ class Utf8 {
* @param string $encoding Input encoding
* @return string $str encoded in UTF-8 or FALSE on failure
*/
public static function convert_to_utf8($str, $encoding)
public function convert_to_utf8($str, $encoding)
{
if (MB_ENABLED)
{
@ -204,7 +204,7 @@ class Utf8 {
* @param string $str String to check
* @return bool
*/
public static function is_ascii($str)
public function is_ascii($str)
{
return (preg_match('/[^\x00-\x7F]/S', $str) === 0);
}

View File

@ -114,7 +114,7 @@ class LayoutManager
private static function getVariables()
{
$vars = array();
$vars['adminURL'] = Config::get('main')->SITE_URL.'admin/';
$vars['adminURL'] = Config::get('main')->base_url.'admin/';
return $vars;
}

View File

@ -39,7 +39,7 @@ return array(
'aliases' => array(),
'dependencies' => array(),
'events' => array(),
'routes' => array('/^admin(|\/(?P<identifier>.*?)(|\/(?<page>.*?)(|\/(?P<subdata>.*?))))$/'),
'routes' => array('admin(|\/(?P<identifier>.*?)(|\/(?<page>.*?)(|\/(?P<subdata>.*?))))'),
'advertise' => array('admin' => array('identifier' => 'fuzeadmin', 'pages' => array(array('name' => 'TEST', 'page_path' => 'testPage', 'icon' => 'fa-plane')))),
'listenFor' => array('admin'),
'name' => 'FuzeWorks Admin Panel',

View File

@ -56,7 +56,7 @@ return array(
// Routes that this module listens on. Any URL that matches this pattern will load this module
// If the URL /example/ gets called, this module will be loaded
// Everything after /example/ will be sent to the route() function in the matches array under the, in this example, 'data' key
'routes' => array('/^example(|\/(?P<data>.*?))$/'),
'routes' => array('example(|\/(?P<data>.*?))$'),
// Advertises some data with the key 'exampleAdvertisement'. This data will be sent to a module which listens for this key.
// This allows for some data to be sent to a module which listens to this key.

View File

@ -3,7 +3,8 @@
"php": ">=5.4.0",
"ext-curl": "*",
"ext-json": "*",
"smarty/smarty": "~3.1"
"smarty/smarty": "~3.1",
"tracy/tracy": "*"
},
"require-dev": {
"phpunit/phpunit": "5.3.*",

View File

@ -30,7 +30,9 @@
* @version Version 0.0.1
*/
use FuzeWorks\Core;
use FuzeWorks\Router;
use FuzeWorks\Factory;
define('ENVIRONMENT', 'PRODUCTION');
// Include framework
require_once dirname(__FILE__).'/Core/System/class.core.php';
@ -38,5 +40,5 @@ require_once dirname(__FILE__).'/Core/System/class.core.php';
// Load it
Core::init();
Router::setPath((isset($_GET['path']) ? $_GET['path'] : null));
Router::route();
$router = Factory::getInstance()->router;
$router->route();

View File

@ -31,6 +31,7 @@
*/
use FuzeWorks\Events;
use FuzeWorks\Layout;
use FuzeWorks\Factory;
/**
* Class CoreTestAbstract.
@ -49,5 +50,6 @@ abstract class CoreTestAbstract extends PHPUnit_Framework_TestCase
Events::$listeners = array();
Layout::reset();
Events::enable();
Factory::getInstance()->output->set_output('');
}
}

View File

@ -41,13 +41,6 @@ require_once 'Core/System/class.core.php';
ob_start();
Core::init();
// Disable debugger
$cfg = Config::get('error');
$cfg->debug = false;
$cfg->error_reporting = false;
$cfg->log_to_file = false;
$cfg->commit();
restore_error_handler();
restore_exception_handler();

View File

@ -30,6 +30,7 @@
* @version Version 0.0.1
*/
use FuzeWorks\Layout;
use FuzeWorks\Factory;
/**
* Class LayoutTest.
@ -122,6 +123,7 @@ class layoutTest extends CoreTestAbstract
ob_start();
Layout::view('test', $directory);
Factory::getInstance()->output->_display();
$output = ob_get_contents();
ob_end_clean();

100
tests/core_outputTest.php Normal file
View File

@ -0,0 +1,100 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
use FuzeWorks\Factory;
/**
* Class OutputTest.
*
* Core testing suite, will test basic output class functionality
*/
class outputTest extends CoreTestAbstract {
public $output;
protected $_output_data = '';
public function setUp()
{
$this->_output_data =<<<HTML
<html>
<head>
<title>Basic HTML</title>
</head>
<body>
Test
</body>
</html>
HTML;
Factory::getInstance()->config->main->charset = 'UTF-8';
$this->output = Factory::getInstance()->output;
}
// --------------------------------------------------------------------
public function test_set_get_append_output()
{
$append = "<!-- comment /-->\n";
$this->assertEquals(
$this->_output_data.$append,
$this->output
->set_output($this->_output_data)
->append_output("<!-- comment /-->\n")
->get_output()
);
}
// --------------------------------------------------------------------
public function test_get_content_type()
{
$this->assertEquals('text/html', $this->output->get_content_type());
}
// --------------------------------------------------------------------
public function test_get_header()
{
$this->assertNull($this->output->get_header('Non-Existent-Header'));
// TODO: Find a way to test header() values as well. Currently,
// PHPUnit prevents this by not using output buffering.
$this->output->set_content_type('text/plain', 'WINDOWS-1251');
$this->assertEquals(
'text/plain; charset=WINDOWS-1251',
$this->output->get_header('content-type')
);
}
}

View File

@ -1,142 +0,0 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
use FuzeWorks\Router;
/**
* Class RouterTest.
*
* This test will test the router
*/
class routerTest extends CoreTestAbstract
{
public function testParsePath()
{
// Act and assert
Router::setPath('a/b/c/d/');
$this->assertEquals('a/b/c/d', Router::getPath());
Router::setPath('//a//b//c');
$this->assertEquals('a/b/c', Router::getPath());
Router::setPath('/');
$this->assertEquals('', Router::getPath());
Router::setPath('');
$this->assertEquals('', Router::getPath());
Router::setPath(false);
$this->assertEquals('', Router::getPath());
Router::setPath(null);
$this->assertEquals('', Router::getPath());
}
/**
* @depends testParsePath
*/
public function testDoRoute()
{
// Act
Router::setPath('a/b/c/d/');
Router::route(false);
// Assert
// Whole route
$this->assertEquals(array('a', 'b', 'c/d'), array(Router::getMatches()['controller'], Router::getMatches()['function'], Router::getMatches()['parameters']));
$this->assertEquals('a', Router::getMatches()['controller']);
// Parameters
$this->assertEquals('c/d', Router::getMatches()['parameters']);
// Function and controller
$this->assertEquals('a', Router::getMatches()['controller']);
$this->assertEquals('b', Router::getMatches()['function']);
}
/**
* @depends testDoRoute
*/
public function testOddRoutes()
{
// Empty path
Router::setPath(null);
Router::route(false);
$this->assertEquals(null, Router::getMatches()['controller']);
// Double slashes
Router::setPath('a///b');
Router::route(false);
$this->assertEquals(array('a', 'b'), array(Router::getMatches()['controller'], Router::getMatches()['function']));
// Escaped path path
Router::setPath('/a\/b\/c/');
Router::route(false);
$this->assertEquals(array('a\\', 'b\\', 'c'), array(Router::getMatches()['controller'], Router::getMatches()['function'], Router::getMatches()['parameters']));
$this->assertNotEquals('a', Router::getMatches()['controller']);
}
public function testCustomRoute()
{
Router::addRoute('/test1\/test2/', 'callable');
$this->assertArraySubset(array('/test1\/test2/' => 'callable'), Router::getRoutes());
}
public function testCustomRouteWithParameters()
{
Router::addRoute('/^b\/(?P<controller>[^\/]+)\/?(?P<function>.+?)$/', 'callable');
Router::addRoute('/e\/(?P<function>[^\/]+)/', 'callable');
Router::addRoute('/b\/b$/', 'callable');
Router::setPath('b/controller_a/function_a');
Router::route(false);
$this->assertEquals('controller_a', Router::getMatches()['controller']);
$this->assertEquals('function_a', Router::getMatches()['function']);
Router::setPath('e/function_b/c');
Router::route(false);
$this->assertFalse(isset(Router::getMatches()['controller']));
$this->assertEquals('function_b', Router::getMatches()['function']);
Router::setPath('b/b');
Router::route(false);
$this->assertFalse(isset(Router::getMatches()['controller']));
$this->assertFalse(isset(Router::getMatches()['function']));
Router::setPath('a/b');
Router::route(false);
$this->assertEquals('a', Router::getMatches()['controller']);
$this->assertEquals('b', Router::getMatches()['function']);
}
}

182
tests/core_uriTest.php Normal file
View File

@ -0,0 +1,182 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
use FuzeWorks\Factory;
/**
* Class URITest.
*
* Core testing suite, will test URI class functionality
*/
class uriTest extends CoreTestAbstract {
public function setUp()
{
$this->uri = new Mock_Core_URI();
}
// --------------------------------------------------------------------
public function test_filter_uri_passing()
{
$this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-');
$str = 'abc01239~%.:_-';
$this->uri->filter_uri($str);
}
// --------------------------------------------------------------------
/**
* @expectedException FuzeWorks\UriException
*/
public function test_filter_uri_throws_error()
{
$this->uri->config->routing->enable_query_strings = false;
$this->uri->_set_permitted_uri_chars('a-z 0-9~%.:_\-');
$segment = '$this()'; // filter_uri() accepts by reference
$this->uri->filter_uri($segment);
}
// --------------------------------------------------------------------
public function test_segment()
{
$this->uri->segments = array(1 => 'controller');
$this->assertEquals($this->uri->segment(1), 'controller');
$this->assertEquals($this->uri->segment(2, 'default'), 'default');
}
// --------------------------------------------------------------------
public function test_rsegment()
{
$this->uri->rsegments = array(1 => 'method');
$this->assertEquals($this->uri->rsegment(1), 'method');
$this->assertEquals($this->uri->rsegment(2, 'default'), 'default');
}
// --------------------------------------------------------------------
public function test_uri_to_assoc()
{
$this->uri->segments = array('a', '1', 'b', '2', 'c', '3');
$this->assertEquals(
array('a' => '1', 'b' => '2', 'c' => '3'),
$this->uri->uri_to_assoc(1)
);
$this->assertEquals(
array('b' => '2', 'c' => '3'),
$this->uri->uri_to_assoc(3)
);
$this->uri->keyval = array(); // reset cache
$this->uri->segments = array('a', '1', 'b', '2', 'c');
$this->assertEquals(
array('a' => '1', 'b' => '2', 'c' => FALSE),
$this->uri->uri_to_assoc(1)
);
$this->uri->keyval = array(); // reset cache
$this->uri->segments = array('a', '1');
// test default
$this->assertEquals(
array('a' => '1', 'b' => FALSE),
$this->uri->uri_to_assoc(1, array('a', 'b'))
);
}
// --------------------------------------------------------------------
public function test_ruri_to_assoc()
{
$this->uri->rsegments = array('x', '1', 'y', '2', 'z', '3');
$this->assertEquals(
array('x' => '1', 'y' => '2', 'z' => '3'),
$this->uri->ruri_to_assoc(1)
);
$this->assertEquals(
array('y' => '2', 'z' => '3'),
$this->uri->ruri_to_assoc(3)
);
$this->uri->keyval = array(); // reset cache
$this->uri->rsegments = array('x', '1', 'y', '2', 'z');
$this->assertEquals(
array('x' => '1', 'y' => '2', 'z' => FALSE),
$this->uri->ruri_to_assoc(1)
);
$this->uri->keyval = array(); // reset cache
$this->uri->rsegments = array('x', '1');
// test default
$this->assertEquals(
array('x' => '1', 'y' => FALSE),
$this->uri->ruri_to_assoc(1, array('x', 'y'))
);
}
// --------------------------------------------------------------------
public function test_assoc_to_uri()
{
//$this->uri->config->set_item('uri_string_slashes', 'none');
$this->assertEquals('a/1/b/2', $this->uri->assoc_to_uri(array('a' => '1', 'b' => '2')));
}
// --------------------------------------------------------------------
public function test_slash_segment()
{
$this->uri->segments[1] = 'segment';
$this->uri->rsegments[1] = 'segment';
$this->assertEquals('/segment/', $this->uri->slash_segment(1, 'both'));
$this->assertEquals('/segment/', $this->uri->slash_rsegment(1, 'both'));
$a = '/segment';
$this->assertEquals('/segment', $this->uri->slash_segment(1, 'leading'));
$this->assertEquals('/segment', $this->uri->slash_rsegment(1, 'leading'));
$this->assertEquals('segment/', $this->uri->slash_segment(1, 'trailing'));
$this->assertEquals('segment/', $this->uri->slash_rsegment(1, 'trailing'));
}
}

View File

@ -1,136 +0,0 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
use FuzeWorks\Events;
use FuzeWorks\Router;
use FuzeWorks\EventPriority;
use FuzeWorks\Layout;
/**
* Class RouterLoadCallableEventTest.
*/
class routerLoadCallableEventTest extends CoreTestAbstract
{
/**
* Check if the event is fired when it should be.
*/
public function test_basic()
{
$mock = $this->getMock('MockEvent', array('mockMethod'));
$mock->expects($this->once())->method('mockMethod');
Router::setPath('/');
Events::addListener(function ($event) {
$event->setCancelled(true);
}, 'layoutLoadViewEvent', EventPriority::HIGHEST);
Events::addListener(array($mock, 'mockMethod'), 'routerLoadCallableEvent', EventPriority::NORMAL);
//Prevent ouputting HTML
ob_start();
Router::route();
ob_end_clean();
}
/**
* Intercept and change.
*/
public function test_change()
{
Events::addListener(function ($event) {
$event->setCancelled(true);
}, 'layoutLoadViewEvent', EventPriority::HIGHEST);
Events::addListener(array($this, 'listener_change'), 'routerLoadCallableEvent', EventPriority::NORMAL);
Router::setPath('x/y/z');
Router::route(true);
Events::$listeners = array();
Events::addListener(function ($event) {
$event->setCancelled(true);
}, 'layoutLoadViewEvent', EventPriority::HIGHEST);
Events::addListener(array($this, 'listener_change'), 'routerLoadCallableEvent', EventPriority::NORMAL);
Router::setPath('x/y/z');
Router::route(true);
$this->assertNotNull(Router::getCallable());
$this->assertInstanceOf('\Application\Controller\Standard', Router::getCallable());
}
// Change title from new to other
public function listener_change($event)
{
// This controller should not exist
$this->assertEquals('x', $event->matches['controller']);
$this->assertEquals('y', $event->matches['function']);
// It should exist now
$event->matches['controller'] = 'standard';
$event->matches['function'] = 'index';
return $event;
}
/**
* Cancel events.
*/
public function test_cancel()
{
ob_start();
// When the callable may execute, the callable will change to the controller
// (because '' will trigger the default callable)
Router::setPath('');
Events::addListener(array($this, 'listener_cancel'), 'routerLoadCallableEvent', EventPriority::NORMAL);
Router::route();
$this->assertTrue(is_callable(Router::getCallable()));
// When disabled, the default controller will be loaded and the callable will be overwritten
// Remove the listener
Events::$listeners = array();
Events::addListener(function ($event) {
$event->setCancelled(true);
}, 'layoutLoadViewEvent', EventPriority::HIGHEST);
Router::route();
$this->assertFalse(is_callable(Router::getCallable()));
ob_end_clean();
}
// Cancel all calls
public function listener_cancel($event)
{
$event->setCancelled(true);
}
}

View File

@ -1,74 +0,0 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
use FuzeWorks\Events;
use FuzeWorks\Router;
use FuzeWorks\EventPriority;
/**
* Class RouterRouteEventTest.
*/
class routerRouteEventTest extends CoreTestAbstract
{
/**
* Check if the event is fired when it should be.
*/
public function test_basic()
{
$mock = $this->getMock('MockEvent', array('mockMethod'));
$mock->expects($this->once())->method('mockMethod');
Events::addListener(array($mock, 'mockMethod'), 'routerRouteEvent', EventPriority::NORMAL);
Router::setPath('a/b/c');
Router::route(false);
}
/**
* Cancel events.
*/
public function test_cancel()
{
Router::setPath('x/y/z');
Events::addListener(array($this, 'listener_cancel'), 'routerRouteEvent', EventPriority::NORMAL);
Router::route(false);
$this->assertNotEquals('x', Router::getMatches()['controller']);
$this->assertNotEquals('y', Router::getMatches()['function']);
$this->assertNotEquals('z', Router::getMatches()['parameters']);
}
// Cancel all calls
public function listener_cancel($event)
{
$event->setCancelled(true);
}
}

View File

@ -1,108 +0,0 @@
<?php
/**
* FuzeWorks.
*
* The FuzeWorks MVC PHP FrameWork
*
* Copyright (C) 2015 TechFuze
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @author TechFuze
* @copyright Copyright (c) 2013 - 2016, Techfuze. (http://techfuze.net)
* @copyright Copyright (c) 1996 - 2015, Free Software Foundation, Inc. (http://www.fsf.org/)
* @license http://opensource.org/licenses/GPL-3.0 GPLv3 License
*
* @link http://fuzeworks.techfuze.net
* @since Version 0.0.1
*
* @version Version 0.0.1
*/
use FuzeWorks\Events;
use FuzeWorks\Router;
use FuzeWorks\EventPriority;
/**
* Class RouterSetPathEventTest.
*/
class routerSetPathEventTest extends CoreTestAbstract
{
/**
* Check if the event is fired when it should be.
*/
public function testRouterSetPathEvent()
{
$mock = $this->getMock('MockEvent', array('mockMethod'));
$mock->expects($this->once())->method('mockMethod');
Events::addListener(array($mock, 'mockMethod'), 'routerSetPathEvent', EventPriority::NORMAL);
Router::setPath('a/b/c');
}
/**
* Intercept and change.
*/
public function testRouterSetPathEvent_change()
{
Events::addListener(array($this, 'listener_change'), 'routerSetPathEvent', EventPriority::NORMAL);
Router::setPath('a/b/c');
$this->assertEquals('x/y/z', Router::getPath());
}
// Change title from new to other
public function listener_change($event)
{
$this->assertEquals('a/b/c', $event->path);
$event->path = 'x/y/z';
}
/**
* Cancel events.
*/
public function testLayoutFunctionCallEvent_cancel()
{
Router::setPath('a/b/c');
Events::addListener(array($this, 'listener_cancel'), 'routerSetPathEvent', EventPriority::NORMAL);
Router::setPath('x/y/z');
$this->assertEquals('a/b/c', Router::getPath());
}
// Cancel all calls
public function listener_cancel($event)
{
$event->setCancelled(true);
}
/**
* Do not cancel events.
*/
public function testLayoutFunctionCallEvent_dontcancel()
{
Router::setPath('a/b/c');
Events::addListener(array($this, 'listener_dontcancel'), 'routerSetPathEvent', EventPriority::NORMAL);
Router::setPath('x/y/z');
$this->assertEquals('x/y/z', Router::getPath());
}
// Cancel all calls
public function listener_dontcancel($event)
{
$event->setCancelled(false);
}
}

31
tests/mocks/core/uri.php Normal file
View File

@ -0,0 +1,31 @@
<?php
use FuzeWorks\Uri;
use FuzeWorks\Factory;
class Mock_Core_URI extends Uri {
public function __construct()
{
$this->config = Factory::getInstance()->config;
// set predictable config values
$this->config->main->index_page = 'index.php';
$this->config->main->base_url = 'http://example.com/';
$this->config->main->application_prefix = 'MY_';
$this->config->routing->enable_query_strings = false;
$this->config->routing->permitted_uri_chars = 'a-z 0-9~%.:_\-';
if ($this->config->routing->enable_query_strings !== TRUE OR is_cli())
{
$this->_permitted_uri_chars = $this->config->routing->permitted_uri_chars;
}
}
public function _set_permitted_uri_chars($value)
{
$this->_permitted_uri_chars = $value;
}
}