First commit. Genres and categories partially fleshed out

This commit is contained in:
Timothy Warren 2012-06-13 13:49:10 -04:00
parent 4bf8891444
commit 13b63edc5f
45 changed files with 4015 additions and 17 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
sys/*.sqlite

115
README.md
View File

@ -1,22 +1,103 @@
#meta # miniMVC
miniMVC is a minimalistic Modular MVC framework, with built-in minifier, and pure-PHP templating system.
So, you know all that client information you need to keep track of, like passwords and servers? Or how about all those serial keys for the software you have? meta is a webapp to organize these kinds of data for easier reference. ### Requirements
* PHP 5.4+
* PDO extensions for databases you wish to use
* Webserver that correctly handles REQUEST_URI, such as:
* Apache
* IIS
* Lighttpd
* SimpleTest library for running unit tests
##Organizing Data ### Unique features
#### Extensive use of PHP's magic methods on the base class
Meta has a four-level hierarchy * `__toString()` method allows a view of the current class object when the current class object is used as a string. If you prefer `var_dump()` or `var_export()`, you can pass the name of that function if you call the `__toString` method directly.
1. Genre
* The broadest category. An example could be titled 'Client Data'
2. Category
* A general item in the genre. For example, an individual client.
3. Section
* A grouping of label-data pairs. Something like 'CMS Access'
4. Data
* Pairs of labels and values.
Eg. Username : admin Eg. `$this . "string"`, `$this->__toString()`, `echo $this`;
* `__call()` method allows the dynamic addition of callable closure objects
Eg. `$this->foo = function($baz){}` is callable as `$this->foo()`, with the current object as the last argument
* `MM` class extends ArrayObject, and all the main classes extend this class. Functions begining with `array_` are callable on object from this class. E.g. `$this->array_keys()` will return a list of the class properties.
#### Database class is an extension of PHP's PDO class.
Database class uses [Query](https://github.com/aviat4ion/Query) as a database abstraction layer and query builder.
Database connections are set in /app/config/db.php
### File Structure
* index.php - framework bootstrap
* app - configuration and app-wide files
* classes - helper classes
* config - configuration files
* modules - MVC triads
* controllers - controller classes
* models - model classes
* views - module-specific views
* views - global page templates
* errors - error page templates
* assets - frontend files
* js - javascript files
* css - css files
* config - minifier configuration files
* sys - core framework classes
### Common Tasks
* Creating a controller
<?php
class Foo extends miniMVC\Controller {
function __construct()
{
parent::__construct();
}
}
* Creating a model
<?php
class Bar extends miniMVC\Model {
function __construct()
This basic hierarchy enables keeping track of simple data in a neat fashion. {
parent::__construct();
}
}
* Loading a database
`$this->db = miniMVC\db::get_instance($db_name);`
Note that multiple databases can be used in the same class
by specifying a different database name.
* Loading a model (From a controller)
`$this->load_model($model)` - creates an instance of that model as a member of the current class. After loading the model, you can call its methods like so
`$this->[model name]->method()`
* Loading a class
Librarys / classes found in `app/classes` or `sys/libraries` are autoloaded.
To call a library, simply instantiate that class.
Classes with a `get_instance` static methods should be called like so:
`$obj =& miniMVC\class::get_instance()`
Other classes should be called using the new operator
`$obj = new miniMVC\class()`

0
app/classes/index.html Normal file
View File

135
app/config/config.php Normal file
View File

@ -0,0 +1,135 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Main config file
*
* @package miniMVC
* @subpackage App
*/
// --------------------------------------------------------------------------
/*
|--------------------------------------------------------------------------
| Display Debug backtrace
|--------------------------------------------------------------------------
|
| If set to TRUE, a backtrace will be displayed along with php errors.
|
*/
define('SHOW_DEBUG_BACKTRACE', TRUE);
/*
|--------------------------------------------------------------------------
| Base Url
|--------------------------------------------------------------------------
|
| This is the url path where the framework is located. Requires trailing
| slash.
|
*/
// Determine the default site url
$ri = $_SERVER['REQUEST_URI'];
$ind_pos = stripos($ri, "index.php");
$default_path = ($ind_pos !== FALSE) ? substr($ri, 0, $ind_pos) : $ri;
$default_baseurl = "//" . str_replace("//", "/", $_SERVER['HTTP_HOST']. $default_path);
define('BASE_URL', $default_baseurl);
/*
|--------------------------------------------------------------------------
| Url index file
|--------------------------------------------------------------------------
|
| This determines whether "index.php" is in generated urls
|
*/
define('URL_INDEX_FILE', 'index.php/');
/*
|--------------------------------------------------------------------------
| Content Domain
|--------------------------------------------------------------------------
|
| This is the domain used for serving content, such as css, javascript.
|
*/
define('CONTENT_DOMAIN', BASE_URL);
/*
|--------------------------------------------------------------------------
| Static Lib Path
|--------------------------------------------------------------------------
|
| This is the path where the 'assets' directory is on the static domain.
|
*/
define('STATIC_LIB_PATH', CONTENT_DOMAIN.'assets/');
/*
|--------------------------------------------------------------------------
| Group Style Path
|--------------------------------------------------------------------------
|
| This is the path that is used to determine the relative path to the
| stylesheet minifier. This should not need to be changed.
|
*/
define('STYLE_PATH', STATIC_LIB_PATH . 'css.php/g/');
/*
|--------------------------------------------------------------------------
| Group Javascript Path
|--------------------------------------------------------------------------
|
| This is the path that is used to determine the relative path to the
| javascript minifier. This should not need to be changed.
|
*/
define('SCRIPT_PATH', STATIC_LIB_PATH . 'js.php/g/');
/*
|--------------------------------------------------------------------------
| Default title
|--------------------------------------------------------------------------
|
| Default title for webpages
|
*/
define('DEFAULT_TITLE', "meta");
/*
|--------------------------------------------------------------------------
| Default css group
|--------------------------------------------------------------------------
|
| Default css group
|
*/
define('DEFAULT_CSS_GROUP', "css");
/*
|--------------------------------------------------------------------------
| Default js group
|--------------------------------------------------------------------------
|
| Default js group
|
*/
define('DEFAULT_JS_GROUP', "js");
// End of config.php

37
app/config/db.php Normal file
View File

@ -0,0 +1,37 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Database config file
*
* @package miniMVC
* @subpackage App
*/
// --------------------------------------------------------------------------
$db_conf = array(
'default' => array(
'type' => 'sqlite',
'host' => '',
'user' => '',
'pass' => '',
'port' => '',
'database' => '',
'file' => MM_SYS_PATH . 'meta.sqlite',
)
);
// End of db.php

41
app/config/routes.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* File to configure routes
*
* Routes work on simple/regex matching.
*
* For a route mapping http://example.com/blog to the blog controller in the blog module:
* 'blog' => 'blog/blog/index'
*
* To route a special 404 page, set '404_route' to the "module/controller/method" you wish to use
*
* @package miniMVC
* @subpackage App
*/
// --------------------------------------------------------------------------
return array(
// Default Paths
'default_controller' => 'welcome',
'default_module' => 'meta',
'genre' => 'meta/genre/index',
'genre/add' => 'meta/genre/add',
'404_route' => '',
);
// End of routes.php

View File

@ -0,0 +1,102 @@
<?php
/**
* meta
*
* Hierarchial data tool
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Genre controller
*
* @package meta
*/
class Genre extends miniMVC\Controller {
/**
* Initialize the Controller
*/
public function __construct()
{
parent::__construct();
$this->load_model('meta\model');
$this->page->build_header();
}
/**
* Default controller method
*/
public function index()
{
// Re-route to detail page if the last segment
// is a valid integer
$id = (int) miniMVC\get_last_segment();
if ($id !== 0)
{
return $this->detail($id);
}
// Otherwise, display list of genres
$data = array();
$data['genres'] = $this->model->get_genres();
$this->load_view('genres', $data);
$this->page->build_footer();
}
/**
* Adds a new genre
*/
public function add()
{
// Strip away tags for the sake of security
$name = strip_tags($_POST['genre']);
// Make sure the name doesn't already exist. If it does, show an error.
$res = $this->model->add_genre($name);
if ($res === TRUE)
{
$this->page->set_message('success', 'Added new genre');
}
else
{
$this->page->set_message('error', 'Genre already exists');
}
// Render the basic page
$this->index();
}
/**
* Returns the categories / editing options for a genre
*
* @param int
*/
public function detail($id)
{
$genre = $this->model->get_genre_by_id($id);
$categories = $this->model->get_categories($id);
$data = array(
'genre' => $genre,
'categories' => $categories,
'genre_id' => $id
);
$this->load_view('genre_detail', $data);
$this->page->build_footer();
}
}
// End of genre.php

