1.1 What is the Router?
The Router
in the DotApp
Framework is a class Dotsystems\App\Parts\Router
that processes incoming HTTP requests and directs them to the appropriate handlers. It works in conjunction with the Request
object, which contains information about the request (path, method, variables). Its primary role is to simplify route definition and ensure the correct code is executed for a given URL and HTTP method.
The Router
is integrated directly into the framework's core, so you don’t need to install or configure it separately – simply use it via $dotApp->router
.
1.2 Key Features
The Router
offers a wide range of features that make application development easier:
- HTTP Method Support: Define routes for
GET
, POST
, PUT
, DELETE
, PATCH
, OPTIONS
, HEAD
, TRACE
, and the universal ANY
method.
- Dynamic Routes: Use variables (e.g.,
{id}
) and regular expressions to capture parts of the URL.
- Middleware: Support for
before
and after
hooks to execute logic before and after the main handler.
- Request Object: Passes request information to callbacks and controllers.
- Flexibility: Ability to use anonymous functions, controllers, or middleware via strings (e.g.,
"module:controller@function"
).
- Chaining: Method chaining for cleaner code.
1.3 Basic Routing Principles
The Router
compares the current URL (obtained from request->getPath()
) and HTTP method (from request->getMethod()
) with defined routes. If a match is found:
- Any
before
hooks are executed.
- The main logic (callback, controller, or middleware) is performed.
- Any
after
hooks are executed.
Routes can be:
- Static: Exact URL match (e.g.,
/home
).
- Dynamic: Contain variables or wildcards (e.g.,
/user/{id}
).
- First Match Wins: The first matching route is used; subsequent matches are ignored.
The Router
resolves requests using the resolve()
method, which is typically called automatically within the DotApp
lifecycle.
Example of a Basic Route:
$dotApp->router->get('/home', function ($request) {
return "Welcome to the homepage!";
});
When accessing the URL http://example.com/home
, the text "Welcome to the homepage!" is displayed.
2. Getting Started
This chapter guides you through the basics of working with the Router
in the DotApp
Framework – from initialization to defining your first route.
2.1 Router Initialization
The Router
is automatically initialized as part of the $dotApp
instance when the application is created in the DotApp
Framework. There’s no need to manually create or configure it – simply access it via $dotApp->router
. During initialization, default values are set, such as the controller directory (__ROOTDIR__/App/Parts/Controllers/
) and empty arrays for routes and hooks.
Technical Details:
- The
Router
is an instance of the Dotsystems\App\Parts\Router
class.
- During construction, it receives
$dotAppObj
(an instance of the main DotApp
class), giving it access to the Request
object and other framework services.
2.2 Accessing the Router in DotApp
You access the Router
through the global $dotApp
instance, which is available anywhere in the application after its bootstrap. The Request
object is automatically available via $dotApp->router->request
and carries information about the current request (path, method, variables).
Example of Access:
// Check the current path
echo $dotApp->router->request->getPath(); // E.g., "/home"
// Check the HTTP method
echo $dotApp->router->request->getMethod(); // E.g., "get"
2.3 Defining Your First Route
The simplest way to start with the Router
is to define a basic route using one of the HTTP methods (e.g., get()
). A route can be linked to an anonymous function (callback), a controller, or middleware.
Example of a First Route with a Callback:
$dotApp->router->get('/home', function ($request) {
return "Welcome to the homepage!";
});
Explanation:
/home
: Static URL path.
function($request)
: Callback that accepts the Request
object and returns a response.
- When calling
http://example.com/home
, the text "Welcome to the homepage!" is displayed.
Example with a Controller:
Suppose you have a controller HomeController
in __ROOTDIR__/App/Parts/Controllers/HomeController.php
with a function index
:
// HomeController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class HomeController {
public static function index($request) {
return "This is the homepage from the controller!";
}
}
// Route definition
$dotApp->router->get('/home', 'HomeController@index');
Explanation:
'HomeController@index'
: Reference to the static index
method in the HomeController
class.
- The
Router
automatically loads and calls this method with the Request
object.
Running the Routing:
The Router
processes requests after calling $dotApp->router->resolve()
, which is typically in the main application script (e.g., index.php
). If the framework is properly set up, this call may be automatic.
// index.php
require_once 'vendor/autoload.php';
$dotApp = new Dotsystems\App\DotApp();
$dotApp->router->get('/home', function ($request) {
return "Welcome!";
});
$dotApp->router->resolve();
3. Defining Routes
This chapter explains how to define routes in the Router
of the DotApp
Framework. The Router
supports various definition methods – from basic HTTP methods to dynamic routes with variables and working with controllers.
3.1 Basic HTTP Methods (GET, POST, etc.)
The Router
provides methods for all standard HTTP methods: get()
, post()
, put()
, delete()
, patch()
, options()
, head()
, and trace()
. Each method defines a route for a specific HTTP request.
Example of a GET Route:
$dotApp->router->get('/about', function ($request) {
return "This is the About Us page!";
});
Example of a POST Route:
$dotApp->router->post('/submit', function ($request) {
return "The form has been submitted!";
});
Note: Each method takes the URL path as the first parameter and a callback (or controller reference) as the second parameter. The callback always receives the $request
object.
3.2 The match()
Method for Multiple Methods and URLs
The match()
method allows defining a route for multiple HTTP methods at once or for an array of URLs. It’s a more flexible approach compared to standalone methods like get()
or post()
.
Example with Multiple Methods:
$dotApp->router->match(['get', 'post'], '/contact', function ($request) {
return "This is the contact page!";
});
This route works for both GET
and POST
requests to /contact
.
Example with Multiple URLs:
$dotApp->router->match(['get'], ['/home', '/index'], function ($request) {
return "Welcome to the homepage!";
});
The route captures requests to both /home
and /index
.
3.3 Static vs. Dynamic Routes
The Router
distinguishes between static and dynamic routes:
- Static Routes: Exact URL match (e.g.,
/home
).
- Dynamic Routes: Contain variables or wildcards (e.g.,
/user/{id}
).
Example of a Static Route:
$dotApp->router->get('/profile', function ($request) {
return "This is a static profile!";
});
Example of a Dynamic Route:
$dotApp->router->get('/user/{id}', function ($request) {
return "User profile with ID: " . $request->matchData()['id'];
});
For the URL /user/123
, it displays "User profile with ID: 123".
3.4 Using Variables in Routes
Dynamic routes can include variables marked with curly braces (e.g., {id}
). These variables are automatically extracted and available via $request->matchData()
.
Basic Usage:
$dotApp->router->get('/article/{slug}', function ($request) {
return "Article: " . $request->matchData()['slug'];
});
For /article/how-to-cook
, it displays "Article: how-to-cook".
Typed Variables:
The Router
also supports variable typing:
{param:s}
: String (no slashes).
{param:i}
: Integer.
{param:l}
: Letters only.
{param?}
: Optional parameter.
{param*}
: Wildcard (captures everything).
$dotApp->router->get('/user/{id:i}', function ($request) {
return "User ID: " . $request->matchData()['id'];
});
Works only for numbers, e.g., /user/123
, but not /user/abc
.
3.5 Working with Controllers and Middleware
In addition to anonymous functions, you can map routes to controllers or middleware using a string in the format "module:controller@function"
or "module:\\middleware\\middleware1@function1"
.
Example with a Controller:
// app/parts/controllers/UserController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class UserController {
public static function show($request) {
return "Displaying the user!";
}
}
// Route definition
$dotApp->router->get('/user', 'UserController@show');
Example with Middleware:
// app/parts/middleware/AuthMiddleware.php
namespace Dotsystems\App\Parts\Middleware;
use Dotsystems\App\DotApp;
class AuthMiddleware {
public static function check($request) {
return "Authentication check!";
}
}
// Route definition
$dotApp->router->get('/secure', 'parts:\\Middleware\\AuthMiddleware@check');
Note: Functions must be defined as public static
and accept $request
as a parameter.
4. Working with the Request Object
The Request
object is an integral part of the Router
in the DotApp
Framework. It carries information about the current HTTP request and is automatically passed to callbacks, controllers, and middleware. This chapter explains how it works and how to use it effectively.
4.1 What is Request?
The Request
is an instance of the Dotsystems\App\Parts\Request
class, serving as an interface for working with request data. It contains information about the path, HTTP method, variables from dynamic routes, and other request attributes. It is automatically created during the Router
initialization and is accessible via $dotApp->router->request
.
Key Features:
- Retrieving the current URL path and method.
- Accessing variables from dynamic routes via
matchData()
.
- Passing data to callbacks and hooks.
4.2 Accessing Data from Request
The Request
object provides methods to retrieve basic request information:
getPath()
: Returns the current URL path (e.g., /home
).
getMethod()
: Returns the HTTP method (e.g., get
, post
).
matchData()
: Returns an array of variables extracted from a dynamic route.
hookData()
: Returns data assigned to hooks (used with standalone before
/after
).
Example of Access:
$dotApp->router->get('/user/{id}', function ($request) {
$path = $request->getPath(); // "/user/123"
$method = $request->getMethod(); // "get"
$id = $request->matchData()['id']; // "123"
return "Path: $path, Method: $method, ID: $id";
});
For a request to /user/123
, it displays: "Path: /user/123, Method: get, ID: 123".
4.3 Using Request in Callbacks
The Request
object is automatically passed as a parameter to all callbacks, controllers, and middleware defined in routes. It allows you to work with request data directly within the route’s logic.
Example with an Anonymous Function:
$dotApp->router->get('/profile/{name}', function ($request) {
$name = $request->matchData()['name'];
return "Hello, $name!";
});
For /profile/Jano
, it displays: "Hello, Jano!".
Example with a Controller:
// app/parts/controllers/ProfileController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class ProfileController {
public static function show($request) {
$name = $request->matchData()['name'];
return "Profile for: $name";
}
}
// Route definition
$dotApp->router->get('/profile/{name}', 'ProfileController@show');
The result is the same as with the anonymous function.
Example with Middleware:
// app/parts/middleware/CheckMiddleware.php
namespace Dotsystems\App\Parts\Middleware;
use Dotsystems\App\DotApp;
class CheckMiddleware {
public static function verify($request) {
$path = $request->getPath();
return "Verified path: $path";
}
}
// Route definition
$dotApp->router->get('/check', 'parts:\\Middleware\\CheckMiddleware@verify');
For /check
, it displays: "Verified path: /check".
Note: matchData()
returns an empty array if the route contains no dynamic variables. Verify the existence of a key before use, e.g., isset($request->matchData()['id'])
, to avoid errors.
5. Middleware (Before and After Hooks)
Middleware in the Router
of the DotApp
Framework allows you to execute additional logic before or after the main route handler. These "hooks" are defined using the before()
and after()
methods and are ideal for tasks such as authentication, logging, or response modification.
5.1 What Are Hooks?
Hooks are functions that run automatically at specific stages of route processing:
before
: Executes before the main route logic (e.g., callback or controller).
after
: Executes after the main logic, with access to the route’s result.
Hooks accept the $request
object as a parameter and can be defined globally, for a specific route, or for a method with a route.
5.2 Defining before()
The before()
method is used to add logic that executes before the main handler. It can be applied in three ways:
- Globally: For all routes.
- For a Specific Route: Only for a given path.
- For a Method and Route: Specifically for an HTTP method and path.
Global Before:
$dotApp->router->before(function ($request) {
return "Before every route!";
});
$dotApp->router->get('/test', function ($request) {
return "Test page";
});
The hook runs for all routes, e.g., for /test
, "Before every route!" executes first.
Before for a Specific Route:
$dotApp->router->get('/secure', function ($request) {
return "Secure page";
})->before(function ($request) {
return "Verifying access...";
});
The hook runs only for /secure
.
Before with a Method and Route:
$dotApp->router->before('get', '/login', function ($request) {
return "Checking login for GET";
});
$dotApp->router->get('/login', function ($request) {
return "Login page";
});
5.3 Defining after()
The after()
method runs after the main handler and has the same definition options as before()
. It’s useful for modifying results or logging.
Global After:
$dotApp->router->after(function ($request) {
return "After every route!";
});
$dotApp->router->get('/test', function ($request) {
return "Test page";
});
The hook runs after every route, e.g., for /test
, "Test page" executes first, followed by "After every route!".
After for a Specific Route:
$dotApp->router->get('/profile', function ($request) {
return "Profile page";
})->after(function ($request) {
return "Profile has been displayed";
});
After with a Method and Route:
$dotApp->router->after('post', '/submit', function ($request) {
return "Form has been processed";
});
$dotApp->router->post('/submit', function ($request) {
return "Submission successful";
});
5.4 Using with Multiple Routes
You can assign hooks to multiple routes at once using an array of paths with the match()
method or by calling before()
/after()
separately.
Example with Match:
$dotApp->router->match(['get'], ['/home', '/index'], function ($request) {
return "Homepage";
})->before(function ($request) {
return "Before the homepage";
})->after(function ($request) {
return "After the homepage";
});
The hooks apply to both paths: /home
and /index
.
Example with an Array of Paths:
$dotApp->router->before('get', ['/page1', '/page2'], function ($request) {
return "Before the pages";
});
$dotApp->router->get('/page1', function ($request) {
return "Page 1";
});
$dotApp->router->get('/page2', function ($request) {
return "Page 2";
});
Note: The output from hooks is appended to the route’s response. To modify the response, work directly with $request->response->body
in the hook (more in advanced features).
6. Error and Exception Handling
The Router
in the DotApp
Framework allows developers to manage errors and exceptions that occur during request processing. This chapter explains how to handle standard errors like 404 and implement custom error-handling logic using callbacks and hooks.
6.1 Handling 404 Errors
If the Router
finds no match for a request (neither a static nor dynamic route), it automatically sets the HTTP code to 404. The default behavior shows no output, so it’s up to the developer to define custom logic to catch and display the error.
Example with a Global After Hook:
$dotApp->router->after("*", function ($request) {
if (http_response_code() === 404) {
return "Page not found: " . $request->getPath();
}
});
$dotApp->router->get('/home', function ($request) {
return "Homepage";
});
For a request to /about
(a non-existent route), it displays: "Page not found: /about". The hook with "*"
runs for all routes and checks the status code.
Example with Script Termination:
$dotApp->router->after("*", function ($request) {
if (http_response_code() === 404) {
echo "404 - Page not found!";
exit;
}
});
$dotApp->router->get('/home', function ($request) {
return "Homepage";
});
For /about
, it displays "404 - Page not found!" and the script terminates.
6.2 Custom Error Handling
Developers can implement custom error-handling logic directly in callbacks or middleware using conditions and HTTP codes.
Example with a Condition in a Callback:
$dotApp->router->get('/user/{id:i}', function ($request) {
$id = $request->matchData()['id'];
if ($id > 100) {
http_response_code(403);
return "Access forbidden for IDs greater than 100!";
}
return "User profile: $id";
});
For /user/150
, it displays "Access forbidden for IDs greater than 100!" with code 403.
Example with Middleware:
$dotApp->router->get('/user/{id:i}', function ($request) {
$id = $request->matchData()['id'];
return "User profile: $id";
})->before(function ($request) {
$id = $request->matchData()['id'];
if (!isset($id)) {
http_response_code(400);
return "ID is missing!";
}
});
For /user/
, it displays "ID is missing!" with code 400.
Note: Using http_response_code()
in callbacks or hooks allows setting custom error states. It’s up to the developer whether to terminate the script with exit
or return an error message.
7. Advanced Features
The Router
in the DotApp
Framework offers advanced features that extend its capabilities. This chapter covers method chaining, dynamic URL matching, a detailed explanation of creating dynamic addresses, and defining API endpoints.
7.1 Method Chaining
The Router
supports method chaining, allowing you to define routes, hooks, and other settings in a single command. This improves code readability and organization.
Example of Chaining:
$dotApp->router->get('/profile/{id}', function ($request) {
$id = $request->matchData()['id'];
return "Profile ID: $id";
})->before(function ($request) {
return "Checking before displaying the profile";
})->after(function ($request) {
return "Profile displayed";
});
For /profile/123
, before
, the main logic, and after
execute sequentially.
7.2 Dynamic Route Matching (matchUrl()
)
The matchUrl()
method is used for manually matching a URL against a routing pattern. It returns an array of extracted variables if the pattern matches, or false
if not. It’s useful for custom validations or route testing.
Example of Use:
$dotApp->router->get('/test', function ($request) {
$pattern = '/user/{id:i}';
$url = '/user/123';
$match = $dotApp->router->matchUrl($pattern, $url);
if ($match !== false) {
return "Match! ID: " . $match['id'];
}
return "No match";
});
For /test
, it displays "Match! ID: 123".
7.3 Dynamic Addresses and Patterns
Dynamic addresses in the Router
allow defining routes with variables and optional parts using special syntax. These patterns are recognized consistently across methods (e.g., get()
, post()
, match()
), and variables are available via $request->matchData()
. Below is a detailed explanation with an example and a list of the most common patterns.
Example of a Dynamic Address:
$dotApp->router->get('/documentation/intro(?:/{language})?', function ($request) {
$language = $request->matchData()['language'] ?? 'default';
return "Introductory documentation, language: $language";
});
Explanation:
/documentation/intro(?:/{language})?
: Defines a route where {language}
is an optional part (marked with ?:
and ?
).
/documentation/intro
: Valid (language is "default").
/documentation/intro/eng
: Valid (language is "eng").
/documentation/intro/
: Invalid (the Router
expects a value after the slash if present).
The language
variable is extracted into $request->matchData()
if provided, otherwise it’s null
.
Most Commonly Used Patterns:
Here’s a list of 10 common dynamic address patterns used in web applications, with examples and explanations:
/{resource}/{id:i}
- Basic CRUD Route
$dotApp->router->get('/users/{id:i}', function ($request) {
return "User ID: " . $request->matchData()['id'];
});
Valid: /users/123
, Invalid: /users/abc
/{category}/{slug:s}
- Category and Article Slug
$dotApp->router->get('/blog/{category}/{slug:s}', function ($request) {
return "Category: " . $request->matchData()['category'] . ", Slug: " . $request->matchData()['slug'];
});
Valid: /blog/tech/how-to-code
/api/v{version}/{endpoint}
- Versioned API
$dotApp->router->get('/api/v{version}/{endpoint}', function ($request) {
return "API v" . $request->matchData()['version'] . ": " . $request->matchData()['endpoint'];
});
Valid: /api/v1/users
/{page}(?:/{subpage})?
- Optional Subpage
$dotApp->router->get('/docs/{page}(?:/{subpage})?', function ($request) {
$subpage = $request->matchData()['subpage'] ?? 'main';
return "Page: " . $request->matchData()['page'] . ", Subpage: $subpage";
});
Valid: /docs/intro
, /docs/intro/setup
/{type}/{id:i}/{action}
- Action on a Resource
$dotApp->router->get('/posts/{id:i}/{action}', function ($request) {
return "ID: " . $request->matchData()['id'] . ", Action: " . $request->matchData()['action'];
});
Valid: /posts/5/edit
/{resource}/{filter:s}?
- Optional Filter
$dotApp->router->get('/products/{filter:s}?', function ($request) {
$filter = $request->matchData()['filter'] ?? 'all';
return "Products, filter: $filter";
});
Valid: /products
, /products/new
/{path*}
- Wildcard for Entire Path
$dotApp->router->get('/files/{path*}', function ($request) {
return "File path: " . $request->matchData()['path'];
});
Valid: /files/images/photo.jpg
/{lang:l}/{section}
- Language and Section
$dotApp->router->get('/{lang:l}/{section}', function ($request) {
return "Language: " . $request->matchData()['lang'] . ", Section: " . $request->matchData()['section'];
});
Valid: /en/news
, Invalid: /123/news
/search(?:/{query})?
- Optional Search Query
$dotApp->router->get('/search(?:/{query})?', function ($request) {
$query = $request->matchData()['query'] ?? 'empty';
return "Search: $query";
});
Valid: /search
, /search/php
/{resource}/{id:i}(?:/{extra})?
- Resource with an Optional Parameter
$dotApp->router->get('/users/{id:i}(?:/{extra})?', function ($request) {
$extra = $request->matchData()['extra'] ?? 'none';
return "ID: " . $request->matchData()['id'] . ", Extra: $extra";
});
Valid: /users/10
, /users/10/details
Note: These patterns are flexible and combinable. Use {?:}
for optional parts and types (:i
, :s
, :l
) for precise constraints.
7.4 Defining API Endpoints with apiPoint
The apiPoint
method in the Router
provides a convenient way to define API endpoints with support for versioning, modules, and dynamic parameters. It offers flexibility in defining custom paths and methods, and when combined with the built-in abstract Controller
class and its apiDispatch
(main logic) and api
(shorter alias) methods, it enables automatic dispatching of requests to specific controller methods with dependency injection (DI) support.
Definition of the apiPoint Method:
public function apiPoint($version, $module, $controller, $custom = null) {
$apiRoutes = array();
if ($custom !== null) {
if (is_array($custom)) {
foreach ($custom as $value) {
$apiRoutes[] = "/api/v".$version."/".$module."/".$value;
}
} else {
$apiRoutes[] = "/api/v".$version."/".$module."/".$custom;
}
} else {
$apiRoutes[] = "/api/v".$version."/".$module."/{resource}(?:/{id})?";
}
$this->any($apiRoutes, $controller);
}
Parameters:
$version
: API version (e.g., "1"
for v1).
$module
: Module name (e.g., "dotcmsfe"
).
$controller
: Callback or string in the format "Controller@method"
(e.g., "PostsController@apiDispatch"
, "PostsController@api"
, or a custom method).
$custom
(optional): Specific path (string) or array of paths. Supports regular expressions (e.g., (?:/{id})?
).
If $custom
is not provided, the default dynamic path /api/v{version}/{module}/{resource}(?:/{id})?
is used. If specified, only the paths from $custom
are applied. First route wins! Static paths must be listed before dynamic ones to avoid being overridden by dynamic logic.
Built-in Controller and apiDispatch/api Methods:
The framework provides an abstract class Dotsystems\App\Parts\Controller
with the apiDispatch
method, which automatically dispatches requests to specific methods in the format
(e.g., postUsers
, getPosts
) based on the HTTP method and the value of the dynamic resource
parameter. Simply point apiPoint
to Controller@apiDispatch
(or Controller@api
as a shorter alias), and automatic dispatching works if the path includes {resource}
. Unlike other frameworks (e.g., Laravel, Django), you don’t need to define routes for each endpoint – apiDispatch
handles it for you with full DI support via self::$di->callStatic
.
// Excerpt from Dotsystems\App\Parts\Controller
public static function apiDispatch($request) {
$method = strtolower($request->getMethod());
$resource = $request->matchData()['resource'] ?? null;
$id = $request->matchData()['id'] ?? null;
// Construct the method name: <httpMethod><Resource>
if ($resource) {
$targetMethod = $method . ucfirst($resource);
if (method_exists(static::class, $targetMethod)) {
return self::$di->callStatic($targetMethod, [$request]);
}
}
// Attempt to call error404 if it exists
if (method_exists(static::class, 'error404')) {
return self::$di->callStatic('error404', [$request]);
}
// Default response if error404 doesn’t exist
http_response_code(404);
return "API: Resource '$resource' not found or method '$method' not supported in " . static::class;
}
public static function api($request) {
// Shorter alias
self::apiDispatch($request);
}
Advantages of Using Controller@apiDispatch with DI:
The apiDispatch
method leverages the DI container to call specific methods, providing automatic dependency injection. This means controller methods can accept additional parameters (e.g., services like \SomeService
) that are automatically injected from the DI container without manual instantiation. This approach simplifies code, increases flexibility, and sets DotApp
apart from other frameworks by eliminating the need for explicit routing for every endpoint when using automation.
Customizing Errors:
If the target method (e.g., postUsers
) doesn’t exist, apiDispatch
first checks if the controller defines an error404
method. If so, it calls it, allowing the user to define custom logic for 404 errors (e.g., JSON response, logging). If error404
isn’t present, it returns a default error message with HTTP code 404.
Using with Automatic Dispatching:
Automatic dispatching via apiDispatch
(or api
) works only if the path includes the dynamic {resource}
parameter in the correct position (e.g., /api/v1/dotcmsfe/{resource}
). If $custom
doesn’t maintain this format, the automation won’t work, and a custom method must be used.
Example without $custom (Automatic Dispatching):
$dotApp->router->apiPoint("1", "dotcmsfe", "PostsController@apiDispatch");
Resulting Paths:
POST /api/v1/dotcmsfe/users
- Triggers postUsers
if it exists.
GET /api/v1/dotcmsfe/posts
- Triggers getPosts
.
GET /api/v1/dotcmsfe/status
- Triggers error404
if it exists, otherwise 404 with a default message.
/api/v1/dotcmsfe/posts/
- Not captured.
Example with $custom and Automatic Dispatching:
$dotApp->router->apiPoint("1", "dotcmsfe", "PostsController@apiDispatch", ["{resource}(?:/{id})?/details"]);
Resulting Paths:
POST /api/v1/dotcmsfe/users/details
- Triggers postUsers
.
GET /api/v1/dotcmsfe/posts/details
- Triggers getPosts
.
GET /api/v1/dotcmsfe/posts/abc123/details
- Triggers getPosts
.
PUT /api/v1/dotcmsfe/status/details
- Triggers error404
if it exists, otherwise 404 with a default message.
/api/v1/dotcmsfe/users/
- Not captured.
Example with Custom Routes and a Custom Method:
$dotApp->router->apiPoint("1", "dotcmsfe", "PostsController@customMethod", ["users/details", "posts/summary"]);
Resulting Paths: Automatic dispatching doesn’t work here because {resource}
is missing. The logic depends on the implementation of customMethod
.
GET /api/v1/dotcmsfe/users/details
- Triggers customMethod
.
POST /api/v1/dotcmsfe/posts/summary
- Triggers customMethod
.
Example Controller with DI and Custom Error:
namespace Dotsystems\App\Modules\Dotcmsfe\Controllers;
class PostsController extends \Dotsystems\App\Parts\Controller {
public static function postUsers($request, \SomeService $service) {
return "Creating users: " . $service->process($request->getPath());
}
public static function getPosts($request) {
$id = $request->matchData()['id'] ?? null;
return "List of posts" . ($id ? " with ID: $id" : "");
}
public static function error404($request) {
http_response_code(404);
return json_encode([
'error' => 'Not Found',
'message' => "Resource '{$request->matchData()['resource']}' not found or method '{$request->getMethod()}' not supported",
'path' => $request->getPath()
]);
}
public static function customMethod($request) {
return "Custom method for path: " . $request->getPath();
}
}
Note: The built-in Controller
simplifies API handling with apiDispatch
(or api
) when the path includes {resource}
. For custom routes without {resource}
, you can use custom methods, but automatic dispatching won’t work. The order of paths in $custom
is critical – static paths must precede dynamic ones.
8. Practical Examples
This chapter provides practical examples of using the Router
in the DotApp
Framework. It demonstrates how to combine basic and advanced features to address common scenarios in web applications.
8.1 Simple GET Route
The most basic example of defining a static route with a simple response.
Example:
$dotApp->router->get('/welcome', function ($request) {
return "Welcome to the application!";
});
For a request to /welcome
, it displays: "Welcome to the application!".
Use Case: Ideal for static pages like homepages or "About Us".
8.2 Dynamic Route with Variables
An example of a dynamic route with variable extraction to display user data.
Example:
$dotApp->router->get('/user/{id:i}/{name}', function ($request) {
$id = $request->matchData()['id'];
$name = $request->matchData()['name'];
return "User ID: $id, Name: $name";
});
For /user/123/Jano
, it displays: "User ID: 123, Name: Jano".
Use Case: Suitable for profiles, product details, or other resources with identifiers.
8.3 Using Middleware
An example combining a route with before
and after
hooks for verification and logging.
Example:
$dotApp->router->get('/dashboard', function ($request) {
return "Welcome to the dashboard!";
})->before(function ($request) {
$user = "guest"; // Simulated verification
if ($user === "guest") {
http_response_code(403);
return "Access denied!";
}
})->after(function ($request) {
return "Dashboard displayed at " . date('H:i:s');
});
For /dashboard
, it displays "Access denied!" with code 403 (since the simulated verification fails). If verification succeeded, it would show "Welcome to the dashboard!" followed by the display time.
Use Case: Authentication, access logging, or response modification.
8.4 Combining with Controllers
An example of integrating a route with a controller to separate logic from routing.
Example:
// app/parts/controllers/ArticleController.php
namespace Dotsystems\App\Parts\Controllers;
use Dotsystems\App\DotApp;
class ArticleController {
public static function detail($request) {
$slug = $request->matchData()['slug'];
return "Article detail: $slug";
}
}
// Route definition
$dotApp->router->get('/article/{slug:s}', 'ArticleController@detail');
For /article/how-to-code
, it displays: "Article detail: how-to-code".
Use Case: Larger applications where code organization into controllers is needed.
9. Tips and Tricks
This chapter offers practical tips and tricks for effectively using the Router
in the DotApp
Framework. These will help you optimize your code, debug issues, and follow best practices.
9.1 Optimizing Routing
The Router
in the DotApp
Framework operates on a "first match wins" principle – the first matching route in the order of definition is used, and others are ignored, regardless of whether they are static or dynamic. The order of definition is therefore critical for optimization.
- Define the most important routes first: Since the first match wins, place critical or frequently used routes at the top.
- Use specific patterns: E.g.,
{id:i}
instead of {id}
to prevent unintended matches on incorrect routes.
- Group similar routes: Use
match()
with an array of paths to reduce code duplication, but be mindful of order.
Example of Optimization:
$dotApp->router->get('/user/{id:i}', function ($request) { // First dynamic route
return "Dynamic user ID: " . $request->matchData()['id'];
});
$dotApp->router->get('/user/123', function ($request) { // Second static route
return "Static user 123";
});
For /user/123
, the first route always wins ("Dynamic user ID: 123") because it was defined first, even though the second is static and more precise. To prioritize the static route, define it earlier.
Example with Reordered Priority:
$dotApp->router->get('/user/123', function ($request) { // First static route
return "Static user 123";
});
$dotApp->router->get('/user/{id:i}', function ($request) { // Second dynamic route
return "Dynamic user ID: " . $request->matchData()['id'];
});
Now, for /user/123
, it displays "Static user 123" because it’s defined first.
9.2 Debugging Routes
When troubleshooting routing issues, use the tools available in the Router
and PHP to identify which route is actually being triggered, especially with the "first match" rule.
- Check the path: Use
$request->getPath()
to verify the URL the Router
is processing.
- Dump variables: Print
$request->matchData()
to see which values were extracted.
- Test order: Add temporary outputs (e.g.,
echo
) in callbacks to determine which route executed.
Example of Debugging:
$dotApp->router->get('/page/{id}', function ($request) {
echo "Dynamic route triggered for ID: " . $request->matchData()['id'];
return "Dynamic page " . $request->matchData()['id'];
});
$dotApp->router->get('/page/1', function ($request) {
echo "Static route triggered for /page/1";
return "Static page 1";
});
For /page/1
, it displays "Dynamic route triggered for ID: 1" and "Dynamic page 1" because the dynamic route is defined first. Changing the order would prioritize the static route.
9.3 Best Practices for Route Structure
Following best practices helps maintain clarity and predictability in routing.
- Logical order: Define routes from most specific to most general to leverage the "first match wins" rule.
- Comments: Add comments above routes to clarify why they are in a specific order.
- Separate logic: Use controllers for complex routes instead of inline callbacks.
Example of Best Practices:
// Most specific static route
$dotApp->router->get('/api/users/guest', function ($request) {
return "Guest user";
});
// Specific dynamic route
$dotApp->router->get('/api/users/{id:i}', function ($request) {
return "User ID: " . $request->matchData()['id'];
});
// General route last
$dotApp->router->get('/api/{resource}', function ($request) {
return "Resource: " . $request->matchData()['resource'];
});
For /api/users/guest
, the first route triggers; for /api/users/5
, the second; and for /api/products
, the third, thanks to logical ordering.
10. Conclusion
This chapter concludes the documentation for the Router
in the DotApp
Framework. It summarizes its benefits and offers a look at its future development and community.
10.1 Why Use the Router in DotApp?
The Router
in the DotApp
Framework is a simple yet powerful tool for managing routing in web applications. Its key advantages include:
- Flexibility: Support for both static and dynamic routes with variables and optional parts.
- Simplicity: Intuitive interface for defining routes via HTTP methods like
get()
and post()
.
- Middleware: Ability to add
before
and after
hooks for extended logic.
- First Match Wins: Predictable behavior based on the order of route definition, giving developers full control.
- Integration: Seamless collaboration with controllers and the
Request
object for request handling.
Whether you’re building a small application or a complex system, the Router
provides the tools to map requests to logic quickly and efficiently.
1. Dependency Injection a Middleware v DotApp
Táto kapitola popisuje dependency injection (DI) a middleware v DotApp
frameworku. Vysvetľuje DI kontajner, jeho registráciu závislostí cez bind
a singleton
, a ako sú tieto závislosti resolvované pomocou resolve
. Tiež popisuje flexibilné volania kontrolerov a middleware cez stringy, polia, callable objekty a anonymné funkcie s automatickým DI.
1.1. Čo je Dependency Injection a Middleware?
Dependency Injection (DI) je technika, ktorá umožňuje automaticky vkladať závislosti (napr. DotApp
) do metód a funkcií namiesto ich manuálneho vytvárania. V DotApp
je DI spravované cez DI kontajner v triede DotApp
, ktorý registruje závislosti a resolvuje ich pri volaniach.
Middleware sú funkcie alebo triedy, ktoré spracúvajú požiadavky pred alebo po hlavnej logike, využívajúc DI pre prístup k registrovaným závislostiam.
1.2. DI Kontajner v DotApp
DI kontajner v DotApp
je jadrom správy závislostí a pozostáva z troch hlavných metód:
1.2.1. bind(string $key, callable $resolver)
Registruje závislosť, ktorá sa vytvorí nanovo pri každom volaní resolve
. Používa sa pre nezdieľané (non-shared) inštancie.
Syntax: bind(string $key, callable $resolver): void
Príklad:
$DotApp->bind('logger', function () {
return new Logger();
});
$logger = $DotApp->resolve('logger'); // Vytvorí novú inštanciu
$logger2 = $DotApp->resolve('logger'); // Vytvorí ďalšiu novú inštanciu
Poznámka: Každé volanie resolve
vráti novú inštanciu, pretože shared
je nastavené na false
.
1.2.2. singleton(string $key, callable $resolver)
Registruje závislosť ako singleton – vytvorí sa iba raz a následne sa zdieľa pri všetkých volaniach resolve
. Používa sa pre zdieľané inštancie, ako je napríklad samotný DotApp
.
Syntax: singleton(string $key, callable $resolver): void
Príklad:
// V konštruktore DotApp
$this->singleton(DotApp::class, function () {
return $this;
});
$dotApp1 = $DotApp->resolve(DotApp::class); // Vráti tú istú inštanciu
$dotApp2 = $DotApp->resolve(DotApp::class); // Vráti tú istú inštanciu
Poznámka: Singleton zaručuje, že existuje iba jedna inštancia danej závislosti, uložená v $this->instances
.
1.2.3. resolve(string $key)
Resolvuje zaregistrovanú závislosť. Ak je to singleton, vráti zdieľanú inštanciu; ak je to bind, vytvorí novú.
Syntax: resolve(string $key)
Príklad:
$DotApp->singleton('db', function () {
return new Database();
});
$db = $DotApp->resolve('db'); // Vráti singleton inštanciu
Výnimka: Ak kľúč nie je registrovaný, vyhodí Exception
.
1.2.4. Ako funguje DI v praxi
DI kontajner ukladá závislosti v poli $this->bindings
s informáciou, či sú zdieľané (shared
). Pri resolúcii kontroluje, či už existuje inštancia (pre singletony) alebo volá resolver (pre bind). V konštruktore DotApp
je napríklad DotApp::class
zaregistrovaný ako singleton, aby bol prístupný všade:
$this->singleton(DotApp::class, function () { return $this; });
1.3. Možnosti volania kontrolerov a middleware
DotApp
využíva DI kontajner na automatické vkladanie závislostí do callbackov:
1.3.1. String-based volania
Syntax: "modul:controller@funkcia"
.
Príklad:
$DotApp->router->get('/login', "auth:controllers\\UserController@login");
Výstup pri GET /login:
Prihlásenie bolo úspešné: GET
1.3.2. Pole ako callback
Syntax: ['modul', 'class', 'function']
.
Príklad:
$DotApp->router->get('/login', ['auth', 'controllers\\UserController', 'login']);
Výstup pri GET /login:
Prihlásenie bolo úspešné: GET
1.3.3. Callable (Closure) s DI
Anonymné funkcie využívajú DI kontajner na resolúciu závislostí.
Príklad:
$DotApp->router->get('/status', function (DotApp $dotApp) {
echo "Aktuálna metóda: " . $dotApp->router->request->getMethod();
});
Výstup pri GET /status:
Aktuálna metóda: GET
1.3.4. Dynamické volania cez di
Príklad:
class AuthService extends Dotsystems\App\Parts\Library {
public function logAction(DotApp $dotApp) {
echo "Akcia: " . $dotApp->router->request->getMethod();
}
}
$service = new AuthService('auth', $DotApp);
$service->di->logAction();
Výstup:
Akcia: GET
1.3.5. Statické volania cez controller2::call
Príklad:
auth\controllers\UserController::call("login");
Výstup:
Prihlásenie bolo úspešné: GET
1.4. Práca s Middleware
Middleware využíva DI kontajner pre prístup k závislostiam:
1.4.1. String-based middleware
Príklad:
$DotApp->router->before(["/user/*"], "auth:controllers\\UserController@checkAuth");
$DotApp->router->get('/user/profile', "auth:controllers\\UserController@showProfile");
Výstup pri GET /user/profile:
Profil zobrazený: GET
1.4.2. Pole v middleware
Príklad:
$DotApp->middleware("authCheck", ['auth', 'controllers\\UserController', 'checkAuth']);
$DotApp->router->get('/secure', $DotApp->middleware("authCheck"));
Výstup pri GET /secure:
Overenie úspešné
1.4.3. Closure s DI v middleware
Príklad:
$DotApp->router->before(["/admin/*"], function (DotApp $dotApp, LogService $log) {
echo "Metóda: " . $dotApp->router->request->getMethod() . ", Log: " . $log->getLogName() . "<br>";
});
$DotApp->router->get('/admin/dashboard', function () {
echo "Admin panel";
});
Výstup pri GET /admin/dashboard:
Metóda: GET, Log: AdminLog<br>Admin panel
1.4.4. Manuálne volanie middleware
Príklad:
$DotApp->middleware("logAccess", function (DotApp $dotApp, ...$args) {
auth\controllers\UserController::call("login", ...$args);
});
$DotApp->router->get('/access', $DotApp->middleware("logAccess"));
Výstup pri GET /access:
Prihlásenie bolo úspešné: GET
1.5. Praktické príklady
1. Registrácia a resolúcia singletonu:
$DotApp->singleton('cache', function () {
return new CacheService();
});
$cache1 = $DotApp->resolve('cache');
$cache2 = $DotApp->resolve('cache');
echo ($cache1 === $cache2) ? "Rovnaká inštancia" : "Rôzne inštancie";
Výstup:
Rovnaká inštancia
2. Middleware s Closure a DI:
$DotApp->router->before(["/api/*"], function (DotApp $dotApp) {
echo "Kontrola: " . $dotApp->router->request->getMethod() . "<br>";
});
$DotApp->router->get('/api/users', "auth:controllers\\UserController@showProfile");
Výstup pri GET /api/users:
Kontrola: GET
Profil zobrazený: GET
3. Kombinácia bind a Closure:
$DotApp->bind('logger', function () {
return new Logger();
});
$DotApp->router->get('/log', function (DotApp $dotApp, Logger $logger) {
echo "Log: " . $logger->getLogId() . ", Metóda: " . $dotApp->router->request->getMethod();
});
Výstup pri GET /log:
Log: 12345, Metóda: GET
1.6. Poznámky
- Singleton vs. Bind: Používajte
singleton
pre zdieľané inštancie (napr. DotApp
, databáza), bind
pre nové inštancie pri každom volaní.
- Closure DI: Funguje automaticky v routeri a middleware vďaka
di
.
- Middleware parametre: Dynamické parametre z
middlewareCall
ešte nie sú implementované – odovzdávajte manuálne.
- Best practice: Registrujte kľúčové služby ako singletony v inicializácii modulu.
1.1 What is DotBridge?
DotBridge
in the DotApp
Framework is a class Dotsystems\App\Parts\Bridge
that serves as a bridge between back-end PHP logic and front-end JavaScript actions. It enables calling PHP functions from HTML elements (e.g., buttons, form inputs) through AJAX requests to the /dotapp/bridge
path. Its primary role is to simplify client-server communication while ensuring it is verified, encrypted, and protected against attacks such as CSRF or request replay.
DotBridge
is integrated directly into the framework’s core, so you don’t need to install or configure it separately – simply use it via $dotApp->bridge
.
1.2 Key Features
DotBridge
offers a wide range of features that simplify the development of secure and dynamic applications:
- Secure Communication: Uses data encryption, key verification, and CRC checks to protect requests.
- Calling PHP Functions: Define PHP functions callable from JavaScript with support for
before
and after
callbacks.
- Validation Filters: Real-time input validation (e.g., email, URL, password) with visual feedback on the client side.
- Rate Limiting: Ability to set request limits per time (
rateLimit(seconds,clicks)
).
- One-Time Keys: Support for
oneTimeUse
and regenerateId
for enhanced security.
- Flexibility: Supports various events (e.g.,
click
, keyup
) and dynamic inputs from HTML.
- Chaining: Method chaining for cleaner code on both PHP and JavaScript sides.
1.3 Basic Operating Principles
DotBridge
handles communication between the client and server in the following steps:
- Generates a unique session key and registers PHP functions on the server side via
fn()
.
- In HTML, events (e.g.,
dotbridge:on(click)
) and inputs (e.g., dotbridge:input
) are defined and linked to PHP functions.
- When an event is triggered (e.g., a click), an AJAX request is sent to
/dotapp/bridge
with encrypted data.
- The server verifies the key, decrypts the data, checks request limits, and executes the requested PHP function.
- The result is returned as a JSON response, which JavaScript can further process.
Communication is safeguarded with data encryption, key verification, and limits to prevent abuse or unauthorized access.
Example of Basic Usage:
<button {{ dotbridge:on(click)="sayHello" }}>Click me</button>
$dotApp->bridge->fn("sayHello", function($data) {
return ["status" => 1, "message" => "Hello from the server!"];
});
Upon clicking the button, the PHP function sayHello
is called and returns a JSON response with the message "Hello from the server!".
2. Getting Started
This chapter guides you through the basics of working with DotBridge
in the DotApp
Framework – from initialization to defining your first function, adding a front-end event, and handling the response in JavaScript.
2.1 Initializing DotBridge
DotBridge
is automatically initialized as part of the $dotApp
instance when creating an application in the DotApp
Framework. You access it via $dotApp->bridge
. During initialization, a unique session key is generated (stored in _bridge.key
in the session) and default settings such as request limits and built-in validation filters are applied.
Technical Details:
Bridge
is an instance of the Dotsystems\App\Parts\Bridge
class.
- It receives a reference to
$dotApp
, giving it access to encryption methods, sessions (dsm
), and the router.
- It automatically registers the
/dotapp/bridge
path in the router for handling AJAX requests.
2.2 Defining a PHP Function
On the server side, you define a callable PHP function using the fn()
method, which takes the function name and a callback. The callback receives a $data
parameter containing data sent from the front-end (e.g., input values). The function should return an array with keys like status
and status_txt
for a consistent response.
Example:
$dotApp->bridge->fn("sendMessage", function($data) {
$message = $data["message"] ?? "No message";
return ["status" => 1, "status_txt" => "Message received: " . $message];
});
The sendMessage
function is now ready to be called from the front-end and will return a JSON response with the received message.
2.3 Adding a Front-End Event
In HTML, use the attribute {{ dotbridge:on(event)="functionName(params)" }}
to link an event (e.g., click
, keyup
) to a PHP function. You can define inputs with dotbridge-input="name"
and add parameters like rateLimitM
or oneTimeUse
to control behavior.
Example:
<input type="text" {{ dotbridge:input="user.message" }}>
<button {{ dotbridge:on(click)="sendMessage(user.message)" rateLimitM="5" }}>Send</button>
When the button is clicked, the value from the user.message
input is sent to the sendMessage
function with a limit of 5 requests per minute.
2.4 Handling the Response in JavaScript
On the client side, you can use $dotapp().bridge()
to define before
and after
callbacks to handle the state before sending the request and after receiving the response. These callbacks allow you to dynamically update the UI based on the server’s response.
Example:
$dotapp().bridge("sendMessage", "click")
.before(function(data, element) {
$(element).text("Sending...");
})
.after(function(data, element) {
$(element).text("Done!");
alert(data["status_txt"]);
});
Before sending, the button text changes to "Sending...", and after receiving the response, it displays the message from the PHP function.
3. Advanced Usage
This chapter covers advanced features of DotBridge
, such as validation filters, rate limiting, method chaining, and working with dynamic data. These tools enable the creation of more robust and secure applications with greater control over behavior.
3.1 Validation Filters
DotBridge
provides built-in validation filters for real-time input validation on the client side. Filters like email
, url
, phone
, or password
apply regular expressions and visual feedback (CSS classes) based on input validity. They are used in HTML via the dotbridge-result="0" dotbridge-input="name"
attribute.
Available Arguments:
filter
: Name of the filter (e.g., email
).
start_checking_length
: Minimum number of characters to start validation.
class_ok
: CSS class for valid input.
class_bad
: CSS class for invalid input.
Example:
<input type="text" {{ dotbridge:input="user.email(email, 5, 'valid-email', 'invalid-email')" }}>
The user.email
input starts validation after 5 characters. If the email is valid, the valid-email
class is added; if invalid, invalid-email
.
3.2 Rate Limiting and Security Mechanisms
DotBridge
allows you to limit the number of requests using the rateLimit(seconds,clicks)
parameters, protecting the application from abuse. Additional security features include oneTimeUse
(single-use key) and regenerateId
(key regeneration after each use).
Usage:
rateLimit(seconds,clicks)
: Maximum of clicks
requests per seconds
.
oneTimeUse
: Key is valid for only one use.
regenerateId
: Generates a new key after each call.
Example:
<button {{ dotbridge:on(click)="submitForm" rateLimit(60,10) rateLimit(3600,100) }}>Submit</button>
<button {{ dotbridge:on(click)="submitForm" oneTimeUse }}>Submit</button>
<button {{ dotbridge:on(click)="submitForm" regenerateId }}>Submit</button>
1. Example - The button allows a maximum of 10 clicks per minute, 100 per hour.
2. Example - The button allows only one click, and the listener is removed.
3. Example - The button regenerates its ID on each click.
3.3 Method Chaining
DotBridge
supports method chaining on both the PHP and JavaScript sides, simplifying the definition of functions and callbacks. In PHP, use fn()
, before()
, and after()
; in JavaScript, use $dotapp().bridge()
with before()
and after()
.
Example:
// PHP
$dotApp->bridge->fn("processData", function($data) {
return ["status" => 1, "result" => $data["value"]];
})
->before(function($data) {
$data["value"] = trim($data["value"] ?? "");
return $data;
})
->after(function($result, $data) {
$result["timestamp"] = time();
return $result;
});
// JavaScript
$dotapp().bridge("processData", "click")
.before(function(data, element) {
$(element).addClass("loading");
})
.after(function(data, element) {
$(element).removeClass("loading");
console.log(data["result"]);
});
Before processing, the input is cleaned (before
), after processing a timestamp is added (after
), and on the client side, a loading state is displayed.
3.4 Working with Dynamic Data
DotBridge
allows sending and processing dynamic data from multiple inputs defined in HTML. Inputs are identified using dotbridge:input
and sent in $_POST['data']
, where the PHP function can process them.
Example:
<input type="text" {{ dotbridge:input="user.name" }}>
<input type="text" {{ dotbridge:input="user.email" }}>
<button {{ dotbridge:on(click)="saveUser(user.name, user.email)" }}>Save</button>
$dotApp->bridge->fn("saveUser", function($data) {
$name = $data["user.name"] ?? "";
$email = $data["user.email"] ?? "";
return ["status" => 1, "status_txt" => "User $name ($email) saved"];
});
Upon clicking, the values from the user.name
and user.email
inputs are sent to the saveUser
function and returned in the response.
4. Best Practices and Tips
This chapter provides recommendations and tips for effectively and securely using DotBridge
. It covers security optimization, debugging issues, and integration with other parts of the DotApp
Framework.
4.1 Optimizing Security
Security is a critical aspect when using DotBridge
. The following recommendations will help minimize risks and ensure robust communication:
- Use rate limiting: Always set
rateLimitM
and rateLimitH
for actions sensitive to repeated calls to prevent abuse (e.g., brute force attacks).
- Enable one-time keys: For critical operations (e.g., form submission), use
oneTimeUse
or regenerateId
to prevent reuse of the same key.
- Validate inputs: Combine validation filters with additional server-side checks (e.g.,
filter_var()
) to ensure consistent validation.
- Monitor sessions: Regularly check and clean old keys in
_bridge.objects
to avoid memory overflow.
- Use encryption: Leverage the built-in
DotApp
encryption (encrypt()
, decrypt()
) for sensitive data in communication.
Example:
<button {{ dotbridge:on(click)="secureAction" rateLimitM="2" oneTimeUse }}>Execute</button>
$dotApp->bridge->fn("secureAction", function($data) {
return ["status" => 1, "status_txt" => "Action executed securely"];
});
This example limits the action to 2 calls per minute and allows only one use of the key.
4.2 Debugging and Troubleshooting
While working with DotBridge
, you may encounter errors. Here are common issues and their solutions:
- CRC check failed (error_code 1): Verify that the data sent from the front-end hasn’t been modified. Check the integrity of the JavaScript code and network requests.
- Bridge key does not match (error_code 2): Ensure the session key (
_bridge.key
) matches what the client sends. This could be due to an expired session.
- Function not found (error_code 3): Confirm that the function is correctly registered with
fn()
and that the name matches the HTML call.
- Rate limit exceeded (error_code 4): You’ve exceeded the set limit. Increase
rateLimitM
/rateLimitH
or inform the user to wait.
Tip: Enable debugging in DotApp
and monitor responses from /dotapp/bridge
in the browser’s developer tools (Network tab) for detailed information.
4.3 Integration with Other Parts of DotApp
DotBridge
is designed to work seamlessly with other DotApp
components, such as Router
, Request
, and the database. Integration allows you to build complex applications with minimal effort.
Integration Examples:
- With Router:
DotBridge
automatically uses $dotApp->router
to register the /dotapp/bridge
path.
- With Request: Data from
$_POST
is made available in the callback as $data
.
- With Database: You can directly insert front-end data into the database via
$dotApp->db
.
Example with Database:
<input type="text" {{ dotbridge:input="user.email" }}>
<button {{ dotbridge:on(click)="saveEmail(user.email)" }}>Save</button>
$dotApp->bridge->fn("saveEmail", function($data) use ($dotApp) {
$email = $data["user.email"] ?? "";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$dotApp->db->insertInto("users")
->values("email", $email)
->execute();
return ["status" => 1, "status_txt" => "Email saved"];
}
return ["status" => 0, "status_txt" => "Invalid email"];
});
Upon clicking, the email is validated and saved to the database, returning a success or error response.