MoePress Mini v1.1.3

MoePress Mini is a micro PHP MVC framework which focuses on ONE thing: Multi-level controller.
That is, each URI corresponds to a controller which is under the same path of the URI.

In simple terms:

URL Controller Controller Parameter
http://site.com/wiki/123 /controller/wiki/main.php 123
http://site.com/wiki/edit/123 /controller/wiki/edit/main.php 123
http://site.com/wiki/edit/cover/123 /controller/wiki/edit/cover/main.php 123
So you would never worry about long URL routing.

Features

  • Automatic routing for multi-level controller.
  • Powerful and multiple URL routing, which can match one URL multiple times.
  • Only ONE core file, which means lightweight and fast.
  • Unrestricted rules for Models, Views and Libraries. Write your codes by your own habits.

Requirements

  • PHP 5.2+
  • Rewrite module (of Apache, Nginx, or etc.)

License

MoePress Mini is is completely open source and released under the MIT license which means it is perfect for personal or commercial projects.

Tutorial

A brief tutorial will be given in this section about how to built a "Hello World" website from simple to advanced step by step.
Before starting, make sure you have installed PHP environment correctly and enabled rewrite module of Apache or Nginx.

"Hello World"

We assume that your project URL is http://localhost/, the web directory is htdocs/. So, for instance, when you visit http://localhost/abc.php, the PHP file htdocs/abc.php will be executed.

See Subdirectory Installation tutorial if your project is not under the root directory of your domain.

MoePress Mini has only one core file index.php, download it, and put it to your project's web directory (in the above case, it is htdocs/), like this:

htdocs/
└── index.php

To make your website work, you should create a controller/ directory and then write a default controller named main.php on it:

htdocs/
├── controller/
│   └── main.php
└── index.php

The content of main.php should be something like this:

<?php if (!defined('MOEPRESS_VERSION')) { die('Access Forbidden'); } class Controller extends MoePress { public function __index() { echo 'Hello World'; } }

Now open http://localhost/, your browser should output the following line as expected:

Hello World

How it works?

All the controllers should be placed in the controller/ directory, and the file name MUST be main.php.
By default, the main.php in the root of controller/ will be called if no extra URI is requested. So when you opened http://localhost/, controller/main.php was called.

As for the controller code, see the commented version below.

<?php // prevent main.php from being executed directly if (!defined('MOEPRESS_VERSION')) { die('Access Forbidden'); } // the controller class MUST be "Controller", and extend "MoePress" class class Controller extends MoePress { // default method MUST be "__index()" // arguments are allowed, like "__index($page = 1)" public function __index() { // do something as you like, such as creating models or loading views echo 'Hello World'; } } // "?>" is not needed in a pure PHP file

Using View

In MVC framework, HTML is written in view layer. To use views, you need to create a view/ directory, and put your view files in it, like this:

htdocs/
├── controller/
│   └── main.php
├── view/
│   └── demo_view.php
└── index.php

Here we create a view named demo_view.php, the content may be something like this:

<html> <body> Hello <?php echo $name; ?> </body> </html>
In view layer, NO template engine is used.
We believe that raw PHP is the best and fastest template engine in PHP environment.
(Anyway, you can still use template engine by extending MoePress Mini.)

Next, modify the method of controller/main.php to load the view:

function __index() { $this->data['name'] = 'MoePress'; $this->view('demo_view.php'); }

Here we pass a variable to the view by using $this->data. The $this->data is an Array, which key is the variable's name and value is the variable's value. Hence, the view can use the variable $name.
And, method $this->view() is used to load this view.

Now open http://localhost/ again and you should get the following line:

Hello MoePress

Using Model & Library

Similarity with view layer, you should have model/ and library/ directory to use model and library:

htdocs/
├── controller/
│   └── main.php
├── library/
│   └── demo_library.php
├── model/
│   └── demo_model.php
├── view/
│   └── demo_view.php
└── index.php