View File

@ -0,0 +1,59 @@
<?php
/**
* meta
*
* Hierarchial data tool
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Default Controller class
*
* @package meta
*/
class Welcome extends miniMVC\Controller {
/**
* Initialize the constructor
*
* @return void
*/
public function __construct()
{
parent::__construct();
$this->load_model('meta\model');
}
// --------------------------------------------------------------------------
/**
* Default route for the controller
*
* @return void
*/
public function index()
{
$data = array();
$data['genres'] = $this->model->get_genres();
$this->page->render('genres', $data);
}
// --------------------------------------------------------------------------
public function login()
{
}
}
// End of welcome.php

View File

@ -0,0 +1,351 @@
<?php
/**
* meta
*
* Simple hierarchial data management
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace meta;
/**
* Main Model for database interaction
*
* @package meta
*/
class Model extends \miniMVC\Model {
/**
* Reference to database connection
*
* @var Query_Builder
*/
protected $db;
/**
* Reference to session
*
* @var Session
*/
protected $session;
/**
* Initialize the model
*/
public function __construct()
{
parent::__construct();
$this->session =& \miniMVC\Session::get_instance();
$this->db =& \miniMVC\db::get_instance();
}
// --------------------------------------------------------------------------
/**
* Delete a genre/category/section or data item
*
* @param string $type
* @param int $id
*/
public function delete($type, $id)
{
$this->db->where('id', (int) $id)
->delete($type);
}
// --------------------------------------------------------------------------
/**
* Move a category/section/data item to another parent
*
* @param string
* @param int
* @param int
*/
public function move($type, $type_id, $parent_id)
{
$parent_type = array(
'data' => 'section',
'section' => 'category',
'category' => 'genre'
);
$parent_field = "{$parent_type[$type]}_id";
$this->db->set($parent_field, $parent_id)
->where('id', (int) $type_id)
->update($type);
}
// --------------------------------------------------------------------------
/**
* Add genre
*
* @param string
* @return bool
*/
public function add_genre($genre)
{
// Check for duplicates
$query = $this->db->from('genre')
->where('genre', $genre)
->get();
// Fetch the data as a workaround
// for databases that do not support
// grabbing result counts (SQLite / Firebird)
$array = $query->fetchAll();
if (count($array) === 0)
{
$this->db->set('genre', $genre)
->insert('genre');
return TRUE;
}
return FALSE;
}
// --------------------------------------------------------------------------
/**
* Rename a genre
*
* @param int
* @param string
*/
public function update_genre($genre_id, $genre)
{
$this->db->set('genre', $genre)
->where('id', $genre_id)
->update('genre');
}
// --------------------------------------------------------------------------
/**
* Add category to genre
*
* @param string
* @param int
*/
public function add_category($cat, $genre_id)
{
$this->db->set('category', $cat)
->set('genre_id', $genre_id)
->insert('category');
}
// --------------------------------------------------------------------------
/**
* Rename a category
*
* @param int
* @param string
*/
public function update_category($cat_id, $category)
{
$this->db->set('category', $category)
->where('id', (int) $cat_id)
->update('category');
}
// --------------------------------------------------------------------------
/**
* Add a section to a category
*
* @param string
* @param int
*/
public function add_section($section, $category_id)
{
$this->db->set('section', $section)
->set('category_id', (int) $category_id)
->insert('section');
}
// --------------------------------------------------------------------------
/**
* Rename a section
*
* @param int
* @param string
*/
public function update_section($section_id, $section)
{
$this->db->set('section', $section)
->where('id', (int) $section_id)
->update('section');
}
// --------------------------------------------------------------------------
/**
* Add key/value data to a section
*
* @param int
* @param mixed object/array
*/
public function add_data($section_id, $data)
{
// Convert the data to json for storage
$data_str = json_encode($data);
// Save the data
$this->db->set('data', $data_str)
->set('section_id', (int) $section_id)
->insert('data');
}
// --------------------------------------------------------------------------
/**
* Update the data
*
* @param int
* @param mixed
*/
public function update_data($data_id, $data)
{
// Convert the data to json for storage
$data_str = json_encode('data', $data_str);
// Save the data
$this->db->set('data', $data_str)
->where('id', (int) $data_id)
->update('data');
}
// --------------------------------------------------------------------------
/**
* Gets the list of genres
*
* @return array
*/
public function get_genres()
{
$genres = array();
$query = $this->db->select('id, genre')
->from('genre')
->order_by('genre', 'asc')
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
{
$genres[$row['id']] = $row['genre'];
}
return $genres;
}
/**
* Gets the name of the genre from its id
*
* @param int
* @return string
*/
public function get_genre_by_id($id)
{
$query = $this->db->select('genre')
->from('genre')
->where('id', (int) $id)
->get();
$row = $query->fetch(\PDO::FETCH_ASSOC);
return $row['genre'];
}
// --------------------------------------------------------------------------
/**
* Get the categories for the specified genre
*
* @param int
* @return array
*/
public function get_categories($genre_id)
{
$cats = array();
$query = $this->db->select('id, category')
->from('category')
->where('genre_id', (int) $genre_id)
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
{
$cats[$row['id']] = $row['category'];
}
return $cats;
}
// --------------------------------------------------------------------------
/**
* Get the sections for the specified category id
*
* @param int
* @return array
*/
public function get_sections($category_id)
{
$sections = array();
$query = $this->db->select('id, section')
->from('section')
->where('category_id', (int) $category_id)
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
{
$sections[$row['id']] = $row['section'];
}
return $sections;
}
// --------------------------------------------------------------------------
/**
* Get the data fro the section
*
* @param int
* @return array
*/
public function get_data($section_id)
{
$data = array();
$query = $this->db->select('id, data')
->from('data')
->where('section_id', (int) $section_id)
->get();
while($row = $query->fetch(\PDO::FETCH_ASSOC))
{
$data[$row['id']] = json_decode($row['data'], TRUE);
}
return $data;
}
}
// End of model.php

View File

@ -0,0 +1,32 @@
<?php
/**
* meta
*
* Simple hierarchial data management
*
* @package meta
* @author Timothy J. Warren
* @copyright Copyright (c) 2012
* @link https://github.com/aviat4ion/meta
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace meta;
/**
* Model for dealing with user logins / permissions
*
* @package meta
*/
class User_model extends \miniMVC\Model {
public function __construct()
{
parent::__construct();
}
}
// End of user_model.php

View File

@ -0,0 +1,23 @@
<h1>meta</h1>
<h3><?= $genre ?></h3>
<h4>Genre Categories</h4>
<ul class="list">
<?php foreach($categories as $id => $cat): ?>
<li><a href="<?= miniMVC\site_url("category/{$id}") ?>"><?= $cat ?></a></li>
<?php endforeach ?>
</ul>
<form action="<?= miniMVC\site_url("category/add") ?>" method="post">
<fieldset>
<lengend>Add Category</lengend>
<dl>
<!-- Weird tag wrapping is intentional for display: inline-block -->
<dt><label for="category">Category name:</label></dt><dd>
<input type="text" name="category" id="category" /></dd>
<dt><input type="hidden" name="genre_id" value="<?= $genre_id ?>" /></dt><dd>
<button type="submit">Add Category</button></dd>
</dl>
</fieldset>
</form>

View File

@ -0,0 +1,22 @@
<h1>Meta</h1>
<h3>Genres</h3>
<ul class="list">
<?php foreach($genres as $id => $name): ?>
<li><a href="<?= miniMVC\site_url("genre/{$id}") ?>"><?= $name ?></a></li>
<?php endforeach ?>
</ul>
<form action="<?= miniMVC\site_url("genre/add") ?>" method="post">
<fieldset>
<lengend>Add Genre</lengend>
<dl>
<!-- Weird tag wrapping is intentional for display: inline-block -->
<dt><label for="genre">Genre name:</label></dt><dd>
<input type="text" name="genre" id="genre" /></dd>
<dt>&nbsp;</dt><dd>
<button type="submit">Add Genre</button></dd>
</dl>
</fieldset>
</form>

