Skip to content

Commit b10d30b

Browse files
committed
Add experimental model
1 parent f0bb443 commit b10d30b

File tree

5 files changed

+440
-147
lines changed

5 files changed

+440
-147
lines changed

README.md

Lines changed: 74 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,23 @@ This package provides QueryBuilder for DynamoDB.
2525
- [Filter Expressions for Scan](#filter-expressions-for-scan)
2626
- [Using Global Secondary Indexes in DynamoDB](#using-global-secondary-indexes-in-dynamodb)
2727
- [Querying a Global Secondary Index](#querying-a-global-secondary-index)
28-
- [Authentication (Custom User Provider)](#authentication-custom-user-provider)
29-
- [Make User model](#make-user-model)
28+
- [Models](#models)
29+
- [Binding model to the QueryBuilder](#binding-model-to-the-querybuilder)
30+
- [Authentication](#authentication)
31+
- [Make user model](#make-user-model)
3032
- [Make custom user provider](#make-custom-user-provider)
31-
- [Register our custom user provider](#register-our-custom-user-provider)
33+
- [Register custom user provider](#register-custom-user-provider)
3234
- [Add config for user provider](#add-config-for-user-provider)
3335

3436
## Motivation
3537

3638
I started trying to make simple QueryBuilder because:
3739

3840
- I want to use DynamoDB with Laravel. (e.g., authenticate with custom user provider)
39-
- I don't want to extend Eloquent because DynamoDB looks quite different from relational databases.
41+
- I don't want to extend Eloquent Query Builder because DynamoDB looks quite different from relational databases.
4042
- I want to use a simple API which doesn't need to worry about cumbersome things like manually handling Expression Attributes.
4143
- I'm longing for [jessengers/laravel-mongodb](https://github.com/jenssegers/laravel-mongodb). What if we have that for DynamoDB?
4244

43-
There's no Model for DynamoDB at this time, but I might add it if there's a good design idea.
44-
4545
## Installation
4646

4747
Install the package via Composer:
@@ -288,200 +288,131 @@ $response = DB::table('Reply')
288288
->query();
289289
```
290290

291-
## Authentication (Custom User Provider)
291+
## Models
292292

293-
We can create Custom User Provider to authenticate with DynamoDB. For the detail, please refer to [Laravel's official document](https://laravel.com/docs/6.x/authentication#adding-custom-user-providers).
293+
`Kitar\Dynamodb\Model\Model` is a experimental Model implementation for this package.
294+
295+
It works like Eloquent Model, but there is no model querying features. Model's features to interact DynamoDB is only `save`, `update` and `delete`.
294296

295-
The Following codes are an example of custom user provider. It's simplified and not tested, so **don't use them in production**.
297+
Instead we don't have model query, we'll tell the QueryBuilder to instantiate DynamoDB response with the specified model.
296298

297-
### Make User model
299+
### Binding model to the QueryBuilder
298300

299-
To bind with authentication, we need to prepare User model which implements `Illuminate\Contracts\Auth\Authenticatable`.
301+
For example, we have some user model below.
300302

301303
```php
304+
<?php
305+
302306
namespace App;
303307

304-
use Illuminate\Support\Facades\DB;
305-
use Illuminate\Contracts\Auth\Authenticatable as AuthAuthenticatable;
308+
use Kitar\Dynamodb\Model\Model;
309+
use Illuminate\Auth\Authenticatable;
310+
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
306311

307-
class User implements AuthAuthenticatable
312+
class User extends Model implements AuthenticatableContract
308313
{
309-
protected $params;
310-
311-
public function __construct($params)
312-
{
313-
$this->params = collect($params);
314-
}
315-
316-
public function __get($name)
317-
{
318-
return $this->params[$name] ?? null;
319-
}
314+
use Authenticatable;
320315

321316
/**
322-
* Get the name of the unique identifier for the user.
317+
* The table associated with the model.
323318
*
324-
* @return string
319+
* @var string
325320
*/
326-
public function getAuthIdentifierName()
327-
{
328-
return 'id';
329-
}
321+
protected $table = 'table_name';
330322

331323
/**
332-
* Get the unique identifier for the user.
333-
*
334-
* @return mixed
324+
* The Primary (Partition) Key.
325+
* @var string
335326
*/
336-
public function getAuthIdentifier()
337-
{
338-
return $this->params['id'];
339-
}
327+
protected $primaryKey = 'id';
340328

341329
/**
342-
* Get the password for the user.
343-
*
344-
* @return string
330+
* The Sort Key.
331+
* @var string|null
345332
*/
346-
public function getAuthPassword()
347-
{
348-
return $this->params['password'];
349-
}
333+
protected $sortKey = 'type';
350334

351335
/**
352-
* Get the token value for the "remember me" session.
353-
*
354-
* @return string
336+
* The default value of the Sort Key.
337+
* @var string|null
355338
*/
356-
public function getRememberToken()
357-
{
358-
return $this->params['remember_token'] ?? null;
359-
}
339+
protected $sortKeyDefault = 'profile';
360340

361341
/**
362-
* Set the token value for the "remember me" session.
342+
* The attributes that are mass assignable.
363343
*
364-
* @param string $value
365-
* @return void
344+
* @var array
366345
*/
367-
public function setRememberToken($value)
368-
{
369-
$this->params['remember_token'] = $value;
346+
protected $fillable = [
347+
'id', 'type'
348+
];
349+
}
350+
```
370351

371-
DB::table('User')->putItem($this->params->toArray());
372-
}
352+
Then, let QueryBuilder know model class by `usingModel`.
373353

374-
/**
375-
* Get the column name for the "remember me" token.
376-
*
377-
* @return string
378-
*/
379-
public function getRememberTokenName()
380-
{
381-
return 'remember_token';
382-
}
383-
}
354+
```php
355+
$response = DB::table('table_name')
356+
->usingModel(App\User::class)
357+
->getItem([
358+
'id' => '[email protected]',
359+
'type' => 'profile'
360+
]);
384361
```
385362

386-
### Make custom user provider
363+
`$response['Item']` will be the User model instance.
364+
365+
> behind the scene when specifying `usingModel`, Query Processor is converting each items to model instance with `(new $modelClass)-newFromBuilder($item)`.
366+
367+
After retrieving the model instance, we can `save`, `update` and `delete` in the same manner as Eloquent Model.
387368

388-
Next, we'll make custom user provider.
369+
Also, we can create new instance like below.
389370

390371
```php
391-
namespace App\Providers;
372+
$user = new App\User([
373+
'id' => '[email protected]',
374+
'type' => 'profile'
375+
]);
376+
377+
$user->save();
378+
```
392379

393-
use App\User;
394-
use Illuminate\Contracts\Auth\Authenticatable;
395-
use Illuminate\Contracts\Auth\UserProvider as BaseUserProvider;
396-
use Illuminate\Support\Facades\DB;
397-
use Illuminate\Support\Facades\Hash;
380+
However, because we don't have model query, we can't use `create` or `firstOrCreate` or things like that.
398381

399-
class AuthUserProvider implements BaseUserProvider
400-
{
401-
/**
402-
* Retrieve a user by their unique identifier.
403-
*
404-
* @param mixed $identifier
405-
* @return \Illuminate\Contracts\Auth\Authenticatable|null
406-
*/
407-
public function retrieveById($identifier)
408-
{
409-
$item = DB::table('User')->getItem(['id' => $identifier])['Item'];
382+
## Authentication
410383

411-
return new User($item);
412-
}
384+
We can create Custom User Provider to authenticate with DynamoDB. For the detail, please refer to [Laravel's official document](https://laravel.com/docs/6.x/authentication#adding-custom-user-providers).
413385

414-
/**
415-
* Retrieve a user by their unique identifier and "remember me" token.
416-
*
417-
* @param mixed $identifier
418-
* @param string $token
419-
* @return \Illuminate\Contracts\Auth\Authenticatable|null
420-
*/
421-
public function retrieveByToken($identifier, $token)
422-
{
423-
$user = $this->retrieveById($identifier);
386+
In this section, we'll use example `App\User` model above to implement DynamoDB authentication.
424387

425-
if ($user->getRememberToken() == $token) {
426-
return $user;
427-
}
428-
}
388+
### Make user model
429389

430-
/**
431-
* Update the "remember me" token for the given user in storage.
432-
*
433-
* @param \Illuminate\Contracts\Auth\Authenticatable $user
434-
* @param string $token
435-
* @return void
436-
*/
437-
public function updateRememberToken(Authenticatable $user, $token)
438-
{
439-
$user->setRememberToken($token);
440-
}
390+
`Kitar\Dynamodb\Model\Model` is compatible to `Illuminate\Auth\Authenticatable`, so our `App\User` class is just using it.
441391

442-
/**
443-
* Retrieve a user by the given credentials.
444-
*
445-
* @param array $credentials
446-
* @return \Illuminate\Contracts\Auth\Authenticatable|null
447-
*/
448-
public function retrieveByCredentials(array $credentials)
449-
{
450-
return $this->retrieveById($credentials['email']);
451-
}
392+
### Make custom user provider
452393

453-
/**
454-
* Validate a user against the given credentials.
455-
*
456-
* @param \Illuminate\Contracts\Auth\Authenticatable $user
457-
* @param array $credentials
458-
* @return bool
459-
*/
460-
public function validateCredentials(Authenticatable $user, array $credentials)
461-
{
462-
return Hash::check($credentials['password'], $user->password);
463-
}
464-
}
465-
```
394+
We'll use `Kitar\Dynamodb\Model\AuthUserProvider` for this time.
466395

467-
### Register our custom user provider
396+
### Register custom user provider
468397

469398
Then we register them at `boot()` method in `App/Providers/AuthServiceProvider.php`.
470399

471400
```php
401+
use Kitar\Dynamodb\Model\AuthUserProvider;
402+
...
472403
public function boot()
473404
{
474405
$this->registerPolicies();
475406

476407
Auth::provider('dynamodb', function ($app, array $config) {
477-
return new AuthUserProvider;
408+
return new AuthUserProvider(new $config['model']);
478409
});
479410
}
480411
```
481412

482413
### Add config for user provider
483414

484-
Finally, we can add config for our custom user provider at `config/database.php`.
415+
Finally, we specify model class name in config at `config/database.php`.
485416

486417
```php
487418
'providers' => [
@@ -494,6 +425,7 @@ Finally, we can add config for our custom user provider at `config/database.php`
494425
// DynamoDB
495426
'users' => [
496427
'driver' => 'dynamodb',
428+
'model' => App\User::class,
497429
],
498430
],
499431
```
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
namespace Kitar\Dynamodb\Model;
4+
5+
use Illuminate\Contracts\Auth\Authenticatable;
6+
use Illuminate\Contracts\Auth\UserProvider as BaseUserProvider;
7+
use Illuminate\Support\Facades\DB;
8+
use Illuminate\Support\Facades\Hash;
9+
10+
class AuthUserProvider implements BaseUserProvider
11+
{
12+
protected $model;
13+
14+
public function __construct(Authenticatable $model)
15+
{
16+
$this->model = $model;
17+
}
18+
19+
/**
20+
* Retrieve a user by their unique identifier.
21+
*
22+
* @param mixed $identifier
23+
* @return \Illuminate\Contracts\Auth\Authenticatable|null
24+
*/
25+
public function retrieveById($identifier)
26+
{
27+
$identifierName = $this->model->getAuthIdentifierName();
28+
29+
$this->model->$identifierName = $identifier;
30+
31+
$response = DB::table($this->model->getTable())
32+
->usingModel(get_class($this->model))
33+
->getItem($this->model->getKey());
34+
35+
return $response['Item'];
36+
}
37+
38+
/**
39+
* Retrieve a user by their unique identifier and "remember me" token.
40+
*
41+
* @param mixed $identifier
42+
* @param string $token
43+
* @return \Illuminate\Contracts\Auth\Authenticatable|null
44+
*/
45+
public function retrieveByToken($identifier, $token)
46+
{
47+
$user = $this->retrieveById($identifier);
48+
49+
if ($user->getRememberToken() == $token) {
50+
return $user;
51+
}
52+
}
53+
54+
/**
55+
* Update the "remember me" token for the given user in storage.
56+
*
57+
* @param \Illuminate\Contracts\Auth\Authenticatable $user
58+
* @param string $token
59+
* @return void
60+
*/
61+
public function updateRememberToken(Authenticatable $user, $token)
62+
{
63+
$user->setRememberToken($token);
64+
}
65+
66+
/**
67+
* Retrieve a user by the given credentials.
68+
*
69+
* @param array $credentials
70+
* @return \Illuminate\Contracts\Auth\Authenticatable|null
71+
*/
72+
public function retrieveByCredentials(array $credentials)
73+
{
74+
return $this->retrieveById($credentials['email']);
75+
}
76+
77+
/**
78+
* Validate a user against the given credentials.
79+
*
80+
* @param \Illuminate\Contracts\Auth\Authenticatable $user
81+
* @param array $credentials
82+
* @return bool
83+
*/
84+
public function validateCredentials(Authenticatable $user, array $credentials)
85+
{
86+
return Hash::check($credentials['password'], $user->password);
87+
}
88+
}

0 commit comments

Comments
 (0)