Requests & IO
The two ends of a route — a typed wrapper over what came in, and the structured responses that go back out — plus the helpers for validation, option lists and searches.
Request
Request wraps the incoming values so nothing is read raw. Every getter returns the type you ask
for, with a default when the field is missing, so a route never juggles isset and casts:
use Framework\IO\Request;
$request->getString("name");
$request->getInt("page", default: 1);
$request->getFloat("price");
$request->getBool("active");
$request->getDate("fromDate"); // a Date instance
$request->getFile("avatar"); // a File instance
Some fields arrive as a list or a nested structure. Those have their own getters, which parse the value into something typed:
$request->getInts("userIDs"); // list<int>
$request->getStrings("tags"); // list<string>
$request->getDict("options"); // a Dictionary
$request->getJSONArray("rows"); // a decoded JSON array
Checking and changing what is there:
$request->has("page"); // the field was sent
$request->hasValue("page"); // …and it is not empty
$request->isEmpty(); // nothing was sent at all
$request->set("page", 2);
$request->remove("page");
$request->toArray(); // and toDictionary()
An API request sends its body as JSON rather than form fields —
addPayload() merges that body into the request, so the getters work the same either way. The
request is iterable too, yielding each value.
<Model>Request replaces these calls with typed properties, and is built from this same
request.Response
Response is what every route returns. Rather than echoing anything, you pick the factory that
matches the outcome and the framework prints the JSON:
| Factory | Returns |
|---|---|
Response::data($data) | A payload — a list, an entity, whatever the screen needs. |
Response::result($result) | A raw result array. |
Response::search($data) | The results of a search. |
Response::empty() | Nothing to send back. |
Response::success($key, $data) | A success, named by a translation key. |
Response::warning($key, $data) | The same, as a warning. |
Response::error($key, $data) | The same, as an error — or an Errors bag. |
Response::invalid() | The request was not valid. |
Response::logout() | The session is over; the client should sign out. |
Response::exit($code) | End a command with an exit code. |
use Framework\IO\Response;
return Response::data([ "list" => $products, "total" => $total ]);
return Response::success("PRODUCT_CREATED", [ "productID" => $id ]);
return Response::error("PRODUCT_ERROR_EXISTS");
The success, warning and error messages are keys, not sentences, so the client renders them in the user's
language. Framework::execute() attaches fresh
tokens to the response on its way out.
Errors
Errors collects validation problems as you check a request, so the client can show each message
next to the field it belongs to instead of one message at a time:
use Framework\IO\Errors;
$errors = new Errors();
$errors->add("name", "PRODUCT_ERROR_NAME");
$errors->add("price", "PRODUCT_ERROR_PRICE");
if ($errors->has()) {
return Response::error($errors);
}
addIf() keeps the checks flat — it only records the error when the condition holds:
$errors->addIf($name === "", "name", "PRODUCT_ERROR_NAME");
$errors->addIf($price <= 0, "price", "PRODUCT_ERROR_PRICE");
$errors->addIf(!Product::exists($id), "id", "PRODUCT_ERROR_EXISTS");
| Method | Does |
|---|---|
add($field, $key) | Record an error for a field. |
addIf($cond, $field, $key) | Record it only when the condition is true. |
addFor($section, $field, $key) | Record it inside a section, for repeated groups of fields. |
form($key) / global($key) | An error about the whole form rather than a field. |
has($field) | Whether there is any error, or one for a given field. |
getTotal() / keys() | How many there are, and which fields failed. |
merge($errors) / mergeFor($section, $errors) | Fold another bag into this one. |
Select
Select builds the option lists a dropdown needs — an id and a name per entry — from whatever
shape the data is already in:
use Framework\IO\Select;
Select::create($rows, keyName: "productID", valName: "name");
Select::createFromArray([ 1 => "Active", 2 => "Blocked" ]);
Select::createFromList([ "Active", "Blocked" ]);
Select::createFromMap($map); // from an enum-keyed Map
create() is the one for database rows: point it at the id and name columns, optionally add a
descName for a second line, extraKey to carry extra columns along, useEmpty
for a blank first option and distinct to drop duplicates. Enums build their own lists through the
same class — that is what getSelect() returns.
Search
Search is the shape returned by an autocomplete or a search box — an id and a title per match,
built from the rows a query returned, skipping repeats:
use Framework\IO\Search;
$results = Search::create($data, idKey: "clientID", nameKey: "name");
// Or build the title from several columns
$results = Search::create($data, idKey: "clientID", nameKey: [ "firstName", "lastName" ]);
return Response::search($results);