Creating Your First Controller and Service
The documentation is constantly evolving and updated alongside the project's progress. Since it is developed in parallel with the code, some sections may temporarily refer to earlier versions of the system-these are gradually adapted to the current state of the application. If you notice any outdated information, please report it or open an Issue / Pull Request.
Documentation
# Creating Your First Controller and Service
This document shows how to create and run your first controller and service in DBM Framework.
# Application Entry Points
DBM Framework provides PHP-based routing through RouteBuilder. A framework example application has a public entry point and keeps its route configuration in example/bootstrap/routes.php. Dybem Platform uses a fuller bootstrap: public/index.php loads bootstrap/runtime.php and bootstrap/autoload.php, then creates the application through bootstrap/app.php. That composition loads bootstrap/web.php and bootstrap/api.php.
- Web entry point:
/ - API entry point:
/api
For the platform autoload sequence and bundled library mappings, see Platform Autoloading. The Platform app bootstrap groups bootstrap/api.php under the /api prefix; therefore a path declared as /crypto/market/{symbol} in that file is reached as /api/crypto/market/{symbol}. Web routes in bootstrap/web.php keep their declared path. The framework example and the platform use the same RouteBuilder model, but the platform separates web and API routes and composes module routes and middleware in bootstrap/app.php.
Routing configuration is loaded from:
bootstrap/web.php
bootstrap/api.php
# Controller Location
Controllers should be placed in:
src/Controller
# Example Controller
declare(strict_types=1);
namespace App\Controller;
use App\Service\IndexService;
use Dbm\Http\Controller\BaseController;
use Dbm\Views\Flash\FlashBag;
use Psr\Http\Message\ResponseInterface;
class IndexController extends BaseController
{
public function __construct(
private readonly IndexService $service,
private readonly FlashBag $flash
) {}
/**
* Index page
* @routing GET '/' name: home
*/
public function index(): ResponseInterface
{
$this->flash->set(
'Your application is now ready and you can start working on a new project.'
);
return $this->render('index/start.phtml', [
'meta' => $this->service->getMetaIndex(),
]);
}
/**
* Start page
* @routing GET '/start' name: start
*/
public function start(): ResponseInterface
{
return $this->render('index/start.phtml', [
'meta' => $this->service->getMetaStart(),
]);
}
}
# Service Location
Services should be placed in:
src/Service
# Example Service
declare(strict_types=1);
namespace App\Service;
use Dbm\Localization\Translation;
class IndexService
{
public function __construct(
private readonly Translation $translation,
) {}
public function getMetaIndex(): array
{
return [
'meta.title' => "Your Web Application Name",
'meta.description' => "Web application description...",
'meta.keywords' => "application keywords",
];
}
public function getMetaStart(): array
{
return [
'meta.title' => $this->translation->trans('index.start_meta_title'),
'meta.description' => $this->translation->trans('index.start_meta_description'),
'meta.keywords' => $this->translation->trans('index.start_meta_keywords'),
'meta.robots' => "noindex,nofollow",
];
}
}
# API Controllers: Framework Helper and Platform Convention
For a lightweight JSON response, BaseApiController::jsonResponse() remains a valid framework helper. DBM Platform controllers commonly use Dbm\Http\Response\ApiResponder to keep a consistent response envelope.
The pattern below is used by src/CryptoAnalytics/Controller/Api/CryptoMarketApiController.php. Similar usage appears in module API controllers such as Payments and Shopping.
return ApiResponder::error(
'Cryptocurrency symbol is required.',
400
);
return ApiResponder::success(
'Market data retrieved.',
$marketData
);
ApiResponder::success() returns a JSON response with status, message, and data fields. ApiResponder::error() returns status and message. These helpers are a framework capability; using them consistently across APIs is a DBM Platform convention. Both approaches are valid and should not be mixed arbitrarily within one API surface.
# Routing
Routes are defined manually in:
bootstrap/web.php
bootstrap/api.php
The @routing annotation in PHPDoc is informational only and does not register routes automatically.
# Dependency Injection
DBM uses automatic dependency injection.
# Constructor Injection (recommended)
public function __construct(
private IndexService $service,
private FlashBag $flash
) {}
Dependencies are resolved automatically from the DI container.
# Method Injection (optional)
public function example(Request $request): ResponseInterface
# Flash Messages
Flash messages are handled via FlashBag. They are typically displayed once (next request).
FlashBag stores a message for display after a redirect. Use the set() method to define the message and its type.
$this->flash->set('Changes saved.');
The second argument specifies the message type. The default type is used when no type is provided.
$this->flash->set('Changes saved successfully.', 'messageSuccess');
$this->flash->set('Please check the submitted data.', 'messageWarning');
$this->flash->set('The operation could not be completed.', 'messageDanger');
$this->flash->set('The operation is in progress.', 'messageInfo');
The available types are defined by FlashBag::TYPES:
| Type | Default CSS class |
|---|---|
messageInfo | alert-info |
messageWarning | alert-warning |
messageDanger | alert-danger |
messageSuccess | alert-success |
These CSS classes follow the Bootstrap 5 alert conventions. Applications can use the message type to apply their own presentation styles.
Flash messages are commonly used with the Post/Redirect/Get pattern:
$this->flash->set('Changes saved successfully.', 'messageSuccess');
return $this->redirect('home');
The message can then be retrieved in the destination template using getFlash(). See Template Features for an example of rendering flash messages.
# Translations
Translations are handled via the Translation service.
# Example
$this->translation->trans('key');
# With parameters
$this->translation->trans('hello', ['name' => 'John']);
# Translation Files
Stored in:
translations/
Example:
return [
'index.start_meta_title' => 'Start page',
];
# Views / Templates
Templates are located in:
templates/
Render using:
$this->render('index/start.phtml', [...]);
# Logger (Optional)
You can inject the logger into services or controllers:
use Dbm\Infrastructure\Log\Logger;
public function __construct(
private Logger $logger
) {}
# Example Usage in Service
$this->logger->info('Meta generated');
# Full Flow
- Request hits
/ - Router resolves route
- Controller is created via DI
- Dependencies are injected
- Action is executed
- View is rendered
- Response is returned
# Running the Application
- Point your web server to:
public/
- Open:
http://localhost/
# Summary
This example demonstrates:
- Clean controller structure
- Automatic dependency injection
- Service-based architecture
- Translation integration
- Flash messaging
- Template rendering
DBM encourages:
- thin controllers
- reusable services
- explicit architecture