Skip to content

Instantly share code, notes, and snippets.

@makoru-hikage
Created August 7, 2017 07:11
Show Gist options
  • Save makoru-hikage/d9469b66b7e8ebbf93c8da5ddc55b54b to your computer and use it in GitHub Desktop.
Save makoru-hikage/d9469b66b7e8ebbf93c8da5ddc55b54b to your computer and use it in GitHub Desktop.
The MenuService technique...
<?php
namespace DeltaX\Crud\MenuService;
/**
* Use to process input from Query Strings
* or HTTP Request bodies. Process Data determines
* if it'll a last step.
*
*/
abstract class MenuService {
/**
* Response: The Status Code
*
* @var int
*/
protected $code = 0;
/**
* Response: The main content
* of the response body
*
* @var mixed
*/
protected $outputData;
/**
* The data to be processed
*
* @var array
*/
protected $inputData = [];
/**
* The constructor
*
* @param array $input
* @return void
*/
public function __construct(array $input = []){
if (! empty($input)) {
$this->inputData = $input;
}
}
/**
* Accept an array of instances of
* MenuService. Each will process their
* input data then return their output
* data so the next instance can use
* the output data as their input data.
* When there is no instance left in
* the array, the last one shall be returned
*
* @return self
*/
public function prepend(self ...$menuServices){
$remainingMenuSvcs = $menuServices;
$currentMenuSvc = array_shift($remainingMenuSvcs);
//Prepare and "prepend" the remaining MenuServices
if ( $currentMenuSvc && $this->code === 0 ) {
$currentMenuSvc = $currentMenuSvc->setInputData($this->inputData);
$currentMenuSvc = $currentMenuSvc->setCode($this->code);
$msData = $currentMenuSvc->processData()->prepareResponse();
$this->code = $msData['code'];
$this->inputData = $msData['data'];
return $this->prepend(...$remainingMenuSvcs);
}
$this->outputData = $this->inputData;
return $this;
}
/**
* Set the input.
* Prefereably called upon __construct()
*
* @param array $input
* @return self
*/
public function setInputData(array $input) {
$this->inputData = $input;
return $this;
}
/**
* Set the code.
* Preferrably, only to be used by
* prepend()
*
* @param int $status
* @return self
*/
public function setCode(int $status) {
$this->code = $status;
return $this;
}
/**
* Response: prepare the response body.
*
* @return array
*/
public function prepareResponse() {
return [
'code' => $this->code,
'data' => $this->outputData
];
}
/**
* Let the $inputData be processed by the
* prepended MenuServices
*
* @param self $menuServices,...
* @return self
*/
public function execute(self ...$menuServices){
if ( ! empty($menuServices) ) {
$prepended = $this->prepend( ...$menuServices )->prepareResponse();
$this->inputData = $prepended['data'];
$this->code = $prepended['code'];
}
if ($this->code === 0) {
$this->processData();
}
return $this;
}
/**
* Process data: implement this method to use the
* $inputData to your will. This must also modify the
* $outputData and $code depending on the circumstance.
*
* @return self
*/
abstract protected function processData();
}
@makoru-hikage
Copy link
Author

makoru-hikage commented Aug 7, 2017

A MenuService can be treated as a step of an HTTP Request-Response transaction.

Usually, when accessing a set of grades in school, there are these questions and happenings. The assumed input is a Query String converted in an associative array.

  1. The raw array shall be converted into a SearchFilter (always return a code 0)
  2. "Are you allowed to access this?" (If no, return a code 401, 0 if yes)
  3. "Is your input valid for this?"(If no, return with a code 400, 0 if yes)
  4. Fetch Data (return with a code 200)

Using prepend(), all steps will be done through processData() of objects of MenuService class. Should a MenuService change the $code through the series, It'll end with that MenuService that changed the $code from 0 to whatever.

To translate into code...

public function getChecklist($request, $response, $arguments){

		$input = $request->getQueryParams();
		$input['student_number'] = $request
			->getAttribute('route')
			->getArgument('student_number');

                $userIdentity = (new StudentIdentity(
			new SentinelAuthenticationAdapter($this->app->sentinel), 
			new CentralRepository))->setIdentityKey($input['student_number']);

		/*** The Main MenuService */
                $studentChecklistSvc = (new MultipleReadService($input))
			->setModelService(new StudentChecklist(new CentralRepository));

                /*** The Prepended MenuServices */
                $searchFilterSvc = new SearchFilterService();

                $authService = new AuthorizationService($userIdentity, ['admin']);
	
		$validatorSvc = new SearchValidatorService(new ChecklistSearchValidation);
		
                /*** THIS IS THE EXAMPLE */
		$output = $studentChecklistSvc
			->execute($searchFilterSvc, $authService, $validatorSvc)
			->prepareResponse();

		return $response->withJson($output['data'], $output['code']);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment