Larite Framework

Lightweight. Laravel-Inspired. 100% Custom. A modern PHP MVC framework built from scratch for developers who demand performance and simplicity.

Version: 4.0.0  |  Author: M. Kashif Sohail

Lightweight
Fast
Laravel-Style
Secure

Introduction

Larite is a lightweight PHP MVC framework inspired by Laravel, but built entirely from scratch. It's designed for developers who love Laravel's syntax and structure but want full control, performance, and simplicity.

Larite is not a Laravel clone. It's a fresh micro-framework for small to medium web apps, dashboards, admin panels, and educational projects — without Composer bloat or hidden magic.

Perfect For: Small to medium web applications, dashboards, admin panels, and educational projects.

Why Choose Larite?

  • Laravel-style routing, middleware, ORM, relations, query builder, eager loading, and validation
  • Laravel-style migrations and seeders
  • Custom-built DI container and lifecycle
  • CSRF protection and input sanitization
  • Auth scaffolding, flash messages, old inputs
  • CLI commands for models, controllers, auth scaffolding and migrations
  • Useful helpers: dd, dump, asset, url, mail, pagination and many more
  • Default exception handler
  • Simple, extendable, and easy to read/learn

Security Features

  • CSRF Protection: <?php csrf_field(); ?> inside <form>
  • Output escaping: <?= e($value) ?>
  • File upload validation
  • Automatic input sanitization

Core Features

  • Auth Scaffolding (Route::authenticate())
  • Pagination: paginate() / simplePaginate()
  • Old input repopulation: old('field')
  • Flash messages and session management
  • Built-in validation system
  • Database migrations and seeding
  • Blade template engine support (for views)

Installation

Note: Larite is continuously evolving. Always install the latest stable release from Packagist and refer to the updated documentation for the most accurate information.

Before you start, make sure you have PHP 8.3 or above and Composer installed on your system.

  1. Create a new project using Composer:
Terminal
composer create-project larite/larite my-project
  1. Navigate into your project directory:
Terminal
cd my-project
  1. Set up your environment:

Copy the .env.example file to .env and update your database and app configuration.

Terminal
cp .env.example .env
  1. Run your local server:

You can now run the application using PHP’s built-in server:

Terminal
php -S localhost:8000 -t public

✅ You’re all set! Open http://localhost:8000 in your browser to view your application.

Remove /public from URL

By default, Larite's index.php is inside the public directory for security. If you want to remove /public from the URL, you can do it in different ways.

  1. Method 1: Move index.php & .htaccess to the root folder

Move both files from public to your project root:

Note: Since index.php handles the /vendor/autoload.php and /bootstrap/app.php file paths dynamically, no changes are required inside the file.
  1. Method 2: .htaccess Redirect

Then edit the .htaccess to redirect requests to /public automatically:

.htaccess
RewriteEngine On

# Remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]

# Send requests to the front controller
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

# Disable directory listing
Options -Indexes

# Allow direct access only to index.php, public assets
<FilesMatch "^(index\.php|favicon\.ico|robots\.txt)$">
    Require all granted
</FilesMatch>
# Deny access to sensitive directories
RedirectMatch 403 ^/(app|config|migrations|logs|routes|views|bootstrap|vendor|tests|database|storage|node_modules)(/|$)

# Hide .env file
<Files .env>
    Order allow,deny
    Deny from all
</Files>
  1. Method 3: Apache Virtual Host (Recommended)

If you have server control (e.g., Laragon, XAMPP, VPS), set the document root directly to the /public folder:

Apache Config
<VirtualHost *:80>
    ServerName larite.local
    DocumentRoot "C:/laragon/www/Larite/public"

    <Directory "C:/laragon/www/Larite/public">
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
  1. Method 4: cPanel

On cPanel hosting, simply set the document root of your domain/subdomain to the public folder:

  • Go to DomainsManage.
  • Edit the document root path to point to public inside your project.
  • Save changes — no need to move any files.

