Request
General flow
Where it all begins...
The Request class
As reacting on requests is likely the most common prerequisite to your programmatic logic, LENKRAD has made handling requests as easy as possible. Let's first look at the static public methods:
Request::getQueries()
Returns assoc array of query parameters
Request::getQuery(string $name)
Return the value of the specified query parameter, or null
Request::getRequestMethod()
Returns a Neoan\Enums\RequestMethod case
Request::getRequestUri()
Returns a string containing the request-uri
Request::getInputs()
Returns client-payload, regardless of method
Request::getInput(string $name)
Returns the value of the specified input, or null
Request::getParameters()
Returns assoc array of route-specific parameters (see Route parameter)
Request::getParameter(string $name)
Returns the value of the specified parameter, or null
Request::getInstance(Request $mockInstance = null)
Return the current instance of the Request facade. (e.g. to mock & test)
Additionally, some useful properties are public:
$request = Request::getInstance();
$request->requestHeaders
Array containing all collected headers
$request->files
Array containing all files submitted via form-data
$request->webPath
Returns string of actual webPath before any sanitation and parsing
Request Unit Testing
To ease testing of your application code, you can set/override values at runtime. This is true for all public properties. Additionally, the following setters work statically:
Request::setParameters(array $parameters)
Expects assoc array
Request::setQueries(array $queryParameters)
Expects assoc array
Request::detachInstance()
Resets the singleton to null. (NOTE: you likely want to run getInstance() with a mock-instance after that to generate a new instance)
Using Request
You must not inject the Request into your controllers. Instead, the static methods can be used after app-instantiation anywhere in your code.
...
use Neoan\Request\Request;
class RandomClass extends Routable
{
public function __invoke(MyValidationClass $validation)
{
[
'terms-accepted' => $accepted,
'email' => $requesterEmail
] = Request::getInputs();
if(!$accepted || !$validation->isValidEmail($requesterEmail)){
$this->doSomething();
}
$this->addToNewsletter($requesterEmail);
Response::redirect('/dashboard')
}
...
}
Request guards
In order to provide a clean input/output structure while separating concerns in a clean manner, you can use validation wrappers called "Request guards". This pattern allows for abstraction similar to models, but for incoming data. Let's take the example above and make the following changes:
...
class RandomClass extends Routable
{
public function __invoke(RandomGuard $request)
{
// if we are here, all existence and validity is already taken care of
$this->addToNewsletter($request->email);
Response::redirect('/dashboard')
}
}
Our RandomGuard extends RouteGuard and may look like this
...
use Neoan\Request\RequestGuard;
class RandomGuard extends RequestGuard
{
// the request REQUIRES the property "email"
public string $email;
// the request CAN have the property "gender"
public ?string $gender;
// the request's value of "termsAccepted" is cast to boolean
public bool $termsAccepted;
// we want to further expand on what should be blocked
public function __invoke(): static
{
// let the parent do it's magic
parent::__invoke();
// now let's block requests that don't fulfil our additional requirements
$validation = new MyValidationClass();
if(!$validation->isValidEmail($this->email) || !$this->termsAccepted) {
$response = Response::getInstance();
$response->setStatusCode(400);
$response->respond('Bad Request');
}
return $this;
}
}
The RequestGuard class uses constants to manipulate default behavior. To change the default behavior, simply overwrite them in your guard.
const requestTypes = ['query', 'parameter', 'post'];
Reads from LENKRAD's request types in the provided order. You can change the order or exclude types.
const throwOnError = true;
By default, the guard stops execution and responds with a 400 status code explaining what is missing/malformed. If you want to handle errors yourself, simply set this to false;
As Guards can be chained, you can use them for complex privilege handling as well.
Before you move on
Many references on this page assume default settings. Your project might differ in behavior, paths etc.