Skip to content

Releases: luminovang/framework

3.7.0

12 Dec 12:48

Choose a tag to compare

Full Changelog: 3.6.8...3.7.0

Fixes

Fixed incorrect mixing of PHP 8.1 standards with PHP 8.0, which caused runtime errors.


New Features


PHP Layout Composition

Improved the PHP layout composition class and introduced new helper features.
The layout object is now automatically available inside PHP template files when App\Config\Template->enableDefaultTemplateLayout is enabled.

Dynamic Template Placeholders

Placeholders defined within a layout section are now resolved automatically when extending or rendering the layout with options:

<?php $this->layout->begin('title'); ?>
<h1>{{ placeholder }}</h1>
<?php $this->layout->end('title'); ?>

Smarty Template Extension

Improved the Smarty extension to provide simpler access to functions and classes, giving it behavior in Luminova closer to Twig.

Object Method Access

You can now call object methods directly without assigning the object to a Smarty variable first:

{{ $self.app->doFoo()->getBar() }}

Smarty & Twig Template Extension

Improved both extensions with a single configuration point for managing custom extensions and modifiers.
Template caching is now handled by Luminova for consistent behavior and integration with the static URL cache system.


Routing System

Optimized the routing system. All HTTP method helpers are now static.
Dependency Injection in routing has been improved to honor default parameter values when a dependency cannot be resolved.

Added the Router::isPrefix(...) helper for checking URI prefixes.

Static HTTP Helpers:

  • get — HTTP GET
  • post — HTTP POST
  • put — HTTP PUT
  • patch — HTTP PATCH
  • delete — HTTP DELETE
  • head — HTTP HEAD
  • options — HTTP OPTIONS
  • any — Any valid HTTP method
  • middleware — Before-middleware handler
  • after — After-middleware handler
  • guard — CLI middleware handler
  • capture — Custom HTTP methods
  • command — CLI command
  • group — CLI command grouping
  • bind — HTTP URI group binding
  • onError — HTTP error handler

HTTP Message Stream

Optimized the message stream class, added a new buffer method, and moved the class namespace from
Luminova\Utility\Storage\Stream to Luminova\Http\Message\Stream.


Global Import Function

The global import() function now supports promise resolving:

use function \Luminova\Funcs\import;

import('view:template', promise: true)
  ->then(fn(string $html) => print($html))
  ->catch(fn(Throwable $e) => echo $e->getMessage());

3.6.8

22 Nov 15:23

Choose a tag to compare

Full Changelog: 3.6.6...3.6.8

Version 3.6.8 brings a major cleanup across Luminova’s core. Many parts were renamed, optimized, or fixed, and several new helper classes were added, including Password, String, and the improved error-handling system. The template view engine and the core exception layer also received substantial tuning.

Default HTTP error templates now support grouped pages using 4xx.php and 5xx.php, replacing the old 404.php and 500.php pattern.


Fixes

Routing System

Fixed an issue where routes defined with HTTP HEAD method were incorrectly returning 404 errors.


New Features

HTTP Controller Methods

HTTP controller routable methods can now return Psr\Http\Message\ResponseInterface, Luminova\Interface\ViewResponseInterface, or the traditional int.

Example

Using Luminova\Template\Response class.

use Luminova\Attributes\Route;
use Luminova\Http\Message\Response;
use Psr\Http\Message\ResponseInterface;

#[Route('/api/hello', methods: ['GET'])]
public function hello(): ViewResponseInterface
{
  return new Response('Hello world', 200);
}

Routing System

Added a new pattern method to define and manage custom URI segment placeholders.
This allows you to create reusable patterns for route parameters, improving maintainability and reducing repetition of patterns.

// In App\Application::onCreate()
Router::pattern('slug', '[a-z0-9-]+');  

// In App\Controllers
#[Luminova\Attributes\Route('/blog/(:slug)', methods: ['GET'])]
public function blog(string $slug): int 
{
  // Handle blog route using the slug value
}

Note:
Once defined, the slug pattern can be reused across multiple routes, ensuring consistent validation.


Password Helper

A new Password helper has been added to handle all password-related operations in one place.

Now:

use Luminova\Security\Password;

$hash = Password::hash('pass');
Password::verify('pass', $hash);

// Additional utilities:
Password::rehash('pass', $hash);
Password::strength('pass');
Password::isCompromised('pass');