✅ The most secure way is Method 3 or 4, keeping index.php inside public.

Environment Setup

Rename .env.example to .env and configure your environment:

Environment

// Application config
APP_NAME=Larite
APP_URL=http://localhost
APP_ENV=development // development, production
LOG_CHANNEL=single // daily, single

// Mail config 
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_USERNAME=example@gmail.com
MAIL_PASSWORD=secret
MAIL_PORT=587
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=example@gmail.com
MAIL_FROM_NAME=Larite

// Database config
APP_ENV=development
DB_HOST=localhost
DB_DATABASE=Larite
DB_USERNAME=root
DB_PASSWORD=secret
AUTH_TABLE=users
Production Mode: Set APP_ENV=production to hide error output in production.

Configuration Files

Larite uses these main configuration files located in the config/ directory:

app.php

PHP

<?php

// Application configuration settings
return [

    /*
    |--------------------------------------------------------------------------
    | Application Name
    |--------------------------------------------------------------------------
    | This value is the name of your application.
    */
    'name' => env('APP_NAME', 'Larite'),

    /* Application URL for console commands */
    'url' => env('APP_URL', 'http://localhost'),

    /* Environment mode: development or production */
    'app_env' => env('APP_ENV', 'development'),

    /* Default timezone */
    'timezone' => 'Asia/Karachi',

    /* Authentication table */
    'table' => env('AUTH_TABLE', 'users'),

    /* Logging channel (daily, single)*/
    'log_channel' => env('LOG_CHANNEL') ?: 'single',

];
        

database.php

PHP

<?php

// Database configuration
return [

    /* Default database connection */
    'db_connection' => env('DB_CONNECTION', 'mysql'),

    /* Database name */
    'db_database' => env('DB_DATABASE', 'larite'),

    /* Database username */
    'db_username' => env('DB_USERNAME', 'root'),

    /* Database host */
    'db_host' => env('DB_HOST', 'localhost'),

    /* Database password */
    'db_password' => env('DB_PASSWORD', ''),

];
        

providers.php

This array lists all of the service providers that will be automatically loaded on the request to your application. Feel free to add your own services to this array to grant expanded functionality to your app.

PHP

<?php

// Application service providers configuration
return [

    /* App Service Provider: registers core services like cache, mail, etc. */
    App\Providers\AppServiceProvider::class,

    /* Route Service Provider: registers all route files (web.php, api.php, etc.) */
    App\Providers\RouteServiceProvider::class,

    /* Custom Service Providers: add your new providers here */

];
    

mail.php

PHP

<?php

// Mail configuration
return [

    /* Mail driver (smtp, sendmail, etc.) */
    'driver' => env('MAIL_DRIVER', 'smtp'),

    /* SMTP server host */
    'host' => env('MAIL_HOST', 'smtp.gmail.com'),

    /* SMTP username */
    'username' => env('MAIL_USERNAME'),

    /* SMTP pssword */
    'password' => env('MAIL_PASSWORD'),

    /* SMTP port */
    'port' => env('MAIL_PORT', '587'),

    /* From address & name */
    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', 'example@gmail.com'),
        'name' => env('MAIL_FROM_NAME', 'Larite'),
    ],

    /* Mail encryption */
    'encryption' => env('MAIL_ENCRYPTION', 'tls'),

];
        

Pagination

Introduction

Larite provides pagination out of the box. You can paginate query results, loop through paginated items, and render navigation links. Both the new New style pagination and the old-style pagination syntax are supported for backward compatibility.

New Pagination (Recommended)

Use the pagination for cleaner and more expressive syntax:

PHP
// In your controller
public function index()
{
    $users = User::paginate(10);
    return view('users', compact('users'));
}
Blade
<!-- In your Blade template -->
@foreach($users as $user)
    <p>{{ $user->name }}</p>
@endforeach

<!-- Laravel-style pagination links -->
{!! $users->links() !!}

