Skip to content

Integracja i Wykorzystanie Frameworka Yii3 w Platformie Ammonly

Platforma Ammonly została zaprojektowana w nowoczesnym paradygmacie API-First oraz Domain-Driven Design (DDD). Zamiast monolitycznego, ciężkiego frameworka, fundamentem technologicznym platformy jest Yii3 — rozproszony, wysoce wyspecjalizowany ekosystem niezależnych bibliotek rozwijanych pod auspicjami yiisoft/*.

Niniejszy artykuł przedstawia kompleksowy przewodnik po tym, gdzie, dlaczego i w jaki sposób poszczególne komponenty Yii3 są zintegrowane w kodzie źródłowym Ammonly, jak wygląda przepływ sterowania w potoku PSR-15 oraz jakie mechanizmy zapewniają 100% spójności, wydajności i bezpieczeństwa aplikacji.

Architektura Dekouplingu i Standardy PSR / PER

Wszystkie komponenty Yii3 wykorzystywane w Ammonly są w pełni zgodne ze standardami PHP-FIG: PSR-7 (HTTP Message), PSR-11 (Container), PSR-12 / PER 2.0 (Coding Style), PSR-14 (Event Dispatcher) oraz PSR-15 (HTTP Server Handlers & Middleware). Kod domenowy pozostaje w 100% odizolowany od warstwy frameworka.


Spis treści


1. Dlaczego Yii3? Założenia Architektoniczne

W przeciwieństwie do tradycyjnych frameworków (takich jak Yii2, Symfony czy Laravel), w których aplikacja jest silnie sprzężona z bazowym jądrem (kernel), Yii3 zostało zaprojektowane od zera jako zbiór odrębnych bibliotek composer. Każda paczka posiada pojedynczą odpowiedzialność (Single Responsibility Principle):

yiisoft/di ───► PSR-11 Kontener wstrzykiwania zależności
yiisoft/router ───► Uniwersalny interfejs routingu i reguł URL
yiisoft/db ───► Zaawansowana abstrakcja SQL, Schema Cache i Query Builder
yiisoft/data-response ───► Formatowanie odpowiedzi PSR-7 (JSON, XML)
yiisoft/assets ───► Pakiety stylów i skryptów z wersjonowaniem i zależnościami

Korzyści dla Ammonly:

  1. Brak vendor lock-in: Warstwa domenowa (Domain/) nie dziedziczy po klasach bazowych frameworka (ActiveRecord, Model itp.). Jest w 100% czystym kodem PHP 8.4+.
  2. Ekstremalna wydajność: Aplikacja ładuje do pamięci tylko te komponenty, które są rzeczywiście niezbędne do obsłużenia danego żądania REST API lub renderowania HTMX.
  3. Płynna testowalność: Każdy komponent współpracuje z interfejsami standardu PSR. Testy jednostkowe (PHPUnit 11) korzystają z mocków i stubów bez konieczności uruchamiania pełnego środowiska serwerowego.

2. Przegląd i Mapa Komponentów Yii3 w Ammonly

Poniższa tabela przedstawia kluczowe biblioteki Yii3 wdrożone w repozytorium app-admin wraz ze wskazaniem miejsc ich zastosowania w architekturze:

Pakiet ComposerRola w architekturzeGłówne klasy i interfejsy w projekcie
yiisoft/runner-httpCykl życia HTTP i uruchomienie aplikacjipublic/index.php, AppBootstrapRunner
yiisoft/router & yiisoft/router-fastrouteRejestracja tras, dopasowywanie URL, grupy trasAppRouterFactory, BootstrapRouteDispatcher, UrlMatcherInterface
yiisoft/di & yiisoft/configKontener PSR-11, Service Providery, definicje DIContainerFactory, CoreServiceProvider, composer.json (extra.config-plugin)
yiisoft/db & yiisoft/db-mysqlPołączenia z bazami danych, Schema Cache, Query BuilderMultiDbRouter, Yiisoft\Db\Connection\ConnectionInterface
yiisoft/data-responseSerializacja i ujednolicone nagłówki odpowiedzi REST APIApiResponseTrait, DataResponseFactoryInterface, JsonDataResponseFormatter
yiisoft/assetsZarządzanie pakietami CSS/JS, minifikacja, zależności zasobówAssetManager, TablerAsset, TomSelectAsset, EngineAsset, TwigAssetExtension
yiisoft/csrfZabezpieczenie przed atakami Cross-Site Request ForgeryCsrfMiddleware, globalne nagłówki HTMX X-CSRF-Token
yiisoft/sessionObsługa sesji użytkowników zgodna z PSR-15SessionMiddleware, zarządzanie czasem życia sesji w a_mod_user_sessions
yiisoft/validatorDeklaratywna walidacja atrybutów DTO i formularzyReguły walidacji danych wejściowych w use case'ach
yiisoft/hydratorRzutowanie nieustrukturyzowanych tablic na obiekty DTOWarstwa Application DTO

2.1. Cykl życia HTTP i wejście aplikacji (yiisoft/runner & runner-http)

Punktem wejścia do aplikacji jest public/index.php. Zgodnie z normami bezpieczeństwa Ammonly, plik ten definiuje stałą ochronną:

php
define('AMMONLY_APP', true);

Następnie inicjalizowany jest runner HTTP (Yiisoft\Yii\Runner\Http\HttpApplicationRunner), który:

  1. Odczytuje konfigurację środowiskową ze zmiennych .env.
  2. Buduje kontener zależności PSR-11 za pośrednictwem yiisoft/di.
  3. Konstruuje potok middleware PSR-15.
  4. Pobiera żądanie PSR-7 ze środowiska (ServerRequestFactory) i emituje odpowiedź za pomocą SapiEmitter.

2.2. Routing i dyspozytor zapytań (yiisoft/router & router-fastroute)

System tras Ammonly dzieli się na dwa poziomy:

  1. Statyczne i wersjonowane trasy REST API oraz Web: Deklarowane deklaratywnie w fabryce tras AppRouterFactory za pomocą metod Route::get(), Route::post(), Route::put(), Route::delete() oraz grupowane hierarchicznie (Group::create('/api/v1')).
  2. Dyspozytor żądań (BootstrapRouteDispatcher):
    • Wykorzystuje Yiisoft\Router\UrlMatcherInterface oparty o kompilator wyrażeń regularnych FastRoute.
    • W przypadku dopasowania trasy wywołuje skojarzony kontroler z zachowaniem parametrów zapytania przekazywanych w atrybutach żądania PSR-7 ($request->getAttribute('id')).
    • W przypadku braku dopasowania w FastRoute, dyspozytor płynnie deleguje żądanie do mechanizmu modułowego Ammonly (dla dynamicznych widoków DataGrid, procesów workflow i formularzy konfiguracyjnych).
php
// Przykład definicji trasy w Yii3 Router:
Group::create('/api/v1')
    ->routes(
        Route::get('/users', [UserApiController::class, 'list']),
        Route::post('/users', [UserApiController::class, 'create']),
        Route::get('/users/{id:\d+}', [UserApiController::class, 'view']),
        Route::put('/users/{id:\d+}', [UserApiController::class, 'update']),
        Route::delete('/users/{id:\d+}', [UserApiController::class, 'delete'])
    );

2.3. Kontener wstrzykiwania zależności (yiisoft/di, factory & config)

Wszystkie klasy usługowe, repozytoria i kontrolery w systemie są rejestrowane i rozwiązywane przez kontener Yiisoft\Di\Container.

W pliku composer.json skonfigurowana jest wtyczka extra.config-plugin, która organizuje pliki konfiguracyjne:

json
"extra": {
    "config-plugin": {
        "params": "config/params.php",
        "common": "config/common.php",
        "web": "config/web.php"
    }
}

Rejestracja usług realizowana jest w modularnych klasach Service Providerów, m.in. CoreServiceProvider:

php
public function getDefinitions(): array
{
    return [
        UrlMatcherInterface::class => static fn (ContainerInterface $c): UrlMatcherInterface =>
            AppRouterFactory::createMatcher(),

        AssetManager::class => static fn (ContainerInterface $c): AssetManager =>
            new AssetManager(
                new Aliases(['@root' => dirname(__DIR__, 3)]),
                new AssetLoader()
            ),
        
        MultiDbRouter::class => static fn (ContainerInterface $c): MultiDbRouter =>
            new MultiDbRouter($c->get(ConfigInterface::class)->get('databases')),
    ];
}

2.4. Nowoczesna warstwa bazy danych (yiisoft/db & db-mysql)

W architekturze wielobazowej Ammonly centralną rolę odgrywa MultiDbRouter. Komponent ten zapewnia pełną koegzystencję tradycyjnych połączeń PDO oraz obiektów Yiisoft\Db\Connection\ConnectionInterface:

php
// Pobranie natywnego obiektu połączenia Yii3 DB:
$yiiDb = $multiDbRouter->getYiiConnection('default');

// Korzystanie z mechanizmu Schema Cache i Query Buildera:
$schema = $yiiDb->getSchema();
$tables = $schema->getTableNames();

// Zoptymalizowane zapytania z bindowaniem parametrów:
$command = $yiiDb->createCommand(
    'SELECT user_id, email, status FROM a_mod_users_records WHERE status = :status',
    [':status' => 'Active']
);
$users = $command->queryAll();

Kluczowe zalety yiisoft/db w Ammonly:

  • Inteligentny Schema Cache: Metadane tabel (kolumny, typy, klucze obce, indeksy) są buforowane w pamięci podręcznej PSR-16, redukując narzut zapytań SHOW COLUMNS i INFORMATION_SCHEMA do zera.
  • Odporność na SQL Injection: Wszystkie zapytania tworzone przez Command rygorystycznie stosują parametryzację :param.
  • Niezależność od dialektu: Możliwość rozszerzenia obsługi o silniki PostgreSQL, SQLite i MSSQL bez modyfikacji zapytań domenowych.

2.5. Ujednolicone formatowanie odpowiedzi API (yiisoft/data-response)

Wszystkie kontrolery API w Ammonly korzystają z cechy ApiResponseTrait. Cechę tę zintegrowano z fabryką Yiisoft\DataResponse\DataResponseFactory:

php
trait ApiResponseTrait
{
    protected function buildJsonResponse(
        ResponseFactoryInterface $factory,
        mixed $payload,
        int $statusCode
    ): ResponseInterface {
        $dataResponseFactory = new DataResponseFactory($factory);
        $formatter = new JsonDataResponseFormatter();

        $dataResponse = $dataResponseFactory
            ->createResponse($payload, $statusCode)
            ->withResponseFormatter($formatter);

        return $factory->createResponse($statusCode)
            ->withHeader('Content-Type', 'application/json')
            ->withBody($dataResponse->getBody());
    }
}

Formatowanie gwarantuje:

  • Poprawną serializację znaków diakrytycznych UTF-8 (brak uszkadzania polskich znaków).
  • Ujednolicony nagłówek Content-Type: application/json.
  • Bezpieczne kodowanie wartości zmiennoprzecinkowych, dat i obiektów JSON.

2.6. Zarządzanie zasobami front-endowymi (yiisoft/assets & AssetBundle)

Zgodnie z zasadami Ammonly dotyczącymi czystości kodu, zabronione jest umieszczanie inline <style> i <script> wewnątrz szablonów Twig. Zamiast tego stosujemy pakiety zasobów Yii3 dziedziczące po Yiisoft\Assets\AssetBundle.

Dostępne pakiety zasobów w src/Core/Asset/Bundle/:

  1. TablerAsset: Główny motyw interfejsu panelu administracyjnego (tabler.min.css, tabler.min.js).
  2. TomSelectAsset: Komponent zaawansowanych pól wyboru wielokrotnego (tom-select.bootstrap5.min.css, tom-select.complete.min.js).
  3. EngineAsset: Dedykowane style silnika Ammonly (engine-core.css, engine-forms.css, engine-layout.css) oraz skrypty HTMX.

Przykład definicji pakietu:

php
final class TomSelectAsset extends AssetBundle
{
    public ?string $basePath = '@root/public/assets';
    public ?string $baseUrl = '/assets';

    public array $css = [
        'vendor/tom-select/css/tom-select.bootstrap5.min.css',
    ];

    public array $js = [
        'vendor/tom-select/js/tom-select.complete.min.js',
    ];

    public array $depends = [
        TablerAsset::class,
    ];
}

Integracja z silnikiem Twig (TwigAssetExtension):

W szablonach Twig rejestracja i renderowanie tagów HTML sprowadzają się do przejrzystych dyrektyw:

twig
{# Rejestracja pakietu dla danego widoku #}
{{ register_asset_bundle('App\\Core\\Asset\\Bundle\\TomSelectAsset') }}

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Ammonly Console</title>
    {# Automatyczne wyrenderowanie zaleznosci CSS we wlasciwej kolejnosci #}
    {{ render_bundle_css()|raw }}
</head>
<body>
    <main>...</main>

    {# Automatyczne wyrenderowanie skryptow JS przed zamknieciem body #}
    {{ render_bundle_js()|raw }}
</body>
</html>

2.7. Bezpieczeństwo i sesje (yiisoft/csrf, security & session)

Bezpieczeństwo aplikacji opiera się na zestawie bibliotek ochronnych:

  • yiisoft/csrf: Zapewnia ochronę przed atakami CSRF. Wszystkie zapytania modyfikujące stan systemu (POST, PUT, PATCH, DELETE) są weryfikowane przez CsrfMiddleware.
  • Integracja z HTMX: W głównym szablonie layout.twig globalny atrybut hx-headers automatycznie dołącza token do każdego żądania AJAX:
    html
    <body hx-headers='{"X-CSRF-Token": "{{ csrf_token() }}"}'>
  • yiisoft/security: Realizuje kryptograficzne haszowanie haseł algorytmem Argon2id/Bcrypt oraz bezpieczne generowanie tokenów autoryzacyjnych.
  • yiisoft/session: Utrzymuje stan sesji użytkowników w relacyjnej bazie danych (a_mod_user_sessions), zapewniając precyzyjną kontrolę nad wygasaniem sesji (NIST AC-12).

2.8. Walidacja i hydratacja DTO (yiisoft/validator & hydrator)

W warstwie aplikacji (Application/) dane przychodzące z żądań HTTP REST API są konwertowane na obiekty transferu danych (DTO) przy użyciu Yiisoft\Hydrator\Hydrator.

Walidacja jest deklaratywna — atrybuty PHP definiują zasady poprawności:

php
final readonly class CreateUserDto
{
    public function __construct(
        #[Required]
        #[Email]
        public string $email,

        #[Required]
        #[Length(min: 8, max: 64)]
        public string $password,

        #[Required]
        #[In(['Active', 'Inactive', 'Blocked'])]
        public string $status = 'Active'
    ) {}
}

Dzięki temu kontroler nie zawiera powtarzalnych instrukcji warunkowych if, a błędy walidacji są automatycznie zwracane w standardowym formacie RFC 7807 Problem Details.


3. Cykl Życia Żądania HTTP (Pipeline PSR-15)

Każde przychodzące żądanie przechodzi przez uporządkowany potok middleware:

mermaid
sequenceDiagram
    autonumber
    actor Client as Przegladarka / Klient API
    participant Nginx as Serwer WWW (Nginx)
    participant Index as public/index.php
    participant Runner as HttpApplicationRunner (Yii3)
    participant Pipe as Potok Middleware (PSR-15)
    participant Router as BootstrapRouteDispatcher (FastRoute)
    participant Controller as Kontroler (Api / Htmx / Web)
    participant MultiDb as MultiDbRouter (Yii3 DB)

    Client->>Nginx: HTTP Request (GET / POST / ...)
    Nginx->>Index: FastCGI / PHP-FPM
    Index->>Runner: run()
    Runner->>Pipe: Przetworz przez potok middleware
    Note over Pipe: SecurityHeaders -> CsrfMiddleware -> SessionMiddleware -> AuthMiddleware
    Pipe->>Router: UrlMatcherInterface::match($request)
    Router->>Controller: Wywolaj akcje kontrolera
    Controller->>MultiDb: Pobierz dane / execute command
    MultiDb-->>Controller: Dane rekordow / Encje domenowe
    Controller-->>Pipe: ResponseInterface (DataResponse / HTML)
    Pipe-->>Runner: Sformatowana odpowiedz PSR-7
    Runner-->>Client: Emisja naglowkow i ciala odpowiedzi

4. Architektura Multi-Database (MultiDbRouter)

Platforma Ammonly obsługuje dwa niezależne profile instalacyjne:

  1. admin (ammonly_admin): Konsola administracyjna, zarządzanie subskrypcjami, audyt, użytkownicy platformy.
  2. client (ammonly_client): Środowisko biznesowe SaaS dla użytkowników końcowych (CRM, Sprzedaż, Projekty, Helpdesk).

Klasa MultiDbRouter zarządza pulą połączeń do obu baz danych:

mermaid
flowchart LR
    Request[Zadanie HTTP / Konsola CLI] --> Router[MultiDbRouter]
    Router -->|getConnection / PDO| PdoPool[(Pula polaczen PDO)]
    Router -->|getYiiConnection| YiiPool[(Pula Yiisoft Db Connection)]
    
    PdoPool --> AdminDb[(ammonly_admin)]
    PdoPool --> ClientDb[(ammonly_client)]
    YiiPool --> AdminDb
    YiiPool --> ClientDb
  • Metoda getConnection(string $key): PDO gwarantuje 100% kompatybilności wstecznej dla starszych modułów.
  • Metoda getYiiConnection(string $key): ConnectionInterface dostarcza pełną moc Schema Cache i Query Buildera Yii3.

5. Warstwa Prezentacji: Twig + HTMX + Yii3 Asset Bundles

W Ammonly warstwa interfejsu łączy trzy technologie:

  • Twig 3: Szablony bez logiki biznesowej, renderowanie po stronie serwera.
  • HTMX: Dynamiczne odświeżanie fragmentów DOM (Out-Of-Band swaps) bez przeładowywania całej strony.
  • Yii3 Asset Bundles: Precyzyjne zarządzanie bibliotekami CSS i JS bez kolizji i duplikatów.
mermaid
graph TD
    subgraph Szablon Twig
        T1[register_asset_bundle 'TablerAsset']
        T2[render_bundle_css]
        T3[Komponent HTMX: hx-get='/api/v1/records']
        T4[render_bundle_js]
    end

    subgraph Yii3 AssetManager
        AM[AssetManager Engine]
        TB[TablerAsset]
        TS[TomSelectAsset]
        ENG[EngineAsset]
        AM --> TB
        AM --> TS
        AM --> ENG
    end

    T1 --> AM
    AM --> T2
    AM --> T4

6. Zgodność z Quality Gate i 100% Pokryciem Testami

Wszystkie moduły, integracje i komponenty Yii3 podlegają rygorystycznemu systemowi kontroli jakości:

  • 100% Pokrycie Testami Jednostkowymi (Line & Branch Coverage): Wszystkie scenariusze i klasy integracyjne (w tym MultiDbRouter, ApiResponseTrait, TwigAssetExtension, AssetBundle, BootstrapRouteDispatcher, CoreServiceProvider) posiadają dedykowane testy w katalogu tests/Unit/.
  • SonarQube Quality Gate (sonar.ammonly.com): Zero długów technologicznych, złożoność cyklomatyczna metod <= 15, brak zduplikowanych literałów i pełne typowanie PHP 8.4+.
  • Standard PER 2.0: Maksymalna długość linii nie przekracza 120 znaków, a każdy plik PHP rozpoczyna się dyrektywą declare(strict_types=1);.

Narzędzia Weryfikacji

Przed wysłaniem zmian do repozytorium uruchamiane są automatyczne skrypty strażnicze:

bash
# Uruchomienie pelnego zestawu testow jednostkowych
vendor/bin/phpunit -c phpunit.xml

# Weryfikacja stylistyki kodu i limitu linii
php vendor/bin/phpcs --standard=PSR12 src/ tests/

Ammonly Documentation System