// and more...

Before:

Crypter::password('pass');
Crypter::isPassword('pass', 'hash');

Proxy Helper

A dedicated Proxy helper is now available for checking and validating HTTP/SOCKS proxies.

Now:

use Luminova\Utility\Proxy;

$proxy = '';
Proxy::validate($proxy);
Proxy::ping($proxy);

// and more...

String Helper

A new Str helper provides object-based string manipulation features.

Now:

use Luminova\Utility\String\Str;

$str = Str::of('peter');

echo $str->length();         // 5
echo $str->toUpperCase()
         ->trim();           // PETER

// and more...

Backend Session Class

The Session class now supports role-based access control, with methods for finer-grained permission management:

  • roles(array $roles)
    Assign user roles to the session.

  • getRoles(): array
    Retrieve all roles currently stored in the session.

  • guard(array $roles, int $mode = Session::GUARD_ANY, ?callable $onDenied = null): bool
    Validate roles against access rules. Returns true if access is denied (fail-fast pattern), false if access is granted.

  • toSessionId(string $id, string $algo = 'sha256')
    Convert a string into a valid PHP session ID.

    Example:

    Convert a system identifier into a valid PHP session ID for persistent CLI logins.

    use Luminova\Command\Terminal;
    use Luminova\Sessions\Session;
    
    $sid = Session::toSessionId(Terminal::getSystemId());

    Supported Guard Modes:

    • Session::GUARD_ANY (default): Access granted if at least one role matches.
    • Session::GUARD_ALL: Access granted only if all roles match.
    • Session::GUARD_EXACT: Access granted only if all and only the specified roles match.
    • Session::GUARD_NONE: Access granted only if none of the roles are present.

Example:

if ($session->guard(['admin', 'moderator'], Session::GUARD_ALL)) {
    throw new AccessDenied('Insufficient privileges.');
}

PHP Route Attribute

A new $aliases property has been added to the Route attribute to define multiple alternative URI patterns for the same controller method.

Before (using multiple attributes)

Previously, to map several URIs to the same method, you had to repeat the Route attribute:

// /app/Controllers/Http/ExampleController.php

use Luminova\Attributes\Route;

#[Route('/', methods: ['GET'])]
#[Route('/home', methods: ['GET'])]
#[Route('/default', methods: ['GET'])]
#[Route('/dashboard', methods: ['GET'])]
public function home(): int 
{
  return $this->view('index');
}

Now (using aliases)

You can achieve the same result with a single attribute, improving readability and reducing duplication:

// /app/Controllers/Http/ExampleController.php

use Luminova\Attributes\Route;

#[Route('/', methods: ['GET'], aliases: [
  '/home',
  '/default'
  '/dashboard'
])]
public function home(): int 
{
  return $this->view('index');
}

PHP Prefix Attribute

The Prefix attribute now supports a new $exclude property that allows you to specify URI prefixes to exclude from controller matching. This removes the need for complex negative-lookahead patterns.

Before (manual regex exclusions)

// /app/Controllers/Http/MainController.php

use Luminova\Attributes\Prefix;

#[Prefix(pattern: '/(?!api(?:/|$)|admin(?:/|$)).*')]
class MainController extends Controller
{
}

Now (using the built-in exclude list)

// /app/Controllers/Http/MainController.php

use Luminova\Attributes\Prefix;

#[Prefix(pattern: '/(:base)', exclude: [
    'api',
    'admin'
])]
class MainController extends Controller
{
}

Full Changes documentation.

3.6.7

05 Aug 11:17

Choose a tag to compare

Full Changelog: 3.6.6...3.6.7

New Features

Core Application Class

Introduced a new static method: onShutdown().
This method acts as a hook that runs when the application terminates due to a fatal error or explicit shutdown. It allows the application to inspect the error and choose to:

  • Return false to suppress default framework handling.
  • Return true to let the framework handle the error normally.

Example:

// /app/Application.php
namespace App;

use Luminova\Core\CoreApplication;

class Application extends CoreApplication
{
    public static function onShutdown(array $error): bool 
    {
        return true;
        // Or handle shutdown and return false
    }
}

This gives developers more control over graceful shutdowns in critical situations.


Optimizations

Global Helper Functions