Write a simple model demo_model.php and a simple library demo_library.php like this:

<?php /* demo_model.php */ class Demo_model { public function run() { echo '<div>Hello Model</div>'; } } <?php /* demo_library.php */ class Demo_library { public function run() { echo '<div>Hello Library</div>'; } }

Next, modify controller/main.php again to use them:

function __index() { $this->model('demo_model.php'); $model = new Demo_model(); $model->run(); $this->library('demo_library.php'); $lib = new Demo_library(); $lib->run(); }

Open http://localhost/ and it will output this two lines:

Hello Model
Hello Library
Model and Library are actually the same thing in MoePress Mini. They are just some PHP classes, we load them in Controller, "new" them and then use them.
The reason why we put them separated is to make the structure of source file more logical and meet the rule of MVC framework.

Multi-level Controller

Highlights come.

2nd-level Controller

Now you're going to build a homepage for a user, the URL should look like this, where peter, alice and bob are the name of certain users:

http://localhost/home/peter
http://localhost/home/alice
http://localhost/home/bob
...

Obviously the URI /home/ requests a second-level controller.

To build the homepage controller under this URL structure, you should create a new directory named home/ under controller/ directory, and create a new controller controller/home/main.php, like this:

htdocs/
├── controller/
│   ├── home/
│   │   └── main.php
│   └── main.php
└── index.php

The method of controller controller/home/main.php should be:

public function __index($name) { echo 'This is' . $name . "'s homepage."; }

Open http://localhost/home/peter, line This is peter's homepage. will be showed as expected. You can change peter in the URL to other people's name, and the output will be changed as well.

The above example shows how to create a second-level controller with one argument.
Simply create a same-named controller directory, then it works.

3rd-level Controller

Further, your users want to have an album page on their homepages. The album's URL should look like http://localhost/home/album/peter, to enhance readability.

So it is a third-level controller. Again, create a same-named directory album/ under controller/home/:

htdocs/
├── controller/
│   ├── home/
│   │   ├── album/
│   │   │   └── main.php
│   │   └── main.php
│   └── main.php
└── index.php

The controller content can be similar:

public function __index($name) { echo 'This is' . $name . "'s album."; }

Now http://localhost/home/album/peter outputs This is peter's album..

Similarly, you can create sub-level controllers by simply adding same-named controller subdirectories, like http://localhost/home/album/photo/peter or http://localhost/home/album/photo/favor/peter. No maximum level limitation.

Using Controller Methods

By default, method __index() will be called when a controller is requested. However, you can write custom methods to response the requests as well.

Take the above case for example, you're going to build several subpages under the homepage, like this:

http://localhost/home/album/peter
http://localhost/home/about/peter
http://localhost/home/work/peter
...

In 3rd-level case, you need to create directories album/, about/ and work/ under controller/home/, then write different main.php controllers for each directory. However, if all these controllers have similar logic, you can do all of it in one 2nd-level controller.

To do so, delete directories controller/home/album, controller/home/about and controller/home/work you have just created. Then edit controller/home/main.php to add some new methods:

public function __index($name) { echo 'This is ' . $name . "'s homepage."; } public function album($name) { echo 'This is ' . $name . "'s album."; } public function about($name) { echo 'About ' . $name; } public function work($name) { echo 'This is ' . $name . "'s work."; }

Now open http://localhost/home/about/peter, it will output the corresponding content.

The above example shows that custom methods can do the job of ONE sub-level controller. But if deeper sub-levels are needed, you still have to use multi-level controllers.

Limit Controller Arguments

When user visit http://localhost/home/mark, controller controller/home/main.php will be called and argument 'mark' will be passed to method __index($name). Without limitation, hackers can pass infinite arguments to the controller by requesting http://localhost/home/v1/v2/v3/v4/.... The method here, however, can only receive 2 arguments, the excess arguments will be ignored, leaving some potential security threats.

