Skip to content

Commit 1c834e4

Browse files
themsaidtaylorotwelldriesvints
authored
[8.x] Accept enums for insert update and where (#39492)
* accept enums for insert update and where * fix style * Update tests/Integration/Database/QueryingWithEnumsTest.php Co-authored-by: Dries Vints <[email protected]> * Update tests/Integration/Database/QueryingWithEnumsTest.php Co-authored-by: Dries Vints <[email protected]> Co-authored-by: Taylor Otwell <[email protected]> Co-authored-by: Dries Vints <[email protected]>
1 parent cb46639 commit 1c834e4

File tree

3 files changed

+131
-5
lines changed

3 files changed

+131
-5
lines changed

src/Illuminate/Database/Query/Builder.php

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Illuminate\Database\Query;
44

5+
use BackedEnum;
56
use Closure;
67
use DateTimeInterface;
78
use Illuminate\Contracts\Support\Arrayable;
@@ -3258,14 +3259,33 @@ public function addBinding($value, $type = 'where')
32583259
}
32593260

32603261
if (is_array($value)) {
3261-
$this->bindings[$type] = array_values(array_merge($this->bindings[$type], $value));
3262+
$this->bindings[$type] = collect($this->bindings[$type])
3263+
->merge($value)
3264+
->map([$this, 'castBinding'])
3265+
->values()
3266+
->toArray();
32623267
} else {
3263-
$this->bindings[$type][] = $value;
3268+
$this->bindings[$type][] = $this->castBinding($value);
32643269
}
32653270

32663271
return $this;
32673272
}
32683273

3274+
/**
3275+
* Cast the given binding value.
3276+
*
3277+
* @param mixed $value
3278+
* @return mixed
3279+
*/
3280+
public function castBinding($value)
3281+
{
3282+
if (function_exists('enum_exists') && $value instanceof BackedEnum) {
3283+
return $value->value;
3284+
}
3285+
3286+
return $value;
3287+
}
3288+
32693289
/**
32703290
* Merge an array of bindings into our bindings.
32713291
*
@@ -3287,9 +3307,13 @@ public function mergeBindings(self $query)
32873307
*/
32883308
public function cleanBindings(array $bindings)
32893309
{
3290-
return array_values(array_filter($bindings, function ($binding) {
3291-
return ! $binding instanceof Expression;
3292-
}));
3310+
return collect($bindings)
3311+
->reject(function ($binding) {
3312+
return $binding instanceof Expression;
3313+
})
3314+
->map([$this, 'castBinding'])
3315+
->values()
3316+
->toArray();
32933317
}
32943318

32953319
/**

tests/Integration/Database/EloquentModelEnumCastingTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,48 @@ public function testEnumsAcceptNullOnSave()
111111
'integer_status' => null,
112112
], DB::table('enum_casts')->where('id', $model->id)->first());
113113
}
114+
115+
public function testFirstOrNew()
116+
{
117+
DB::table('enum_casts')->insert([
118+
'string_status' => 'pending',
119+
'integer_status' => 1,
120+
]);
121+
122+
$model = EloquentModelEnumCastingTestModel::firstOrNew([
123+
'string_status' => StringStatus::pending,
124+
]);
125+
126+
$model2 = EloquentModelEnumCastingTestModel::firstOrNew([
127+
'string_status' => StringStatus::done,
128+
]);
129+
130+
$this->assertTrue($model->exists);
131+
$this->assertFalse($model2->exists);
132+
133+
$model2->save();
134+
135+
$this->assertEquals(StringStatus::done, $model2->string_status);
136+
}
137+
138+
public function testFirstOrCreate()
139+
{
140+
DB::table('enum_casts')->insert([
141+
'string_status' => 'pending',
142+
'integer_status' => 1,
143+
]);
144+
145+
$model = EloquentModelEnumCastingTestModel::firstOrCreate([
146+
'string_status' => StringStatus::pending,
147+
]);
148+
149+
$model2 = EloquentModelEnumCastingTestModel::firstOrCreate([
150+
'string_status' => StringStatus::done,
151+
]);
152+
153+
$this->assertEquals(StringStatus::pending, $model->string_status);
154+
$this->assertEquals(StringStatus::done, $model2->string_status);
155+
}
114156
}
115157

116158
class EloquentModelEnumCastingTestModel extends Model
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace Illuminate\Tests\Integration\Database;
4+
5+
use Illuminate\Database\Schema\Blueprint;
6+
use Illuminate\Support\Facades\DB;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
if (PHP_VERSION_ID >= 80100) {
10+
include_once 'Enums.php';
11+
}
12+
13+
/**
14+
* @requires PHP >= 8.1
15+
*/
16+
class QueryingWithEnumsTest extends DatabaseTestCase
17+
{
18+
protected function setUp(): void
19+
{
20+
parent::setUp();
21+
22+
Schema::create('enum_casts', function (Blueprint $table) {
23+
$table->increments('id');
24+
$table->string('string_status', 100)->nullable();
25+
$table->integer('integer_status')->nullable();
26+
});
27+
}
28+
29+
public function testCanQueryWithEnums()
30+
{
31+
DB::table('enum_casts')->insert([
32+
'string_status' => 'pending',
33+
'integer_status' => 1,
34+
]);
35+
36+
$record = DB::table('enum_casts')->where('string_status', StringStatus::pending)->first();
37+
$record2 = DB::table('enum_casts')->where('integer_status', IntegerStatus::pending)->first();
38+
$record3 = DB::table('enum_casts')->whereIn('integer_status', [IntegerStatus::pending])->first();
39+
40+
$this->assertNotNull($record);
41+
$this->assertNotNull($record2);
42+
$this->assertNotNull($record3);
43+
$this->assertEquals('pending', $record->string_status);
44+
$this->assertEquals(1, $record2->integer_status);
45+
}
46+
47+
public function testCanInsertWithEnums()
48+
{
49+
DB::table('enum_casts')->insert([
50+
'string_status' => StringStatus::pending,
51+
'integer_status' => IntegerStatus::pending,
52+
]);
53+
54+
$record = DB::table('enum_casts')->where('string_status', StringStatus::pending)->first();
55+
56+
$this->assertNotNull($record);
57+
$this->assertEquals('pending', $record->string_status);
58+
$this->assertEquals(1, $record->integer_status);
59+
}
60+
}

0 commit comments

Comments
 (0)