Old-Style Pagination (Still Supported)

For projects using the older syntax, the classic pagination API is still available.

PHP
// In your controller (old style)
public function index()
{
    $users = User::paginate(10);
    return view('users', compact('users'));
}
Blade
<!-- In your Blade template (old style) -->
@foreach($pagination as $user)
    <p>{{ $user->name }}</p>
@endforeach

<!-- Old-style pagination links -->
{!! $render->links !!}

Available Methods

The paginate object provides helpful methods and properties:

Methods

  • links() – Returns pagination HTML (Laravel-style)
  • render() – Alias for links()
  • toArray() – Returns pagination data as an array
  • count() – Number of items on the current page
  • getIterator() – Allows foreach iteration over items

Properties

  • data – Collection of items for the current page
  • current_page – Current page number
  • per_page – Items per page
  • total – Total number of items
  • last_page – Last page number
  • from – Starting item index
  • to – Ending item index
  • first_page_url – URL for the first page
  • last_page_url – URL for the last page
  • next_page_url – URL for the next page
  • prev_page_url – URL for the previous page
  • path – Base path for pagination

Blade Templating

Introduction

Blade is Larite’s powerful templating engine. It provides clean syntax for writing views with template inheritance, control structures, loops, and even custom directives.

Template Inheritance

Create a base layout and extend it in child views:

Blade
<!-- views/layouts/app.blade.php -->
<!doctype html>
<html>
    <body>
        @yield('content')
    </body>
</html>
Blade
<!-- views/home.blade.php -->
@extends('layouts.app')

@section('content')
    <h1>Welcome Home</h1>
@endsection

Echoing Data

Safely output variables or allow raw HTML:

Blade
<!-- Escaped output -->
{{ $name }}

<!-- Raw HTML output -->
{!! $htmlContent !!}

Control Structures

Blade provides shortcuts for common PHP control structures:

Blade
@if($user->isAdmin())
    <p>Welcome, Admin!</p>
@else
    <p>Hello, User!</p>
@endif

Loops

Loop through data collections easily:

Blade
@foreach($users as $user)
    <li>{{ $user->name }}</li>
@endforeach

Including Partials

Include sub-views with the @include directive:

Blade
@include('partials.header')

Using Raw PHP

You can run raw PHP code with @php (both single-expression and block forms):

Blade
<!-- Inline PHP expression -->
@php(time())

<!-- Multi-line PHP block -->
@php
    $counter = 0;
    $message = 'Hello World';
@endphp

Error Handling

Use @error / @enderror to show validation error messages for a specific field:

Blade
@error('email')
    <div class="alert alert-danger">{{ error('email') }}</div>
@enderror

Push and Stack

Use @push / @endpush to push content into a named stack, and @stack to render it:

Blade
@push('scripts')
    <script src="/example.js"></script>
@endpush

@stack('scripts')

CSRF Protection

Use @csrf to include a CSRF token in your forms:

Blade
<form method="POST" action="/submit">
    @csrf
    <button type="submit">Submit</button>
</form>

Checking Variables

Use @isset / @endisset and @empty / @endempty for conditional checks:

Blade
@isset($records)
    <p>Records found.</p>
@endisset

@empty($records)
    <p>No records.</p>
@endempty

Unless Statement

The @unless directive is the inverse of @if:

Blade
@unless($user->isAdmin())
    <p>You are not an admin.</p>
@endunless

Switch Statement

Blade also supports PHP-style switch statements:

Blade
@switch($role)
    @case('admin')
        <p>Admin Panel</p>
        @break

    @case('user')
        <p>User Dashboard</p>
        @break

    @default
        <p>Guest View</p>
@endswitch

Debugging

Use @dump and @dd for quick debugging (prints and optionally stops execution):

Blade
@dump($user)
@dd($settings)

Custom Directives

You can register your own Blade directives in AppServiceProvider or a dedicated BladeServiceProvider. Example below adds a simple @datetime directive:

