Skip to content

Commit 93ed863

Browse files
authored
Merge pull request #56 from kitar/support-laravel-12.x
Support Laravel 12.x and PHP 8.4
2 parents 0e76904 + c880aac commit 93ed863

File tree

8 files changed

+90
-25
lines changed

8 files changed

+90
-25
lines changed

.github/workflows/php.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ jobs:
1010
strategy:
1111
matrix:
1212
include:
13+
- php: 8.4
14+
illuminate: ^12.0
1315
- php: 8.3
1416
illuminate: ^11.0
1517
- php: 8.2

CLAUDE.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Commands
6+
7+
### Testing
8+
- Run all tests: `./vendor/bin/phpunit`
9+
- Run a single test: `vendor/bin/phpunit tests/Path/To/TestFile.php`
10+
- Run a single test method: `vendor/bin/phpunit --filter testMethodName`
11+
12+
### Development
13+
- Install dependencies: `composer install`
14+
- Update dependencies: `composer update`
15+
16+
## Architecture Overview
17+
18+
This is a Laravel package that provides DynamoDB integration by adapting Laravel's database layer to work with AWS DynamoDB.
19+
20+
### Key Design Patterns
21+
22+
1. **Adapter Pattern**: The package adapts Laravel's database abstractions to DynamoDB
23+
- `Connection` extends Laravel's base connection class
24+
- `Model` extends Eloquent with DynamoDB-specific behavior
25+
- Query results are processed through `Processor` to match Laravel's expectations
26+
27+
2. **Builder Pattern**: DynamoDB queries are constructed using a fluent interface
28+
- `Query\Builder` provides chainable methods
29+
- Separate query objects for different DynamoDB operations (filter, condition, keyCondition)
30+
- `ExpressionAttributes` manages placeholder generation for expressions
31+
32+
3. **Grammar Translation**: `Query\Grammar` translates Laravel-style queries to DynamoDB API format
33+
- Uses AWS Marshaler for type conversions
34+
- Compiles expressions using DynamoDB syntax
35+
- Handles reserved words and attribute name conflicts
36+
37+
### Important Architectural Decisions
38+
39+
- **No Eloquent Relationships**: Models intentionally don't support relationships as DynamoDB is NoSQL
40+
- **Primary Keys**: Models require `primaryKey` and optionally `sortKey` properties
41+
- **Authentication**: Custom `AuthUserProvider` supports both primary key and API token authentication using DynamoDB indexes
42+
- **Batch Operations**: Native support for DynamoDB batch operations (batchGetItem, batchPutItem, etc.)
43+
- **Testing**: Use `dryRun()` method to inspect generated DynamoDB parameters without making API calls
44+
45+
### Testing Approach
46+
47+
Tests use Mockery to mock AWS SDK calls. When writing tests:
48+
- Mock the DynamoDB client for unit tests
49+
- Use `dryRun()` to test query building without API calls
50+
- Follow existing test patterns in the `tests/` directory
51+
52+
### Version Compatibility
53+
54+
- PHP: 7.3, 7.4, 8.0, 8.1, 8.2, 8.3, 8.4
55+
- Laravel: 6.x through 12.x
56+
- AWS SDK: ^3.0

README.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Install the package via Composer:
8282
$ composer require kitar/laravel-dynamodb
8383
```
8484

85-
### Laravel (6.x, 7.x, 8.x, 9.x, 10.x, 11.x)
85+
### Laravel (6.x, 7.x, 8.x, 9.x, 10.x, 11.x, 12.x)
8686

8787
Add dynamodb configs to `config/database.php`:
8888

@@ -110,6 +110,14 @@ Update the `DB_CONNECTION` variable in your `.env` file:
110110
DB_CONNECTION=dynamodb
111111
```
112112

