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.

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:

TypeDefault CSS class
messageInfoalert-info
messageWarningalert-warning
messageDangeralert-danger
messageSuccessalert-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

  1. Request hits /
  2. Router resolves route
  3. Controller is created via DI
  4. Dependencies are injected
  5. Action is executed
  6. View is rendered
  7. Response is returned

# Running the Application

  1. Point your web server to:
public/
  1. 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