Skip to content
LibxaFrame

LibxaFrame

The framework itself.

Version
0.11.2
Category
Core
Requires
PHP 8.3
Install
composer require libxa/framework

LibxaFrame is a PHP framework that looks a great deal like Laravel and differs in enough places to catch you out. The differences are the useful thing to know about it, so they are listed plainly below.

Installing

composer create-project libxa/libxa my-app

Or with the installer, which does the rest of the setup too:

libxa new my-app

The layout

src/
  app/            controllers, middleware, requests, models
  bootstrap/      the container is built here
  config/         app, auth, cache, database, mail, queue, session
  database/migrations/
  public/         DOCUMENT ROOT: index.php, .htaccess, build/
  resources/views/
  routes/web.php
  storage/        logs, cache, compiled views, sessions
libxa             the CLI

Note src/app/ and src/public/, not app/ and public/. resource_path() resolves to src/resources, and a top-level resources/ directory is read by nothing.

Routing

$router->get('/posts/{slug}', [PostController::class, 'show'])
    ->where('slug', '[a-z0-9-]+');

$router->group(['middleware' => 'auth'], function (Router $router) {
    $router->get('/dashboard', [DashboardController::class, 'index']);
});

Routes match in registration order, with no specificity sorting. A parameter registered before a literal swallows it:

$router->get('/posts/{slug}', ...);
$router->get('/posts/new', ...);   // unreachable

Parameters stop at a slash, so a catch-all needs saying so:

$router->get('/{path}', [PageController::class, 'notFound'])->where('path', '.*');

Controllers

Plain classes with no base to extend.

class PostController
{
    public function index(): Response
    {
        return view('posts.index', ['posts' => Post::all()]);
    }
}

Response has getStatus() and getContent(). Not getStatusCode(): that is Symfony's name and it does not exist here.

Blade

Mostly what you expect, with two differences that bite.

@extends takes exactly one argument. A second is a parse error, not an ignored argument, and it surfaces as a syntax error inside a compiled file nowhere near the template you wrote.

{{ }} is inert inside a @php block: there you are writing PHP, so the braces are just characters in a string.

A compiled view is served until it is recompiled, including one containing a parse error, so php libxa view:clear is worth doing reflexively whenever a change is not appearing.

Atlas

DB::table('posts')->where('published', true)->orderByLatest()->get();
DB::table('posts')->find($id);

Rows come back as stdClass, not arrays.

A migration whose class name does not match its filename is skipped without an error. When a column never appears, check that pairing first.

Console

php libxa serve
php libxa migrate
php libxa make:controller Foo
php libxa route:cache
php libxa view:clear
php libxa key:generate

Run php libxa list for the rest.

Deploying

Point the document root at src/public/ and send anything that is not a real file to index.php.

Locally php libxa serve passes src/public/router.php to PHP's built-in server, which emulates that rewrite, so a missing rule only shows up once deployed: the home page works and every other route 404s. The starter kit ships the Apache rules; for nginx it is try_files $uri $uri/ /index.php?$query_string;.

Subdirectory installs do not work. Routes match on the full request path, so a request for /my-app/about is looked up as /my-app/about and matches nothing. Use a subdomain or a virtual host.