113+
> **Note for Laravel 11+**: Laravel 11 and later versions default to `database` driver for session, cache, and queue, which are not compatible with this DynamoDB package. You'll need to configure these services to use alternative drivers. For instance:
114+
>
115+
> ```
116+
> SESSION_DRIVER=file
117+
> CACHE_STORE=file
118+
> QUEUE_CONNECTION=sync
119+
> ```
120+
113121
### Non-Laravel projects
114122
115123
For usage outside Laravel, you can create the connection manually and start querying with [Query Builder](#query-builder).
@@ -397,7 +405,7 @@ Then specify driver and model name for authentication in `config/auth.php`.
397405

398406
### Registration Controller
399407

400-
You might need to modify the registration controller. For example, if we use Laravel Breeze, the modification looks like below.
408+
You might need to modify the registration controller. For example, if we use Laravel Starter Kits, the modification looks like below.
401409

402410
```php
403411
class RegisteredUserController extends Controller
@@ -408,31 +416,30 @@ class RegisteredUserController extends Controller
408416
{
409417
$request->validate([
410418
'name' => 'required|string|max:255',
411-
'email' => ['required', 'string', 'email', 'max:255', function ($attribute, $value, $fail) {
419+
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', function ($attribute, $value, $fail) {
412420
if (User::find($value)) {
413421
$fail('The '.$attribute.' has already been taken.');
414422
}
415423
}],
416-
'password' => 'required|string|confirmed|min:8',
424+
'password' => ['required', 'confirmed', Rules\Password::defaults()],
417425
]);
418426

419-
$user = new User([
427+
$user = User::create([
420428
'name' => $request->name,
421429
'email' => $request->email,
422430
'password' => Hash::make($request->password),
423431
]);
424-
$user->save();
425-
426-
Auth::login($user);
427432

428433
event(new Registered($user));
429434

430-
return redirect(RouteServiceProvider::HOME);
435+
Auth::login($user);
436+
437+
return to_route('dashboard');
431438
}
432439
}
433440
```
434441

435-
There are two modifications. The first one is adding the closure validator for `email` instead of `unique` validator. The second one is using the `save()` method to create user instead of the `create()` method.
442+
The change is in the email validation rules. Instead of using the `unique` rule, we pass a closure to perform the duplicate check directly.
436443

437444
## Query Builder
438445

composer.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
"ci-test": "vendor/bin/phpunit --coverage-clover coverage.xml"
2121
},
2222
"require": {
23-
"php": "^7.3|^7.4|^8.0|^8.1|^8.2|^8.3",
24-
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
25-
"illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
26-
"illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
27-
"illuminate/hashing": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
23+
"php": "^7.3|^7.4|^8.0|^8.1|^8.2|^8.3|^8.4",
24+
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
25+
"illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
26+
"illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
27+
"illuminate/hashing": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
2828
"aws/aws-sdk-php": "^3.0"
2929
},
3030
"require-dev": {
31-
"illuminate/auth": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
31+
"illuminate/auth": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
3232
"symfony/var-dumper": "^5.0|^6.0|^7.0",
3333
"vlucas/phpdotenv": "^4.1|^5.0",
3434
"mockery/mockery": "^1.3",

src/Kitar/Dynamodb/Connection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ protected function getDefaultPostProcessor()
124124
*/
125125
protected function getDefaultQueryGrammar()
126126
{
127-
return $this->withTablePrefix(new Query\Grammar());
127+
return new Query\Grammar();
128128
}
129129

130130
/**

src/Kitar/Dynamodb/Query/Builder.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,8 @@ public function newQuery()
577577
*/
578578
protected function process($query_method, $processor_method)
579579
{
580+
$table_name = $this->connection->getTablePrefix() . $this->from;
581+
580582
// Compile columns and wheres attributes.
581583
// These attributes needs to interact with ExpressionAttributes during compile,
582584
// so it need to run before compileExpressionAttributes.
@@ -590,13 +592,13 @@ protected function process($query_method, $processor_method)
590592
// Compile rest of attributes.
591593
$params = array_merge(
592594
$params,
593-
$this->grammar->compileTableName($this->from),
595+
$this->grammar->compileTableName($table_name),
594596
$this->grammar->compileIndexName($this->index),
595597
$this->grammar->compileKey($this->key),
596598
$this->grammar->compileItem($this->item),
597599
$this->grammar->compileUpdates($this->updates),
598-
$this->grammar->compileBatchGetRequestItems($this->from, $this->batch_get_keys),
599-
$this->grammar->compileBatchWriteRequestItems($this->from, $this->batch_write_request_items),
600+
$this->grammar->compileBatchGetRequestItems($table_name, $this->batch_get_keys),
601+
$this->grammar->compileBatchWriteRequestItems($table_name, $this->batch_write_request_items),
600602
$this->grammar->compileDynamodbLimit($this->limit),
601603
$this->grammar->compileScanIndexForward($this->scan_index_forward),
602604
$this->grammar->compileExclusiveStartKey($this->exclusive_start_key),

src/Kitar/Dynamodb/Query/Grammar.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function __construct()
5555
public function compileTableName($table_name)
5656
{
5757
return [
58-
'TableName' => $this->tablePrefix . $table_name
58+
'TableName' => $table_name
5959
];
6060
}
6161

@@ -146,8 +146,6 @@ public function compileBatchGetRequestItems($table_name, $keys)
146146
return $marshaler->marshalItem($key);
147147
})->toArray();
148148

149-
$table_name = $this->tablePrefix . $table_name;
150-
151149
return [
152150
'RequestItems' => [
153151
$table_name => [
@@ -174,8 +172,6 @@ public function compileBatchWriteRequestItems($table_name, $request_items)
174172
});
175173
})->toArray();
176174

177-
$table_name = $this->tablePrefix . $table_name;
178-
179175
return [
180176
'RequestItems' => [
181177
$table_name => $marshaled_items,

tests/Query/BuilderTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,7 @@ public function it_can_process_scan_with_columns_specified()
11651165
public function it_can_process_process()
11661166
{
11671167
$connection = m::mock(Connection::class);
1168+
$connection->shouldReceive('getTablePrefix');
11681169
$connection->shouldReceive('scan')
11691170
->with(['TableName' => 'Forum'])
11701171
->andReturn(new Result(['Items' => []]))
@@ -1179,6 +1180,7 @@ public function it_can_process_process()
11791180
public function it_can_process_process_with_no_processor()
11801181
{
11811182
$connection = m::mock(Connection::class);
1183+
$connection->shouldReceive('getTablePrefix');
11821184
$connection->shouldReceive('putItem')
11831185
->with([
11841186
'TableName' => 'Thread',

0 commit comments

Comments
 (0)