View File

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<head>
<title>404 Not Found</title>
<style type="text/css">
div{position:relative; margin:0.5em auto; padding:0.5em; width:95%; border:1px solid #924949; background: #f3e6e6;}
</style>
</head>
<body>
<div class="message error">
<?php if (isset($title)) : ?>
<h1><?= $title ?></h1>
<?php endif ?>
<?= $message; ?>
</div>
</body>
</html>

View File

@ -0,0 +1,7 @@
<div style="position:relative; margin:0.5em auto; padding:0.5em; width:95%; border:1px solid #924949; background: #f3e6e6;">
<h4>A Database Error was encountered</h4>
<p>Code: <?= $code ?></p>
<p>Driver Code: <?= $driver_code ?></p>
<p>Message: <?= $message ?></p>
</div>

View File

@ -0,0 +1,19 @@
<!DOCTYPE HTML>
<html>
<head>
<title>404 Not Found</title>
<style type="text/css">
div{position:relative; margin:0.5em auto; padding:0.5em; width:95%; border:1px solid #924949; background: #f3e6e6;}
</style>
</head>
<body>
<div class="message error">
<?php if (isset($title)) : ?>
<h1><?= $title ?></h1>
<?php endif ?>
<?= $message; ?>
</div>
</body>
</html>

View File

@ -0,0 +1,22 @@
<div style="position:relative; margin:0.5em auto; padding:0.5em; width:95%; border:1px solid #924949; background: #f3e6e6;">
<h4>An uncaught exception was thrown.</h4>
<p>Message: <?= $message; ?></p>
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === TRUE): ?>
<p>Backtrace: </p>
<?php foreach($exception->getTrace() as $error): ?>
<?php if (isset($error['file']) && ! stristr($error['file'], MM_SYS_PATH)): ?>
<p style="margin-left:10px">
File: <?= str_replace(MM_BASE_PATH, "", $error['file']) ?><br />
Line: <?= $error['line'] ?><br />
Function: <?= $error['function'] ?>
</p>
<?php endif ?>
<?php endforeach ?></p>
<?php endif ?>
</div>

6
app/views/footer.php Normal file
View File

@ -0,0 +1,6 @@
<?php if ($foot_js != ""): ?>
<?= $foot_js ?>
<?php endif ?>
</body>
</html>

11
app/views/header.php Normal file
View File

@ -0,0 +1,11 @@
<head>
<?= $meta ?>
<?= $css ?>
<?= $head_tags ?>
<title><?= $title ?></title>
<?php if (!empty($base)) { ?><base href="<?=$base ?>" /><?php } ?>
<?= $head_tags ?>
<?= $head_js ?>
</head>
<body<?= (!empty($body_class)) ? "class=\"" . $body_class . "\"" : ""; ?><?= (!empty($body_id)) ? " id=\"" . $body_id . "\"" : ""; ?>>

5
app/views/message.php Normal file
View File

@ -0,0 +1,5 @@
<div class="message <?= $stat_class ?>">
<span class="icon"></span>
<?= $message ?>
<span class="close" onclick="this.parentElement.style.display='none'"></span>
</div>

76
assets/config/config.php Executable file
View File

@ -0,0 +1,76 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* Asset management configuration file
*
* @package miniMVC
* @subpackage Assets
*/
/*
|--------------------------------------------------------------------------
| Document Root
|--------------------------------------------------------------------------
|
| The folder where the index of the website exists. In most situations,
| this will not need to be changed.
|
| If the website is in a folder off of the domain name, like:
| http://example.com/website/
| you will need to add that folder to the document root.
|
*/
$document_root = './';
/*
|--------------------------------------------------------------------------
| CSS Folder
|--------------------------------------------------------------------------
|
| The folder where css files exist, in relation to the document root
|
*/
$css_root = $document_root. 'css/';
/*
|--------------------------------------------------------------------------
| Path from
|--------------------------------------------------------------------------
|
| Path fragment to rewrite in css files
|
*/
$path_from = '';
/*
|--------------------------------------------------------------------------
| Path to
|--------------------------------------------------------------------------
|
| The path fragment replacement for the css files
|
*/
$path_to = '';
/*
|--------------------------------------------------------------------------
| JS Folder
|--------------------------------------------------------------------------
|
| The folder where javascript files exist, in relation to the document root
|
*/
$js_root = $document_root. '/js/';

View File

@ -0,0 +1,29 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* This is the config array for css files to concatenate and minify
*/
return array(
/*-----
Css
-----*/
'css' => array(
'normalize.css',
'message.css',
'theme.css'
)
);
// End of css_groups.php

28
assets/config/js_groups.php Executable file
View File

@ -0,0 +1,28 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* This is the config array for javascript files to concatenate and minify
*/
return [
/*
For each group create an array like so
'my_group' => array(
'path/to/css/file1.css',
'path/to/css/file2.css'
),
*/
];

135
assets/css.php Executable file
View File

@ -0,0 +1,135 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* CSS Minifier and Cacher
*
* @package miniMVC
* @subpackage Assets
*/
//Get config files
require('./config/config.php');
//Include the css groups
$groups = require("./config/css_groups.php");
//The name of this file
$this_file = __FILE__;
// --------------------------------------------------------------------------
/**
* CSS Minifier
*
* @param string $buffer
* @return string
*/
function compress($buffer) {
//Remove CSS comments
$buffer = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $buffer);
//Remove tabs, spaces, newlines, etc.
$buffer = preg_replace('`\s+`', ' ', $buffer);
$replace = [
' )' => ')',
') ' => ')',
' }' => '}',
'} ' => '}',
' {' => '{',
'{ ' => '{',
', ' => ',',
': ' => ':',
'; ' => ';',
];
//Eradicate every last space!
$buffer = trim(strtr($buffer, $replace));
$buffer = str_replace('{ ', '{', $buffer);
$buffer = str_replace('} ', '}', $buffer);
return $buffer;
}
// --------------------------------------------------------------------------
//Creative rewriting
$pi = $_SERVER['PATH_INFO'];
$pia = explode('/', $pi);
$pia_len = count($pia);
$i = 1;
while($i < $pia_len)
{
$j = $i+1;
$j = (isset($pia[$j])) ? $j : $i;
$_GET[$pia[$i]] = $pia[$j];
$i = $j + 1;
};
$css = '';
$modified = [];
if (isset($groups[$_GET['g']]))
{
foreach ($groups[$_GET['g']] as &$file)
{
$new_file = $css_root.$file;
$css .= file_get_contents($new_file);
$modified[] = filemtime($new_file);
}
}
//Add this page too
$modified[] = filemtime($this_file);
//Get the latest modified date
rsort($modified);
$last_modified = $modified[0];
$requested_time= (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: time();
if ($last_modified === $requested_time)
{
header("HTTP/1.1 304 Not Modified");
exit();
}
if (!isset($_GET['debug']))
{
$css = compress($css);
}
$size = strlen($css) * 8;
//This GZIPs the CSS for transmission to the user
//making file size smaller and transfer rate quicker
ob_start("ob_gzhandler");
header("Content-Type: text/css; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $last_modified)." GMT");
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime($this_file) + 691200))." GMT");
echo $css;
ob_end_flush();
//End of css.php

36
assets/css/message.css Normal file
View File

@ -0,0 +1,36 @@
.message{
position:relative;
margin:0.5em auto;
padding:0.5em;
width:95%;
}
.message .close{
width:1em;
height:1em;
border:1px solid #000;
position:absolute;
right:0.5em;
top:0.5em;
}
.message .icon{
left:0.5em;
top:0.5em;
margin-right:1em;
}
.error{
border:1px solid #924949;
background: #f3e6e6;
}
.success{
border:1px solid #1f8454;
background: #70dda9;
}
.info{
border:1px solid #bfbe3a;
background: #FFFFCC;
}

504
assets/css/normalize.css vendored Normal file
View File

