Skip to content

Commit

Permalink
feat: insert(), update(), save() can save Email Identity with Model E…
Browse files Browse the repository at this point in the history
…vents

Remove saveWithEmailIdentity().
  • Loading branch information
kenjis committed Jul 15, 2022
1 parent 9487136 commit 51bb61b
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 37 deletions.
107 changes: 75 additions & 32 deletions src/Models/UserModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ class UserModel extends Model
];
protected $useTimestamps = true;
protected $afterFind = ['fetchIdentities'];
protected $afterInsert = ['saveEmailIdentity'];
protected $afterUpdate = ['saveEmailIdentity'];

/**
* Whether identity records should be included
* when user records are fetched from the database.
*/
protected bool $fetchIdentities = false;

/**
* Save the User for afterInsert and afterUpdate
*/
protected ?User $tempUser = null;

/**
* Mark the next find* query to include identities
*
Expand All @@ -53,7 +60,7 @@ public function withIdentities(): self
* returned from a find* method. Called
* automatically when $this->fetchIdentities == true
*
* Model event callback called `afterFind`.
* Model event callback called by `afterFind`.
*/
protected function fetchIdentities(array $data): array
{
Expand Down Expand Up @@ -185,71 +192,107 @@ public function activate(User $user): void
{
$user->active = true;

$this->saveWithEmailIdentity($user);
$this->save($user);
}

/**
* Override the BaseModel's `save()` method to allow
* updating of user email, password, or password_hash fields
* if they've been modified.
*
* @param User $data
*
* @throws ValidationException
*
* @retrun true|int|string Insert ID if $returnID is true
*/
public function save($data): bool
public function insert($data = null, bool $returnID = true)
{
assert($data instanceof User);

$this->saveWithEmailIdentity($data);
$this->tempUser = $data;

return true;
$result = parent::insert($data, $returnID);

$this->checkQueryReturn($result);

return $returnID ? $this->insertID : $result;
}

/**
* Save User and its Email Identity (email, password, or password_hash fields)
* if they've been modified.
* @param array|int|string|null $id
* @param User $data
*
* @throws ValidationException
*/
public function saveWithEmailIdentity(User $data): void
public function update($id = null, $data = null): bool
{
assert($data instanceof User);

$this->tempUser = $data;

try {
/** @throws DataException */
$result = parent::save($data);
$result = parent::update($id, $data);
} catch (DataException $e) {
$messages = [
lang('Database.emptyDataset', ['insert']),
lang('Database.emptyDataset', ['update']),
];

if (in_array($e->getMessage(), $messages, true)) {
// Save updated email identity
$user = $data;
$user->saveEmailIdentity();
$this->tempUser->saveEmailIdentity();

return;
return true;
}

throw $e;
}

if ($result) {
if ($data->id === null) {
// Insert
/** @var User $user */
$user = $this->find($this->db->insertID());

$user->email = $data->email ?? null;
$user->password = $data->password ?? '';
$user->password_hash = $data->password_hash ?? '';
} else {
// Update
$user = $data;
}
$this->checkQueryReturn($result);

return true;
}

/**
* Override the BaseModel's `save()` method to allow
* updating of user email, password, or password_hash fields
* if they've been modified.
*
* @param User $data
*
* @throws ValidationException
*/
public function save($data): bool
{
assert($data instanceof User);

$result = parent::save($data);

$this->checkQueryReturn($result);

return true;
}

/**
* Save Email Identity
*
* Model event callback called by `afterInsert` and `afterUpdate`.
*/
protected function saveEmailIdentity(array $data): array
{
// Insert
if ($this->tempUser->id === null) {
/** @var User $user */
$user = $this->find($this->db->insertID());

$user->email = $this->tempUser->email ?? '';
$user->password = $this->tempUser->password ?? '';
$user->password_hash = $this->tempUser->password_hash ?? '';

$user->saveEmailIdentity();

return $data;
}

$this->checkQueryReturn($result);
// Update
$this->tempUser->saveEmailIdentity();

return $data;
}
}
2 changes: 1 addition & 1 deletion tests/Controllers/ActionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ public function testEmailActivateVerify(): void

$this->user->active = false;
$model = auth()->getProvider();
$model->saveWithEmailIdentity($this->user);
$model->save($this->user);

$result = $this->actingAs($this->user, true)
->withSession($this->getSessionUserInfo(EmailActivator::class))
Expand Down
63 changes: 62 additions & 1 deletion tests/Unit/UserModelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@ public function testSaveInsertUser(): void
]);
}

public function testInsertUser(): void
{
$users = $this->createUserModel();

$user = $this->createNewUser();

$users->insert($user);

$user = $users->findByCredentials(['email' => 'foo@bar.com']);
$this->seeInDatabase('auth_identities', [
'user_id' => $user->id,
'secret' => 'foo@bar.com',
]);
$this->seeInDatabase('users', [
'id' => $user->id,
'active' => 0,
]);
}

private function createNewUser(): User
{
$user = new User();
Expand Down Expand Up @@ -76,6 +95,30 @@ public function testSaveUpdateUserWithUserDataToUpdate(): void
]);
}

public function testUpdateUserWithUserDataToUpdate(): void
{
$users = $this->createUserModel();
$user = $this->createNewUser();
$users->save($user);

$user = $users->findByCredentials(['email' => 'foo@bar.com']);

$user->username = 'bar';
$user->email = 'bar@bar.com';
$user->active = 1;

$users->update(null, $user);

$this->seeInDatabase('auth_identities', [
'user_id' => $user->id,
'secret' => 'bar@bar.com',
]);
$this->seeInDatabase('users', [
'id' => $user->id,
'active' => 1,
]);
}

public function testSaveUpdateUserWithNoUserDataToUpdate(): void
{
$users = $this->createUserModel();
Expand All @@ -86,7 +129,25 @@ public function testSaveUpdateUserWithNoUserDataToUpdate(): void

$user->email = 'bar@bar.com';

$users->saveWithEmailIdentity($user);
$users->save($user);

$this->seeInDatabase('auth_identities', [
'user_id' => $user->id,
'secret' => 'bar@bar.com',
]);
}

public function testUpdateUserWithNoUserDataToUpdate(): void
{
$users = $this->createUserModel();
$user = $this->createNewUser();
$users->save($user);

$user = $users->findByCredentials(['email' => 'foo@bar.com']);

$user->email = 'bar@bar.com';

$users->update(null, $user);

$this->seeInDatabase('auth_identities', [
'user_id' => $user->id,
Expand Down
6 changes: 3 additions & 3 deletions tests/Unit/UserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public function testUpdateEmail(): void
$this->user->active = 0;

$users = model(UserModel::class);
$users->saveWithEmailIdentity($this->user);
$users->save($this->user);

$user = $users->find($this->user->id);

Expand All @@ -134,7 +134,7 @@ public function testUpdatePassword(): void
$this->user->active = 0;

$users = model(UserModel::class);
$users->saveWithEmailIdentity($this->user);
$users->save($this->user);

$user = $users->find($this->user->id);

Expand All @@ -153,7 +153,7 @@ public function testUpdatePasswordHash(): void
$this->user->active = 0;

$users = model(UserModel::class);
$users->saveWithEmailIdentity($this->user);
$users->save($this->user);

$user = $users->find($this->user->id);

Expand Down

0 comments on commit 51bb61b

Please sign in to comment.