Skip to content

Commit ee159c0

Browse files
committed
feat: Laravel 12 compatibility
1 parent 06ac6c8 commit ee159c0

14 files changed

+218
-152
lines changed

composer.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
"require": {
1717
"php": "^8.0",
1818
"doctrine/dbal": "^2.6|^3.5|^4.0",
19-
"illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
20-
"illuminate/database": "^6.0|^7.0|^8.79|^9.0|^10.0|^11.0",
21-
"illuminate/events": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
22-
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
19+
"illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
20+
"illuminate/database": "^6.0|^7.0|^8.79|^9.0|^10.0|^11.0|^12.0",
21+
"illuminate/events": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
22+
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
2323
"spatie/regex": "^2.0|^3.0"
2424
},
2525
"require-dev": {
2626
"composer/semver": "^3.4",
2727
"friendsofphp/php-cs-fixer": "^2.19.3|^3.5.0",
2828
"larastan/larastan": "^1.0|^2.1|^3.0",
2929
"nesbot/carbon": "^2.7|^3.3",
30-
"orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0",
30+
"orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0|^10.0",
3131
"phpstan/extension-installer": "^1.1",
3232
"phpstan/phpstan": "^1.5|^2.0",
3333
"phpunit/phpunit": "^8.5.23|^9.5.13|^10.5|^11.4",

phpstan-baseline.neon

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,30 +36,31 @@ parameters:
3636
count: 1
3737
path: src/Eloquent/Mixins/BuilderReturning.php
3838

39-
-
40-
message: '#^Call to function method_exists\(\) with Tpetry\\PostgresqlEnhanced\\Query\\Grammar and ''setConnection'' will always evaluate to true\.$#'
41-
identifier: function.alreadyNarrowedType
42-
count: 1
43-
path: src/PostgresEnhancedConnection.php
44-
45-
-
46-
message: '#^Call to function method_exists\(\) with Tpetry\\PostgresqlEnhanced\\Schema\\Grammars\\Grammar and ''setConnection'' will always evaluate to true\.$#'
47-
identifier: function.alreadyNarrowedType
48-
count: 1
49-
path: src/PostgresEnhancedConnection.php
50-
5139
-
5240
message: '#^Call to function method_exists\(\) with \$this\(Tpetry\\PostgresqlEnhanced\\Query\\Builder\) and ''applyBeforeQueryCal…'' will always evaluate to true\.$#'
5341
identifier: function.alreadyNarrowedType
5442
count: 7
5543
path: src/Query/Builder.php
5644

45+
-
46+
message: '#^Method Illuminate\\Database\\Schema\\Grammars\\PostgresGrammar\:\:compileChange\(\) invoked with 3 parameters, 2 required\.$#'
47+
identifier: arguments.count
48+
count: 1
49+
path: src/Schema/Grammars/Grammar.php
50+
reportUnmatched: false
51+
5752
-
5853
message: '#^Return type \(array\<int, string\>\) of method Tpetry\\PostgresqlEnhanced\\Schema\\Grammars\\Grammar\:\:compileAdd\(\) should be compatible with return type \(string\) of method Illuminate\\Database\\Schema\\Grammars\\PostgresGrammar\:\:compileAdd\(\)$#'
5954
identifier: method.childReturnType
6055
count: 1
6156
path: src/Schema/Grammars/Grammar.php
6257

58+
-
59+
message: '#^Parameter \#2 \$replace of function substr_replace expects array\|string, int\|false given\.$#'
60+
identifier: argument.type
61+
count: 1
62+
path: src/Support/Helpers/MigrationIndex.php
63+
6364
-
6465
message: '#^Call to an undefined method Illuminate\\Database\\Migrations\\Migration\:\:timeoutDown\(\)\.$#'
6566
identifier: method.notFound
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tpetry\PostgresqlEnhanced\Backports;
6+
7+
use Illuminate\Database\Connection;
8+
9+
/**
10+
* To support some features these commits from laravel needed to be backported for older versions:
11+
* - [12.x] Fix accessing Connection property in Grammar classes (https://github.com/laravel/framework/commit/c78fa3d0684206f721b9a3b76e8c596aa8a08cd0)
12+
*/
13+
trait GrammarBackportConstructor
14+
{
15+
/**
16+
* The connection used for escaping values.
17+
*
18+
* @var Connection
19+
*/
20+
protected $connection;
21+
22+
/**
23+
* Create a new grammar instance.
24+
*/
25+
public function __construct(Connection $connection)
26+
{
27+
$this->connection = $connection;
28+
}
29+
}

src/Backports/GrammarBackportEscape.php

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,12 @@
44

55
namespace Tpetry\PostgresqlEnhanced\Backports;
66

7-
use RuntimeException;
8-
97
/**
108
* To support some features these commits from laravel needed to be backported for older versions:
119
* - [10.x] Escaping functionality within the Grammar (https://github.com/laravel/framework/commit/e953137280cdf6e0fe3c3e4c49d7209ad86c92c0).
1210
*/
1311
trait GrammarBackportEscape
1412
{
15-
/**
16-
* The connection used for escaping values.
17-
*
18-
* @var \Illuminate\Database\Connection
19-
*/
20-
protected $connection;
21-
2213
/**
2314
* Escapes a value for safe SQL embedding.
2415
*
@@ -27,22 +18,6 @@ trait GrammarBackportEscape
2718
*/
2819
public function escape($value, $binary = false): string
2920
{
30-
if (null === $this->connection) {
31-
throw new RuntimeException("The database driver's grammar implementation does not support escaping values.");
32-
}
33-
3421
return $this->connection->escape($value, $binary);
3522
}
36-
37-
/**
38-
* Set the grammar's database connection.
39-
*
40-
* @param \Illuminate\Database\Connection $connection
41-
*/
42-
public function setConnection($connection): static
43-
{
44-
$this->connection = $connection;
45-
46-
return $this;
47-
}
4823
}

src/PostgresEnhancedConnection.php

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -117,11 +117,8 @@ public function serverVersion(): string
117117
*/
118118
protected function getDefaultQueryGrammar(): QueryGrammar
119119
{
120-
$grammar = new QueryGrammar();
120+
$grammar = new QueryGrammar($this);
121121
$grammar->setTablePrefix($this->tablePrefix);
122-
if (method_exists($grammar, 'setConnection')) {
123-
$grammar->setConnection($this);
124-
}
125122

126123
return $grammar;
127124
}
@@ -131,11 +128,8 @@ protected function getDefaultQueryGrammar(): QueryGrammar
131128
*/
132129
protected function getDefaultSchemaGrammar(): SchemaGrammar
133130
{
134-
$grammar = new SchemaGrammar();
131+
$grammar = new SchemaGrammar($this);
135132
$grammar->setTablePrefix($this->tablePrefix);
136-
if (method_exists($grammar, 'setConnection')) {
137-
$grammar->setConnection($this);
138-
}
139133

140134
return $grammar;
141135
}

src/Query/Grammar.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66

77
use Illuminate\Database\Query\Builder as BaseBuilder;
88
use Illuminate\Database\Query\Grammars\PostgresGrammar;
9+
use Tpetry\PostgresqlEnhanced\Backports\GrammarBackportConstructor;
910
use Tpetry\PostgresqlEnhanced\Backports\GrammarBackportEscape;
1011
use Tpetry\PostgresqlEnhanced\Backports\GrammarBackportSubstituteBindings;
1112

1213
class Grammar extends PostgresGrammar
1314
{
15+
use GrammarBackportConstructor;
1416
use GrammarBackportEscape;
1517
use GrammarBackportSubstituteBindings;
1618
use GrammarCte;

src/Schema/Blueprint.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,38 @@
44

55
namespace Tpetry\PostgresqlEnhanced\Schema;
66

7+
use Closure;
8+
use Illuminate\Database\Connection;
79
use Illuminate\Database\Schema\Blueprint as BaseBlueprint;
10+
use Illuminate\Database\Schema\Grammars\Grammar as BaseGrammar;
811

12+
// In Laravel 12.0.0 the BaseBlueprint constructor was changed so the behaviour of before/after is emulated:
13+
// - Laravel >=12: store($this->connection, $this->grammar, $this->table), execute($callback)
14+
// - Laravel <=11: store($this->table, $this->prefix), execute($callback)
915
class Blueprint extends BaseBlueprint
1016
{
1117
use BlueprintIndex;
1218
use BlueprintTable;
1319
use BlueprintTrigger;
1420
use BlueprintTypes;
21+
22+
protected Connection $connection;
23+
protected BaseGrammar $grammar;
24+
protected $prefix;
25+
protected $table;
26+
27+
public function __construct(
28+
Connection $connection,
29+
string $table,
30+
?Closure $callback = null,
31+
) {
32+
$this->connection = $connection;
33+
$this->grammar = $connection->getSchemaGrammar();
34+
$this->table = $table;
35+
$this->prefix = $connection->getTablePrefix();
36+
37+
if (null !== $callback) {
38+
$callback($this);
39+
}
40+
}
1541
}

src/Schema/Builder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ public function getConnection(): PostgresEnhancedConnection
3333
*/
3434
protected function createBlueprint($table, ?Closure $callback = null): Blueprint
3535
{
36-
return new Blueprint($table, $callback);
36+
return new Blueprint($this->getConnection(), $table, $callback);
3737
}
3838
}

src/Schema/Grammars/Grammar.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
namespace Tpetry\PostgresqlEnhanced\Schema\Grammars;
66

77
use Illuminate\Database\Schema\Grammars\PostgresGrammar;
8+
use Tpetry\PostgresqlEnhanced\Backports\GrammarBackportConstructor;
89
use Tpetry\PostgresqlEnhanced\Backports\GrammarBackportEscape;
910

1011
class Grammar extends PostgresGrammar
1112
{
13+
use GrammarBackportConstructor;
1214
use GrammarBackportEscape;
1315
use GrammarIndex;
1416
use GrammarTable;

src/Schema/Grammars/GrammarIndex.php

Lines changed: 5 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@
44

55
namespace Tpetry\PostgresqlEnhanced\Schema\Grammars;
66

7-
use Closure;
8-
use Illuminate\Contracts\Database\Query\Expression as ExpressionContract;
9-
use Illuminate\Database\Query\Expression as ExpressionClass;
107
use Illuminate\Database\Schema\Blueprint;
11-
use Illuminate\Support\Arr;
12-
use Illuminate\Support\Facades\DB;
138
use Illuminate\Support\Fluent;
14-
use Illuminate\Support\Str;
15-
use Tpetry\PostgresqlEnhanced\Support\Helpers\Query;
9+
use Tpetry\PostgresqlEnhanced\Support\Helpers\MigrationIndex;
1610

1711
trait GrammarIndex
1812
{
@@ -79,15 +73,15 @@ public function compileFulltext(Blueprint $blueprint, Fluent $command): string
7973
{
8074
$command['algorithm'] ??= 'gin';
8175

82-
return $this->genericCompileCreateIndex($blueprint, $command, false);
76+
return (new MigrationIndex())->compileCommand($this, $blueprint->getTable(), $command, false);
8377
}
8478

8579
/**
8680
* Compile a plain index key command.
8781
*/
8882
public function compileIndex(Blueprint $blueprint, Fluent $command): string
8983
{
90-
return $this->genericCompileCreateIndex($blueprint, $command, false);
84+
return (new MigrationIndex())->compileCommand($this, $blueprint->getTable(), $command, false);
9185
}
9286

9387
/**
@@ -97,87 +91,14 @@ public function compileSpatialIndex(Blueprint $blueprint, Fluent $command): stri
9791
{
9892
$command['algorithm'] = 'gist';
9993

100-
return $this->genericCompileCreateIndex($blueprint, $command, false);
94+
return (new MigrationIndex())->compileCommand($this, $blueprint->getTable(), $command, false);
10195
}
10296

10397
/**
10498
* Compile a unique key command.
10599
*/
106100
public function compileUnique2(Blueprint $blueprint, Fluent $command): string
107101
{
108-
return $this->genericCompileCreateIndex($blueprint, $command, true);
109-
}
110-
111-
private function genericCompileCreateIndex(Blueprint $blueprint, Fluent $command, bool $unique): string
112-
{
113-
// If the index is partial index using a closure a dummy query builder is provided to the closure. The query is
114-
// then transformed to a static query and the select part is removed to only keep the condition.
115-
if ($command['where'] instanceof Closure) {
116-
$query = ($command['where'])(DB::query());
117-
$command['where'] = trim(str_replace('select * where', '', Query::toSql($query)));
118-
}
119-
120-
// If the storage parameters for the index are provided in array form they need to be serialized to PostgreSQL's
121-
// string format.
122-
if (\is_array($command['with'])) {
123-
$with = array_map(fn (mixed $value) => match ($value) {
124-
true => 'on',
125-
false => 'off',
126-
default => (string) $value,
127-
}, $command['with']);
128-
$with = array_map(fn (string $value, string $key) => "{$key} = {$value}", $with, array_keys($with));
129-
$command['with'] = implode(', ', $with);
130-
}
131-
132-
// If the additions for column specifications are used the columns need to be columnized different to the
133-
// standard laravel logic which is expecting plain references.
134-
// Note: The ExpressionContract has been added with Laravel 10, older versions used the ExpressionClass.
135-
$columns = array_map(function (string|ExpressionContract|ExpressionClass $column): string {
136-
// Expressions generated by rawIndex() should by definition not processed anymore and used as provided
137-
if ($column instanceof ExpressionClass || $column instanceof ExpressionContract) {
138-
return $this->getValue($column);
139-
}
140-
141-
// When a functional index or escaped column name is provided the column string is already a valid raw
142-
// column index string and can be used exactly as provided.
143-
if (Str::startsWith($column, ['(', '"'])) {
144-
return $column;
145-
}
146-
147-
// In case index parameters are provided the column needs to escaped correctly and the rest is provided
148-
// exactly as provided.
149-
return $this->columnizeWithSuffix([$column]);
150-
}, $command['columns']);
151-
152-
// A fulltext index needs special handling to wrap the columns into to_tsvector calls.
153-
if ('fulltext' === $command['name']) {
154-
$columns = array_map(function (string $column, int $index) use ($command): string {
155-
$language = $command['language'] ?? 'english';
156-
157-
return match (isset($command['weight'][$index])) {
158-
true => "setweight(to_tsvector({$this->quoteString($language)}, {$column}), {$this->quoteString($command['weight'][$index])})",
159-
false => "to_tsvector({$this->quoteString($language)}, {$column})",
160-
};
161-
}, $columns, array_keys(array_values($columns)));
162-
$columns = ['('.implode(' || ', $columns).')'];
163-
}
164-
165-
$index = [
166-
$unique ? 'create unique index' : 'create index',
167-
$command['concurrently'] ? 'concurrently' : null,
168-
$command['ifNotExists'] ? 'if not exists' : null,
169-
$this->wrap($command['index']),
170-
'on',
171-
$this->wrapTable($blueprint),
172-
$command['algorithm'] ? "using {$command['algorithm']}" : null,
173-
'('.implode(', ', $columns).')',
174-
$command['include'] ? 'include ('.implode(',', $this->wrapArray(Arr::wrap($command['include']))).')' : null,
175-
$command['nullsNotDistinct'] ? 'nulls not distinct' : null,
176-
$command['with'] ? "with ({$command['with']})" : null,
177-
$command['where'] ? "where {$command['where']}" : null,
178-
];
179-
$sql = implode(' ', array_filter($index, fn (?string $part) => filled($part)));
180-
181-
return $sql;
102+
return (new MigrationIndex())->compileCommand($this, $blueprint->getTable(), $command, true);
182103
}
183104
}

0 commit comments

Comments
 (0)