Getting Started
Lines with asterisks(*) are comments for developers.
Requirements:
PHP 5.5 and above
Installation:
Download the latest release here and unzip. That's all!
Ensure the storage path is writable, preferably 777.
On UNIX systems, you can do this with the command#!/bin/bash
chmod 0777 -R storage
Still need it the Composer way?
#!/bin/bash
composer create-project avonnadozie/liteframe
Running LiteFrame
On Production
No extra setup required, simply place the application files on your server document root folder, most likely to be public_html
On Local
Run the cli serve command to start the local server and optionally specify a port
#!/bin/bash
php cli serve --port=500
This will start the local server at address 127.0.0.1:500
Architecture Concept
Request Lifecycle:
This part of the document aims to give you an overall view on how the framework works to help you understand the framework better. If you find some terms strange, it's okay, you will understand them and get familiar as you read on.
Like most PHP applications, all requests to the framework is directed to the index.php file. The index.php file does not contain much. Rather, it is a starting point for loading the rest of the framework.
The index.php file loads all files required by the framework (including Composer files if present) and then creates a \LiteFrame\Kernel object to handle the request.
The Kernel instance gets the LiteFrame\Http\Request and LiteFrame\Http\Routing\Route objects for the current request, and obtains the target Closure or Controller from the Route object. See this section on how to define routes using LiteFrame\Http\Routing\Router.
All Middlewares attached to the target (if any) are then executed before executing the target, and the Kernel finally terminates the framework.
Directory Structure:
Important directories and files
app
|____ Commands //Application commands
|____ Controllers //Application controllers
|____ Middlewares //Application middlewares
|____ Models //Application model
|____ Routes //Application route files
|____ Views //Application view files
|____ .htaccess //Prevents direct access to files in this folder and subfolders
assets //(Optional) public assets such as css, images and JavaScript files
components
|____ composer //(Optional) Composer files
|____ config //Config files
|____ helpers //Helper files
|____ libraries //3rd party libraries
|____ env.php //Environment specific configurations (to be created by you)
|____ env.sample //Sample env.php file
|____ .htaccess //Prevents direct access to files in this folder and subfolders
core //Core files, do not modify
docs //(Optional) Documentation
storage
|____ logs //Error logs
|____ private //Private application data
|____ public //Public application data
| |____ .htaccess //Allows direct access to files in this folder and subfolders
|____ .htaccess //Prevents direct access to files in this folder and subfolders
tests //Test files
.htaccess //Important .htaccess file
cli //Entry point for command line requests
index.php //Entry point for HTTP requests
The Basics
Routing
Basics:
All routes are defined in your route files, which are located in the app/Routes directory. These files are automatically loaded by the framework. The app/Routes/web.php file defines routes that are for your web interface. The routes in app/Routes/api.php are stateless and are suited for API calls, while app/Routes/cli.php are for commands.
The simpler method for web and api routes accepts just a URI and a Closure
Router::get('foo', function () {
return 'Hello World';
});
Alternatively, you can specify a controller action in place of the closure.
Router::get('foo', 'AppController@helloworld');
This will be explained further down
Available Router Methods:
The router allows you to register routes that respond to the common HTTP verb:
//Match GET requests
Router::get($route, $target);
//match POST requests
Router::post($route, $target);
//Match PUT requests
Router::put($route, $target);
//Match PATCH requests
Router::patch($route, $target);
//Match DELETE requests
Router::delete($route, $target);
Sometimes you may need to register a route that responds to multiple HTTP verbs. You can do so using the Router::anyOf method.
Or, you may even register a route that responds to all HTTP verbs using the Router::all method:
//Match any of the request method specified
Router::anyOf('POST|PUT|GET', $route, $target);
//Match all request methods
Router::all($route, $target);
Mapping:
To map your routes, use the any of the methods.//Match GET requests
Router::get($route, $target);
//match POST requests
Router::post($route, $target);
//Match PUT requests
Router::put($route, $target);
//Match PATCH requests
Router::patch($route, $target);
//Match DELETE requests
Router::delete($route, $target);
//Match any of the request method specified in the first parameter
Router::anyOf($method, $route, $target);
//Match all request methods
Router::all($route, $target);
Parameters
$method | string
This is a pipe-delimited string of the accepted HTTP requests methods.
Example: GET|POST|PATCH|PUT|DELETE
$route | string
This is the route pattern to match against. This can be a plain string, one of the predefined regex filters or a custom regex. Custom regexes must start with @.
Route | Example Match | Variables |
---|---|---|
/contact/ | /contact/ | nil |
/users/[i:id]/ | /users/12/ | $id = 12 |
$target | mixed
This can be either a function callback or a Controller@action string.
Example using a function callback:
Router::get('user/profile', function () {
//Do something
});
Example using a Controller@action string:
Router::get('user/profile', 'UserController@showProfile');
Interestingly, we can also match multiple routes at once by supplying an array of routes to the Router::matchAll method. For example,
Router::matchAll(array(
array('POST|PUT', 'profile/create', 'ProfileController@create'),
array('GET', 'profile', 'ProfileController@show'),
array('DELETE', 'profile/[i:id]', 'ProfileController@delete'),
));
Match Types
You can use the following limits on your named parameters. The framework will create the correct regexes for you
* // Match all request URIs
[i] // Match an integer
[i:id] // Match an integer as 'id'
[a:action] // Match alphanumeric characters as 'action'
[h:key] // Match hexadecimal characters as 'key'
[:action] // Match anything up to the next / or end of the URI as 'action'
[*] // Catch all (lazy, stops at the next trailing slash)
[*:trailing] // Catch all as 'trailing' (lazy)
[**:trailing] // Catch all (possessive - will match the rest of the URI)
.[:format]? // Match an optional parameter 'format' - a / or . before the block is also optional
The character before the colon (the 'match type') is a shortcut for one of the following regular expressions
'i' => '[0-9]++'
'a' => '[0-9A-Za-z]++'
'h' => '[0-9A-Fa-f]++'
'*' => '.+?'
'**' => '.++'
'' => '[^/\.]++'
You can register your own match types using the addMatchTypes() method.
Router::getInstance()->addMatchTypes(array('cId' => '[a-zA-Z]{2}[0-9](?:_[0-9]++)?'));
Once your routes are all mapped you can start matching requests and continue processing the request.
Named Routes:
If you want to use reversed routing, Named routes allow you to conveniently specify a name parameter so you can later generate URL's using this route. You may specify a name for a route by chaining the setName method onto the router:
Router::get('user/profile', function () {
//To do
})->setName('profile');
Or you may specify the route name after the target:
//For anyOf
Router::anyOf('GET|POST','user/profile', 'AppController@showProfile','profile');
//For other Router methods
Router::get('user/profile', 'AppController@showProfile','profile');
To reverse a route, use the route($routeName, $params); helper with optional parameters
Parameters
$routeName | string - Name of route
$params | array - Optional parameters to build the URL with
Redirect Route:
With Redirect Route you can redirect a route permanently to another route or a url.
Redirecting to a route:
Router::redirect($route, 'another-route-name');
This route will redirect to the route named another-route-name
Redirecting to a url:
Router::redirect($route, 'https://example.com');
This route will redirect to the URL http://example.com
View Route:
This allows you to return a view as response directly without the need for closures or controllers.
Router::view($route, 'view-name');
Where view-name is the name of the view.
Additionally, you can pass data to the view as such.
$data = array('name'=>'John Doe');
Router::view($route, 'view-name', $data);
Requests
Explain the LiteFrame\Http\Request object.
Middleware
The Basics:
Middleware provide a convenient mechanism for filtering HTTP requests entering your application and responses sent by the application.
All of these middleware are located in the app/Middlewares directory and should extend Middlewares/Middleware class in the same directory.
<?php
namespace Middlewares;
use Closure;
use LiteFrame\Http\Request;
class MySampleMiddleware extends Middleware
{
public function run(Closure $next = null, Request $request = null)
{
//Do something before controller
$response = $next($request);
//Do something after controller
return $response;
}
}
For the framework to run your middleware, you have to register it in the components/config/middleware.php file. Simply add your middleware class to the before_core or after_core key of the array.
return [
/*
* Array of middleware classes that should be executed before core middleware
* classes are executed on every request.
*/
'before_core' => [
Middlewares\MySampleMiddleware ::class
],
/*
* Array of middleware classes that should be executed after core middleware
* classes are executed.
*/
'after_core' => [
Middlewares\MySampleMiddleware ::class
],
];
Named/Route Middleware:
You may also specify middleware to run only for specific routes. To do this, you have to register your middleware with a name
return [
/*
* Example of a route/named middleware
*/
'sample' => Middlewares\MySampleMiddleware::class
];
Then set it for the required routes like this
Router::get('user/profile', 'AppController@showProfile')->setMiddlewares("sample");
To juice things up, the setMiddlewares method can accept multiple middleware names:
Router::get('user/profile', 'AppController@showProfile')->setMiddlewares("sample1", "sample2");
Or
Router::get('user/profile', 'AppController@showProfile')->setMiddlewares(["sample1", "sample2"]);
Controllers
Instead of defining all of your request handling logic as Closures in route files, you may wish to organize this behavior using Controller classes. Controllers can group related request handling logic into a single class. Controllers are stored in the app/Controllers directory and extends the Controllers/Controller class.
Routing to a controller action/method:
Router::get('user/profile', 'AppController@showHelloWorld');
Controller Middleware:
Middleware may be assigned to the controller's routes in your route files:
Route::get('profile', 'UserController@show')->setMiddleware('sample');
However, it is more convenient to specify middleware within your controller's constructor. Using the middleware method from your controller's constructor:
class AppController extends Controller
{
public function __construct()
{
$this->middleware('sample');
}
}
Models
Explain how to create and use models.
Views
Explain how to create views.
Response
Explain the LiteFrame\Http\Response object.
Commands
Basics:
Explain the basics in creating commands.
Scheduling
Explain scheduling.
Errors & Logging
Environment Variables:
Explain how to configure app environment variables.
Error Pages:
Explain how to create error pages to overide the default error page on production.
Helpers:
Explain how to add helper functions.
Database
Getting Started
Explain how to setup database.
RedBeanPHP
Explain the underneath RedBeanPHP.
Working with Libraries
Autoloading Files
Explain thow to autoload custom files.
3rd-Party Libraries
Explain how to autoload 3rd party libraries.
Composer
In as much as we "really" avoided the need for commands, we couldn't help supporting composer. Composer files are autoloaded by the framework if available but we changed the vendor directory to components/composer for security reasons.
Security
URI Security
Explain URI security using type hints
Use of .htaccess
Explain strategic .htaccess files
Request Validation
Explain Validator
Filtering Output
Explain output filtering using e()
Testing
Explain how to run tests
Contributing
To contribute,
- Fork the project on Github
- Make your bug fix or feature addition.
- Add tests for it. This is important so we don't break it in a future version unintentionally.
- Send a pull request.