@ -0,0 +1,504 @@
/*! normalize.css 2012-03-11T12:53 UTC - http://github.com/necolas/normalize.css */
/* =============================================================================
HTML5 display definitions
========================================================================== */
/*
* Corrects block display not defined in IE6/7/8/9 & FF3
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
nav,
section,
summary {
display: block;
}
/*
* Corrects inline-block display not defined in IE6/7/8/9 & FF3
*/
audio,
canvas,
video {
display: inline-block;
*display: inline;
*zoom: 1;
}
/*
* Prevents modern browsers from displaying 'audio' without controls
* Remove excess height in iOS5 devices
*/
audio:not([controls]) {
display: none;
height: 0;
}
/*
* Addresses styling for 'hidden' attribute not present in IE7/8/9, FF3, S4
* Known issue: no IE6 support
*/
[hidden] {
display: none;
}
/* =============================================================================
Base
========================================================================== */
/*
* 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units
* http://clagnut.com/blog/348/#c790
* 2. Prevents iOS text size adjust after orientation change, without disabling user zoom
* www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/
*/
html {
font-size: 100%; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-ms-text-size-adjust: 100%; /* 2 */
}
/*
* Addresses font-family inconsistency between 'textarea' and other form elements.
*/
html,
button,
input,
select,
textarea {
font-family: sans-serif;
}
/*
* Addresses margins handled incorrectly in IE6/7
*/
body {
margin: 0;
}
/* =============================================================================
Links
========================================================================== */
/*
* Addresses outline displayed oddly in Chrome
*/
a:focus {
outline: thin dotted;
}
/*
* Improves readability when focused and also mouse hovered in all browsers
* people.opera.com/patrickl/experiments/keyboard/test
*/
a:hover,
a:active {
outline: 0;
}
/* =============================================================================
Typography
========================================================================== */
/*
* Addresses font sizes and margins set differently in IE6/7
* Addresses font sizes within 'section' and 'article' in FF4+, Chrome, S5
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
h2 {
font-size: 1.5em;
margin: 0.83em 0;
}
h3 {
font-size: 1.17em;
margin: 1em 0;
}
h4 {
font-size: 1em;
margin: 1.33em 0;
}
h5 {
font-size: 0.83em;
margin: 1.67em 0;
}
h6 {
font-size: 0.75em;
margin: 2.33em 0;
}
/*
* Addresses styling not present in IE7/8/9, S5, Chrome
*/
abbr[title] {
border-bottom: 1px dotted;
}
/*
* Addresses style set to 'bolder' in FF3+, S4/5, Chrome
*/
b,
strong {
font-weight: bold;
}
blockquote {
margin: 1em 40px;
}
/*
* Addresses styling not present in S5, Chrome
*/
dfn {
font-style: italic;
}
/*
* Addresses styling not present in IE6/7/8/9
*/
mark {
background: #ff0;
color: #000;
}
/*
* Addresses margins set differently in IE6/7
*/
p,
pre {
margin: 1em 0;
}
/*
* Corrects font family set oddly in IE6, S4/5, Chrome
* en.wikipedia.org/wiki/User:Davidgothberg/Test59
*/
pre,
code,
kbd,
samp {
font-family: monospace, serif;
_font-family: 'courier new', monospace;
font-size: 1em;
}
/*
* Improves readability of pre-formatted text in all browsers
*/
pre {
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
}
/*
* 1. Addresses CSS quotes not supported in IE6/7
* 2. Addresses quote property not supported in S4
*/
/* 1 */
q {
quotes: none;
}
/* 2 */
q:before,
q:after {
content: '';
content: none;
}
small {
font-size: 75%;
}
/*
* Prevents sub and sup affecting line-height in all browsers
* gist.github.com/413930
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* =============================================================================
Lists
========================================================================== */
/*
* Addresses margins set differently in IE6/7
*/
dl,
menu,
ol,
ul {
margin: 1em 0;
}
dd {
margin: 0 0 0 40px;
}
/*
* Addresses paddings set differently in IE6/7
*/
menu,
ol,
ul {
padding: 0 0 0 40px;
}
/*
* Corrects list images handled incorrectly in IE7
*/
nav ul,
nav ol {
list-style: none;
list-style-image: none;
}
/* =============================================================================
Embedded content
========================================================================== */
/*
* 1. Removes border when inside 'a' element in IE6/7/8/9, FF3
* 2. Improves image quality when scaled in IE7
* code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/
*/
img {
border: 0; /* 1 */
-ms-interpolation-mode: bicubic; /* 2 */
}
/*
* Corrects overflow displayed oddly in IE9
*/
svg:not(:root) {
overflow: hidden;
}
/* =============================================================================
Figures
========================================================================== */
/*
* Addresses margin not present in IE6/7/8/9, S5, O11
*/
figure {
margin: 0;
}
/* =============================================================================
Forms
========================================================================== */
/*
* Corrects margin displayed oddly in IE6/7
*/
form {
margin: 0;
}
/*
* Define consistent border, margin, and padding
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/*
* 1. Corrects color not being inherited in IE6/7/8/9
* 2. Corrects text not wrapping in FF3
* 3. Corrects alignment displayed oddly in IE6/7
*/
legend {
border: 0; /* 1 */
padding: 0;
white-space: normal; /* 2 */
*margin-left: -7px; /* 3 */
}
/*
* 1. Corrects font size not being inherited in all browsers
* 2. Addresses margins set differently in IE6/7, FF3+, S5, Chrome
* 3. Improves appearance and consistency in all browsers
*/
button,
input,
select,
textarea {
font-size: 100%; /* 1 */
margin: 0; /* 2 */
vertical-align: baseline; /* 3 */
*vertical-align: middle; /* 3 */
}
/*
* Addresses FF3/4 setting line-height on 'input' using !important in the UA stylesheet
*/
button,
input {
line-height: normal; /* 1 */
}
/*
* 1. Improves usability and consistency of cursor style between image-type 'input' and others
* 2. Corrects inability to style clickable 'input' types in iOS
* 3. Removes inner spacing in IE7 without affecting normal text inputs
* Known issue: inner spacing remains in IE6
*/
button,
input[type="button"],
input[type="reset"],
input[type="submit"] {
cursor: pointer; /* 1 */
-webkit-appearance: button; /* 2 */
*overflow: visible; /* 3 */
}
/*
* Re-set default cursor for disabled elements
*/
button[disabled],
input[disabled] {
cursor: default;
}
/*
* 1. Addresses box sizing set to content-box in IE8/9
* 2. Removes excess padding in IE8/9
* 3. Removes excess padding in IE7
Known issue: excess padding remains in IE6
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
*height: 13px; /* 3 */
*width: 13px; /* 3 */
}
/*
* 1. Addresses appearance set to searchfield in S5, Chrome
* 2. Addresses box-sizing set to border-box in S5, Chrome (include -moz to future-proof)
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/*
* Removes inner padding and search cancel button in S5, Chrome on OS X
*/
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: none;
}
/*
* Removes inner padding and border in FF3+
* www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/*
* 1. Removes default vertical scrollbar in IE6/7/8/9
* 2. Improves readability and alignment in all browsers
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
}
/* =============================================================================
Tables
========================================================================== */
/*
* Remove most spacing between table cells
*/
table {
border-collapse: collapse;
border-spacing: 0;
}

28
assets/css/theme.css Normal file
View File

@ -0,0 +1,28 @@
/* ---------------- */
/* ! General Styles */
/* ---------------- */
html, body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight:200;
max-width:800px;
margin: 0 auto;
}
/* form styles */
form dt, form dd {
display:inline-block;
padding:0.25em 0;
}
form dt {
width:40%;
text-align:right;
}
form dd {
width:59%;
text-align:left;
margin-left:0;
padding-left:.25em;
}

188
assets/js.php Executable file
View File