Improved performance and flexibility of global functions.

  • import() now supports resolving virtual paths using predefined URI-style schemes. This simplifies file inclusion across common system directories.

Examples:

import('app:Config/settings.php');
import('view:layouts/header.php');
import('package:brick/math/src/BigNumber.php');

This update enhances code readability and keeps file paths consistent across modules.
You can still pass a full file path if preferred. The scheme prefix is entirely optional.

Full Changes

3.6.6

25 Jul 16:20

Choose a tag to compare

This release introduces background task handling, improved CLI tooling, and namespace support for global functions.

View Full Changelog – Complete list of changes in Luminova 3.6.6


New Features

  • Background Task Queue
    Built-in task queue system with novakit CLI support. Run background tasks with commands like php novakit task:run.
    Includes a Luminova\Models\Task model, default App\Tasks\TaskQueue controller, and optional Luminova\Interface\QueueableInterface.

  • Webhook Helper
    New class for sending and receiving webhook requests with support for signature verification and payload decoding.

  • Global Helper Function
    object_column - To get column(s), from an object. Similar to PHP array_column for designed for object.


Improvements

  • Namespaced Global Functions
    All global functions are now under Luminova\Funcs\*.
    Example:

    use function Luminova\Funcs\root;
    root('/public/', 'robots.txt');
  • Novakit CLI Enhancements

    • task -h now shows grouped commands helps.
    • list now accepts --command or -c to filter output.
  • Function Optimizations

    • root() supports appending a file.
    • import() allows control over error and include/require behavior.
    • get_column() now returns objects when used with objects.

Removed

  • Luminova\Command\Terminal::explain() – use perse() instead.
  • Luminova\Database\Builder->caching() – use cacheable() instead.

Fixes

  • table Command
    Fixed blank output when using 0 as the column value.

Full Changelog: 3.6.4...3.6.6

3.6.5

07 Jul 12:04

Choose a tag to compare

Full Changelog: 3.6.4...3.6.5

Optimization

Database Drivers

  • Improved getType method in both MySQLi and PDO drivers to accurately detect binary values, especially those containing non-printable characters.

Database Builder Class

Significant optimizations were made to the query builder parsing logic and method signatures:

  • join – Made parameter types less strict, now accepts null for join type argument.

  • Improved clause construction in:

    • onClause
    • match
    • clause
    • against
    • orderAgainst
  • unionAlias – Improved how aliases are generated for grouped union queries, ensuring consistent and predictable results.


Fixed

Database Drivers

  • Updated MySQLi emulate prepares to loosen the binding position requirement. Parameter bindings no longer need to match the order of positional placeholders in the query strictly.

Before Fix (would fail or return incorrect results):

$sql = 'SELECT * FROM users WHERE uid = :uid AND phone = :phone AND email = :email LIMIT 1';

$result = (new Luminova\Database\Connection())
    ->database()
    ->prepare($sql)
    ->bind(':email', '[email protected]')
    ->bind(':uid', 100)
    ->bind(':phone', '08036750000')
    ->fetchNext();

// Or Using Builder Class
$result = Luminova\Database\Builder::query($sql)->execute([
    'email' => '[email protected]',
    'uid'   => 100,
    'phone' => '08036750000',
], RETURN_NEXT);

In previous versions, because :uid appears before :phone and :email, but the bindings were not ordered to match, the result would be empty or incorrect.

3.6.4

25 Jun 17:30

Choose a tag to compare

Full Changelog: 3.6.3...3.6.4

This update includes micro-optimizations and internal fixes to the Database Builder class, focusing on performance improvements, safer state handling, and more consistent transaction behavior.


New

  • safeMode – Enables internal transaction wrapping for insert, update, delete, truncate, drop, and temp operations. Use this when you want safe commit and rollback behavior without manually managing transactions.

  • release – Internally releases any active transaction. Similar to rollback(), but returns false on error instead of throwing an exception.


Optimized

  • Improved query result caching. Cache is now checked before executing any query. This reduces unnecessary query processing and improves performance.

  • Replaced foreach with for loops where applicable for faster iteration over numerically indexed arrays.


Fixed

  • Resolved minor issues in the Database Builder that affected consistency and state resets during operations.

Changed

  • Internal transaction handling has been moved to the new safeMode method.
  • Removed all optional transaction arguments from methods that previously supported inline transaction enabling.

