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 @.

Examples:
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,

  1. Fork the project on Github
  2. Make your bug fix or feature addition.
  3. Add tests for it. This is important so we don't break it in a future version unintentionally.
  4. Send a pull request.

Copyright © 2018 LiteFrame