Lepton is a lightweight MVC framework for building web applications in PHP. It's free and open-source.
- First, download Lepton, either directly or by cloning the repo.
- Run
composer updateto install the project dependencies. - Add routes, create controllers, views and models.
- That's it!
See below for more details.
Configuration settings are stored as constants in App/Config.php. Default settings include database connection data, SMTP settings and others. You can use the settings in your code like this: Config::DB_HOST. You may also add your own configuration settings there.
// Config.php
public const int TRANSACTION_LIMIT = 5000;
// Use it in any controller
echo Config::TRANSACTION_LIMIT;The router translates URLs into controllers and actions.
Routes are located in Routes.php and added using the $router->add() method. You can add predefined URL routes and specify the controller and action, like this:
$router->add("", ["controller" => "Home", "action" => "index"]);
$router->add("posts/index", ["controller" => "Posts", "action" => "index"]);Or you can add route wildcards, like this:
$router->add("{controller}/{action}");This way, navigating to /posts/comments will automatically route to the comments action in PostsController.
In addition to the controller and action, you can specify any parameter you like within curly braces and also specify a custom regular expression for that parameter:
// A route with an id that matches integers only
$router->add('{controller}/{id:\d+}/{action}');We'll see how to recover parameters later.
To keep things apart, you can also specify a namespace for the controller:
$router->add("admin/{controller}/{action}", ["namespace" => "Admin"]);This will access any controllers in the App/Controllers/Admin/ folder.
As Lepton is built in an object-oriented language, you can reuse controller names in different scopes. For instance, App\UsersController and Admin\UsersController share the same name but are perfectly valid because they belong to different scopes.
Controllers respond to user actions (clicking on a link, submitting a form, etc.). Controllers are kept in the App/Controllers folder and must contain the Controller suffix (e.g., HomeController, PostsController, UsersController). They also need to be in the App\Controllers namespace and extend the Core\Controller class as well.
// App/Controllers/HomeController.php
namespace App\Controllers;
use Core\Controller;
use Core\View;
class HomeController extends Controller
{
public function index(): void
{
// ...add your functionality here...
View::renderTemplate();
}
}Tip
A sample HomeController is included.
Controller classes contain methods that are called actions. To create an action, just create a new method with the desired name. The method View::renderTemplate() in it is required to render the corresponding HTML file — we'll see more about it soon.
public function index(): void
{
// some script
View::renderTemplate();
}
public function add(): void
{
// more scripts
View::renderTemplate();
}You can access route parameters (for example, the "id" parameter shown in the route examples above) in actions via the $this->route_params property.
Controllers can have before and after filter methods. These are methods that are called before and after every action method call in a controller, useful for authentication, for example, making sure that a user is logged in before letting them execute an action. To use them, optionally add a beforeFilter() or afterFilter() to a controller like this:
protected function beforeFilter(): void
{
if (!$isAuthenticated) {
return false; // this will prevent the action from executing
}
}Views are HTML files that are used to display information on screen. Those HTML files go to the App/Views folder and need to follow the path App/Views/{controller}/{action}.html.
It uses Twig as an engine, and you can render a standard PHP view, optionally passing in variables, using the View::renderTemplate() method, like this:
// Controllers/HomeController.php
public function index(): void
{
$starship = "USS Enterprise";
View::renderTemplate([
"name" => "Captain Kirk",
"starship" => $starship,
"colors" => ["dark blue", "green", "purple"]
]);
}And then, in your view, you can get those data like this:
<!-- Views/Home/index.php -->
<h1>Hello, {{name}} of the {{starship}}!</h1>
<p>Your favorite colors are:</p>
<ul>
{% for color in colors %}
<li>{{color}}</li>
{% endfor %}
</ul>Using Twig allows you to have simpler, safer templates that can take advantage of things like template inheritance and even cache. A sample view is included in App/Views/Home/index.html, a welcome message that inherits from the master template in App/Views/layout.html that contains the header, meta tags, CSS and JS.
For APIs, you may use View::renderJson(). The response's content type will be automatically changed to JSON, and the data will be returned correctly.
public function authenticate(): void
{
// ...perform authentication...
View::renderJson([ "token" => $generatedToken ]);
}Models are used to get and store data in your application. They extend the Core\Model class and use PDO to access and perform queries to the database. All models are kept in the App/Models folder, and each model is linked to a corresponding database table. Models need to be named in the singular and UpperCamelCase. A model User points to a table named users; a model TransactionDetail points to the table transaction_details.
Important
The embedded inflector only works in English. For other languages, you may need to create a custom inflector.
// App/Models/User.php
namespace App\Models;
use Core\Model;
class User extends Model
{
protected static $table = 'users';
}Neutrino is our embedded query builder built from scratch. As your model now inherits the App\Models class, you can now use all the query builder methods that could make your life easier:
$officer = new Officer(); // this is a model in Model/Officer.php
// get all records
$officer->select()->fetch();
// select only name and email
$officer->select(["name", "email"])->fetch();
// get the record with ID 1
$officer->find(1)->fetch();
// get records with ID 13 and 14
$officer->find([13, 14])->fetch();
// delete the record with ID 20
$officer->delete(20);
// get the latest five users
$officer->select()
->order("id", "DESC")
->limit(5)
->fetch();
// insert a new record into the database
$officer->insert([
"name" => "Jean-Luc Picard",
"rank" => "Captain"
]);
// update the record where the field `name` equals to `Geordi La Forge`
$geordi = $officer->findBy("name", "Geordi La Forge");
$officer->update($geordi["id"], [
"rank" => "Lieutenant Commander"
]);
// or, if you prefer to have all the control...
$officer->raw("SELECT * FROM officers
INNER JOIN departments ON (departments.id = officers.department_id)
WHERE starship = 'USS Enterprise'
ORDER BY name;");Tip
Neutrino is quite extensive. There's a dedicated Wiki about it.
You can also create a method inside the model, for example:
// App/Models/Starship.php
public function GetOldShips(): array {
// in the model, $link is an instance of PDO
$self::$link->query("SELECT * FROM starships WHERE launch_date < '2300-01-01';");
}
// App/Controllers/StarshipsController.php
$starship = new Starship();
$starship->GetOldShips();Tip
A sample user model class is included in App/Models/User.php.
If the SHOW_ERRORS configuration setting is set to true, full error detail will be shown in the browser if an error or exception occurs. If it's set to false, errors are logged into a TXT file and a generic message will be shown using the App/Views/404.html or App/Views/500.html views, depending on the error.
Friendly URLs are enabled using web server rewrite rules. An .htaccess file is included in the "public" folder. Remember to have mod_rewrite enabled in Apache.
Equivalent nginx configuration is in the nginx-configuration.txt file.