To answer my own question, I've decided that the best place for this is to create an AccountController
that accepts a LoginHandlerInterface
interface as a constructor argument.
The AccountController then looks like this:
namespace App\Controllers;
class AccountController
{
protected $LoginHandler;
public function __construct(\Framework\Interfaces\LoginHandlerInterface $LoginHandler)
{
$this->LoginHandler = $LoginHandler;
}
public function login()
{
if (/* ... form validation stuff ... */)
{
try
{
$this->LoginHandler->login($email, $password);
}
catch (\Framework\Exceptions\Login $e)
{
// Assign login errors to template etc...
}
}
}
}
Then whichever LoginHandler
I end up using, has everything it needs to do all of the logging in (looking up the user, validating the password, updating the session etc). This keeps my AccountController
clean, flexible, and testable.
I inject the desired LoginHandler
(and RegistrationHandler
, which I haven't shown here) via a configuration in an IoC container that auto-resolves constructor dependencies.