You can now explicitly use:

$builder = Builder::table('foo')
    ->transaction();

// ...perform operations
$builder->commit();

Or simply call:

Builder::table('foo')
    ->safeMode(true);

// ...perform operations

to auto-wrap safe operations.

Affected Methods:

  • temp() – Removed transaction argument.
  • truncate() – Removed transaction argument.
  • insert() – Removed automatic transaction when inserting more than one row.

Deprecated

  • caching() – Deprecated in favor of the clearer cacheable() method.

3.6.3

22 Jun 13:50

Choose a tag to compare

Full Changelog: 3.6.2...3.6.3

Luminova Database Update v3.6.3

Major rewrite of the Database Management System with performance optimizations, enhanced query building, and modern usage patterns.

New Features

Database Builder Class

  • get()
    Executes the prepared query and returns the result. Acts as a unified shortcut to trigger execution, similar to calling fetch(), stmt(), or promise().

    Used After:

    • select() — Fetch multiple records.
    • find() — Fetch a single record.
    • total() — Count total rows.
    • sum() — Sum numeric column.
    • average() — Average numeric column.

Call get() when you want the final result immediately after building the query.

  • union()
    Supports combining multiple queries using UNION.

  • unionAll()
    Supports combining multiple queries using UNION ALL.

  • columns()
    Allows defining specific or mapping columns to use with union() and unionAll().

  • promise()
    Executes the query and returns a promise object that resolves to the result.

  • distinct()
    Enables DISTINCT selection, changing SELECT to SELECT DISTINCT.

  • onCompound()
    Supports compound join conditions, such as ON (column1 = foo OR column2 = bar).

  • freeStmt()
    Allows manually freeing the statement object after execution using the stmt() method.


Database Drivers

  • connect() Method
    Now supports manual connection. A connection is no longer automatically established when a driver instance is created, giving you more control over when to connect.

  • MySQLi new Feature

    • Added support for Emulate Prepares, matching PDO’s behavior when reusing the same named placeholder multiple times.
    • Supports binding by reference, allowing bound values to be modified before execution, for dynamic queries.

Optimizations

Database Builder Class

Several builder methods have been enhanced to support closures, allowing dynamic values to be evaluated at execution time.

  • copy()
    Now supports conditional copying from one table to another with support for WHERE clauses, ON DUPLICATE, REPLACE INTO, and optional transaction wrapping.

  • execute()
    Updated to support RETURN_* return modes and FETCH_* fetch modes. Also adds support for escaping placeholders when needed.

  • escape()
    Improved to handle resources (e.g., streams) and closures that return dynamic values, making it more flexible for handling binary, large, or delayed content.


Return Types Changes

Database Builder

Several methods in Luminova\Database\Builder no longer execute the query directly. Instead, they now return an instance of the Builder class, allowing for further method chaining and manual execution.

To execute the query and retrieve results, you must now explicitly call one of the following methods:

  • get() — to fetch results
  • fetch() — Fetch one row at a time (for while loops or streaming).
  • stmt() — to get the prepared statement object ready to read result.
  • promise() — to defer execution result as a promise

Affected Methods:

  • select() – Prepares selected columns for fetching multiple results.
  • find() – Prepares selected columns for a single result.
  • total() – Prepares a query to count total records.
  • sum() – Prepares a query to compute the sum of a column.
  • average() – Prepares a query to compute the average of a column.

For full changes visit https://luminova.ng/docs/3.5.6/

3.6.2

10 Jun 00:44

Choose a tag to compare

Full Changelog: 3.6.1...3.6.2

New Features

Database Builder Class

  • escape() Method
    Added support for safely escaping values for SQL queries.
    Handles strings, numbers, nulls, booleans, arrays (JSON), and raw expressions.

Template View Class

  • setAssetDepth() Method
    Allows manual control of how many ../ prefixes are added to asset or URI paths.
    Overrides the default auto-detection based on URI segments.

Optimizations

Database Builder Class

Refined return types for better consistency and reliability:

  • average() now returns int|float and defaults to 0 on failure (previously false).
  • sum() now returns int|float and defaults to 0 on failure (previously false).
  • total() now returns int and defaults to 0 on failure (previously false).

3.6.1

31 May 12:12

Choose a tag to compare

Full Changelog: 3.5.9...3.6.1

