Skip to content

Extending functionality

vanqard edited this page Apr 5, 2015 · 8 revisions

Adding functionality to this package

(or: Why have you "disabled" inheritance for the PasswordManager class?)

The PasswordManager object, which is the only class you need to interact with in this package, is presently feature complete within the scope of its intent. Strictly speaking, this means it's considered unnecessary to derive a child class from it. To do so would open the developer up to either violating its intended mode of operation, through overriding the parent methods, or to muddy its interface by adding unrelated methods to the child class, thereby violating the Single Responsibiliy Principle.

In this way, inheritance is intentionally restricted through three code constructs

  • The static factory method is marked final
  • The return type of the factory method is marked 'return self()'
  • The constructor is marked private to encourage use of the factory method.

If you really do need to modify the behaviour of this object, bearing in mind that it already completely fulfils its role, the recommended approach is to decorate the PasswordManager instance with your own class - thereby favouring composition over inheritance.

The unit test suite in this package also includes a check to ensure that the PasswordManager object can still be mocked in your own application's unit tests.

Example decorator

<?php
namespace MyVendor\MyApp;

use Vanqard\PassMan\PasswordManager;

class SimpleFormToken
{
    private $pm;

    public function __construct()
    {
        $this->pm = PasswordManager::factory(); // collect your $pm instance
    }

    public function __call($method, $args)
    {
        // Proxy unimplemented methods to $pm
        if (is_callable(array($this->pm, $method))) {
            return $this->pm->{$method}($args);
        }
    }

    public function getFormToken()
    {
        $token = base64encode($this->pm->passwordHash(microtime(true)));

        // Write token into server side session storage
        $_SESSION['token'] = $token;

        // Return $token for adding to an html form
        return $token; 
    }

    public function validateToken($formToken = $_POST['token']) 
    {
        // Collect a copy of the token value from session storage
        $serverSideToken = $_SESSION['token'];

        // Nullify current token in session
        $_SESSION['token'] = false;

        // Compare the form submitted token value to session value
        return $formToken == $serverSideToken;
    }
}

Warning: Please do not use this example as a single use token generator in your own applications. It is just an example of decorating the original PasswordManager object. Single use token generators should use a much better source of entropy than microtime(true), which is about as entropic as a predictable snail.

As you might deduce, this decorator doesn't actually do any decorating. The original PasswordManager methods are still available to client code (albeit via the magic __call() method) but this class also presents an expanded interface in terms of the getFormToken() and validateToken() methods. I've taken a rather spurious example to try and make clear how you might expand on the functionality of the consumed PasswordManager object without resorting to inheritance.

Clone this wiki locally