Overview
MINI uses a simple, convention-based routing system where URLs directly map to controller classes and methods. No route configuration files are needed—the framework automatically determines which code to execute based on the URL structure.
URL Structure
All URLs follow this pattern:
http://yoursite.com/controller/action/param1/param2/param3
└────┬────┘ └──┬──┘ └────────┬────────┘
│ │ │
Controller Method Parameters
Examples
URL Controller Method Parameters /homeindex[]/songssongsindex[]/songs/edit/5songsedit['5']/users/profile/john/settingsusersprofile['john', 'settings']
If no controller is specified (root URL /), MINI defaults to the home controller’s index() method.
How Routing Works
1. URL Rewriting with .htaccess
Apache’s mod_rewrite converts clean URLs into a query parameter:
application/public/.htaccess
# Prevent directory listing
Options -MultiViews
Options -Indexes
# Enable URL rewriting
RewriteEngine On
# If the following conditions are true:
RewriteCond %{REQUEST_FILENAME} !-d # Not a directory
RewriteCond %{REQUEST_FILENAME} !-f # Not a file
RewriteCond %{REQUEST_FILENAME} !-l # Not a symbolic link
# Rewrite the URL:
# /songs/edit/5 becomes index.php?url=songs/edit/5
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
What this does:
Converts /songs/edit/5 → index.php?url=songs/edit/5
Preserves existing query strings with [QSA] (Query String Append)
Stops processing other rules with [L] (Last)
Only rewrites if the path isn’t an actual file/directory (allows CSS, JS, images to load normally)
2. URL Parsing with splitUrl()
The Application class parses the URL into components:
application/core/application.php
private function splitUrl ()
{
if ( isset ( $_GET [ 'url' ])) {
// Clean and split the URL
$url = trim ( $_GET [ 'url' ], '/' );
$url = filter_var ( $url , FILTER_SANITIZE_URL );
$url = explode ( '/' , $url );
// Extract components
$this -> url_controller = isset ( $url [ 0 ]) ? $url [ 0 ] : null ;
$this -> url_action = isset ( $url [ 1 ]) ? $url [ 1 ] : null ;
// Remove controller and action from array
unset ( $url [ 0 ], $url [ 1 ]);
// Remaining elements are parameters
$this -> url_params = array_values ( $url );
}
}
Example: URL songs/edit/5/preview
$this -> url_controller = 'songs' ;
$this -> url_action = 'edit' ;
$this -> url_params = [ '5' , 'preview' ];
3. Controller Resolution
The Application class determines which controller to load:
application/core/application.php
public function __construct ()
{
$this -> splitUrl ();
// Case 1: No controller specified - load home
if ( ! $this -> url_controller ) {
require APP . 'controller/home.php' ;
$page = new Home ();
$page -> index ();
}
// Case 2: Controller file exists
elseif ( file_exists ( APP . 'controller/' . $this -> url_controller . '.php' )) {
// Load and instantiate controller
require APP . 'controller/' . $this -> url_controller . '.php' ;
$this -> url_controller = new $this -> url_controller ();
// Case 2a: Method exists - call it
if ( method_exists ( $this -> url_controller , $this -> url_action )) {
if ( ! empty ( $this -> url_params )) {
// Call with parameters
call_user_func_array (
array ( $this -> url_controller , $this -> url_action ),
$this -> url_params
);
} else {
// Call without parameters
$this -> url_controller -> { $this -> url_action }();
}
}
// Case 2b: No method specified - call index()
else {
if ( strlen ( $this -> url_action ) == 0 ) {
$this -> url_controller -> index ();
}
// Case 2c: Method doesn't exist - error page
else {
header ( 'location: ' . URL . 'problem' );
}
}
}
// Case 3: Controller doesn't exist - error page
else {
header ( 'location: ' . URL . 'problem' );
}
}
Routing Examples
Let’s trace how different URLs are handled:
Example 1: Root URL /
URL Rewriting
No $_GET['url'] parameter exists
splitUrl()
$this -> url_controller = null ;
$this -> url_action = null ;
$this -> url_params = [];
Controller Resolution
Falls into “no controller” case: require APP . 'controller/home.php' ;
$page = new Home ();
$page -> index ();
Example 2: /songs
URL Rewriting
index.php?url=songs
splitUrl()
$this -> url_controller = 'songs' ;
$this -> url_action = null ;
$this -> url_params = [];
Controller Resolution
Controller file exists: application/controller/songs.php
Load and instantiate Songs class
No action specified, call index() method
Example 3: /songs/deletesong/42
URL Rewriting
index.php?url=songs/deletesong/42
splitUrl()
$this -> url_controller = 'songs' ;
$this -> url_action = 'deletesong' ;
$this -> url_params = [ '42' ];
Controller Resolution
Controller exists: Songs
Method exists: deleteSong()
Call with parameters:
call_user_func_array (
array ( $this -> url_controller , 'deletesong' ),
[ '42' ]
);
Which executes: Songs::deleteSong('42')
Real-World Routing Examples
Here’s how the songs controller handles different routes:
application/controller/songs.php
class Songs extends Controller
{
// Route: /songs or /songs/index
public function index ()
{
$songs = $this -> model -> getAllSongs ();
$amount_of_songs = $this -> model -> getAmountOfSongs ();
require APP . 'view/_templates/header.php' ;
require APP . 'view/songs/index.php' ;
require APP . 'view/_templates/footer.php' ;
}
// Route: /songs/editsong/5
public function editSong ( $song_id )
{
if ( isset ( $song_id )) {
$song = $this -> model -> getSong ( $song_id );
require APP . 'view/_templates/header.php' ;
require APP . 'view/songs/edit.php' ;
require APP . 'view/_templates/footer.php' ;
} else {
header ( 'location: ' . URL . 'songs/index' );
}
}
// Route: /songs/deletesong/5
public function deleteSong ( $song_id )
{
if ( isset ( $song_id )) {
$this -> model -> deleteSong ( $song_id );
}
header ( 'location: ' . URL . 'songs/index' );
}
}
Parameter Handling
Parameters are passed as method arguments:
// URL: /songs/deletesong/42
public function deleteSong ( $song_id )
{
// $song_id = '42'
}
// URL: /users/profile/john/edit
public function profile ( $username , $action = 'view' )
{
// $username = 'john'
// $action = 'edit'
}
All URL parameters are strings. Cast them to appropriate types: public function deleteSong ( $song_id )
{
$song_id = ( int ) $song_id ; // Cast to integer
// ...
}
Generating URLs
Use the URL constant to generate links:
// Simple link
< a href = "<?php echo URL; ?>songs" > View Songs </ a >
// Link with action
< a href = "<?php echo URL; ?>songs/editsong/<?php echo $song -> id ; ?>" > Edit </ a >
// Form action
< form action = "<?php echo URL; ?>songs/addsong" method = "POST" >
<!-- form fields -->
</ form >
The URL constant is defined in application/config/config.php:
define ( 'URL' , URL_PROTOCOL . URL_DOMAIN . URL_SUB_FOLDER );
// Example: //yoursite.com/myapp/
Method Name Conventions
Method names are case-insensitive in URLs. Both /songs/editSong and /songs/editsong work.
However, use camelCase in your controller methods for readability:
// Good: Clear and readable
public function editSong ( $song_id ) { }
public function exampleOne () { }
public function addNewUser () { }
// Works but less readable
public function editsong ( $song_id ) { }
public function exampleone () { }
public function addnewuser () { }
Debugging Routes
Uncomment these lines in splitUrl() to debug routing:
application/core/application.php
private function splitUrl ()
{
if ( isset ( $_GET [ 'url' ])) {
// ... URL parsing code ...
// Debug output
echo 'Controller: ' . $this -> url_controller . '<br>' ;
echo 'Action: ' . $this -> url_action . '<br>' ;
echo 'Parameters: ' . print_r ( $this -> url_params , true ) . '<br>' ;
}
}
Error Handling
The framework redirects to /problem for:
Non-existent controllers
Non-existent methods (when an action is specified)
Missing required parameters (if your code checks for them)
Create a problem controller to display custom error pages:
application/controller/problem.php
class Problem extends Controller
{
public function index ()
{
require APP . 'view/_templates/header.php' ;
require APP . 'view/problem/index.php' ;
require APP . 'view/_templates/footer.php' ;
}
}
Limitations
Named routes : MINI doesn’t support named routes like Laravel or Symfony. URLs are tightly coupled to controller/method names.Route parameters : No regex constraints or type hints in routes. Validation must happen in controller methods.HTTP verbs : No built-in route filtering by HTTP method (GET, POST, etc.). Handle this in your controller:public function deleteSong ( $song_id )
{
if ( $_SERVER [ 'REQUEST_METHOD' ] !== 'POST' ) {
header ( 'location: ' . URL . 'songs' );
exit ;
}
// ...
}
Architecture Understand the overall MVC structure
Controllers Learn how to create controller methods
Configuration Configure URL settings and .htaccess