Search by

rasuvaeff / yii3-clickhouse-toolkit

rasuvaeff

Yii3 config bridge for rasuvaeff/clickhouse-toolkit: DI wiring and console commands from environment.

Package info

github.com/rasuvaeff/yii3-clickhouse-toolkit

pkg:composer/rasuvaeff/yii3-clickhouse-toolkit

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 2

v1.2.0 2026-09-10 17:57 UTC

README

Stable Version Total Downloads Build Static analysis Psalm Level License Русская версия

Yii3 config bridge for rasuvaeff/clickhouse-toolkit. Install it and a ClickHouse client, migration runner and the three migration console commands are wired into the container straight from CLICKHOUSE_* environment variables — no hand-written config/di.php boilerplate.

This package ships only configuration (config/di.php + config/params.php) and a small parameter factory. All the actual ClickHouse machinery lives in rasuvaeff/clickhouse-toolkit; this is the glue that makes it a one-line install in a Yii3 application.

Using an AI coding assistant? llms.txt has a compact API reference you can use.

Requirements

  • PHP 8.3–8.5
  • rasuvaeff/clickhouse-toolkit ^1.2 (pulled in automatically; migration commands need ≥ 1.2.0)
  • A Yii3 application using yiisoft/config with the standard RecursiveMerge::groups('params', …) setup (the app template default)
  • A PSR-18 HTTP client + PSR-17 factories (e.g. guzzlehttp/guzzle)

Installation

composer require rasuvaeff/yii3-clickhouse-toolkit

yiisoft/config discovers the bundled config plugin automatically.

What it wires

Once installed, the following container entries resolve from the merged config:

Container id Resolves to Notes
Rasuvaeff\ClickHouseToolkit\ClickHouseConfig ClickHouseConfig built from the params below
Rasuvaeff\ClickHouseToolkit\ClickHouseClientFactory ClickHouseClientFactory picks up an app-bound PSR-18 client / PSR-17 factories if present
SimPod\ClickHouseClient\Client\PsrClickHouseClient live client via ClickHouseClientFactory::create()
SimPod\ClickHouseClient\Client\ClickHouseClient alias → PsrClickHouseClient type-hint the interface
Rasuvaeff\ClickHouseToolkit\ClickHouseMigrationRunner migration runner needs migrationsPath (see below)
Rasuvaeff\ClickHouseToolkit\ClickHouseMigrationRunnerInterface alias → runner
Rasuvaeff\ClickHouseToolkit\ClickHouseMigrationGenerator migration generator needs migrationsPath
Rasuvaeff\ClickHouseToolkit\ClickHouseMutationBuilder mutation builder ALTER … UPDATE/DELETE, over the live client
Rasuvaeff\ClickHouseToolkit\ClickHousePartitionManager partition manager drop/attach/freeze/move partitions, over the live client

Three console commands are registered under yiisoft/yii-console:

Command Action
clickhouse:migrations:generate <description> create the next NNN_*.sql file
clickhouse:migrations:status show applied / pending / missing / diverged
clickhouse:migrations:migrate apply pending migrations

Configuration

Defaults come from environment variables. Override any of them by redefining the rasuvaeff/yii3-clickhouse-toolkit params key in your application config.

Param Env var Default
host CLICKHOUSE_HOST 127.0.0.1
port CLICKHOUSE_PORT 8123
database CLICKHOUSE_DB default
username CLICKHOUSE_USER default
password CLICKHOUSE_PASSWORD ''
secure CLICKHOUSE_SECURE false (accepts 1/true/on/yes)
migrationsPath CLICKHOUSE_MIGRATIONS_PATH unset — required for migrations
migrationsTable CLICKHOUSE_MIGRATIONS_TABLE _migrations
migrationPlaceholders []

Where the values are read from

Each variable is looked up in getenv() first, then in $_ENV, then in $_SERVER; the first non-empty one wins, and the default applies only when none has it.

The fallback matters for .env-based deployments. vlucas/phpdotenv's Dotenv::createImmutable() — the variant the library recommends — deliberately does not call putenv(): it writes to $_ENV and $_SERVER only. Reading through getenv() alone therefore sees nothing on a plain PHP-FPM or CLI deployment that relies on the .env file (a php yii some:command cron entry is the typical case), and the package would silently use its defaults — 127.0.0.1:8123, database default, empty password — instead of reporting a configuration error. Under Docker Compose it happens to work, because env_file: puts the values into the container's process environment.