@ -0,0 +1,188 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* JS Minifier and Cacher
*
* @package miniMVC
* @subpackage Assets
*/
//Get config files
require('./config/config.php');
//Include the js groups
$groups_file = "./config/js_groups.php";
$groups = require($groups_file);
//The name of this file
$this_file = __FILE__;
// --------------------------------------------------------------------------
/**
* Get Files
*
* Concatenates the javascript files for the current
* group as a string
* @return string
*/
function get_files()
{
global $groups, $js_root;
$js = '';
foreach ($groups[$_GET['g']] as &$file)
{
$new_file = realpath($js_root.$file);
$js .= file_get_contents($new_file);
}
return $js;
}
// --------------------------------------------------------------------------
/**
* Google Min
*
* Minifies javascript using google's closure compiler
* @param string $new_file
* @return string
*/
function google_min($new_file)
{
//Get a much-minified version from Google's closure compiler
$ch = curl_init('http://closure-compiler.appspot.com/compile');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'output_info=compiled_code&output_format=text&compilation_level=SIMPLE_OPTIMIZATIONS&js_code=' . urlencode($new_file));
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
// --------------------------------------------------------------------------
//Creative rewriting of /g/groupname to ?g=groupname
$pi = $_SERVER['PATH_INFO'];
$pia = explode('/', $pi);
$pia_len = count($pia);
$i = 1;
while ($i < $pia_len)
{
$j = $i+1;
$j = (isset($pia[$j])) ? $j : $i;
$_GET[$pia[$i]] = $pia[$j];
$i = $j + 1;
};
$js = '';
$modified = [];
// --------------------------------------------------------------------------
//Aggregate the last modified times of the files
if (isset($groups[$_GET['g']]))
{
$cache_file = $js_root.'cache/'.$_GET['g'];
foreach ($groups[$_GET['g']] as &$file)
{
$new_file = realpath($js_root.$file);
$modified[] = filemtime($new_file);
}
//Add this page too, as well as the groups file
$modified[] = filemtime($this_file);
$modified[] = filemtime($groups_file);
$cache_modified = 0;
//Add the cache file
if (is_file($cache_file))
{
$cache_modified = filemtime($cache_file);
}
}
else //Nothing to display? Just exit
{
die("You must specify a group that exists");
}
// --------------------------------------------------------------------------
//Get the latest modified date
rsort($modified);
$last_modified = $modified[0];
$requested_time=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
? strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])
: time();
// If the browser's cached version is up to date,
// don't resend the file
if ($last_modified === $requested_time)
{
header("HTTP/1.1 304 Not Modified");
exit();
}
// --------------------------------------------------------------------------
//Determine what to do: rebuild cache, send files as is, or send cache.
if ($cache_modified < $last_modified)
{
$js = google_min(get_files());
$cs = file_put_contents($cache_file, $js);
//Make sure cache file gets created/updated
if ($cs === FALSE)
{
die("Cache file was not created. Make sure you have the correct folder permissions.");
}
}
elseif (isset($_GET['debug']))
{
$js = get_files();
}
else
{
$len = filesize($cache_file);
header("Content-Length: {$len}");
$js = file_get_contents($cache_file);
}
// --------------------------------------------------------------------------
//This GZIPs the js for transmission to the user
//making file size smaller and transfer rate quicker
ob_start("ob_gzhandler");
header("Content-Type: text/javascript; charset=utf8");
header("Cache-control: public, max-age=691200, must-revalidate");
header("Last-Modified: ".gmdate('D, d M Y H:i:s', $last_modified)." GMT");
header("Expires: ".gmdate('D, d M Y H:i:s', (filemtime($this_file) + 691200))." GMT");
echo $js;
ob_end_flush();
//end of js.php

14
assets/js/meta.js Normal file
View File

@ -0,0 +1,14 @@
var meta = (function (){
"use strict";
var meta = window.meta || {};
meta.addItem = function() {
};
// Return the object to the global scope
return meta;
)());

56
index.php Normal file
View File

@ -0,0 +1,56 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* miniMVC bootstrap file
*
* @package miniMVC
* @subpackage App
*/
// --------------------------------------------------------------------------
namespace miniMVC;
// Set as either DEVELOPMENT or PRODUCTION
// DEVELOPMENT enables error reporting
// PRODUCTION disables error reporting
define('ENVIRONMENT', 'DEVELOPMENT');
if(ENVIRONMENT == 'DEVELOPMENT')
{
error_reporting(-1);
}
else if(ENVIRONMENT == 'PRODUCTION')
{
error_reporting(0);
}
// Set the default paths
define('MM_BASE_PATH', __DIR__);
define('MM_SYS_PATH', __DIR__.'/sys/');
define('MM_APP_PATH', __DIR__.'/app/');
define('MM_MOD_PATH', MM_APP_PATH.'modules/');
// Require the basic configuration file
require(MM_APP_PATH .'config/config.php');
// Require the most important files
require(MM_SYS_PATH . 'common.php');
// And away we go!
init();
// End of index.php

