Skip to content

Commit

Permalink
Merge 71d2cfe into 27196b5
Browse files Browse the repository at this point in the history
  • Loading branch information
MGatner committed Dec 28, 2021
2 parents 27196b5 + 71d2cfe commit ea456df
Show file tree
Hide file tree
Showing 11 changed files with 419 additions and 54 deletions.
16 changes: 1 addition & 15 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,11 @@
->exclude('build')
->append([__FILE__]);

// Remove overrides for incremental changes
$overrides = [
'array_indentation' => false,
'braces' => false,
'indentation_type' => false,
];
$overrides = [];

$options = [
'finder' => $finder,
'cacheFile' => 'build/.php-cs-fixer.cache',
];

return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects();

/* Reenable For libraries after incremental changes are applied
return Factory::create(new CodeIgniter4(), $overrides, $options)->forLibrary(
'Tatter ________',
'Tatter Software',
'',
2021
);
*/
79 changes: 77 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ user is authenticated.

```php
if ($user = service('auth')->user()) {
echo 'Logged in!';
echo 'Logged in!';
}
```

Expand All @@ -54,8 +54,83 @@ You may also load the helper to use the `user_id()` convenience method as outlin
helper('auth');

if ($userId = user_id()) {
return true;
return true;
}

throw new RuntimeException('You must be authenticated!');
```

## Users

`Imposter` comes with a minimal set of classes to be fully compatible with
[Tatter\Users](https://github.com/tattersoftware/codeigniter4-users). This means that any
project or library which uses the interfaces from `Tatter\Users` can be tested using
`Imposter` without the need of an actual authentication library or even a database.

### User Entity

The `Tatter\Imposter\Entities\User` entity class implements all three entity interfaces from
`Tatter\Users`: `UserEntity`, `HasGroup`, and `HasPermission`. Use it like any regular entity,
except that the `$groups` and `$permissions` atributes are simple CSV casts for storing your
entity relationships:
```php
$user = new \Tatter\Imposter\Entities\User();
$user->groups = ['Administrators', 'Editors'];
```

### Imposter Factory

The `ImposterFactory` class allows `UserProvider` to use the `Imposter` classes automatically
during testing. To enable `ImposterFactory` add it to the list of providers during
your test's `setUp` or `setUpBeforeClass` phase:
```php
<?php

use CodeIgniter\Test\CIUnitTestCase;
use Tatter\Imposter\Factories\ImposterFactory;
use Tatter\Users\UserProvider;

final class UserWidgetTest extends CIUnitTestCase
{
public static setUpBeforeClass(): void
{
UserProvider::add(ImposterFactory::class, ImposterFactory::class);
}
...
```

Because `Imposter` is a database-free solution `UserFactory` has its own local storage for
`User` entities. Use the static methods to manipulate the storage to stage your tests:

* `index()` - Gets the current index of the store
* `add(User $user)` - Adds a `Tatter\Imposter\Entities\User` object to the store, returning the new index
* `reset()` - Resets the store and the index
* `fake()` - Returns a new `Tatter\Imposter\Entities\User` object using Faker's generated data (note: not added to the store)

For example:
```php

protected function setUp(): void
{
parent::setUp();

$user = ImposterFactory::fake();
$user->permissions = ['widgets.create'];
UserFactory::add($user);

$this->userId = ImposterFactory::index();
}

protected function tearDown(): void
{
parent::tearDown();

ImposterFactory::reset();
}

public testUserCanCreateWidget()
{
$user = service('users')->findById($this->userId);
service('auth')->login($user);
...
```
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
}
],
"require": {
"php": "^7.3 || ^8.0"
"php": "^7.3 || ^8.0",
"tatter/users": "^1.2"
},
"provide": {
"codeigniter4/authentication-implementation": "1.0"
Expand Down
38 changes: 19 additions & 19 deletions src/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,29 @@ class Auth
*/
public function login($user): void
{
if (is_int($user) || is_string($user)) {
$user = new User(['id' => $user]);
}
if (is_int($user) || is_string($user)) {
$user = new User(['id' => $user]);
}

$this->user = $user;

session()->set('logged_in', $this->user->id);
session()->set('user_id', $this->user->id);
session()->set('logged_in', $this->user->id);
session()->set('user_id', $this->user->id);

Events::trigger('login', $this->user);
Events::trigger('login', $this->user);
}

/**
* Logs out any users.
*/
public function logout(): void
{
if ($this->user !== null) {
Events::trigger('logout', $this->user);
$this->user = null;
}
if ($this->user !== null) {
Events::trigger('logout', $this->user);
$this->user = null;
}

session()->remove(['logged_in', 'user_id']);
session()->remove(['logged_in', 'user_id']);
}

/**
Expand All @@ -61,14 +61,14 @@ public function id()
*/
public function user(): ?User
{
// If there is no login then check the Session
if ($this->user === null) {
if ($id = session('logged_in')) {
$this->login($id);
} elseif ($id = session('user_id')) {
$this->login($id);
}
}
// If there is no login then check the Session
if ($this->user === null) {
if ($id = session('logged_in')) {
$this->login($id);
} elseif ($id = session('user_id')) {
$this->login($id);
}
}

return $this->user;
}
Expand Down
88 changes: 87 additions & 1 deletion src/Entities/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Tatter\Imposter\Entities;

use CodeIgniter\Entity\Entity;
use Tatter\Users\Interfaces\HasGroup;
use Tatter\Users\Interfaces\HasPermission;

class User extends Entity
class User extends Entity implements HasGroup, HasPermission
{
protected $dates = [
'created_at',
Expand All @@ -14,4 +16,88 @@ class User extends Entity
protected $attributes = [
'id' => null,
];
protected $casts = [
'groups' => 'csv',
'permissions' => 'csv',
];

//--------------------------------------------------------------------
// Tatter\Users Interface Methods
//--------------------------------------------------------------------

/**
* Returns the name of the column used to
* uniquely identify this user, typically 'id'.
*/
public function getIdentifier(): string
{
return 'id';
}

/**
* Returns the value for the identifier,
* or `null` for "uncreated" users.
*
* @return int|string|null
*/
public function getId()
{
return $this->attributes['id'] ?? null;
}

/**
* Returns the email address.
*/
public function getEmail(): ?string
{
return $this->attributes['email'] ?? null;
}

/**
* Returns the username.
*/
public function getUsername(): ?string
{
return $this->attributes['username'] ?? null;
}

/**
* Returns the name for this user.
* If names are stored as parts "first",
* "middle", "last" they should be
* concatenated with spaces.
*/
public function getName(): ?string
{
return $this->attributes['name'] ?? null;
}

/**
* Returns whether this user is eligible
* for authentication.
*/
public function isActive(): bool
{
return $this->attributes['active'] ?? false;
}

/**
* Returns whether this user is a
* member of the given group.
*/
public function hasGroup(string $group): bool
{
return in_array($group, $this->groups, true);
}

/**
* Returns whether this user has the given permission.
* Must be comprehensive and cascading (i.e. if auth
* support global or group permissions those should
* both be checked in addition to explicit user rights).
*/
public function hasPermission(string $permission): bool
{
return in_array($permission, $this->permissions, true);
}
}

0 comments on commit ea456df

Please sign in to comment.