Extending Laravel Auth with simple POPOs

By default, Laravel uses Eloquent for authentication. In some instances, you might wish to swap out Eloquent with something else. In this example, I have implemented authentication using a simple `ArrayUserRepository` that "stores" plain old PHP objects (PHP). This is implemented through a BDD approach, using Behat and phpspec. Storing users in an array, is not very suitable in the real world, but with this approach, it is super easy to swap out the repository and use something else. Maybe something like Doctrine.

First, here is the feature that I have implemented:

```gherkin
Feature: Authenticating a user
  In order to access restricted content
  As a user
  I need to be able to authenticate myself

  Scenario: Authenticating a user with valid credentials
    Given I am registered with the credentials:
      | email           | password |
      | foo@example.com | foob@r   |
    When I attempt to authenticate myself with the credentials:
      | email           | password |
      | foo@example.com | foob@r   |
    Then I should see that I am successfully authenticated

  Scenario: Authenticating a user with invalid credentials
    Given I am registered with the credentials:
      | email           | password |
      | foo@example.com | foob@r   |
    When I attempt to authenticate myself with the credentials:
      | email           | password |
      | foo@example.com | foobar   |
    Then I should see that I am not authenticated
```

Here is the service provider that registers the new extension:

```php
<?php

namespace Suhm\Auth;

use Illuminate\Support\ServiceProvider;

class AuthServiceProvider extends ServiceProvider {

    public function boot()
    {
        $this->app['auth']->extend('suhm_auth', function($app)
        {
            return $app['Suhm\Storage\UserRepository'];
        });
    }

    public function register()
    {
        // ...
    }
}
```

The repository is implementing Laravel's `UserProviderInterface` that is used by the Auth package:

```php
<?php

namespace Suhm\Storage;

use Suhm\Entity\User;
use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\UserInterface;

use Illuminate\Hashing\HasherInterface as Hasher;

class ArrayUserRepository implements UserRepository, UserProviderInterface
{
    protected $hasher;
    protected $users = [];

    public function __construct(Hasher $hasher)
    {
        $this->hasher = $hasher;
    }

    public function newInstance($input = null)
    {
        return new User($input);
    }

    public function persist(User $user)
    {
        $this->users[] = $user;
    }

    [...]

    /**
     * Validate a user against the given credentials.
     *
     * @param  \Illuminate\Auth\UserInterface  $user
     * @param  array  $credentials
     * @return bool
     */
    public function validateCredentials(UserInterface $user, array $credentials)
    {
        if (($user->email == $credentials['email']) and $this->hasher->check($credentials['password'], $user->getAuthPassword())) {
            return true;
        }

        return false;
    }
}
```

The repository returns users of the type `Suhm\Entity\User` that implements Laravel's `UserInterface`.

The simple `ArrayUserRepository` is bound to the IoC container using a singleton, since the array has to stay in memory during execution:

```php
<?php

namespace Suhm\Storage;

use Illuminate\Support\ServiceProvider;

class StorageServiceProvider extends ServiceProvider {

    public function register()
    {
        // I'm using a singleton because array needs to stay in memory
        $this->app->singleton(
            'Suhm\Storage\UserRepository',
            'Suhm\Storage\ArrayUserRepository'
        );
    }
}
```

## Test Output

```bash
$ vendor/bin/behat 
Feature: Authenticating a user
  In order to access restricted content
  As a user
  I need to be able to authenticate myself

  Scenario: Authenticating a user with valid credentials        # features/integration/auth.feature:6
    Given I am registered with the credentials:                 # IntegrationFeatureContext::iAmRegisteredWithTheCredentials()
      | email           | password |
      | foo@example.com | foob@r   |
    When I attempt to authenticate myself with the credentials: # IntegrationFeatureContext::iAttemptToAuthenticateMyselfWithTheCredentials()
      | email           | password |
      | foo@example.com | foob@r   |
    Then I should see that I am successfully authenticated      # IntegrationFeatureContext::iShouldSeeThatIAmSuccessfullyAuthenticated()

  Scenario: Authenticating a user with invalid credentials      # features/integration/auth.feature:15
    Given I am registered with the credentials:                 # IntegrationFeatureContext::iAmRegisteredWithTheCredentials()
      | email           | password |
      | foo@example.com | foob@r   |
    When I attempt to authenticate myself with the credentials: # IntegrationFeatureContext::iAttemptToAuthenticateMyselfWithTheCredentials()
      | email           | password |
      | foo@example.com | foobar   |
    Then I should see that I am not authenticated               # IntegrationFeatureContext::iShouldSeeThatIAmNotAuthenticated()

2 scenarios (2 passed)
6 steps (6 passed)
0m1.13s (16.13Mb)
```

```bash
$ vendor/bin/phpspec run --format=pretty

      Suhm\Entity\User

  10  ✔ is initializable (187ms)
  16  ✔ constructs user from input

      Suhm\Storage\ArrayUserRepository

  18  ✔ is initializable (57ms)
  25  ✔ creates a new instance
  30  ✔ persists a user instance
  37  ✔ retrieves a user from identifier
  49  ✔ retrieves a user from credentials
  61  ✔ validates a user against credentials


2 specs
8 examples (8 passed)
312ms
```

Check the [diff](https://github.com/petersuhm/laravel-bdd/pull/2/files) in order to see all files!