Skip to content

Commit 3169956

Browse files
committed
update
1 parent 4ae7157 commit 3169956

File tree

6 files changed

+152
-10
lines changed

6 files changed

+152
-10
lines changed

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
"autoload": {
2323
"psr-4": {
2424
"BoredProgrammers\\LaravelEloquentMappable\\": "src/"
25-
}
25+
},
26+
"files": [
27+
"src/helpers.php"
28+
]
2629
},
2730
"extra": {
2831
"laravel": {

src/MappableGrammar.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace BoredProgrammers\LaravelEloquentMappable;
4+
5+
use Illuminate\Database\Query\Builder;
6+
use Illuminate\Database\Query\Grammars\Grammar;
7+
8+
class MappableGrammar
9+
{
10+
11+
public function __construct(
12+
private array $attributeToColumn,
13+
private Grammar $originalGrammar,
14+
)
15+
{
16+
}
17+
18+
public function compileInsert(Builder $query, array $values): string
19+
{
20+
return $this->originalGrammar->compileInsert($query, $this->mappedValues($values));
21+
}
22+
23+
public function compileUpdate(Builder $query, array $values): string
24+
{
25+
$newValues = $values;
26+
27+
foreach ($values as $column => $columnValue) {
28+
if ($mappedColumn = $this->attributeToColumn[$column] ?? null) {
29+
$newValues = array_key_rename($newValues, $column, $mappedColumn);
30+
}
31+
}
32+
33+
return $this->originalGrammar->compileUpdate($query, $newValues);
34+
}
35+
36+
public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update): string
37+
{
38+
$newUniqueBy = $uniqueBy;
39+
40+
foreach ($uniqueBy as $key => $column) {
41+
if (is_scalar($column) && $mappedColumn = $this->attributeToColumn[$column] ?? null) {
42+
$newUniqueBy[$key] = $mappedColumn;
43+
}
44+
}
45+
46+
$newUpdate = $update;
47+
48+
foreach ($update as $key => $value) {
49+
if (is_scalar($value) && $mappedColumn = $this->attributeToColumn[$value] ?? null) {
50+
$newUpdate[$key] = $mappedColumn;
51+
}
52+
53+
if (!is_numeric($key) && $mappedColumn = $this->attributeToColumn[$key] ?? null) {
54+
$newUpdate = array_key_rename($newUpdate, $key, $mappedColumn);
55+
}
56+
}
57+
58+
return $this->originalGrammar->compileUpsert($query, $this->mappedValues($values), $newUniqueBy, $newUpdate);
59+
}
60+
61+
private function mappedValues(array $values): array
62+
{
63+
if (!is_array(reset($values))) {
64+
$values = [$values];
65+
}
66+
67+
$newValues = $values;
68+
69+
foreach ($values as $index => $value) {
70+
foreach ($value as $column => $columnValue) {
71+
if ($mappedColumn = $this->attributeToColumn[$column] ?? null) {
72+
$newValues[$index] = array_key_rename($value, $column, $mappedColumn);
73+
}
74+
}
75+
}
76+
77+
return $newValues;
78+
}
79+
80+
public function __call($method, $parameters)
81+
{
82+
return $this->originalGrammar->$method(...$parameters);
83+
}
84+
85+
}

src/Models/Scopes/MappedColumnsScope.php

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

33
namespace BoredProgrammers\LaravelEloquentMappable\Models\Scopes;
44

5+
use BoredProgrammers\LaravelEloquentMappable\MappableGrammar;
56
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
67
use Illuminate\Database\Eloquent\Model;
78
use Illuminate\Database\Eloquent\Scope;
@@ -13,15 +14,18 @@ class MappedColumnsScope implements Scope
1314

1415
public function apply(EloquentBuilder $builder, Model $model): void
1516
{
16-
$builder->beforeQuery(function (QueryBuilder $builder) use ($model) {
17-
if (!$attributeToColumn = $model->mapAttributeToColumn ?? null) {
18-
return;
19-
}
17+
if (!$attributeToColumn = $model->mapAttributeToColumn ?? null) {
18+
return;
19+
}
20+
21+
$modelTable = $model->getTable();
22+
$attributeToColumnWithTable = collect($attributeToColumn)
23+
->mapWithKeys(fn($value, $key) => [$modelTable . '.' . $key => $modelTable . '.' . $value])
24+
->merge($attributeToColumn)
25+
->toArray();
2026

21-
$modelTable = $model->getTable();
22-
$attributeToColumnWithTable = collect($attributeToColumn)
23-
->mapWithKeys(fn($value, $key) => [$modelTable . '.' . $key => $modelTable . '.' . $value])
24-
->merge($attributeToColumn);
27+
$builder->beforeQuery(function (QueryBuilder $builder) use ($attributeToColumnWithTable) {
28+
$builder->grammar = new MappableGrammar($attributeToColumnWithTable, $builder->grammar);
2529

2630
$builder->columns = $this->mapColumns($builder->columns, $attributeToColumnWithTable);
2731
$builder->wheres = $this->mapColumns($builder->wheres, $attributeToColumnWithTable);

src/helpers.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php declare(strict_types=1);
2+
3+
if (!function_exists('array_key_rename')) {
4+
function array_key_rename(array $array, $oldKey, $newKey): array
5+
{
6+
$newArray = [];
7+
8+
foreach ($array as $key => $value) {
9+
$newArray[$key === $oldKey ? $newKey : $key] = $value;
10+
}
11+
12+
return $newArray;
13+
}
14+
}

tests/Unit/EloquentTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace BoredProgrammers\LaravelEloquentMappable\Tests\Unit;
44

55
use BoredProgrammers\LaravelEloquentMappable\Tests\TestCase;
6+
use Illuminate\Support\Facades\DB;
67
use Workbench\App\Models\Post;
78

89
class EloquentTest extends TestCase
@@ -37,4 +38,39 @@ public function test_delete()
3738
$this->assertEquals(1, Post::count());
3839
}
3940

41+
public function test_insert()
42+
{
43+
Post::query()->insert([
44+
'mapped_title' => 'testing title2',
45+
'content' => 'testing content2',
46+
]);
47+
48+
$firstPost = Post::first();
49+
50+
$this->assertEquals('testing title2', $firstPost->mapped_title);
51+
$this->assertEquals('testing title2', $firstPost->title);
52+
}
53+
54+
public function test_upsert()
55+
{
56+
Post::create([
57+
'mapped_title' => 'testing title2',
58+
'content' => 'testing content2',
59+
]);
60+
61+
$this->assertEquals('testing title2', Post::first()->mapped_title);
62+
63+
Post::upsert([
64+
'mapped_title' => 'testing title2',
65+
'content' => 'testing content3',
66+
], ['mapped_title'], ['mapped_title' => DB::raw('content')]);
67+
68+
$post = Post::first();
69+
70+
$this->assertEquals('testing content2', $post->mapped_title);
71+
$this->assertEquals('testing content2', $post->title);
72+
73+
$this->assertEquals(1, Post::count());
74+
}
75+
4076
}

workbench/database/migrations/2023_10_22_155026_create_posts_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public function up(): void
1111
Schema::create('posts', function (Blueprint $table) {
1212
$table->id();
1313
$table->timestamps();
14-
$table->string('title');
14+
$table->string('title')->unique();
1515
$table->text('content');
1616
});
1717
}

0 commit comments

Comments
 (0)