Created
April 17, 2015 13:13
-
-
Save tox2ik/1f5d4123759f44673132 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* Service-registration with the command design-pattern: | |
* For details, see: http://www.oodesign.com/command-pattern.html | |
* | |
* A notable deviation from recommended approach in this implementation; | |
* A command (RegistrationTask) does most of the work. The recommended structure | |
* is to do the expensive work in the Receiver (taskReceiver). | |
* | |
* I'm not sure how we can make the receiver do the work without redefining a | |
* receiver for every service. | |
* | |
* The intention here is to reuse common registration steps without duplicating | |
* much code. Thhis is acheived because only the task-creation code (new Task()) | |
* is duplicated in each service. | |
* | |
* Besides, we do not need to run the various tasks in separate threads | |
* or via a (complex) queue. So I think it's ok to do the work in the | |
* Task->execute(). Perhaps we could think about forking things like the | |
* payex-registration in the future. | |
* | |
*/ | |
interface TaskInterface { | |
/** | |
* @return void | |
*/ | |
public function execute(); | |
public function setReceiver(TaskReceiver $taskReceiver); | |
} | |
class TaskInvoker { | |
private $tasks = []; | |
function addTask(RegistrationTask $task) { | |
$tasks[]= $task; | |
} | |
function runTasks() { | |
foreach ($tasks as $e) | |
$e->execute(); | |
} | |
} | |
class RegistrationTaskReceiver { | |
private $completedTasks; | |
private $failedTasks; | |
function receiveReport(TaskReport $tr) { | |
if ($tr->isCompleted()) { | |
$this->completedTasks[] = $tr; | |
} else { | |
$this->failedTasks[]= $tr; | |
} | |
} | |
function getSuccessReports() { | |
return $this->completedTasks; | |
} | |
function getFailureReports() { | |
return $this->failedTasks; | |
} | |
} | |
/* | |
* | |
* Tasks | |
* | |
* | |
*/ | |
abstract class RegistrationTask implements TaskInterface { | |
/* @var RegistrationTaskWorker */ | |
protected $taskReceiver; | |
public function setReceiver(TaskReceiver $tr) { | |
$this->taskReceiver = $taskReceiver; | |
} | |
public function execute() { | |
if (empty($this->taskReceiver)) { | |
throw new \mko\IllegalArgumentException('execute() can not be invoked before a taskReceiver is set.'); | |
} | |
} | |
} | |
class PlaceOrderWithPayexTask extends RegistrationTask { | |
/* @var PayexGateway */ | |
private $payex; | |
/* @var User */ | |
private $customer; | |
/* @var Order */ | |
private $order; | |
public function __construct( | |
PayexGateway $payex, | |
User $customer, | |
Order $order | |
) { | |
$this->payex = $payex; | |
$this->customer = $customer; | |
$this->order = $order; | |
} | |
public function execute() { | |
parent::execute(); | |
$failureReason = new Exception('Order could not be completed.'); | |
if (! $customer->hasPayexAgreementRef()) { | |
$payex->createAgreementRef($customer); | |
} | |
$orderRef = $payex->completeOrder($customer, $order); | |
$report = TaskReport::createFailureReport()->setData([ | |
'errors' => [ $failureReason ] | |
]); | |
if ($payex->checkUserHasPaid($orderRef)) { | |
$report = TaskReport::createSuccessfulReport()->setData([ | |
'success' => __CLASS__ | |
]); | |
} | |
$this->taskReceiver->receiveReport($report); | |
} | |
} | |
class CreateUserTask extends RegistrationTask { | |
private $user; | |
private $userRepository; | |
public function __construct(User $user, UserRepository $userRepo) { | |
$this->user = $user; | |
} | |
public function execute() { | |
$failureReason = new Exception('User was not created. Unknown reason.'); | |
try { | |
$haveUser = $userRepo->addNew($this->user); | |
} catch (\Exception $e) { | |
$failureReason = $e; | |
} | |
$report = TaskReport::createFailureReport()->addData([ 'errors' => [ $failureReason]]); | |
if ($haveUser) { | |
$report = TaskReport::createSuccessfulReport()->setData([ | |
'success' => __CLASS__, | |
'user' => $this->user , | |
]); | |
} | |
$this->taskReceiver->receiveReport($report); | |
} | |
} | |
/* | |
* | |
* Services | |
* | |
* | |
*/ | |
abstract class RegistrationService { | |
use \Myworkout\Traits\SetOrGetTrait; | |
private $taskReceiver; | |
private $taskInvoker; | |
/* registration steps */ | |
private $registrationTaskList; | |
public $request; | |
/* state flags */ | |
private $registrationSuccessState; | |
/* | |
These dependencies should not be in the constructor of the service, | |
because they belong to a task | |
"check coupon" is a task | |
CouponService $couponService, | |
$this->couponService = $couponService; | |
"create user" is a task. | |
UserRepositoryInterface $userRepository | |
$this->userRepository = $userRepository; | |
"send email" is a task. | |
MailerInterface $mailer, | |
$this->mailer = $mailer; | |
The nonce interface is should not be here because the controller | |
(validation) should not pass bad requests to the registration service | |
NonceInterface $nonce, | |
$this->nonce = $nonce; | |
*/ | |
public function __construct( | |
Config $config, | |
SessionInterface $session, | |
TaskInvoker $taskInvoker, | |
TaskReceiver $taskReceiver | |
) { | |
$this->config = $config; | |
$this->session = $session; | |
$this->taskInvoker = $taskReceiver; | |
$this->taskReceiver = $taskReceiver; | |
} | |
public function addRegistrationTask(TaskInterface $task) { | |
$this->registrationTasksList[] = $task; | |
} | |
public function processRegistration($request) { | |
$this->request = $request; | |
foreach ($this->registrationTasksList as $e) { | |
$this->taskInvoker->addTask($e); | |
} | |
$this->taskInvoker->runTasks(); | |
$failedTasks = $this->taskInvoker->getFailureReports(); | |
$completedTasks = $this->taskInvoker->getFailureReports(); | |
if (!empty($failedTasks)) { | |
$this->isSuccessfulRegistration(false); | |
//return? | |
$this->signalController(array_merge($failedTasks, $completedTasks)); | |
} else { | |
$this->isSuccessfulRegistration(true); | |
//return? | |
$this->signalController($completedTasks); | |
} | |
} | |
/* Helpers that subclasses will need */ | |
protected function createUserFromRequest() { | |
return User::create() | |
->firstName($this->request->get('user_name')) | |
->emal($this->request->get('user_email')) | |
->password($this->request->get('user_password')); | |
} | |
public function isSuccessfulRegistration() { | |
return $this->setOrGet(func_get_args(), $this->registrationSuccessState); | |
} | |
} | |
class PutUserInGroupTask extends RegistrationTask { | |
} | |
class MyworkoutRegistrationService extends RegistrationService { | |
public function __construct( | |
Config $config, | |
SessionInterface $session, | |
TaskInvoker $taskInvoker, | |
TaskReceiver $taskReceiver, | |
PayexGateway $payex | |
) { | |
$this->config = $config; | |
$this->session = $session; | |
$this->taskInvoker = $taskReceiver; | |
$this->taskReceiver = $taskReceiver; | |
$this->payex = $payex; | |
} | |
public function processRegistration($request) { | |
$user = $this->createUserFromForm(); | |
$createUserTask = new CreateUserTask( | |
$user, | |
$this->userRepo | |
); | |
$payexTask = new PlaceOrderWithPayexTask( | |
$this->payex, | |
$user, | |
$this->order | |
); | |
$this->addRegistrationTask($createUserTask); | |
$this->addRegistrationTask($payexTask); | |
return parent::processRegistration($request); | |
} | |
} | |
class PowelRegistrationService extends RegistrationService { | |
public function __construct( | |
Config $config, | |
SessionInterface $session, | |
TaskInvoker $taskInvoker, | |
TaskReceiver $taskReceiver, | |
MkoGroup $rootGroup | |
) { | |
$this->config = $config; | |
$this->session = $session; | |
$this->taskInvoker = $taskReceiver; | |
$this->taskReceiver = $taskReceiver; | |
$this->rootGroup = $rootGroup; | |
} | |
public function processRegistration($request) { | |
$user = $this->createUserFromForm(); | |
$createUserTask = new CreateUserTask( | |
$user, | |
$this->userRepo | |
); | |
$putUserInGroupTask = new PutUserInGroupTask( | |
$user, | |
$request->group_id, | |
$rootGroup | |
); | |
$this->addRegistrationTask($createUserTask); | |
$this->addRegistrationTask($putUserInGroupTask); | |
return parent::processRegistration($request); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment