189 lines
7.6 KiB
Markdown
189 lines
7.6 KiB
Markdown
---
|
|
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
|
|
---
|
|
|
|
<objective>
|
|
## 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)
|
|
</objective>
|
|
|
|
<context>
|
|
## Project Context
|
|
@.paul/PROJECT.md
|
|
@.paul/ROADMAP.md
|
|
@.paul/STATE.md
|
|
|
|
## Source Files
|
|
@autoload/Domain/Integrations/IntegrationsRepository.php
|
|
@tests/Unit/Domain/Integrations/IntegrationsRepositoryTest.php
|
|
</context>
|
|
|
|
<acceptance_criteria>
|
|
|
|
## 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ą
|
|
```
|
|
|
|
</acceptance_criteria>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Utwórz ApiloRepository — ekstrakcja metod Apilo</name>
|
|
<files>autoload/Domain/Integrations/ApiloRepository.php</files>
|
|
<action>
|
|
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.
|
|
</action>
|
|
<verify>
|
|
php -l autoload/Domain/Integrations/ApiloRepository.php zwraca "No syntax errors"
|
|
Klasa ma dokładnie 8 publicznych metod apilo* + 6 prywatnych helperów.
|
|
</verify>
|
|
<done>AC-1 i AC-2 spełnione</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Utwórz ApiloRepositoryTest</name>
|
|
<files>tests/Unit/Domain/Integrations/ApiloRepositoryTest.php</files>
|
|
<action>
|
|
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.
|
|
</action>
|
|
<verify>
|
|
./test.ps1 tests/Unit/Domain/Integrations/ApiloRepositoryTest.php — wszystkie testy green
|
|
./test.ps1 — pełna suite green (817+ testów, brak regresji)
|
|
</verify>
|
|
<done>AC-3 i AC-4 spełnione</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<boundaries>
|
|
|
|
## 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.
|
|
|
|
</boundaries>
|
|
|
|
<verification>
|
|
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
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- 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)
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.paul/phases/06-integrations-refactoring/06-01-SUMMARY.md`
|
|
</output>
|