concept-labs/expression

(C)oncept-Labs Expression

Installs: 31

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

pkg:composer/concept-labs/expression

1.1.3 2025-10-12 08:49 UTC

This package is auto-updated.

Last update: 2025-10-13 10:11:52 UTC


README

License PHP Version

A flexible and powerful PHP library for building and composing expressions with decorators. Perfect for constructing SQL queries, configuration strings, or any text-based DSL in a programmatic and maintainable way.

Features

  • ๐Ÿ”ง Fluent API - Chain methods for clean, readable code
  • ๐ŸŽจ Decorator Pattern - Transform expressions with decorators
  • ๐Ÿ—๏ธ Composable - Nest expressions within expressions
  • ๐Ÿ”„ Immutable Context - Safe context interpolation
  • ๐Ÿงฉ Extensible - Easy to extend with custom decorators
  • โœจ Type Safe - Full PHP 8.2+ type hints
  • ๐Ÿงช Well Tested - Comprehensive test coverage with PHPUnit and Pest

Installation

Install via Composer:

composer require concept-labs/expression

Quick Start

use Concept\Expression\Expression;
use Concept\Expression\Expression;

// Create an expression
$expression = new Expression();

// Build a simple expression
$expression->push('SELECT', 'id', 'name', 'FROM', 'users');
echo $expression; // Output: SELECT id name FROM users

// Use decorators for more control
$columns = (new Expression())
    ->push('id', 'name', 'email')
    ->wrapItem('`')
    ->join(', ');

$query = (new Expression())
    ->push('SELECT', $columns, 'FROM', 'users');
    
echo $query; // Output: SELECT `id`, `name`, `email` FROM users

Basic Usage

Creating Expressions

$expr = new Expression();

// Add expressions
$expr->push('SELECT', 'column');
$expr->push('FROM', 'table');

// Add to beginning
$expr->unshift('EXPLAIN');

echo $expr; // Output: EXPLAIN SELECT column FROM table

Using __invoke() for Concise Syntax

// You can also use the __invoke() method for a more concise syntax
$expr = new Expression();
$expr('SELECT', 'column')('FROM', 'table');

// Equivalent to:
// $expr->push('SELECT', 'column')->push('FROM', 'table');

echo $expr; // Output: SELECT column FROM table

Nested Expressions

$columns = (new Expression())
    ->push('id', 'name')
    ->join(', ');

$mainExpr = (new Expression())
    ->push('SELECT', $columns, 'FROM', 'users');

echo $mainExpr; // Output: SELECT id, name FROM users

Using Decorators

Wrap Expressions

$expr = (new Expression())
    ->push('value')
    ->wrap('(', ')');
    
echo $expr; // Output: (value)

Wrap Items

$expr = (new Expression())
    ->push('id', 'name', 'email')
    ->wrapItem('`')
    ->join(', ');
    
echo $expr; // Output: `id`, `name`, `email`

Custom Decorators

// Item decorator - applied to each item
$expr = (new Expression())
    ->push('select', 'from', 'where')
    ->decorateItem(fn($item) => strtoupper($item));

echo $expr; // Output: SELECT FROM WHERE

// Expression decorator - applied to final result
$expr = (new Expression())
    ->push('column')
    ->decorate(fn($str) => "SELECT $str FROM users");

echo $expr; // Output: SELECT column FROM users

// Join decorator - custom join logic
$expr = (new Expression())
    ->push('condition1', 'condition2')
    ->decorateJoin(fn($items) => implode(' AND ', $items));

echo $expr; // Output: condition1 AND condition2

Context Interpolation

$template = (new Expression())
    ->push('SELECT', '{column}', 'FROM', '{table}');

$concrete = $template->withContext([
    'column' => 'name',
    'table' => 'users'
]);

echo $concrete; // Output: SELECT name FROM users
echo $template; // Output: SELECT {column} FROM {table} (unchanged)

Clone and Prototype

$base = (new Expression())
    ->push('SELECT', 'id');

// Clone creates independent copy
$clone = clone $base;
$clone->push('FROM', 'users');

echo $base;  // Output: SELECT id
echo $clone; // Output: SELECT id FROM users

// Prototype is alias for clone
$proto = $base->prototype();

Reset

$expr = (new Expression())
    ->push('SELECT', 'column')
    ->type('select');

$expr->reset(); // Clears everything

echo $expr; // Output: (empty string)

Advanced Usage

Building Complex SQL Queries

// Build a complex SELECT query
$columns = (new Expression())
    ->push('u.id', 'u.name', 'u.email', 'p.title')
    ->wrapItem('`')
    ->join(', ');

$joins = (new Expression())
    ->push('JOIN', 'posts', 'p', 'ON', 'u.id = p.user_id');

$where = (new Expression())
    ->push('u.active = 1', 'p.published = 1')
    ->join(' AND ')
    ->wrap('WHERE ', '');

$query = (new Expression())
    ->push('SELECT', $columns)
    ->push('FROM', 'users', 'u')
    ->push($joins)
    ->push($where);

echo $query;
// Output: SELECT `u.id`, `u.name`, `u.email`, `p.title` FROM users u JOIN posts p ON u.id = p.user_id WHERE u.active = 1 AND p.published = 1

Multiple Decorator Layers

$expr = (new Expression())
    ->push('a', 'b', 'c')
    ->decorateItem(fn($item) => strtoupper($item))  // Items: A, B, C
    ->decorateItem(fn($item) => "`$item`")          // Items: `A`, `B`, `C`
    ->join(', ')                                     // Join: `A`, `B`, `C`
    ->decorate(fn($str) => "SELECT $str")            // Wrap: SELECT `A`, `B`, `C`
    ->decorate(fn($str) => "$str FROM table");       // Wrap: SELECT `A`, `B`, `C` FROM table

echo $expr; // Output: SELECT `A`, `B`, `C` FROM table

API Reference

For detailed API documentation, see docs/api-reference.md.

Main Classes

  • Expression - Main expression class
  • ExpressionInterface - Interface for expressions
  • DecoratorManager - Manages decorators for expressions
  • Decorator - Static helper methods for common decorators

Key Methods

Expression Methods

  • __invoke(...$expressions) - Add expressions (alias for push, enables callable syntax)
  • push(...$expressions) - Add expressions to the end
  • unshift(...$expressions) - Add expressions to the beginning
  • wrap($left, $right = null) - Wrap the entire expression
  • wrapItem($left, $right = null) - Wrap each item
  • join($separator) - Set the join separator
  • decorate(callable ...$decorator) - Add expression decorator
  • decorateItem(callable ...$decorator) - Add item decorator
  • decorateJoin(callable $decorator) - Set join decorator
  • withContext(array $context) - Create new expression with context
  • reset() - Reset the expression
  • type(string $type) - Set expression type
  • isEmpty() - Check if expression is empty
  • prototype() - Create a clone

Testing

The package includes comprehensive tests using both PHPUnit and Pest.

# Run all tests with Pest
composer test

# Run PHPUnit tests
composer test:phpunit

# Run with coverage
composer test:coverage

Contributing

Contributions are welcome! Please see docs/contributing.md for details.

License

This package is licensed under the Apache License 2.0. See LICENSE file for details.

Credits

  • Viktor Halytskyi - Original author
  • Part of the Concept Labs ecosystem

Links