PHP
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Blade;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Blade::directive('datetime',
            function ($expression) {
                return "<?php echo (".$expression.") ? date('Y-m-d H:i', strtotime(".$expression.")) : ''; ?>";
            }
        );
    }
}

Usage:

Blade
@datetime($user->created_at)

Routing

Basic Route Definition

Define routes in routes/web.php:

PHP
Route::get('/', [HomeController::class, 'index']);

Route Groups

Group routes with common attributes:

PHP
Route::group(['prefix' => 'admin', 'middleware' => ['auth']], function () {
    Route::get('dashboard', [DashboardController::class, 'index']);
});

You can also use the prefix() and middleware() methods for a more fluent syntax:

PHP
Route::prefix('api')->group(function () {
    Route::get('/users', [UserController::class, 'index']);
});

Or combine prefix() with middleware() for chained grouping:

PHP
Route::prefix('api')
    ->middleware('api')
    ->group(function () {
        Route::get('/users', [UserController::class, 'index']);
});

Named Routes

Named routes allow you to generate URLs for specific routes using a name instead of hardcoding the URL. This makes your application more maintainable and flexible.

Defining Named Routes

PHP
// In routes/web.php
Route::get('/', [HomeController::class, 'index'])->name('home.index');
Route::get('/about', [HomeController::class, 'about'])->name('about');
Route::get('/users/{id}', [UserController::class, 'show'])->name('users.show');

Using Named Routes

PHP
// Generate URL for a named route
echo route('home.index'); // Outputs: /

// Generate URL with parameters
echo route('users.show', ['user' => 5]); // Outputs: /users/5

// Use in views
<a href="<?= route('home.index') ?>">Home</a>
<a href="<?= route('users.show', ['user' => 1]) ?>">View User</a>

// Use in redirects
redirect(route('users.index'));
redirect(route('users.show', ['user' => 5]));

Resource Routes

Resource routes provide a quick way to create all the necessary routes for a resource controller. A resource controller typically handles CRUD operations for a model.

Defining Resource Routes

PHP
// In routes/web.php
Route::resource('users', UserController::class);

This single line creates the following routes:

Method URI Name Action Description
GET /users users.index index() Display a listing of the resource
GET /users/create users.create create() Show the form for creating a new resource
POST /users users.store store() Store a newly created resource
GET /users/{user} users.show show() Display the specified resource
GET /users/{user}/edit users.edit edit() Show the form for editing the specified resource
PUT/PATCH /users/{user} users.update update() Update the specified resource
DELETE /users/{user} users.destroy destroy() Remove the specified resource

Route Parameters

Route parameters allow you to capture segments of the URI within your route definition.

Required Parameters

PHP
Route::get('/user/{id}', function ($id) {
    return 'User ' . $id;
});

Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
    // Handle multiple parameters
});

Optional Parameters

PHP
Route::get('/user/{name?}', function ($name = 'Guest') {
    return $name;
});

Extending Routes

Register route files in `app/Providers/RouteServiceProvider.php`

public function register(): void
{
     $this->routes(function () {
        return [
            'routes/web.php', // default route file for web routes
            'routes/api.php', // default route file for api routes
            // Add more route files here...
        ];
    });
}
Note: Larite will autoload all route files bound via $this->routes() automatically.

Middleware System

You can create new middleware by running the below command:

Terminal
php larite make:middleware Authenticate

Register middleware in App\Kernel.php:

PHP
public $routeMiddleware = [
    'auth' => Authenticate::class,
    'web'  => WebMiddleware::class,
    'api'  => ApiMiddleware::class,
];

You can define middleware in any controller's constructor:

PHP
$this->middleware(['auth', 'web']);

Middleware per route

PHP
Route::get('/profile', [ProfileController::class, 'index'])->middleware('auth');

Middleware with Route Groups

