--- phase: 06-integrations-refactoring plan: 01 type: execute wave: 1 depends_on: [] files_modified: - autoload/Domain/Integrations/ApiloRepository.php - tests/Unit/Domain/Integrations/ApiloRepositoryTest.php autonomous: true --- ## Goal Wyekstrahować wszystkie metody Apilo z `IntegrationsRepository` do nowej klasy `ApiloRepository` — non-breaking (IntegrationsRepository pozostaje bez zmian do planu 06-02). ## Purpose `IntegrationsRepository` ma 875 linii z czego ~650 to logika Apilo (OAuth, keepalive, fetchList, produkty). Po ekstrakcji każda klasa będzie mieć jedną odpowiedzialność, zgodnie z zasadami projektu (jedna klasa = jedna odpowiedzialność, max ~50 linii na metodę). ## Output - Nowy plik: `autoload/Domain/Integrations/ApiloRepository.php` (~650 linii) - Nowy plik testów: `tests/Unit/Domain/Integrations/ApiloRepositoryTest.php` - `IntegrationsRepository` bez zmian (backward compatible) ## Project Context @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md ## Source Files @autoload/Domain/Integrations/IntegrationsRepository.php @tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php ## AC-1: ApiloRepository zawiera wszystkie metody Apilo ```gherkin Given plik autoload/Domain/Integrations/ApiloRepository.php istnieje When przeglądamy jego publiczne metody Then klasa ma: apiloAuthorize, apiloGetAccessToken, apiloKeepalive, apiloIntegrationStatus, apiloFetchList, apiloFetchListResult, apiloProductSearch, apiloCreateProduct ``` ## AC-2: ApiloRepository ma własny dostęp do DB (DI przez konstruktor) ```gherkin Given ApiloRepository(db: $mdb) jest tworzona When wywoływana jest dowolna metoda apilo* Then używa $db do zapytań bez zależności od IntegrationsRepository ``` ## AC-3: IntegrationsRepository nie zmieniona (backward compatible) ```gherkin Given istniejące testy IntegrationsRepositoryTest przechodzą When uruchamiane jest ./test.ps1 Then wszystkie 817+ testów green, brak nowych błędów ``` ## AC-4: Testy ApiloRepository pokrywają kluczowe metody ```gherkin Given nowy plik ApiloRepositoryTest.php When uruchamiane jest ./test.ps1 Then testy dla: apiloGetAccessToken, apiloKeepalive, apiloIntegrationStatus, apiloFetchListResult, apiloFetchList (invalid type), prywatnych helperów przechodzą ``` Task 1: Utwórz ApiloRepository — ekstrakcja metod Apilo autoload/Domain/Integrations/ApiloRepository.php Utwórz nowy plik `autoload/Domain/Integrations/ApiloRepository.php`. Namespace: `Domain\Integrations` Klasa ma: - `private $db;` - `private const SETTINGS_TABLE = 'pp_shop_apilo_settings';` - Konstruktor: `public function __construct($db)` Przenieś (skopiuj) z IntegrationsRepository **bez modyfikacji logiki**: - Metody publiczne: `apiloAuthorize`, `apiloGetAccessToken`, `apiloKeepalive`, `apiloIntegrationStatus`, `apiloFetchList`, `apiloFetchListResult`, `apiloProductSearch`, `apiloCreateProduct` - Metody prywatne: `refreshApiloAccessToken`, `shouldRefreshAccessToken`, `isFutureDate`, `normalizeApiloMapList`, `isMapListShape`, `extractApiloErrorMessage` Dostosowania niezbędne po przeniesieniu: - Wszędzie gdzie metody apilo* wewnętrznie wołają `$this->getSettings('apilo')` — zamień na `$this->db->select(self::SETTINGS_TABLE, ['name', 'value'])` i mapuj na `[$row['name'] => $row['value']]` (ta sama logika co w IntegrationsRepository::getSettings) - Wszędzie gdzie wołają `$this->saveSetting('apilo', ...)` — zamień na bezpośrednie `$this->db->update(self::SETTINGS_TABLE, ['value' => $value], ['name' => $name])` i `$this->db->insert(self::SETTINGS_TABLE, ['name' => $name, 'value' => $value])` z `count()` przed jak w saveSetting (dokładna kopia logiki) Unikaj: dziedziczenia z IntegrationsRepository, jakichkolwiek zależności poza $db. PHP < 8.0: brak match, named args, union types, str_contains. php -l autoload/Domain/Integrations/ApiloRepository.php zwraca "No syntax errors" Klasa ma dokładnie 8 publicznych metod apilo* + 6 prywatnych helperów. AC-1 i AC-2 spełnione Task 2: Utwórz ApiloRepositoryTest tests/Unit/Domain/Integrations/ApiloRepositoryTest.php Utwórz `tests/Unit/Domain/Integrations/ApiloRepositoryTest.php`. Namespace: `Tests\Unit\Domain\Integrations` Klasa extends `PHPUnit\Framework\TestCase` Przenieś (skopiuj) z IntegrationsRepositoryTest wszystkie testy dotyczące metod Apilo: - `testApiloGetAccessTokenReturnsNullWithoutSettings` - `testShouldRefreshAccessTokenReturnsFalseForFarFutureDate` - `testShouldRefreshAccessTokenReturnsTrueForNearExpiryDate` - `testApiloFetchListThrowsForInvalidType` - `testApiloFetchListResultReturnsDetailedErrorWhenConfigMissing` - `testApiloIntegrationStatusReturnsMissingConfigMessage` - `testNormalizeApiloMapListRejectsErrorPayload` - `testNormalizeApiloMapListAcceptsIdNameList` Dostosuj w skopiowanych testach: - Zmień `new IntegrationsRepository($this->mockDb)` → `new ApiloRepository($this->mockDb)` - Use statement: `use Domain\Integrations\ApiloRepository;` - setUp: `$this->repository = new ApiloRepository($this->mockDb);` Uwaga: w testach mockujących `select` z `pp_shop_apilo_settings` — sprawdź czy ApiloRepository używa dokładnie tej samej tabeli i struktury zapytania co IntegrationsRepository. Jeśli zmieniło się wywołanie (np. bezpośrednie select zamiast przez getSettings), dostosuj expect() w testach. Nie usuwaj tych testów z IntegrationsRepositoryTest — zostają tam do planu 06-02. ./test.ps1 tests/Unit/Domain/Integrations/ApiloRepositoryTest.php — wszystkie testy green ./test.ps1 — pełna suite green (817+ testów, brak regresji) AC-3 i AC-4 spełnione ## DO NOT CHANGE - `autoload/Domain/Integrations/IntegrationsRepository.php` — bez żadnych zmian w tym planie - `tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php` — tylko dodajemy, nie usuwamy - Żadne kontrolery, App.php, cron.php — migracja konsumentów to plan 06-02 - Żadne zmiany logiki biznesowej — czysta ekstrakcja, zero refaktoringu logiki ## SCOPE LIMITS - Ten plan tworzy tylko nową klasę + testy. Konsumenci nadal używają IntegrationsRepository. - Nie zmieniamy nazw metod, sygnatur, zachowania. - Nie optymalizujemy kodu Apilo podczas przenoszenia. Before declaring plan complete: - [ ] php -l autoload/Domain/Integrations/ApiloRepository.php — no syntax errors - [ ] ApiloRepository ma 8 publicznych metod: apiloAuthorize, apiloGetAccessToken, apiloKeepalive, apiloIntegrationStatus, apiloFetchList, apiloFetchListResult, apiloProductSearch, apiloCreateProduct - [ ] ./test.ps1 tests/Unit/Domain/Integrations/ApiloRepositoryTest.php — all green - [ ] ./test.ps1 — full suite green, żadna regresja w IntegrationsRepositoryTest - [ ] IntegrationsRepository.php nie został zmodyfikowany - ApiloRepository.php istnieje z pełnym zestawem metod Apilo - ApiloRepositoryTest.php istnieje z testami dla kluczowych metod - Pełna suite testów green (817+ testów) - IntegrationsRepository niezmieniony (backward compatible) After completion, create `.paul/phases/06-integrations-refactoring/06-01-SUMMARY.md`