Introduction & Philosophy

phpLiteCore is a modern, lightweight, and fast PHP framework for building web applications of any size.

The framework follows a clear design philosophy as defined in its constitution (Section 2):

Core Structure

The framework uses a clear file structure to separate responsibilities (Constitution Section 3 & 4):

Routing System

All web routes are defined in the routes/web.php file. This file registers routes to the $router object.

Router.php matches the current URL against the registered routes and dispatches the appropriate controller action.

Route Examples

Basic Routes (GET / POST):

// routes/web.php
$router->get('/', ['HomeController', 'index']);
$router->get('/about', ['AboutController', 'index']);
$router->post('/posts', ['PostController', 'store']);

Dynamic Routes (and Order):

Important (Route Order): Static routes (like /posts/create) must always be defined before dynamic routes (like /posts/{id}). Otherwise, the router will mistakenly treat "create" as an ID value.
// routes/web.php (Correct Example)

// (Correct) Static route first
$router->get('/posts/create', ['PostController', 'create']);

// (Correct) Dynamic route second
$router->get('/posts/{id}', ['PostController', 'show']);

Controllers

Controllers reside in app/Controllers and are responsible for handling request logic (Constitution Section 2 - MVC).

All controllers should extend BaseController. This gives them access to the application instance ($this->app) and the template rendering method $this->view().

Full Example: HomeController.php

This is a perfect example demonstrating "Strict Separation of Concerns" (Constitution Section 2).

<?php
namespace App\Controllers;

use App\Models\User;

class HomeController extends BaseController
{
    public function index(): void
    {
        // 1. Business Logic
        $user = User::find(1);

        // 2. Prepare ALL translated variables for the view
        $pageTitle = $this->app->translator->get('messages.home.page_title');
        $heroSubtitle = $this->app->translator->get(
            'messages.home.hero_subtitle',
            ['name' => $user->name ?? $this->app->translator->get('messages.guest')]
        );
        $versionLabel = $this->app->translator->get('messages.home.version_label');

        // 3. Render the view, passing all final translated strings.
        $this->view('home', compact(
            'pageTitle',
            'heroSubtitle',
            'versionLabel'
        ));
    }
}

Models & Database

The framework uses the **"Hybrid Active Record"** pattern (Constitution Section 2).

This is achieved by having all models (like User.php and Post.php) extend src/Database/Model/BaseModel.php.

Due to the extensive nature of this component, a separate, detailed guide is provided.

Go to: Comprehensive Query Builder Guide

The new guide explains in detail how to perform:

Views & Templates

Views follow the "Strict Separation" rule (Constitution Section 2 - MVC):

Example: View File views/themes/default/post.php

Data Contract Check (1.6.1): Notice the use of $post->title (object access) because it receives an Object from PostController.
<article>
    <h1><?= htmlspecialchars($post->title) ?></h1>
    <p><?= nl2br(htmlspecialchars($post->body)) ?></p>
    <hr>

    <!-- Uses translated variables passed from the controller -->
    <small><?= htmlspecialchars($publishedOnText) ?> <?= date('Y-m-d', strtotime($post->created_at)) ?></small>

</article>
<a href="/posts"><?= htmlspecialchars($backLinkText) ?></a>

Translation System (i18n)

Translation is **mandatory** for all user-facing text (Constitution Section 1.5).

The framework uses a modular system with lazy loading.

"Dot Notation" Mechanism

To access a translated string, use $translator->get('filename.key').

Example 1: Nested Key

// Key 'page_title' inside 'home' array in 'messages.php'
$title = $this->app->translator->get('messages.home.page_title');
// $title = "Welcome to phpLiteCore"

Example 2: Lazy Loading

// The translator will automatically load "validation.php"
$error = $this->app->translator->get('validation.required');
// $error = "The {{field}} field is required."

Example 3: Passing Placeholders

// Key: 'messages.posts.not_found' => 'Post with ID {{id}} not found.'
$id = urldecode($id_from_url);

$message = $this->app->translator->get(
    'messages.posts.not_found',
    ['id' => $id]
);

// $message = "Post with ID {decoded_id} not found."

Input Validation

The framework provides a simple Validator class (in src/Validation/Validator.php) which is now connected to the translation service.

Example: From PostController

// Inside the store() method in PostController

try {
    $rules = [
        'title' => 'required|min:5',
        'body'  => 'required|min:10',
    ];

    $validatedData = Validator::validate($_POST, $rules);

    // (Success) Create the post...
    $post = new Post($validatedData);
    $post->save();
    Response::redirect('/posts');

} catch (ValidationException $e) {
    // (Failure) $e->getErrors() will contain the translated errors
    http_response_code(422);
    echo json_encode(['errors' => $e->getErrors()]);
}

Error Handling

Error handling is managed by src/Bootstrap/ErrorHandler.php (Constitution Section 2).

Production Environment (ENV=production)

The system hides details, logs the error, emails the developer, and displays a generic, translated error page.

404 Not Found Errors

Trigger a translated 404 page from any controller using Response::notFound().

// Use the default translated 404 message
Response::notFound();

// Use a custom (must be pre-translated) message
$message = $this->app->translator->get('messages.posts.not_found', ['id' => $id]);
Response::notFound($message);

Asset Management

The framework relies on Webpack, NPM, and SCSS (Constitution Section 2).

Dependencies are defined in package.json, and build settings are in webpack.config.js.

Workflow

  1. Modify source files: resources/js/app.js or resources/scss/app.scss.
  2. Run npm run dev (for development) or npm run build (for production).
  3. Webpack builds the final files into public/assets/app.js and public/assets/app.css.
<!-- views/partials/header.php -->
<head>
    <meta charset="UTF-8">
    <title><?= htmlspecialchars($pageTitle ?? 'phpLiteCore') ?></title>

    <!-- Include the built CSS file -->
    <link rel="stylesheet" href="/assets/app.css">
</head>