To prevent this kind of threats, the controller should limit the number of arguments it may received. Using $argc property in controller like this:

protected $argc = array( '__index' => 0, // default method does not accept any argument 'name' => 2, // 'name' method accept 2 arguments only 'book' => array(1, 3) // 'book' method accept 1 to 3 arguments ); public function __index() { // do something... } public function name($firstname, $lastname) { echo 'Your name is: ['.$firstname.' '.$lastname.']'; } public function book($tag, $type = 'edu', $page = 1) { echo 'Tag: ['.$tag.'], Type: ['.$type.'], Current Page: ['.$page.']'; }

Shown as above, $argc property is an array in which keys are the methods' name and values are the restrictions, like this: array('method' => $restriction). The restriction can be a number or an array. When it is a number, the number of arguments for corresponding method must be equal to it. When it is an array, the array should be array($min_num, $max_num), where $min_num, $max_num are the minimum and maximum number of the arguments that the method will accept.

When the actual arguments do not meet the restriction, an exception will be threw.

Using Configuration

MoePress Mini provides a way for making configurations outside the controller class. To make configurations, you need to create a new file config.php:

htdocs/
├── config.php
└── index.php

The config.php should have an array variable $_CONFIG which contains configured information:

<?php // $_CONFIG structure sample $_CONFIG = array( 'debug' => true, // whether the site is under development 'base_uri' => '', // the root directory of website 'auto_load' => array( // PHP files which should be loaded automatically before loading controller ), 'routes' => array( // controller routing rules ) );
The config.php file is not required by default. For some special cases, however, you have to do configuration to keep MoePress Mini running properly. See Configuration for more details.

Routing Controller

Regular expressions are used for routing controllers. The regular expressions should be written in $_CONFIG['routes'], where the array key is the URI to be matched while the array value is the matched result used to call the target controller. Here are some examples:

$_CONFIG['routes'] = array( // route 1 '#^homepage\/(.*)$#' => 'home/$1', // route 2 '#^home\/([a-z0-9_\-]+)\/album#' => 'home/album/$1' );

In route 1, when you visit http://localhost/homepage/peter, the URL is equal to http://localhost/home/peter.

In route 2, when you visit http://localhost/home/peter/album, the URL is equal to http://localhost/home/album/peter.

Note that the URI can be matched more than once. For instance, URI /homepage/peter/album will be routed to /home/peter/album by route 1, and then it will be routed to /home/album/peter by route 2.

Auto Loading

MoePress Mini allows you to load some PHP files (model, library, etc.) before calling the controller, so you don't need to load commonly used models or library manually by using $this->model() or $this->library() in controller. The file paths should be written in array $_CONFIG['auto_load'].

$_CONFIG['auto_load'] = array( 'model/base_model.php', 'library/lib_helper.php' )

One of the usage of $_CONFIG['auto_load'] is to extend the default Controller class.
For example, you want to do some actions while calling the controller, and these actions are the same in every controllers. It is not a good idea to write the same code in each controller.
The best way is that we build a auto-loaded custom base controller class by extending MoePress class, which is the default base class for Controller class, and then let every controller extend the custom controller class.
Here is the example. Firstly, write a base controller library/base_controller.php:

<?php class Base_Controller extends MoePress { function __construct() { // do something you like... $this->data['site_title'] = 'My Site'; } }

Then, create your normal controller which extends the base controller, like controller/main.php:

<?php class Controller extends Base_Controller { public function __index() { // $site_title will be passed to the view ( defined in __construct() ) $this->view('site_index.php'); } }

To make it work, the base controller's file should be auto-loaded in config.php:

$_CONFIG['auto_load'] = array( 'library/base_controller.php' )

Subdirectory Installation

MoePress Mini works well when it is installed in the root directory of the website. But if you put it in a subdirectory, like http://localhost/blog/, something may go wrong.
To run properly in a subdirectory, you need to configure the $_CONFIG['base_uri'] argument.

For example, if you want to use MoePress Mini in a subdirectory blog/, the $_CONFIG['base_uri'] should be:

$_CONFIG['base_uri'] = 'blog';

Again, if you want to run your site in another subdirectory project/blog/, then it should be:

$_CONFIG['base_uri'] = 'project/blog';

Documentation

It is strongly recommended to go through the Tutorial first since more usages, examples and explanations will be given in the tutorial rather then the documentation.

[class] MoePress

Class MoePress is the base class of every controller. The controller's class name must be Controller and it must extend MoePress class.
See How it Works tutorial for more details about the basic usage of controller.

[property] $MP

  • Description
    The instance of current controller object.
  • Type
    Object, public static property
  • Usage $controller = MoePress::$MP;
    $controller->data['site_title'] = 'My Site';

[property] $config

  • Description
    The configuration value in config.php, the value is equal to $_CONFIG.
    See Advanced Configuration tutorial for more details about the configuration value.
  • Type
    Array, public static property
  • Usage $config = MoePress::$config;
    $base_uri = $config['base_uri'];

[property] $data

  • Description
    The variables to be used in views. The key is the variable's name, and the value is the variable's value. See Using View tutorial for more details about how to pass variables to view layer.
  • Type
    Array, public property
  • Usage $this->data['site_title'] = 'My Site';

[property] $argc

  • Description
    The limitation of the number of arguments for each method. The keys are the methods' name, the values are the restrictions. The restrictions can be numbers or arrays array($min_num, $max_num).
    See Limit Controller Arguments tutorial for more details about how to limit the arguments.
  • Type
    Array, protected property
  • Usage $argc = array( '__index' => 0, 'method1' => 2, 'method2' => array(1, 3) );

[method] __index( [string $arg1 [, string $arg2 [, $...]]] )

  • Description
    The default method of a controller. When a controller is loaded, this default method will be called if no request URI matches the custom method of the controller.
    See Using Controller Methods tutorial for more details about the controller methods.
  • Parameter
    None
  • Return
    None
  • Usage
    No parameter:
    public function __index() { echo 'Hello World'; }
    Multiple parameters:
    public function __index($name, $age) { echo "My name is " . $name . ", I'm " . $age; }

[method] view( string $file [, array $data [, boolean $return]])

  • Description
    The default method of a controller. When a controller is loaded, this default method will be called if no request URI matches the custom method of the controller.
    See Using View tutorial for more details about how to use view.
  • Parameters
    • $file
      Required. The path of view file.
    • $data
      Optional. The variables to be passed to the view. Default is an empty array.
    • $return
      Optional. Return the view output as a string or output to browser directly. Default is false.
  • Return
    Object | Boolean
    If the parameter $return == false, then this method will return an object $this pointed to the current controller. Or it will return true for success.
  • Usage
    Basic:
    $this->data['home_user'] = 'Peter'; $this->view('home/body.php');
    Pass parameter:
    $this->view('home/body.php', array('home_user'=>'Peter'));
    Multiple calls:
    $this->view('home/header.php')->view('home/body.php')->view('home/footer.php');
    Return as a string:
    $html = $this->view('home/body.php', array(), true);

[method] model( string|array $files )

  • Description
    Load model file(s). This method is is equivalent to library() method.
    See Using Model & Library tutorial for more usages of the this method.
  • Parameter
    • $files
      Required. The paths of single or multiple models to be loaded.
  • Return
    Object
    An object $this pointed to the current controller will be returned.
  • Usage
    Load single model:
    $this->model('user_model.php');
    Load multiple models:
    $this->model(array( 'user_model.php', 'home_model.php' ));
    Or in this way:
    $this->model('user_model.php')->model('home_model.php');

[method] library( string|array $files )

  • Description
    Load library file(s). This method is is equivalent to model() method.
    See Using Model & Library tutorial for more usages of the this method.
  • Parameter
    • $files
      Required. The paths of single or multiple libraries to be loaded.
  • Return
    Object
    An object $this pointed to the current controller will be returned.
  • Usage
    Load single library:
    $this->library('image_lib.php');
    Load multiple libraries:
    $this->library(array( 'image_lib.php', 'wiki_lib.php' ));
    Or in this way:
    $this->library('image_lib.php')->library('wiki_lib.php');

[method] site_url( [string $uri] )

  • Description
    A helper function. Return the URL of the current website.
  • Parameter
    • $uri
      Optional. The URI to be appended to the site's URL. Default is an empty string.
  • Return
    String
  • Usage
    Basic:
    $url = $this->site_url();
    // result: http://your-site-url.com/
    Use URI:
    $home_url = $this->site_url('home');
    // result: http://your-site-url.com/home

[method] current_url()

  • Description
    A helper function. Return the current URL, including all the request URIs.
  • Parameter
    None
  • Return
    String
  • Usage $url = $this->current_url();
    // result: http://your-site-url.com/home/peter?page=2

[method] redirect( [string $url [, int $code]] )

  • Description
    A helper function. Redirect the page to a new URL. This function MUST be called before any result output to the browser, otherwise it will fail.
  • Parameters
    • $url
      Optional. Both URI or full URL are allowed. For URI input, like 'home', your site's URL will be prepended to the URI to keep the input is a correct URL. Default is an empty string.
    • $code
      Optional. The HTTP response code. Default is 302.
  • Return
    None
  • Usage
    Basic:
    $this->redirect('home');
    // 302 redirect to http://your-site-url.com/home
    Other HTTP response code:
    $this->redirect('http://www.google.com/', 307);
    // 307 redirect to http://www.google.com/

Configuration

Extra configurations should be made in config.php. The config.php file is optional, but it is helpful for some cases, tutorial can be found at Using Configuration

config.php file need to be created manually, and it contains one array variable $_CONFIG for configuration. Here is a sample config.php:

<?php $_CONFIG = array( 'debug' => false, 'base_uri' => '', 'auto_load' => array(), 'routes' => array() );

[key] debug

  • Description
    'debug' is used to mark whether the site is under development mode. When 'debug' is true, MoePress's system exception detail will be printed on the browser. Otherwise, the exception detail will be hidden.
  • Type
    Boolean
  • Usage $_CONFIG['debug'] = true;

[key] base_uri

  • Description
    'base_uri' is used when MoePress Mini is not installed in the root directory of website.
    For instance, if MoePress Mini is in a subdirectory blog/, like http://your-site-url.com/blog/, then the 'base_uri' should be blog.
  • Type
    String
  • Usage $_CONFIG['base_uri'] = 'project/blog';

[key] auto_load

  • Description
    'auto_load' is an array which contains the file paths of models or libraries which need to be loaded automatically before calling the controller.
  • Type
    Array
  • Usage $_CONFIG['auto_load'] = array( 'model/user_model.php', 'library/image_lib.php' );

[key] routes

  • Description
    'routes' is an array used for routing controller. The array keys are regular expressions used to match URIs, and the array values are the matched results. One URI can be matched sequentially more than once.
  • Type
    Array
  • Usage $_CONFIG['routes'] = array( '#^homepage\/(.*)$#' => 'home/$1', '#^home\/([a-z0-9_\-]+)\/album#' => 'home/album/$1' );

About

As a micro framework, MoePress Mini just focuses on few things: multi-level controller, routing and view action. So it's a good choice for lightweight projects.

Changelog

  • v1.1.1 - 2014.10.12
    Fix bug, change site_url from $_SERVER['SERVER_NAME'] to $_SERVER['HTTP_HOST'].
  • v1.1 - 2014.09.06
  • v1.0 - 2013.10.13
    First version released.