PHPackages                             inkant/engi - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. inkant/engi

ActiveLibrary

inkant/engi
===========

SQL template engine

0205↓100%PHP

Since Nov 11Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/theinkant/engi)[ Packagist](https://packagist.org/packages/inkant/engi)[ RSS](/packages/inkant-engi/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

SQL template engine (engi)
--------------------------

[](#sql-template-engine-engi)

Acts like [sprintf](https://www.php.net/manual/en/function.sprintf.php), but placeholders are customizable, extendable, its behavior flexible and sql-oriented.

### Install

[](#install)

`composer require inkant/engi`

### TL;DR

[](#tldr)

#### DO NOT USE `DummyEscaper` IN PRODUCTION

[](#do-not-use-dummyescaper-in-production)

Please, use [PgEscaper](src/Escapers/PostgresqlEscaper.php), [PdoEscaper](src/Escapers/PdoEscaper.php) or your custom escape implementation instead of `DummyEscaper`.
`DummyEscaper` only for examples.

`i?` - trying convert to int sql type positional parameter
`i?name1` - trying convert to int sql named parameter "name1"
`?` - trying resolve passed positional parameter type to reasonable sql type
`?name1` - trying resolve passed named parameter "name1" type to reasonable sql type

```
$query = new \Inkant\Engi\Query(
    'SELECT i?, ?, ?name1, i?name1', [
    '100',
    100,
    'name1' => '454'
]);

$result = "SELECT 100, 100, '454', 454";
$compiler = new Compiler(new DummyEscaper());
$compiler->compile($query) === $result
    ?: throw new \Exception();
```

[More](tests/QueryTest.php) and [most](tests/Ast/TemplateTest.php) descriptive test cases with subquery and parameter types
Check resolvers setup example in [Query](src/Query.php)::resolvers() it can be extended to customize placeholders or/and customize resolvers

### Architecture

[](#architecture)

[Contracts that describing concepts](src/Contracts)

[Parsers](src/Contracts/ParserInterface.php) are responsible for providing [placeholders](src/Contracts/PlaceholderInterface.php) from string template as parts of [Abstract syntax tree](src/Contracts/AstInterface.php).
[Abstract syntax tree](src/Contracts/AstInterface.php) is an implementation of `composite` pattern, where leaf is a [token](src/Contracts/TokenInterface.php)(must have string representation) in sql context and [composites](src/Contracts/AstNodeInterface.php)(e.g.[placeholders](src/Contracts/PlaceholderInterface.php)) are more complex sql structures.
Every [composite](src/Contracts/AstNodeInterface.php) must be transformed to [tokens](src/Contracts/TokensInterface.php)by calling `compile(mixed ...$dependencies)` method.
Every [token](src/Contracts/TokenInterface.php) must be transformed to string by calling `compile(mixed ...$dependencies)` method.
[Tokens](src/Contracts/TokensInterface.php) must be assembled by [assembler](src/Contracts/AssemblerInterface.php) calling method `assemble` providing [Tokens](src/Contracts/TokensInterface.php) and `...$dependencies`.

`...$dependencies` are any required dependencies during `compile`(e.g. database version/name, escape string mechanism).

### Placeholders

[](#placeholders)

Placeholders are just substrings with optionally following by name `[a-zA-Z0-9_]+` string:
`?` - if no name provided, using next positional parameter
`?email` - using array parameters item with key `email`
`i?id` - convert using array parameters item with key `id` to `int`

Placeholders making possible using named and positional parameters at once.
Also, it lets reusing one value in different contexts:
`i?id` - will convert string value '100' to sql `integer` value 100
`s?id` - (value type is obvious, can be replaced by "?id") will convert string value '100' to sql `text` value '100'
`?id` - will resolve value '100' to sql `text` value '100' based on value type that is string

```
$query = new \Inkant\Engi\Query(
    'SELECT i?id, s?id, ?id', [
    'id' => '100'
]);

$result = "SELECT 100, '100', '100'";
$compiler = new Compiler(new DummyEscaper());
$compiler->compile($query) === $result
    ?: throw new \Exception();
```

To determine by what exactly placeholder must be replaced, placeholders using [resolvers](#resolvers).

### Escape placeholders

[](#escape-placeholders)

Sometimes placeholders can interfere with sql syntax. For example, postgresql has jsonb operator "?" and if "?" using as placeholder, then it can be escaped by doubling it.
So, placeholder "??" will be resolved to "?" and will not affect postgresql syntax.
It is possible by [EscapeResolver](src/Resolvers/EscapeResolver.php)

### Escape values

[](#escape-values)

Different databases have different ways to escape(avoid sql injections) value tokens(e.g. strings).
[PgEscaper](src/Escapers/PostgresqlEscaper.php) and [PdoEscaper](src/Escapers/PdoEscaper.php) implements necessary interfaces for escaping strings and avoid sql injections.

#### Escape strings

[](#escape-strings)

To be database-agnostic [StringToken](src/Tokens/StringToken.php), for example, require [EscapeStringInterface](src/Contracts/EscapeStringInterface.php) among its `...$dependencies` during `compile(...$dependencies)`

#### Escape binary

[](#escape-binary)

[BinaryToken](src/Tokens/BinaryToken.php)require [EscapeBinaryInterface](src/Contracts/EscapeBinaryInterface.php) among its `...$dependencies` during `compile(...$dependencies)`

#### Escape identifier

[](#escape-identifier)

Sometimes table names, column names and so on need to be escaped. [IdentifierToken](src/Tokens/IdentifierToken.php) require [EscapeIdentifierInterface](src/Contracts/EscapeIdentifierInterface.php) among its `...$dependencies` during `compile(...$dependencies)`
[PgEscaper](src/Escapers/PostgresqlEscaper.php) implements [EscapeIdentifierInterface](src/Contracts/EscapeIdentifierInterface.php)using postgresql driver specific function `pg_escape_identifier`.
[PdoEscaper](src/Escapers/PdoEscaper.php) also implements [EscapeIdentifierInterface](src/Contracts/EscapeIdentifierInterface.php), but PDO does not provide any escape-identifier function, so `PdoEscaper::escapeIdentifier` returns identifier ASIS.

### Resolvers

[](#resolvers)

[All resolvers](src/Resolvers)
[Use cases](tests/Resolvers)

Resolvers responsible for resolving passed values to placeholders into sql values/structures.
Resolvers are simple, here is [StringResolver](src/Resolvers/StringResolver.php) example:

```
class StringResolver extends ResolverAbstract
{
    public function resolve(mixed $value): ?StringToken
    {
        return is_string($value)
            ? new StringToken($value)
            : null;
    }
}
```

#### KeyValueResolver

[](#keyvalueresolver)

Useful in `UPDATE SET` resolving associative array to key=value list `['column1' => 1, 'column2' => 2] => 'column1=1,column2=2'`

#### ListResolver

[](#listresolver)

Useful inside `IN`. If `array_is_list` then list resolving to comma separated sql list.
`[1, 2.38] => '1,2.38'`

#### AstResolver

[](#astresolver)

Make nesting queries possible.
If value is AstInterface(e.g. Query), then it will be embedded and compiled during `compile`

#### IdentifierResolver

[](#identifierresolver)

placeholder for table and column names, will not be quoted as string value.

###  Health Score

21

—

LowBetter than 19% of packages

Maintenance50

Moderate activity, may be stable

Popularity13

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity12

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/c9b766df7f6bd16873952ca4a30e7875d1b665347fd585ca5651f4a7a9e0177d?d=identicon)[theinkant](/maintainers/theinkant)

---

Top Contributors

[![theinkant](https://avatars.githubusercontent.com/u/69956756?v=4)](https://github.com/theinkant "theinkant (4 commits)")

### Embed Badge

![Health badge](/badges/inkant-engi/health.svg)

```
[![Health](https://phpackages.com/badges/inkant-engi/health.svg)](https://phpackages.com/packages/inkant-engi)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
