Page logic conventions - phpgt/WebEngine GitHub Wiki
Page logic filenames should be identical to their corresponding page view filename - just with a php extension instead of html.
The following functions can be declared within the file, within global scope (WebEngine will automatically wrap global functions in a Logic Stream Wrapper):
-
gofor the normal page handler -
go_beforeandgo_afterfor the surrounding hooks, used when nested logic files need their order of execution tweaking -
do_*for named actions, such asdo_saveordo_submit
Action names should stay explicit and readable. The function name is made from any user input with the name of do. For example, a button like <button name="do" value="reset">Reset everything</button> will execute the do_reset function if it exists. This naming convention only applies to the do name being in the incoming request.
If a do button's value contains hyphens, these can be replaced with underscores to form a valid function name.
It's also possible to use camel casing on the do function name if preferred. Matching camel case functions will automatically be detected and executed. For example, <button name="do" value="reset-form">Reset form</button> can trigger function do_reset_form() or function do_resetForm(), whichever you prefer. The do portion of the function name is always separated by an underscore.
It's a good rule of thumb to keep the page logic as thin as possible by separating orchestration from business rules. What this means is that the page logic should do as little itself as it can, passing control over to application classes as soon as possible. That means the logic's go/do functions act as an orchestrator, requesting only the parts of the project that are required from the service container, and then getting out of the way quickly.
The less a page logic's function does itself, the more robust an application will become.
If a page needs a more local structure, the logic can optionally be wrapped in its own class, but the same underlying rules still apply: clear entry points, small handlers, and minimal hidden behaviour.
To wrap the go/do functions within a class, add a namespace starting with the App namespace, according to the directory the class is in. For example, a page accessed at /shop/plants/cactus can have its logic file at page/shop/@category/@item.php and contain the following:
namespace App\Page\Shop\_Category;
use GT\DomTemplate\Binder;
use GT\Input\Input;
use GT\Routing\Path\DynamicPath;
use App\Shop\Basket;
class _ItemPage {
public function go(
DynamicPath $path,
Binder $binder,
):void {
$binder->bindKeyValue("category", $path->get("category"));
$binder->bindKeyValue("item", $path->get("item"));
}
public function do_add_to_basket(
Basket $basket,
DynamicPath $path,
Input $input,
):void {
$category = $path->get("category");
$item = $path->get("item");
$quantity = $input->getInt("quantity") ?? 1;
$basket->add($item, $quantity);
}
}Dynamic path markers are used to match the URL, and are represented by a leading underscore in the generated class name. The @category directory becomes _Category, and the @item.php file becomes _ItemPage. In full, WebEngine looks for App\Page\Shop\_Category\_ItemPage for the file above.
The underscore to prevent dynamic and static files from colliding. For example, page/shop/@category/@item.php and page/shop/@category/item.php are different route targets, so their page logic classes must also be different: _ItemPage for the dynamic @item.php file, and ItemPage for the static item.php file.
Hypermedia here simply means HTML over HTTP. When the page uses explicit actions, deliberate redirects, and clear URL-based state, the behavioural flow stays much easier to trace.
Once a web application is built to respect hypermedia (real links, form submissions, etc.) it's so much easier to progressively enhance the application to provide a fluid user experience, without changing the core, simple request logic.
Move on to the view and binding reference page next.