PHP (^8.5) and Laravel (^13) requirements are unchanged. Still on 1.x?
Follow Upgrading from 1.x to 2.0 first, then come
back here.
3.0 renames the package and its namespace:
| 2.x | 3.0 | |
|---|---|---|
| Composer package | oralunal/phpclickhouse-laravel |
oralunal/laravel-clickhouse |
| Namespace | PhpClickHouseLaravel\ |
Oralunal\LaravelClickHouse\ |
Nothing else changes. Class names below the namespace, the folder layout,
configuration, the generated SQL and the behavior are the same as in 2.0.2, for
example PhpClickHouseLaravel\ClickhouseSchemaBuilder\Tables\MergeTree becomes
Oralunal\LaravelClickHouse\ClickhouseSchemaBuilder\Tables\MergeTree. 2.0.2 is
the last release of oralunal/phpclickhouse-laravel, and the package is
abandoned. 3.0 conflicts with it, so Composer never installs both.
Switch the package and install the skills:
composer remove oralunal/phpclickhouse-laravel --no-update
composer require oralunal/laravel-clickhouse:^3.0 --with-all-dependencies
php artisan clickhouse:install-skills
In your agent, run:
/lc-upgrade-2x-to-3x
If your agent does not offer skills as slash commands, ask it to “upgrade phpclickhouse-laravel to laravel-clickhouse 3.x”.
The agent renames the namespace everywhere, refreshes Laravel’s caches, checks
the result, and reports how the test suite compares with the run before the
upgrade. clickhouse:install-skills finds your agents from their project
files (.claude/, .cursor/, AGENTS.md, …); pass --agent=claude_code and
so on to choose them yourself.
If php artisan fails after step 1 with a class-not-found error for a
PhpClickHouseLaravel\… class, your app uses the 2.x namespace while it boots.
Copy the skill by hand instead of running clickhouse:install-skills, for
example:
mkdir -p .claude/skills
cp -r vendor/oralunal/laravel-clickhouse/resources/skills/lc-upgrade-2x-to-3x .claude/skills/
Switch the package:
composer remove oralunal/phpclickhouse-laravel --no-update
composer require oralunal/laravel-clickhouse:^3.0 --with-all-dependencies
The artisan scripts that Composer runs may fail with a class-not-found
error until step 2 is done.
Rename the namespace in your code, migrations, config and tests. This keeps
the escaping of strings such as 'PhpClickHouseLaravel\\BaseModel':
grep -rlI 'PhpClickHouseLaravel' . \
--exclude-dir=vendor --exclude-dir=node_modules --exclude-dir=storage \
--exclude-dir=.git --exclude-dir=cache --exclude=composer.lock \
| xargs perl -pi -e 's/PhpClickHouseLaravel(\\+)/Oralunal$1LaravelClickHouse$1/g'
Then search for PhpClickHouseLaravel again and check what is left, such
as mentions in comments.
Run php artisan package:discover and php artisan optimize:clear. If they
fail with Class "PhpClickHouseLaravel\ClickhouseServiceProvider" not found,
delete bootstrap/cache/packages.php and bootstrap/cache/services.php and
run php artisan package:discover again.
Values serialized with the 2.x class names cannot be unserialized by 3.0:
cache entries, queued jobs and sessions that hold objects of the package’s
classes, such as RawColumn or the builder enums. If your app stores such
values, let the queues drain before you deploy and clear the cache
afterwards.
These steps take you to oralunal/phpclickhouse-laravel 2.0.2. Continue with
Upgrading from 2.x to 3.0 afterwards.
PHP (^8.5) and Laravel (^13) requirements are unchanged.
Upgrade to 2.0.2 or later. 2.0.0 was tagged before the schema builder and the enum base class were bundled. In 2.0.1, parallel test processes drop each other’s ClickHouse tables (see step 7).
2.0 bundles the libraries this package used to pull in:
oralunal/clickhouse-builder);Migration::createMergeTree()
(glushkovds/php-clickhouse-schema-builder);myclabs/php-enum).They generate the same SQL as before, but their classes are in this package’s
namespaces now. Apart from Laravel, the only remaining dependency is
smi2/phpclickhouse.
Do you need to change anything? Only in these cases:
Tinderbox\ClickhouseBuilder,
PhpClickHouseSchemaBuilder or MyCLabs\Enum.raw(), tp() or array_flatten().migrate:fresh while MySQL or PostgreSQL holds the migrations
table (see step 7).Apps that only use BaseModel, Migration::write(), RawColumn and
DB::connection('clickhouse') keep working without changes.
The package ships an agent skill that performs this whole upgrade and checks
the result. It works with Claude Code, Cursor, GitHub Copilot, Codex, Junie,
OpenCode, Amp, Gemini/Antigravity, Kiro, Pi, Zed, Grok Build, Factory Droid and
other agents that read AGENTS.md. Nothing else needs to be installed.
Update the package:
composer require oralunal/phpclickhouse-laravel:^2.0.2 --with-all-dependencies
Install the skill:
php artisan clickhouse:install-skills
The command looks for each agent’s files in your project (.claude/,
.cursor/, .github/copilot-instructions.md, AGENTS.md, …) and writes
the skill to that agent’s skills directory, for example
.claude/skills/plc-upgrade-1x-to-2x/SKILL.md. To choose the agents
yourself, pass --agent=claude_code --agent=cursor. Run
php artisan clickhouse:install-skills --help for the list of names.
In your agent, run:
/plc-upgrade-1x-to-2x
If your agent does not offer skills as slash commands, ask it to “upgrade phpclickhouse-laravel to 2.x”. The skill is picked up from its description.
The agent then follows every step below. It stops to ask you before changing code whose meaning it cannot decide alone, such as uses of the removed file/temporary-table API. At the end it reports what it changed and how the test suite compares with the run before the upgrade.
If php artisan fails right after step 1 with
Class "Tinderbox\ClickhouseBuilder\...\ClickhouseServiceProvider" not found,
delete bootstrap/cache/packages.php and bootstrap/cache/services.php and
try again. If the app still does not boot, copy the skill by hand, for
example:
mkdir -p .claude/skills
cp -r vendor/oralunal/phpclickhouse-laravel/resources/skills/plc-upgrade-1x-to-2x .claude/skills/
To find what needs changing, run:
grep -rnE 'Tinderbox\\ClickhouseBuilder|PhpClickHouseSchemaBuilder|MyCLabs\\Enum|[^>:$a-zA-Z_]raw\(|array_flatten\(|[^a-zA-Z_]tp\(|into_memory_table|file_from|addFile\(|getFiles\(' \
app config database routes tests
composer require oralunal/phpclickhouse-laravel:^2.0.2
If your composer.json lists oralunal/clickhouse-builder or
glushkovds/php-clickhouse-schema-builder directly, remove them. The bundled
copies replace them:
composer remove oralunal/clickhouse-builder glushkovds/php-clickhouse-schema-builder
the-tinderbox/clickhouse-php-client and myclabs/php-enum are no longer
installed either. If your own code uses one of them, require it yourself.
The builder classes are in PhpClickHouseLaravel\ClickhouseBuilder now, and
the schema builder classes are in PhpClickHouseLaravel\ClickhouseSchemaBuilder.
Only the namespace prefix changes; class names and the folder layout are the
same.
| 1.x | 2.0 |
|---|---|
Tinderbox\ClickhouseBuilder\Query\Expression |
PhpClickHouseLaravel\ClickhouseBuilder\Query\Expression |
Tinderbox\ClickhouseBuilder\Query\Enums\Operator |
PhpClickHouseLaravel\ClickhouseBuilder\Query\Enums\Operator |
Tinderbox\ClickhouseBuilder\Query\TwoElementsLogicExpression |
PhpClickHouseLaravel\ClickhouseBuilder\Query\TwoElementsLogicExpression |
Tinderbox\ClickhouseBuilder\Query\BaseBuilder |
PhpClickHouseLaravel\ClickhouseBuilder\Query\BaseBuilder |
Tinderbox\ClickhouseBuilder\Query\Grammar |
PhpClickHouseLaravel\ClickhouseBuilder\Query\Grammar |
Tinderbox\ClickhouseBuilder\Exceptions\* |
PhpClickHouseLaravel\ClickhouseBuilder\Exceptions\* |
PhpClickHouseSchemaBuilder\Tables\MergeTree |
PhpClickHouseLaravel\ClickhouseSchemaBuilder\Tables\MergeTree |
PhpClickHouseSchemaBuilder\Expression |
PhpClickHouseLaravel\ClickhouseSchemaBuilder\Expression |
PhpClickHouseSchemaBuilder\Engine, Column, TTL, Exceptions\* |
PhpClickHouseLaravel\ClickhouseSchemaBuilder\Engine, Column, TTL, Exceptions\* |
Your migration files count too. A migration that still imports
PhpClickHouseSchemaBuilder\Tables\MergeTree fails with Class not found
the next time it runs, for example on a fresh install or in CI.
To replace them across your app (GNU sed; on macOS use sed -i ''):
grep -rlE 'Tinderbox\\ClickhouseBuilder|PhpClickHouseSchemaBuilder\\' app config database routes tests \
| xargs sed -i -e 's/Tinderbox\\ClickhouseBuilder/PhpClickHouseLaravel\\ClickhouseBuilder/g' \
-e 's/PhpClickHouseSchemaBuilder\\/PhpClickHouseLaravel\\ClickhouseSchemaBuilder\\/g'
raw(), tp() and array_flatten() used to be global functions. They are
now in the PhpClickHouseLaravel\ClickhouseBuilder namespace. If you call them
without importing them, PHP fails with Call to undefined function raw().
// 1.x
$query->select(raw('count() AS n'));
// 2.0
use function PhpClickHouseLaravel\ClickhouseBuilder\raw;
$query->select(raw('count() AS n'));
You can also use the classes directly:
use PhpClickHouseLaravel\ClickhouseBuilder\Query\Expression;
use PhpClickHouseLaravel\RawColumn;
$query->select(new Expression('count() AS n'));
$query->select(new RawColumn('count()', 'n')); // count() AS `n`
These parts only worked with the-tinderbox/clickhouse-php-client. This
package’s Builder runs queries through smi2/phpClickHouse, so they never
did anything useful here. They are no longer included:
| Removed | Use instead |
|---|---|
addFile(), getFiles(), values(), getValues() |
Insert the rows with insertAssoc(), insertBulk() or buffer() |
into_memory_table(), file_from() |
Same as above |
Tinderbox\ClickhouseBuilder\Query\Builder (Tinderbox-client builder) |
BaseModel::select() / where(), or DB::connection('clickhouse')->table(...) |
Tinderbox\ClickhouseBuilder\Integrations\Laravel\Connection / Builder |
PhpClickHouseLaravel\Connection and PhpClickHouseLaravel\Builder |
Tinderbox\ClickhouseBuilder\Integrations\Laravel\ClickhouseServiceProvider |
PhpClickHouseLaravel\ClickhouseServiceProvider (auto-discovered) |
If you registered the old ClickhouseServiceProvider yourself in
bootstrap/providers.php or config/app.php, remove it. The class no longer
exists, so the app fails to boot while it is still listed.
If every artisan command, package:discover included, fails with
Class "Tinderbox\ClickhouseBuilder\Integrations\Laravel\ClickhouseServiceProvider" not found,
Laravel’s cached package manifest still lists the 1.x provider. This happens
when Composer ran with --no-scripts. Delete bootstrap/cache/packages.php
and bootstrap/cache/services.php; Laravel regenerates them on the next
php artisan package:discover.
whereIn() with a string valueIn 1.x, whereIn(), preWhereIn(), whereGlobalIn() and havingIn() turned
a string into a table reference, but only when it matched a file added with
addFile(). Since addFile() is gone, a string is now always quoted as a
value:
$query->whereIn('id', 'ids'); // WHERE `id` IN 'ids'
To compare against a table or a sub-query, write it out explicitly:
use function PhpClickHouseLaravel\ClickhouseBuilder\raw;
$query->whereIn('id', raw('allowed_ids')); // WHERE `id` IN allowed_ids
$query->whereIn('id', fn ($q) => $q->select('id')->from('allowed')); // WHERE `id` IN (SELECT `id` FROM `allowed`)
Column::subQuery() return typeColumn::subQuery() and Column::getSubQuery() now declare BaseBuilder as
their return type. In 1.x they declared the Tinderbox-client Query\Builder,
which made column sub-queries built from this package’s Builder throw a
TypeError. Only code that type-checks the return value against the old class
needs a change.
migrate:fresh also empties secondary ClickHouse connectionsThis step only applies when MySQL or PostgreSQL holds the migrations table
and some migrations write to ClickHouse. In 1.x, migrate:fresh emptied only
the MySQL or PostgreSQL database and left ClickHouse as it was. Migrations
written with CREATE TABLE IF NOT EXISTS therefore kept their ClickHouse data
across migrate:fresh.
In 2.0, migrate:fresh also empties these ClickHouse connections:
database/schema.ClickHouse connections that no migration or dump refers to are left alone. The command still asks for confirmation in production.
RefreshDatabase and the other database test traits run migrate:fresh too.
If you run your tests with --parallel, use 2.0.2 or later. From 2.0.2 on,
each test process gets its own database on these ClickHouse connections,
<database>_test_<token> (for example analytics_test_1), just as Laravel
does for the default connection. In 2.0.1 every process shared the configured
ClickHouse database, so one process’s migrate:fresh dropped the tables that
another process was using. The ClickHouse user needs permission to create and
drop databases. Test runs without --parallel keep using the configured
database.
See
Which connection holds the migrations table.
Enum classOperator, Format, JoinType, JoinStrict and OrderDirection now extend
PhpClickHouseLaravel\Enum\Enum instead of MyCLabs\Enum\Enum. Their constants
and methods (isValid(), getValue(), Operator::EQUALS() and so on) are
unchanged. Only code that type-checks against MyCLabs\Enum\Enum needs to
change.