PHP
Route::group(['middleware' => ['auth']], function () {
    Route::get('dashboard', [DashboardController::class, 'index']);
});

Middleware chaining with API routes

PHP
Route::middleware('api')
    ->group(function () {
        Route::get('/users', [UserController::class, 'index']);
});

Service Providers

Service Providers in Larite are the central place to register application services, such as caching, mail, routes, and custom services. All providers are listed in the config/providers.php file.

How to register a Service Provider

To register a service provider, add its class to the providers.php array. Larite will automatically load and resolve them.

PHP

<?php

// Providers configuration file
return [

    /* App Service Provider: core application services */
    App\Providers\AppServiceProvider::class,

    /* Route Service Provider: registers all route files */
    App\Providers\RouteServiceProvider::class,

    /* Custom Service Providers: add new providers here */

];
        

How to create a new Service Provider

You can create a new service provider using the Larite CLI:

Terminal

php larite make:provider CacheProvider
        

This will generate a new provider class CacheProvider inside app/Providers. You can then add its class to config/providers.php to have it automatically loaded during application bootstrapping.

Custom Facades

Facades in Larite provide a simple static interface to services registered in the container, such as cache, mail, or custom services.

Creating a Facade

PHP

namespace App\Facades;

use Larite\Support\Facade;

class Cache extends Facade
{
    // Define the service key this facade will resolve

protected static functiongetFacadeAccessor()
{
    return 'cache';
}
        

Registering the Facade

To register a facade, you first need to bind the underlying service in a service provider:

PHP

<?php
namespace App\Providers;

use App\Services\CustomeService;
use Larite\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    // Bind the service to the container
    public function register(): void
    {
        app()->bind('cache', CustomeService::class);  // here define facade name and the related class to bind
    }
}
        

Using the Facade

PHP

use App\Facades\Cache;

// Call methods on the service via the facade
Cache::put('key', 'value', 3600);
$value = Cache::get('key');
        

Facades allow you to use services with a clean static interface without manually resolving them from the container. Make sure the service is bound in a provider and the facade class defines the correct $service key.

Validation

Larite provides a Validator facade to validate request data easily. You can define rules for each field, check if validation fails, and redirect back with errors. Supported rules include required, email, unique, min, max, and more.

Example: validating a registration request with email and password fields. If validation fails, the user is redirected back with the validation errors.

PHP
use Lumite\Support\Facades\Validator;

$rules = [
    'email' => 'required|email|unique:users,email',
    'password' => 'required|min:6|max:20'
];

$validation = Validator::validate($request->all(), $rules);

if ($validation->fails()) {
    return redirect()->back()->withErrors($validation->errors());
}

Mail Support

Here is the Mail facade. Mails can be sent in Larite as shown below:

PHP
use Lumite\Support\Facades\Mail;

Mail::send('mail', [], function($mail) {
    $mail->subject('Welcome');
    $mail->to('admin@example.com', 'Admin');
    $mail->from('noreply@example.com', 'Larite');
    $mail->attachment('path/to/file.pdf');
});

Migrations

Create a new migration file

Terminal
php Larite make:migration create_users_table

This will generate a file in the database/migrations/ directory.

Define the schema

Each migration file contains up() and down() methods. You can define your table structure using the Blueprint class inside the up() method:

PHP
Migrate::create('users', function (Blueprint $table) {
    $table->increments('id');
    $table->string('name')->nullable();
    $table->string('email')->unique();
    $table->string('password');
    $table->timestamps();
});

Rollback the table

PHP
Migrate::dropIfExists('users');

Database Seeding

Larite supports seeders for populating your database with initial or dummy data.

Create a Seeder

Terminal
php Larite make:seeder AdminSeeder

Example Seeder

PHP
use App\Models\User;

class AdminSeeder extends Seeder
{
    public function run(): void
    {
        User::updateOrCreate([
            'email' => 'admin@example.com',
        ], [
            'name' => 'Admin',
            'password' => bcrypt('password'),
            'role' => 'admin',
        ]);
    }
}

