Motyw
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
- 2. Przegląd i Mapa Komponentów Yii3 w Ammonly
- 2.1. Cykl życia HTTP i wejście aplikacji (yiisoft/runner & runner-http)
- 2.2. Routing i dyspozytor zapytań (yiisoft/router & router-fastroute)
- 2.3. Kontener wstrzykiwania zależności (yiisoft/di, factory & config)
- 2.4. Nowoczesna warstwa bazy danych (yiisoft/db & db-mysql)
- 2.5. Ujednolicone formatowanie odpowiedzi API (yiisoft/data-response)
- 2.6. Zarządzanie zasobami front-endowymi (yiisoft/assets & AssetBundle)
- 2.7. Bezpieczeństwo i sesje (yiisoft/csrf, security & session)
- 2.8. Walidacja i hydratacja DTO (yiisoft/validator & hydrator)
- 3. Cykl Życia Żądania HTTP (Pipeline PSR-15)
- 4. Architektura Multi-Database (MultiDbRouter)
- 5. Warstwa Prezentacji: Twig + HTMX + Yii3 Asset Bundles
- 6. Zgodność z Quality Gate i 100% Pokryciem Testami
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ściamiKorzyści dla Ammonly:
- Brak vendor lock-in: Warstwa domenowa (
Domain/) nie dziedziczy po klasach bazowych frameworka (ActiveRecord,Modelitp.). Jest w 100% czystym kodem PHP 8.4+. - 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.
- 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 Composer | Rola w architekturze | Główne klasy i interfejsy w projekcie |
|---|---|---|
yiisoft/runner-http | Cykl życia HTTP i uruchomienie aplikacji | public/index.php, AppBootstrapRunner |
yiisoft/router & yiisoft/router-fastroute | Rejestracja tras, dopasowywanie URL, grupy tras | AppRouterFactory, BootstrapRouteDispatcher, UrlMatcherInterface |
yiisoft/di & yiisoft/config | Kontener PSR-11, Service Providery, definicje DI | ContainerFactory, CoreServiceProvider, composer.json (extra.config-plugin) |
yiisoft/db & yiisoft/db-mysql | Połączenia z bazami danych, Schema Cache, Query Builder | MultiDbRouter, Yiisoft\Db\Connection\ConnectionInterface |
yiisoft/data-response | Serializacja i ujednolicone nagłówki odpowiedzi REST API | ApiResponseTrait, DataResponseFactoryInterface, JsonDataResponseFormatter |
yiisoft/assets | Zarządzanie pakietami CSS/JS, minifikacja, zależności zasobów | AssetManager, TablerAsset, TomSelectAsset, EngineAsset, TwigAssetExtension |
yiisoft/csrf | Zabezpieczenie przed atakami Cross-Site Request Forgery | CsrfMiddleware, globalne nagłówki HTMX X-CSRF-Token |
yiisoft/session | Obsługa sesji użytkowników zgodna z PSR-15 | SessionMiddleware, zarządzanie czasem życia sesji w a_mod_user_sessions |
yiisoft/validator | Deklaratywna walidacja atrybutów DTO i formularzy | Reguły walidacji danych wejściowych w use case'ach |
yiisoft/hydrator | Rzutowanie nieustrukturyzowanych tablic na obiekty DTO | Warstwa 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:
- Odczytuje konfigurację środowiskową ze zmiennych
.env. - Buduje kontener zależności PSR-11 za pośrednictwem
yiisoft/di. - Konstruuje potok middleware PSR-15.
- 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:
- Statyczne i wersjonowane trasy REST API oraz Web: Deklarowane deklaratywnie w fabryce tras
AppRouterFactoryza pomocą metodRoute::get(),Route::post(),Route::put(),Route::delete()oraz grupowane hierarchicznie (Group::create('/api/v1')). - Dyspozytor żądań (
BootstrapRouteDispatcher):- Wykorzystuje
Yiisoft\Router\UrlMatcherInterfaceoparty 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).
- Wykorzystuje
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 COLUMNSiINFORMATION_SCHEMAdo zera. - Odporność na SQL Injection: Wszystkie zapytania tworzone przez
Commandrygorystycznie 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/:
TablerAsset: Główny motyw interfejsu panelu administracyjnego (tabler.min.css,tabler.min.js).TomSelectAsset: Komponent zaawansowanych pól wyboru wielokrotnego (tom-select.bootstrap5.min.css,tom-select.complete.min.js).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 przezCsrfMiddleware.- Integracja z HTMX: W głównym szablonie
layout.twigglobalny atrybuthx-headersautomatycznie 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 odpowiedzi4. Architektura Multi-Database (MultiDbRouter)
Platforma Ammonly obsługuje dwa niezależne profile instalacyjne:
admin(ammonly_admin): Konsola administracyjna, zarządzanie subskrypcjami, audyt, użytkownicy platformy.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): PDOgwarantuje 100% kompatybilności wstecznej dla starszych modułów. - Metoda
getYiiConnection(string $key): ConnectionInterfacedostarcza 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 --> T46. 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 katalogutests/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/