New Features

Database Connection Class

Introduced connection sharding support, enabling database operations to route through specific servers based on user ID, region, or custom logic.

  • Connection::shard(string $key, bool $fallback = false, ...): Manually connect to a specific shard server using a unique key.

Database Configuration Class

Added sharding-related configuration options:

  • static bool $connectionSharding – Globally enable or disable automatic sharding.
  • static bool $shardFallbackOnError – Whether to fallback to backup servers if the selected shard is unreachable.
  • static getShardServerKey(): string – Returns the shard key used to determine the target database server.

cURL HTTP Client

Added support for parallel requests using PHP’s CurlMultiHandle, allowing you to queue and execute multiple HTTP requests concurrently.

  • Uses PHP native curl_multi_* functions.
  • Ideal for executing multiple requests in one network cycle.
  • Non-blocking and efficient for APIs and bulk operations.
use Luminova\Http\Client\Curl;
use Luminova\Http\Method;

$multi = Curl::multi();

$multi->add(Method::GET, 'https://example.com')
    ->add(Method::POST, 'https://example.org')
    ->run();

print_r($multi->getResponses());

Optimizations

NovaLogger Class

The Luminova logging system has been enhanced to optionally include log context when sending messages to Telegram.
You can enable this feature by:

  • Setting the environment variable:
    logger.telegram.send.context=true

  • Or toggling the static property in your configuration class:
    App\Config\Logger::$telegramSendContext = true;

Use Case:
Helps provide detailed debugging information in Telegram alerts without cluttering logs by default.


Renamed

Database Configuration Properties

The following properties have been renamed for clarity and consistency:

  • Environment File: database.pdo.enginedatabase.pdo.version
  • Configuration Array Key: pdo_enginepdo_version
  • Connection Servers and Backup: static array $databaseBackupsstatic array $databaseServers

These changes help better reflect their purpose—defining the PDO driver version (e.g., mysql, pgsql, etc.).


Corrections

Luminova Console Command

All NovaKit commands extending BaseConsole have been updated and should be updated for consistency.
The command identifier has been moved from the $name property to the protected $group property to align with the BaseCommand structure.

Why this matters:
Ensures consistent behavior and cleaner command registration across all CLI components.


ToDo

Update Your Database Configuration

To enable sharding support, update your Database Configuration Class with the following properties and method:

// /app/Config/Database.php

namespace App\Config;

use Luminova\Core\CoreDatabase;

class Database extends CoreDatabase
{
    /**
     * Enable or disable global connection sharding.
     * This setting does not affect direct use of the `shard()` method.
     */
    public static bool $connectionSharding = false;

    /**
     * If enabled, fallback to a backup server when the selected shard fails.
     * This setting does not affect direct use of the `shard()` method.
     */
    public static bool $shardFallbackOnError = false;

    /**
     * Optional list of sharded or backup database servers.
     */
    protected static array $databaseServers = [
        'NG' => [
            //...
            'pdo_version'  => 'mysql', // renamed from pdo_engine
        ],
    ];

    /**
     * Return a shard key used to select a target database server.
     * Typically based on geo-location, user ID, or any custom logic.
     */
    public static function getShardServerKey(): string 
    {
        return ''; // Return a key like 'NG', 'US', etc.
    }
}

Note:
Rename pdo_engine to pdo_version in all defined connections.
Also rename the property name $databaseBackups to $databaseServers.

Application Logging Configuration

Add a new static boolean property $telegramSendContext to the application logger configuration. This controls whether log context data is sent to Telegram when Telegram logging is enabled.

// /app/Config/Logger.php

namespace App\Config;

class Logger extends BaseConfig
{
    /**
     * Whether to include log context when sending messages to Telegram.
     */
    public static bool $telegramSendContext = false;
}

Purpose:
Allows fine-tuned control over the verbosity of logs sent to Telegram.

3.5.9

26 May 10:49

Choose a tag to compare

Full Changelog: 3.5.8...3.5.9

New Features

Introduced in Version 3.5.9

Dependency Injection Manager

Added support for custom dependency bindings using the Luminova\Routing\DI class or the bind method in the application instance.

Database Builder Enhancements

Introduced row-level locking support via the new method:

  • lockFor(...) – Enables row locking with either update (exclusive) or shared (read-only) modes.