Register the Seeder

After creating a seeder, register it inside DatabaseSeeder so it will be executed when you run the seeding command:

PHP
class DatabaseSeeder extends Seeder
{
    public function run(): void
    {
        // Call your custom seeders here
        $this->call([
           AdminSeeder::class
        ]);
    }
}

Run All Seeders

Terminal
php Larite db:seed

We can run specific seeder like below

Terminal
php Larite db:seed--class=AdminSeeder

Model Attributes

PHP
namespace App\Models;

use Lumite\Database\BaseModel;

class User extends BaseModel
{
    // Disable timestamps in fetch/create/update queries
    protected $timestamps = false;

    // Hide specific fields from query results
    protected $hidden = ['password'];
}

You can manage timestamps and hidden fields directly in your model:

  • $timestamps = false; → Disables automatic created_at and updated_at fields in ORM operations.
  • $hidden → An array of attributes you want excluded from query results (e.g., passwords).

Queries & ORM

Larite offers an ORM for interacting with your database using expressive and chainable syntax.

Fetching Data (ORM)

PHP

// Truncate table
User::truncate();

// Get all users
$users = User::get();

// Find a specific user by ID
$user = User::find(1);

// Find a specific user by ID or fail
$user = User::findOrFail(1);

// Get first user 
$user = User::first();

// Get first or fail user 
$user = User::firstOrFail();

// Get users with conditions
$activeUsers = User::where('status', 'active')->get();

// Get user with array conditions
$user = User::where(['age' => '20'])->get();

// First matching result
$user = User::where('email', '=', 'john@example.com')->first();

// Get specific voloumn's values directly
$userName = User::value('name');

// Create a user (returns user object)
$user = User::create([
    'name' => 'Test User',
    'email' => 'user@gmail.com',
    'password' => bcrypt('123456'),
]); // user object

// Insert a user (for single record)
$user = User::insert([
    'name' => 'Test User',
    'email' => 'user@gmail.com',
    'password' => bcrypt('123456'),
]); // true, false

// Insert multiple users (bulk insert)
$users = User::insert([
    [
        'name' => 'Test User 1',
        'email' => 'user1@gmail.com',
        'password' => bcrypt('123456'),
    ],
    [
        'name' => 'Test User 2',
        'email' => 'user2@gmail.com',
        'password' => bcrypt('123456'),
    ],
    [
        'name' => 'Test User 3',
        'email' => 'user3@gmail.com',
        'password' => bcrypt('123456'),
    ],
]); // true, false


// Insert a user and get the inserted ID
$user = User::insertGetId([
    'name' => 'Test User',
    'email' => 'user@gmail.com',
    'password' => bcrypt('123456'),
]); // return user id

Query Builder (DB Facade)

PHP
use Lumite\Support\Facades\DB;

// Truncate table
DB::table('users')->truncate();

// Get all users
$users = DB::table('users')->get();

// Get first user 
$user = DB::table('users')->first();

// Get first user or fail
$user = DB::table('users')->firstOrFail();

// Find user with id  
$user = DB::table('users')->find('id');

// Find or fail user with id
$user = DB::table('users')->findOrFail('id');

// Get single user name
$userName = DB::table('users')->value('name');

// Paginate results
$users = DB::table('users')->paginate(10);

// Get users with conditions
$activeUsers = DB::table('users')->where('status', 'active')->get();

// Create a new user (returns user object)
$user = DB::table('users')->create([
    'name' => 'Test User',
    'email' => 'user@gmail.com',
    'password' => bcrypt('123456'),
]); // user object

// Insert a user (for singel record)
$user = DB::table('users')->insert([
    'name' => 'Test User',
    'email' => 'user@gmail.com',
    'password' => bcrypt('123456'),
]); // true, false