26
phpdoc.dist.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<title>miniMVC</title>
<parser>
<target>docs</target>
</parser>
<transformer>
<target>docs</target>
</transformer>
<transformations>
<template name="responsive" />
</transformations>
<files>
<directory>.</directory>
<directory>tests</directory>
<directory>assets</directory>
<directory>app/config</directory>
<directory>app/views</directory>
<directory>sys/db/tests</directory>
<ignore>tests/*</ignore>
<ignore>assets/*</ignore>
<ignore>sys/db/tests/*</ignore>
<ignore>app/config/*</ignore>
<ignore>app/views/*</ignore>
</files>
</phpdoc>

499
sys/common.php Normal file
View File

@ -0,0 +1,499 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
/**
* File including common framework-wide functions
*
* @package miniMVC
* @subpackage System
*/
namespace miniMVC;
// --------------------------------------------------------------------------
// ! Autoloading
// --------------------------------------------------------------------------
/**
* Function to autoload system libraries
*
* @param string
*/
function _autoload($name)
{
if ($name == '') return;
// strip off namespaces - they all go to the same folder
$names = explode('\\', trim($name));
$name = end($names);
// Paths to load from
$sys_path = MM_SYS_PATH . "core/{$name}.php";
$lib_path = MM_SYS_PATH . "libraries/{$name}.php";
$class_path = MM_APP_PATH . "classes/{$name}.php";
if (is_file($sys_path))
{
require_once($sys_path);
}
elseif (is_file($lib_path))
{
require_once($lib_path);
}
if (is_file($class_path))
{
require_once($class_path);
}
}
// Start the autoloader
spl_autoload_register('miniMVC\_autoload');
// --------------------------------------------------------------------------
// ! Error handling / messages
// --------------------------------------------------------------------------
/**
* Function to run on script shutdown
* -used to catch most fatal errors, and
* display them cleanly
*
* @return void
*/
function shutdown()
{
// Catch the last error
$error = error_get_last();
// types of errors that are fatal
$fatal = [E_ERROR, E_PARSE, E_RECOVERABLE_ERROR];
// Display pretty error page
if (in_array($error['type'], $fatal))
{
$file = str_replace(MM_BASE_PATH, "", $error['file']);
$err_msg = "<h2>Fatal Error: </h2>
{$error['message']}<br /><br />
<strong>File:</strong> {$file}<br /><br />
<strong>Line:</strong> {$error['line']}";
show_error($err_msg);
}
}
// --------------------------------------------------------------------------
/**
* Custom error handler
*
* @param int $severity
* @param string $message
* @param string $filepath
* @param int $line
* @return ErrorException
*/
function on_error($severity, $message, $filepath, $line)
{
throw new \ErrorException($message, 0, $severity, $filepath, $line);
}
// --------------------------------------------------------------------------
/**
* Custom exception handlererror_get_last
*
* @param Exception $exception
* @return void
*/
function on_exception($exception)
{
// This is passed to the error template
$message = $exception->getMessage();
// Contain the content for buffering
ob_start();
include(MM_APP_PATH . '/views/errors/error_php_exception.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
// --------------------------------------------------------------------------
/**
* General 404 function
*
* @return void
*/
function show_404()
{
@header('HTTP/1.1 404 Not Found', TRUE, 404);
// Contain the content for buffering
ob_start();
// This is passed to the error template
$message = '404 Not Found';
include(MM_APP_PATH . '/views/errors/error_404.php');
$buffer = ob_get_contents();
ob_end_clean();
die($buffer);
}
// --------------------------------------------------------------------------
/**
* Fatal Error page function
*
* @param string $message
* @param int $status_code
*/
function show_error($message, $status_code=null)
{
if ( ! is_null($status_code))
{
@header("HTTP/1.1 {$status_code}", TRUE, (int) $status_code);
}
// Contain the content for buffering
ob_start();
include(MM_APP_PATH . '/views/errors/error_general.php');
$buffer = ob_get_contents();
ob_end_clean();
die($buffer);
}
// --------------------------------------------------------------------------
// ! Utility Functions
// --------------------------------------------------------------------------
/**
* Utility function to check if a variable is set, and is an array or object
*
* @param mixed $var
* @return bool
*/
function is_like_array(&$var)
{
if ( ! isset($var))
{
return FALSE;
}
return (is_array($var) OR is_object($var)) && ( ! empty($var));
}
// --------------------------------------------------------------------------
/**
* Returns routable methods for the specified controller class
*
* @param string $controller
* @return array
*/
function controller_methods($controller)
{
$methods = \get_class_methods($controller);
// Eliminate methods from Controller and Model classes
$skip_methods = array_merge(\get_class_methods('miniMVC\Controller'), \get_class_methods('miniMVC\Model'));
$methods = array_diff($methods, $skip_methods);
return $methods;
}
// --------------------------------------------------------------------------
/**
* Returns a full url from a url segment
*
* @param string $segment
* @return string
*/
function site_url($segment)
{
return $url = BASE_URL . URL_INDEX_FILE . $segment;
}
// --------------------------------------------------------------------------
/**
* Prints out the contents of the object
*
* @param object/array $data
* @param string $method
* @return string
*/
function to_string($data, $method='print_r')
{
$output = '<pre>';
if ($method == "var_dump")
{
ob_start();
var_dump($data);
$output .= ob_get_contents();
ob_end_clean();
}
elseif ($method == "var_export")
{
ob_start();
var_export($data);
$output .= ob_get_contents();
ob_end_clean();
}
else
{
$output .= print_r($data, TRUE);
}
return $output . '</pre>';
}
// --------------------------------------------------------------------------
if ( ! function_exists('do_include'))
{
/**
* Array_map callback to load a folder of classes at once
*
* @param string $path
* @return void
*/
function do_include($path)
{
require_once($path);
}
}
// --------------------------------------------------------------------------
// ! Bootstrap functions
// --------------------------------------------------------------------------
/**
* Load required classes for bootstraping
*
* @return void
*/
function init()
{
// Catch fatal errors, don't show them
error_reporting((-1) & ~(E_ERROR | E_PARSE));
register_shutdown_function('miniMVC\shutdown');
//Set error handlers
set_error_handler('miniMVC\on_error');
set_exception_handler('miniMVC\on_exception');
// Load Database classes
require_once(MM_SYS_PATH . 'db/autoload.php');
// Map to the appropriate module/controller/function
route();
}
// --------------------------------------------------------------------------
/**
* Returns the last segment of the current url
*
* @return string
*/
function get_last_segment()
{
$array = get_segments();
return end($array);
}
// --------------------------------------------------------------------------
/**
* Gets an array of the segments of the current url
*
* @return array
*/
function get_segments()
{
$sn = $_SERVER['SCRIPT_NAME'];
$ru = $_SERVER['REQUEST_URI'];
// Get the equivalent to path info
$pi = (isset($_SERVER['PATH_INFO']))
? str_replace($sn, '', $ru)
: '/';
// Correct for being in a sub-directory
if (strlen($sn) > strlen($ru))
{
$pi = '/';
}
return explode('/', $pi);
}
// --------------------------------------------------------------------------
/**
* Calls the appropriate module/controller/function based on the url
*
* @return void
*/
function route()
{
$sn = $_SERVER['SCRIPT_NAME'];
$ru = $_SERVER['REQUEST_URI'];
// Get the equivalent to path info
$pi = (isset($_SERVER['PATH_INFO']))
? str_replace($sn, '', $ru)
: '/';
// Make sure the home page works when in a sub_directory
if (strlen($sn) > strlen($ru))
{
$pi = '/';
}
// Load the routes config file
$routes = require_once(MM_APP_PATH . 'config/routes.php');
// Set the default route
$module = $routes['default_module'];
$controller = $routes['default_controller'];
$func = "index";
$route_set = FALSE;
// If it isn't the index page
if ( ! empty($pi) && $pi !== "/")
{
//Remove trailing slash and begining slash
$pi = trim($pi, '/');
$segments = explode("/", $pi);
// URL matches the route exactly? Cool, that was easy
if (isset($routes[$pi]))
{
list($module, $controller, $func) = explode("/", $routes[$pi]);
run($module, $controller, $func);
return;
}
else
{
$custom_routes = $routes;
// Skip required routes
unset($custom_routes['default_module']);
unset($custom_routes['default_controller']);
unset($custom_routes['404_handler']);
foreach($custom_routes as $uri => $map)
{
if (preg_match("`{$uri}`i", $pi))
{
list($module, $controller, $func) = explode("/", $map);
run($module, $controller, $func);
return;
}
}
}
// Doesn't match a predefined route?
// Match on module/controller/method, module/controller, controller/method, or method
if ( ! $route_set)
{
$num_segments = 0;
if (strpos($pi, '/') === FALSE && ! empty($pi))
{
$num_segments = 1;
}
else
{
$segments = explode('/', $pi);
$num_segments = count($segments);
}
// Determine route based on uri segments
if ($num_segments === 1)
{
$func = $pi;
}
elseif ($num_segments === 2)
{
list($module, $controller) = $segments;
// If it's just controller/function
if ($controller == 'index')
{
$controller = $module;
$module = $routes['default_module'];
$func = 'index';
}
}
else
{
list($module, $controller, $func) = $segments;
}
}
}
run($module, $controller, $func);
return;
}
/**
* Instantiate the appropriate controller
*
* @param string
* @param string
* @param string
*/
function run($module, $controller, $func)
{
$path = MM_MOD_PATH . "{$module}/controllers/{$controller}.php";
if (is_file($path))
{
require_once($path);
// Get the list of valid methods for that controller
$methods = controller_methods($controller);
if (in_array($func, $methods))
{
// Define the name of the current module for file loading
define('MM_MOD', $module);
$class = new $controller();
return call_user_func([&$class, $func]);
}
}
// Function doesn't exist...404
show_404();
}
// End of common.php

128
sys/core/Controller.php Normal file
View File

@ -0,0 +1,128 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Base Controller Class
*
* @package miniMVC
* @subpackage System
*/
class Controller extends miniMVC {
/**
* Instance of Page class
*
* @var Page
*/
protected $page;
/**
* Create the controller object
*
* @return void
*/
public function __construct()
{
parent::__construct();
// Create the page object
$this->page = new Page($this);
}
// --------------------------------------------------------------------------
/**
* Function for loading a model into the current class
*
* @param string $file
* @param array $args
* @return void
*/
public function load_model($file, $args=[])
{
$segments = explode('\\', $file);
$file_name = end($segments);
// The module is set via the router
$module = strtolower(MM_MOD);
$path = MM_MOD_PATH . "{$module}/models/{$file_name}.php";
if (is_file($path))
{
require_once($path);
}
if ( ! empty($args))
{
$this->$file_name = new $file($args);
}
else
{
$this->$file_name = new $file;
}
}
// --------------------------------------------------------------------------
/**
* Function for loading a view
*
* @param string $file
* @param array $data
* @param bool $return
* @return mixed
*/
public function load_view($file, array $data=[], $return=FALSE)
{
$path = "";
// The module is set via the router
$module = strtolower(MM_MOD);
$path = MM_MOD_PATH . "{$module}/views/{$file}.php";
// If it's not a module, or doesn't exist in the module view folder
// look in the app view folder
if ( ! is_file($path))
{
$path = MM_APP_PATH . "views/{$file}.php";
}
// Contain the content for buffering
ob_start();
// Extract the data array
extract($data);
// Include the file
include($path);
$buffer = ob_get_contents();
ob_end_clean();
if ($return == TRUE)
{
return $buffer;
}
else
{
$this->page->append_output($buffer);
}
}
}
// End of controller.php

70
sys/core/MM.php Normal file
View File

@ -0,0 +1,70 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class for standalone JSObject objects
*
* @package miniMVC
* @subpackage System
*/
class MM extends \ArrayObject {
/**
* Create the ArrayObject hybrid object
*
* @param array
*/
public function __construct($members = array())
{
parent::__construct($members);
// Add the passed parameters to the object
foreach ($members as $name => &$value)
{
$this->$name = $value;
}
}
// --------------------------------------------------------------------------
/**
* Allow calling of array methods on the object and
* dynamic methods
*
* @param string $name
* @param array $params
* @return mixed
*/
public function __call($name, $params = array())
{
// Allow array operations on the object
if (substr($name, 0, 6) === 'array_' && is_callable($name))
{
$args = array_merge($this->getArrayCopy(), $args);
return call_user_func_array($name, $args);
}
// Allow dynamic method calls
if (is_callable($this->$name))
{
//Call the dynamic function
return call_user_func_array($this->$name, $params);
}
}
}
// End of MM.php

38
sys/core/Model.php Normal file
View File

@ -0,0 +1,38 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Base Model Class
*
* @package miniMVC
* @subpackage System
*/
class Model extends miniMVC {
/**
* Initialize the model class
*
* @param array $args
* @return void
*/
public function __construct(array $args = array())
{
parent::__construct($args);
}
}
// End of model.php

156
sys/core/Output.php Normal file
View File

@ -0,0 +1,156 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class for displaying output and setting http headers
*
* @package miniMVC
* @subpackage System
*/
class Output extends MM {
/**
* Content for outputting
*
* @var string
*/
private $buffer;
/**
* HTTP headers to send
*
* @var array
*/
private $headers;
/**
* Initialize the output class
*
* @return void
*/
public function __construct()
{
$this->buffer = "";
$this->headers = array();
}
// --------------------------------------------------------------------------
/**
* PHP magic method called when ending the script
* Used for outputing HTML
*
* @return void
*/
public function __destruct()
{
if ( ! empty($this->headers))
{
// Set headers
foreach($this->headers as $key => $val)
{
if ( ! isset($val))
{
@header($key);
}
else
{
@header("$key: $val");
}
}
}
if ( ! empty($this->buffer))
{
if (is_null(error_get_last()))
{
// Compression is good!
ob_start("ob_gzhandler");
}
else
{
ob_start();
}
echo $this->buffer;
ob_end_flush();
}
}
// --------------------------------------------------------------------------
/**
* Sets a header for later output
*
* @param string $key
* @param string $val
*/
public function set_header($key, $val)
{
$this->headers[$key] = $val;
}
// --------------------------------------------------------------------------
/**
* Adds text to the output buffer
*
* @param string $string
*/
public function append_output($string)
{
$this->buffer .= $string;
}
// --------------------------------------------------------------------------
/**
* Sets the output buffer
*
* @param string $string
*/
public function set_output($string)
{
$this->buffer = $string;
}
// --------------------------------------------------------------------------
/**
* Sends headers and then removes them
*/
public function flush_headers()
{
// Set headers
foreach ($this->headers as $key => &$val)
{
if ( ! isset($val))
{
@header($key);
}
else
{
@header("{$key}: {$val}");
}
}
// Empty headers
$this->headers = array();
}
}
// End of Output.php

555
sys/core/Page.php Normal file
View File

@ -0,0 +1,555 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class for building pages
*
* All methods are chainable, with the exception of the constructor,
* build_header(), build_footer(), and _headers() methods.
*
* @package miniMVC
* @subpackage System
*/
class Page extends Output {
/**
* Meta tags
*
* @var string
*/
private $meta;
/**
* JS tags for the header
*
* @var string
*/
private $head_js;
/**
* JS tags for the footer
*
* @var string
*/
private $foot_js;
/**
* CSS tags for the page
*
* @var string
*/
private $css;
/**
* Page title
*
* @var string
*/
private $title;
/**
* Additional header tags
*
* @var string
*/
private $head_tags;
/**
* Class(es) to apply to the main body tag
*
* @var string
*/
private $body_class;
/**
* Id to apply to the body tag
*
* @var string
*/
private $body_id;
/**
* Base tag
*
* @var string
*/
private $base;
/**
* Set up the page class
*
* @param object
* @return void
*/
public function __construct(&$controller)
{
$this->meta = "";
$this->head_js = "";
$this->foot_js = "";
$this->css = "";
$this->title = "";
$this->head_tags = "";
$this->body_class = "";
$this->body_id = "";
$this->base = "";
$this->mm = $controller;
}
// --------------------------------------------------------------------------
/**
* call the parent destructor
*/
public function __destruct()
{
parent::__destruct();
}
// --------------------------------------------------------------------------
/**
* Sets server headers and doctype
*
* Also sets page mime type, based on if sent as
* html or xhtml, and what the target browser
* supports
*
* @param bool $html5
* @return Page
*/
private function _headers($html5)
{
$this->set_header("Cache-Control", "must-revalidate, public");
$mime = "";
//Variable for accept keyword
$accept = ( ! empty($_SERVER['HTTP_ACCEPT'])) ? $_SERVER['HTTP_ACCEPT'] : "";
//Predefine doctype
$doctype_string = ($html5 == TRUE) ? '<!DOCTYPE html>' : '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">';
//Predefine charset
$charset = "UTF-8";
$mime = "text/html";
if ($html5 == FALSE)
{
$doctype_string = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">';
}
$doctype_string .= "<html lang='en'>";
// finally, output the mime type and prolog type
$this->set_header("Content-Type", "{$mime};charset={$charset}");
$this->set_header("X-UA-Compatible", "chrome=1, IE=edge");
$this->set_output($doctype_string);
return $this;
}
// --------------------------------------------------------------------------
/**
* Set Meta
*
* Sets meta tags, with codeigniter native meta tag helper
*
* @param array $meta
* @return Page
*/
public function set_meta($meta)
{
$this->meta .= $this->_meta($meta);
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets minified javascript group in header
*
* @param string $group
* @param bool $debug
* @return Page
*/
public function set_head_js_group($group, $debug = FALSE)
{
if ($group === FALSE)
{
return $this;
}
$file = SCRIPT_PATH . $group;
$file .= ($debug == TRUE) ? "/debug/1" : "";
$this->head_js .= $this->script_tag($file, FALSE);
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets a minified css group
* @param string $group
* @return Page
*/
public function set_css_group($group)
{
$link = [
'href' => STYLE_PATH . $group,
'rel' => 'stylesheet',
'type' => 'text/css'
];
$this->css .= $this->_link_tag($link);
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets a minified javascript group for the page footer
*
* @param string $group
* @param bool $debug
* @return Page
*/
public function set_foot_js_group($group, $debug = FALSE)
{
$file = SCRIPT_PATH . $group;
$file .= ($debug == TRUE) ? "/debug/1" : "";
$this->foot_js .= $this->script_tag($file, FALSE);
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets html title string
*
* @param string $title
* @return Page
*/
public function set_title($title = "")
{
$title = ($title == "") ? DEFAULT_TITLE : $title;
$this->title = $title;
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets custom body class
*
* @param string $class
* @return Page
*/
public function set_body_class($class = "")
{
$this->body_class = $class;
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets custom body id
*
* @param string $id
* @return Page
*/
public function set_body_id($id = "")
{
$this->body_id = $id;
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets custom base href
*
* @param string href
* @return Page
*/
public function set_base($href)
{
$this->base = $href;
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets custom css tags
*
* @param string $name
* @param bool $domain
* @param string $media
* @return Page
*/
public function set_css_tag($name, $domain = TRUE, $media = "all")
{
$path = CONTENT_DOMAIN;
$css_file = "{$path}/css/{$name}.css";
if ($domain == FALSE)
{
$css_file = $name;
}
$this->css_tags .= $this->_link_tag([
'rel' => 'stylesheet',
'type' => 'text/css',
'media' => $media,
'href' => $css_file,
]);
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets a custom tag in the header
*
* @param string $tag
* @return Page
*/
public function set_head_tag($tag)
{
$this->head_tags .= $tag;
return $this;
}
// --------------------------------------------------------------------------
/**
* Sets custom page header
*
* @param bool $html5
* @return Page
*/
public function build_header($html5 = TRUE)
{
$data = array();
//Set Meta Tags
$this->meta = ($html5 == TRUE)
? '<meta charset="utf-8" />'. $this->meta
: $this->_meta([
'http-equiv' => 'Content-Type',
'content' => 'text/html; charset=utf-8',
]) . $this->meta;
$data['meta'] = $this->meta;
//Set CSS
if ($this->css !== "")
{
$data['css'] = $this->css;
}
else
{
//Set default CSS group
$this->set_css_group(DEFAULT_CSS_GROUP);
$data['css'] = $this->css;
}
//Set head javascript
$data['head_js'] = ( ! empty($this->head_js)) ? $this->head_js : "";
//Set Page Title
$data['title'] = ($this->title !== '') ? $this->title : DEFAULT_TITLE;
//Set Body Class
$data['body_class'] = $this->body_class;
//Set Body Id
$data['body_id'] = $this->body_id;
//Set Base HREF
$data['base'] = $this->base;
//Set individual head tags
$data['head_tags'] = $this->head_tags;
//Set Server Headers and Doctype
$this->_headers($html5);
//Output Header
$this->mm->load_view('header', $data);
return $this;
}
// --------------------------------------------------------------------------
/**
* Builds common footer with any additional js
*/
public function build_footer()
{
$data = array();
$data['foot_js'] = ($this->foot_js != "") ? $this->foot_js : '';
$this->mm->load_view('footer', $data);
}
// --------------------------------------------------------------------------
/**
* Script Tag
*
* Helper function for making script tags
*
* @param string $js
* @param bool $domain
* @return string
*/
private function script_tag($js, $domain = TRUE)
{
$path = CONTENT_DOMAIN;
$js_file = "{$path}/js/{$js}.js";
if ($domain == FALSE)
{
$js_file = $js;
}
$tag = '<script src="' . $js_file . '"></script>';
return $tag;
}
// --------------------------------------------------------------------------
/**
* Set Message
*
* Adds a message to the page
* @param string $type
* @param string $message
* @param bool $return
* @return void
*/
public function set_message($type, $message, $return=FALSE)
{
$data['stat_class'] = $type;
$data['message'] = $message;
return $this->mm->load_view('message', $data, $return);
}
// --------------------------------------------------------------------------
/**
* Redirect 303
*
* Shortcut function for 303 redirect
* @param string $url
*/
function redirect_303($url)
{
$this->set_header("HTTP/1.1 303 See Other");
$this->set_header("Location:" . $url);
}
// --------------------------------------------------------------------------
/**
* Render
*
* Shortcut function for building a page
* @param string $view
* @param array $data
*/
function render($view, $data=array())
{
$this->build_header();
$this->mm->load_view($view, $data);
$this->build_footer();
}
// --------------------------------------------------------------------------
/**
* Output String
*
* Similar to render(), this is a shortcut
* to output a string in the body of the
* page.
* @param string $string
*/
function output_string($string)
{
$this->build_header();
$this->append_output($string);
$this->build_footer();
}
// --------------------------------------------------------------------------
/**
* Private helper function to generate meta tags
*
* @param array $params
* @return string
*/
private function _meta($params)
{
$string = "<meta ";
foreach ($params as $k => &$v)
{
$string .= $k.'="'.$v.'" ';
}
$string .= " />";
return $string;
}
// --------------------------------------------------------------------------
/**
* Private helper function to generate link tags
*
* @param array $params
* @return string
*/
private function _link_tag($params)
{
$string = "<link ";
foreach ($params as $k => &$v)
{
$string .= $k . '="'.$v.'" ';
}
$string .= "/>";
return $string;
}
}
// End of page.php

100
sys/core/db.php Normal file
View File

@ -0,0 +1,100 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Extend PHP's PDO class to add some more functionality
*
* @package miniMVC
* @subpackage System
*/
class DB extends \Query_Builder {
/**
* DB connection instances
*
* @var array
*/
private static $instance = array();
// --------------------------------------------------------------------------
/**
* Indexed singleton method
*
* @param string $dbname
* @param array $options
* @return DB
*/
public static function &get_instance($dbname="default", array $options=array())
{
if ( ! isset(self::$instance[$dbname]))
{
// Include the database config file
require_once(MM_APP_PATH.'config/db.php');
// Get the correct database in the config file
if ( ! is_like_array($db_conf[$dbname]))
{
// Apparently the database doesn't exist
$this->get_last_error();
trigger_error("Database does not exist", E_USER_ERROR);
die();
}
//echo 'Creating new instance of db class.';
self::$instance[$dbname] = new DB($db_conf[$dbname]);
}
return self::$instance[$dbname];
}
// --------------------------------------------------------------------------
/**
* Returns the last error from the database
*
* @return string
*/
public function get_last_error()
{
$error = array();
if (isset($this->statement))
{
$error = $this->statement->errorInfo();
}
else
{
$error = $this->errorInfo();
}
$code = $error[0];
$driver_code = $error[1];
$message = $error[2];
// Contain the content for buffering
ob_start();
include(MM_APP_PATH.'/views/errors/error_db.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
}
// End of db.php

84
sys/core/miniMVC.php Normal file
View File

@ -0,0 +1,84 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Base class for the framework
*
* @package miniMVC
* @subpackage System
*/
class miniMVC extends MM {
/**
* Constructor - Any classes loaded here become subclasses of miniMVC
*
* @param array $members
*/
public function __construct($members = array())
{
// Allow the class to be used like an array
parent::__construct($members);
}
// --------------------------------------------------------------------------
/**
* Convenience function to load config files
*
* @param string $name
*/
public function load_config($name)
{
$path = MM_APP_PATH . "config/{$name}.php";
if (is_file($path))
{
require_once($path);
}
}
// --------------------------------------------------------------------------
/**
* Singleton getter function
*
* @return self
*/
public static function &get_instance()
{
if ( ! isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
// --------------------------------------------------------------------------
/**
* Magic function called when cloning an object
*/
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
// End of miniMVC.php

1
sys/db Submodule

@ -0,0 +1 @@
Subproject commit 977434977e4177fe5a09fffa0f3a152faa82f606

View File

@ -0,0 +1,153 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class for using JSON as a key->value data store
*
* @package miniMVC
* @subpackage Libraries
*/
class Data_Store {
/**
* Settings object represented by the currently loaded JSON file
*/
private $current;
/**
* Singleton instance
*/
private static $instance;
/**
* Create and/or load json file
*/
protected function __construct()
{
$path = MM_APP_PATH .'config/data_store.json';
if ( ! is_file($path))
{
touch($path);
$this->current = (object)[];
}
else
{
// Load the file
$json = file_get_contents($path);
// Load the object into the class
$this->current = json_decode($json);
}
}
// --------------------------------------------------------------------------
/**
* Output the data on destruct
*/
public function __destruct()
{
$file_string = json_encode($this->current, JSON_PRETTY_PRINT);
file_put_contents(MM_APP_PATH . 'config/data_store.json', $file_string);
}
// --------------------------------------------------------------------------
/**
* Magic function called when cloning an object
*/
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
// --------------------------------------------------------------------------
/**
* Magic method to simplify isset checking for config options
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return (isset($this->current->{$key}))
? $this->current->{$key}
: NULL;
}
// --------------------------------------------------------------------------
/**
* Magic method to simplify setting config options
*
* @param string $key
* @param mixed
*/
public function __set($key, $val)
{
return $this->current->{$key} = $val;
}
// --------------------------------------------------------------------------
/**
* Static method to retreive current instance
* of the singleton
*
* @return self
*/
public static function &get_instance()
{
if( ! isset(self::$instance))
{
$name = __CLASS__;
self::$instance = new $name();
}
return self::$instance;
}
// --------------------------------------------------------------------------
/**
* Removes a key from the data store
*
* @param string $key
* @return void
*/
public function del($key)
{
unset($this->current->{$key});
}
// --------------------------------------------------------------------------
/**
* Return the entire data store object
*
* @return object
*/
public function get_all()
{
return $this->current;
}
}
// End of data store.php

121
sys/libraries/Session.php Normal file
View File

@ -0,0 +1,121 @@
<?php
/**
* MiniMVC
*
* Convention-based micro-framework for PHP
*
* @package miniMVC
* @author Timothy J. Warren
* @copyright Copyright (c) 2011 - 2012
* @link https://github.com/aviat4ion/miniMVC
* @license http://philsturgeon.co.uk/code/dbad-license
*/
// --------------------------------------------------------------------------
namespace miniMVC;
/**
* Class to improve handling of PHP sessions
*
* @package miniMVC
* @subpackage Libraries
*/
class Session {
/**
* Reference to session superglobal
*
* @var array
*/
protected $sess = array();
/**
* Reference to current instance
*
* @var Session
*/
protected static $instance;
/**
* Start a session
*/
protected function __construct()
{
session_start();
// Save a reference to the session for later access
$_SESSION['MM_SESSION'] = (isset($_SESSION['MM_SESSION'])) ?: array();
$this->sess =& $_SESSION['MM_SESSION'];
}
// --------------------------------------------------------------------------
/**
* Set a session value
*
* @param string $key
* @param mixed $val
* @return void
*/
public function __set($key, $val)
{
$this->sess[$key] = $val;
}
// --------------------------------------------------------------------------
/**
* Retreive a session value
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->sess[$key];
}
// --------------------------------------------------------------------------
/**
* Destroy a session
*
* @return void
*/
public function destroy()
{
sess_destroy();
}
// --------------------------------------------------------------------------
/**
* Singleton getter function
*
* @return self
*/
public static function &get_instance()
{
if ( ! isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
// --------------------------------------------------------------------------
/**
* Magic function called when cloning an object
*/
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
// End of session.php

BIN
sys/meta.sqlite Normal file

Binary file not shown.