An empty value counts as unset and falls through to the next source; "0" does not, so CLICKHOUSE_SECURE=0 reads as configured.

migrationsPath has no safe default: resolving the migration runner or generator without it throws a clear RuntimeException rather than silently operating relative to the working directory. Set the env var, or point the param at your migrations directory:

// config/common/params.php
return [
    'rasuvaeff/yii3-clickhouse-toolkit' => [
        'migrationsPath' => dirname(__DIR__, 2) . '/resources/clickhouse-migrations',
    ],
];

Migration bookkeeping table

migrationsTable names the table the runner records applied migrations in. Two situations need something other than _migrations:

  • Adopting this package where _migrations already exists with a different schema — a home-grown (name, applied_at) table, say. The runner's CREATE TABLE IF NOT EXISTS finds it and does nothing, then the first read fails on the missing checksum column — before any migration file is read, so the repair cannot itself ship as a migration. Point the runner at a fresh name, let it re-apply the (idempotent) migrations, and drop the old table whenever convenient.
  • Two applications sharing one ClickHouse database — give each its own.
CLICKHOUSE_MIGRATIONS_TABLE=app_schema_migrations

The name is interpolated into SQL rather than bound, so clickhouse-toolkit validates it as a plain identifier and throws otherwise; a db-qualified analytics._migrations is refused too. A non-string param falls back to the default rather than reaching a string argument.

Migration placeholders

migrationPlaceholders is passed to the runner as {{key}} substitutions, applied to every migration file before it is hashed and executed. That is how a package can ship DDL whose table name the application configures instead of hard-coding it:

// config/common/params.php
'rasuvaeff/yii3-clickhouse-toolkit' => [
    'migrationPlaceholders' => [
        'exposures_table' => 'ab_exposures',
    ],
],

Non-string keys and non-scalar values are dropped rather than reaching str_replace(). An unresolved {{…}} makes the runner throw, naming the file and the token — a typo does not travel to ClickHouse. Changing a value after a migration has been applied is reported as a divergence; see the rasuvaeff/clickhouse-toolkit README for what to do then.

Usage

Type-hint the client (or the interface) anywhere in your app:

use SimPod\ClickHouseClient\Client\ClickHouseClient;

final readonly class ReportService
{
    public function __construct(private ClickHouseClient $client) {}

    public function activeUsers(): int
    {
        return (int) $this->client->select('SELECT count() FROM events')->getRows()[0]['count()'];
    }
}

Run migrations from the Yii3 console:

./yii clickhouse:migrations:generate "create events table"
./yii clickhouse:migrations:migrate
./yii clickhouse:migrations:status

Custom PSR-18 client (timeouts / TLS)

Bind your own configured PSR-18 client in the app; the bridge injects it into ClickHouseClientFactory automatically (it reads Psr\Http\Client\ClientInterface and the PSR-17 factories from the container when they are bound, otherwise falls back to auto-discovery):

// config/common/di.php
use Psr\Http\Client\ClientInterface;
use GuzzleHttp\Client;

return [
    ClientInterface::class => static fn (): Client => new Client(['timeout' => 5.0]),
];

Composition with backend packages

This bridge is the single binder of the toolkit client/config. Backend packages such as rasuvaeff/yii3-outbox-clickhouse consume ClickHouseClientFactory but never bind it, so installing both is conflict-free (verified against a real yiisoft/config merge). Their console commands and params co-exist under the standard recursive params merge.

Security

  • Connection credentials travel through environment variables and X-ClickHouse-* headers, never in the URI. Keep CLICKHOUSE_PASSWORD in your secret store, not in committed config.
  • All query safety (parameterized queries, identifier validation) is the responsibility of rasuvaeff/clickhouse-toolkit — see its README.

Examples

Runnable, server-independent examples live in examples/.

Development

No PHP/Composer on the host — everything runs in Docker via the composer:2 image.

make install
make build          # validate → normalize → require-checker → cs → psalm → test
make cs-fix
make mutation       # minMsi 100
make release-check

License

BSD-3-Clause. See LICENSE.md.