// Insert multiple users (bulk insert)
$users = DB::table('users')->insert([
    [
        'name' => 'Test User 1',
        'email' => 'user1@gmail.com',
        'password' => bcrypt('123456'),
    ],
    [
        'name' => 'Test User 2',
        'email' => 'user2@gmail.com',
        'password' => bcrypt('123456'),
    ],
    [
        'name' => 'Test User 3',
        'email' => 'user3@gmail.com',
        'password' => bcrypt('123456'),
    ],
]); // true, false

// Insert a user and get inserted ID
$user = DB::table('users')->insertGetId([
    'name' => 'Test User',
    'email' => 'user@gmail.com',
    'password' => bcrypt('123456'),
]); // user id

Where Clauses

Larite supports a wide variety of where clauses for filtering data. You can use these with Models (ORM) or directly with the DB facade.

Note: You can chain multiple where clauses and use variations like whereYear, whereMonth, whereBetween, orWhere, etc.

ORM (Model) Examples

PHP
// Basic where
$users = User::where('status', 'active')->get();

// orWhere
$users = User::where('status', 'active')->orWhere('role', 'admin')->get();

// whereIn
$users = User::whereIn('id', [1, 2, 3])->get();

// whereNull / whereNotNull
$users = User::whereNull('deleted_at')->get();
$users = User::whereNotNull('email_verified_at')->get();

// whereDate / orWhereDate
$users = User::whereDate('created_at', '2025-08-13')->get();

$users = User::orWhereDate('updated_at', '2025-08-01')->get();

// whereMonth / whereYear
$users = User::whereMonth('created_at', 8)->get();

$users = User::whereYear('created_at', 2025)->get();

// whereDay / whereDayOfWeek / whereTime
$users = User::whereDay('created_at', 23)->get();

$users = User::whereDayOfWeek('created_at', 2)->get();

$users = User::whereTime('created_at', 12:00:00)->get();


// whereBetween / whereNotBetween / orWhereBetween / orWhereNotBetween
$users = User::whereBetween('age', [18, 25])->get();

$users = User::whereNotBetween('age', [26, 35])->get();

$users = User::orWhereBetween('score', [50, 100])->get();

$users = User::orWhereNotBetween('score', [0, 49])->get();

// having clause
$users = User::having('total', '>', 100)->get();

Query Builder (DB Facade) Examples

PHP
use Lumite\Support\Facades\DB;

// Basic where
$users = DB::table('users')->where('status', 'active')->get();

// whereIn
$users = DB::table('users')->whereIn('id', [1,2,3])->get();

// whereNull / whereNotNull
$users = DB::table('users')->whereNull('deleted_at')->get();

// whereDate / whereMonth / whereYear / whereDay / whereDayOfWeek / whereTime
$users = DB::table('users')->whereDate('created_at', '2025-08-13')->get();

$users = DB::table('users')->whereMonth('created_at', 8)->get();

$users = DB::table('users')->whereYear('created_at', 2025)->get();

$users = DB::table('users')->whereDay('created_at', 22)->get();

$users = DB::table('users')->whereDayOfWeek('created_at', 2)->get();

$users = DB::table('users')->whereTime('created_at', 12:00:00)->get();


// whereBetween / whereNotBetween
$users = DB::table('users')->whereBetween('age', [18,25])->get();

$users = DB::table('users')->orWhereNotBetween('score', [0,49])->get();

// having clause
$users = DB::table('users')->having('total', '>', 100)->get();

Defining Relationships

One-to-One

PHP
public function profile()
{
    return $this->hasOne(Profile::class, 'user_id');
}

One-to-Many

PHP
public function posts()
{
    return $this->hasMany(Post::class, 'user_id');
}

Inverse (Belongs To)

PHP
public function user()
{
    return $this->belongsTo(User::class, 'user_id');
}

Belongs To Many

PHP
public function roles()
{
    return $this->belongsToMany(Role::class,
        'role_user', 'user_id',
        'role_id', 'id',
        'id');
}
Note: Eager loading is supported and implemented.

CLI Commands

Terminal
php Larite make:auth auth
php Larite make:model User
php Larite make:controller PostController
php larite make:controller PostController --resource
php Larite make:migration create_posts_table
php larite make:seeder AdminSeeder // To create seeder
php larite db:seed // to run all seeders
php larite db:seed --class=AdminSeeder // to run specific seeder
php Larite make:provider CacheProvider
php Larite migrate
php Larite migrate:rollback
php larite make:middleware Authenticate
php larite make:command SyncUser
php larite schedule:run
php Larite route:list
php Larite route:list --method=GET // to list specific method's routes
php Larite route:list --method=POST // to list specific method's routes
                        

Task Scheduler

Larite supports a simple scheduler.

PHP
public function schedule(Schedule $schedule): void
{
    $schedule->command(SyncUser::class)->everyMinute();
}

Supported Schedule Methods

Method Cron Expression Description
everyMinute() * * * * * Every minute
everyFiveMinutes() */5 * * * * Every 5 minutes
everyTenMinutes() */10 * * * * Every 10 minutes
everyFifteenMinutes() */15 * * * * Every 15 minutes
everyThirtyMinutes() 0,30 * * * * Every 30 minutes
hourly() 0 * * * * Once per hour
daily() 0 0 * * * Once a day at midnight
twiceDaily() 0 0,12 * * * Once at 12:00 AM and once at 12:00 PM every day
weekdays() 0 0 * * * Once a week, at midnight (00:00) every weekday — Monday through Friday.
weekends() 0 0 * * 6,0 Once in weekends, at midnight (00:00) every Saturday and Sunday
weekly() 0 0 1 * * Once a week (Sunday midnight)
monthly() 0 0 * * 0 Once a month
yearly() 0 0 * * 0 Once a year

Exception Handling

Your global exception handling logic is located at:

PHP
// app/Exceptions/Handler.php
protected bool $exception = true; // true, false

public function handle(Throwable $e)
{
    $this->render($e, function (Throwable $e) {
        if ($e instanceof NotFoundException) {
            response()->json(['NotFoundException' => $e->getMessage()], 404);
        } elseif ($e instanceof ValidationException) {
            response()->json(['ValidationException' => $e->getErrors()], 422);
        } elseif ($e instanceof AuthException) {
            response()->json('Unauthenticated.', 401);
        } else {
            response()->json(['Exception' => 'Something went wrong.'], 500);
        }
    });
    return true;
}

Larite Welcome Page

Here is the Larite welcome page view.

Larite Welcome Page

ChatGPT Review

Here is the ChatGPT comparison after reviewing the complete Larite's code.

ChatGPT Review

Performance Benchmark

We ran backend performance benchmarks to compare Larite and Laravel under the same environment (Laragon, Apache 2.4, PHP 8.x, MySQL 8.x). The goal was to measure relative framework overhead, not absolute production values.

Test Setup

  • Tool: ApacheBench (ab)
  • Requests: 1,000
  • Concurrency: 50 users
  • Database Query: Fetching 20,000 records

Results

Metric Larite Laravel
Requests per second 14.24 7.24
Average latency (ms) 70 138
Peak memory usage ~27 MB ~48 MB
Execution time (query load) 328 ms 364 ms

Conclusion

In concurrency benchmarks (1,000 requests with 50 users), Larite handled double the throughput of Laravel while maintaining lower latency and a smaller memory footprint. This confirms Larite as a truly lightweight alternative for building high-performance PHP applications.

Note: These benchmarks were conducted on localhost (Laragon, Windows). Results may vary based on server configuration and production environment. The comparison demonstrates relative framework efficiency under identical conditions.

Contribute

Want to improve this Laravel-style lightweight framework? Submit a PR or open an issue. All contributions are welcome!

Open Source: Larite is open-source and licensed under the MIT license.
PHP 8+
MVC Architecture
Laravel-Style
Secure