--- phase: 02-bug-fixes plan: 04 type: execute wave: 1 depends_on: [] files_modified: - src/Modules/Cron/CronHandlerFactory.php - src/Core/Application.php - bin/cron.php autonomous: true --- ## Cel Wydzielić `CronHandlerFactory` — jedyne miejsce, które buduje graf obiektów dla crona. Zastąpić nią ręczną konstrukcję w `Application::maybeRunCronOnWeb()` oraz `bin/cron.php`. ## Powód `Application.php` (linie 274–353) zawiera 80+ linii ręcznego `new X($this->db)` powielających okablowanie z `bin/cron.php`. Oba miejsca mogą się rozjechać — już teraz `bin/cron.php` przekazuje `AllegroOAuthClient` tam, gdzie powinien być `AllegroTokenManager`, oraz używa `AllegroOrderSyncStateRepository` zamiast `ShopproOrderSyncStateRepository` dla shopPRO. ## Output - Nowy plik `src/Modules/Cron/CronHandlerFactory.php` - `Application.php::maybeRunCronOnWeb()` skrócona do ~10 linii - `bin/cron.php` skrócone do ~15 linii - Oba błędy w `bin/cron.php` naprawione przy okazji ## Kontekst projektu @.paul/PROJECT.md @.paul/ROADMAP.md @.paul/STATE.md ## Pliki źródłowe @src/Core/Application.php @bin/cron.php @routes/web.php ## Required Skills (from SPECIAL-FLOWS.md) | Skill | Priority | When to Invoke | Loaded? | |-------|----------|----------------|---------| | /code-review | required | Po implementacji, przed UNIFY | ○ | | sonar-scanner | required | Po APPLY, przed UNIFY | ○ | **BLOCKING:** Required skills MUST be loaded before APPLY proceeds. ## Skill Invocation Checklist - [ ] /code-review loaded - [ ] sonar-scanner run po zakończeniu implementacji ## AC-1: Jeden punkt definicji handlerow crona ```gherkin Given codebase z trzema miejscami budującymi graf obiektów crona When plik CronHandlerFactory.php istnieje Then Application.php i bin/cron.php nie zawierają już new AllegroIntegrationRepository / new ShopproIntegrationsRepository / new AllegroOrderImportService w kontekście crona — wszystkie obiekty buduje fabryka ``` ## AC-2: Web cron działa identycznie jak przed zmianą ```gherkin Given ustawienie cron_run_on_web = true w bazie When użytkownik odwiedza dowolną stronę aplikacji Then maybeRunCronOnWeb() uruchamia CronRunner z tymi samymi handlerami co wcześniej — brak regresji funkcjonalnej ``` ## AC-3: bin/cron.php używa poprawnych zależności ```gherkin Given bin/cron.php przed zmianą używał AllegroOAuthClient zamiast AllegroTokenManager (arg #2 AllegroOrderImportService i AllegroOrdersSyncService) oraz AllegroOrderSyncStateRepository zamiast ShopproOrderSyncStateRepository dla ShopproOrdersSyncService When bin/cron.php zostanie zaktualizowany do użycia CronHandlerFactory Then oba błędy są naprawione — fabryka przekazuje AllegroTokenManager i ShopproOrderSyncStateRepository ``` Task 1: Utwórz CronHandlerFactory src/Modules/Cron/CronHandlerFactory.php Utwórz klasę `App\Modules\Cron\CronHandlerFactory` w nowym pliku. Konstruktor: `__construct(private readonly \PDO $db, private readonly string $integrationSecret)`. Metoda publiczna: `build(CronRepository $cronRepository, \App\Core\Support\Logger $logger): CronRunner`. Wewnątrz `build()` skonstruuj dokładnie te same obiekty co w `Application::maybeRunCronOnWeb()` (stan po naprawie z planu 02-03, czyli wersja z `Application.php` — NIE z `bin/cron.php`): ``` $integrationRepository = new AllegroIntegrationRepository($this->db, $this->integrationSecret) $oauthClient = new AllegroOAuthClient() $tokenManager = new AllegroTokenManager($integrationRepository, $oauthClient) $apiClient = new AllegroApiClient() $statusMappingRepository = new AllegroStatusMappingRepository($this->db) $orderImportService = new AllegroOrderImportService( $integrationRepository, $tokenManager, $apiClient, new OrderImportRepository($this->db), $statusMappingRepository, new OrdersRepository($this->db) ) $ordersSyncService = new AllegroOrdersSyncService( $integrationRepository, new AllegroOrderSyncStateRepository($this->db), $tokenManager, $apiClient, $orderImportService ) $shopproIntegrationsRepo = new ShopproIntegrationsRepository($this->db, $this->integrationSecret) $shopproSyncService = new ShopproOrdersSyncService( $shopproIntegrationsRepo, new ShopproOrderSyncStateRepository($this->db), new ShopproApiClient(), new OrderImportRepository($this->db), new ShopproStatusMappingRepository($this->db), new OrdersRepository($this->db) ) $shopproStatusSyncService = new ShopproStatusSyncService($shopproIntegrationsRepo, $shopproSyncService) $shopproPaymentSyncService = new ShopproPaymentStatusSyncService( $shopproIntegrationsRepo, new ShopproApiClient(), new OrdersRepository($this->db), $this->db ) ``` Zwróć `new CronRunner($cronRepository, $logger, [ handlers array ])` — lista handlerów identyczna jak w `Application.php` (allegro_token_refresh, allegro_orders_import, allegro_status_sync, shoppro_orders_import, shoppro_order_status_sync, shoppro_payment_status_sync). Dodaj wszystkie potrzebne `use` na górze pliku. Klasa powinna być `final`. UNIKAJ: przyjmowania całego `Application` lub tablicy konfiguracji jako parametru — tylko `$db` i `$integrationSecret` są potrzebne. Plik istnieje: `src/Modules/Cron/CronHandlerFactory.php`. Składnia PHP poprawna: `php -l src/Modules/Cron/CronHandlerFactory.php` zwraca "No syntax errors detected". AC-1 częściowo — fabryka istnieje i buduje kompletny graf obiektów Task 2: Uproszczenie Application::maybeRunCronOnWeb() src/Core/Application.php W metodzie `maybeRunCronOnWeb()` zastąp blok `try { ... $runner = new CronRunner(...) ... }` wywołaniem fabryki: ```php $factory = new CronHandlerFactory( $this->db, (string) $this->config('app.integrations.secret', '') ); $runner = $factory->build($repository, $this->logger); $runner->run($webLimit); ``` Zachowaj blok `finally { $this->releaseWebCronLock(); }`. Dodaj `use App\Modules\Cron\CronHandlerFactory;` do importów na górze pliku. Usuń z `Application.php` wszystkie `use` instrukcje które były potrzebne wyłącznie dla ręcznej konstrukcji grafu crona (AllegroIntegrationRepository, AllegroOAuthClient, AllegroTokenManager, AllegroApiClient, AllegroStatusMappingRepository, AllegroOrderImportService, AllegroOrdersSyncService, AllegroOrderSyncStateRepository, AllegroStatusSyncService, ShopproApiClient, ShopproIntegrationsRepository, ShopproOrdersSyncService, ShopproOrderSyncStateRepository, ShopproPaymentStatusSyncService, ShopproStatusSyncService, ShopproStatusMappingRepository, OrderImportRepository, OrdersRepository) — TYLKO jeśli nie są używane nigdzie indziej w Application.php. UNIKAJ usuwania `use` dla CronRunner, CronRepository, AllegroOrdersImportHandler i innych klas Cron, bo mogą być używane. SPRAWDŹ przed usunięciem każdego `use` czy nie pojawia się w innych metodach lub właściwościach klasy. `php -l src/Core/Application.php` — brak błędów składni. Metoda `maybeRunCronOnWeb()` liczy ≤25 linii (było 80+). Grep na "new AllegroIntegrationRepository" w Application.php — brak wystąpień w metodzie maybeRunCronOnWeb. AC-1 spełnione — Application.php nie buduje już własnego grafu crona; AC-2 spełnione — ta sama fabryka, te same handlery Task 3: Uproszczenie bin/cron.php z naprawą błędów bin/cron.php Zastąp całą sekcję od `$cronRepository = new CronRepository(...)` do `$runner = new CronRunner(...)` wywołaniem fabryki: ```php $cronRepository = new CronRepository($app->db()); $factory = new CronHandlerFactory( $app->db(), (string) $app->config('app.integrations.secret', '') ); $runner = $factory->build($cronRepository, $app->logger()); ``` Zachowaj blok `$result = $runner->run($limit)` i `fwrite(...)`. Zachowaj blok parsowania `--limit` z `$argv`. Usuń wszystkie `use` instrukcje które nie są już potrzebne — zastąp je jednym `use App\Modules\Cron\CronHandlerFactory;` (obok `use App\Core\Application;` i `use App\Modules\Cron\CronRepository;`). To NAPRAWIA dwa istniejące błędy w bin/cron.php: - AllegroOAuthClient zamiast AllegroTokenManager w AllegroOrderImportService i AllegroOrdersSyncService - AllegroOrderSyncStateRepository zamiast ShopproOrderSyncStateRepository dla ShopproOrdersSyncService `php -l bin/cron.php` — brak błędów składni. bin/cron.php liczy ≤25 linii łącznie (było 123). Grep "AllegroOAuthClient" w bin/cron.php — brak (usunięto nieprawidłowe użycie). Grep "AllegroOrderSyncStateRepository" w bin/cron.php — brak (usunięto nieprawidłowe użycie). AC-3 spełnione — bin/cron.php używa poprawnych zależności przez fabrykę ## DO NOT CHANGE - Logika wewnątrz handlerów (AllegroOrdersImportHandler, AllegroStatusSyncHandler, itp.) - Klasa CronRunner — interfejs publiczny pozostaje niezmieniony - Metody Application poza maybeRunCronOnWeb() i blokiem use - routes/web.php — nie dotykamy, nie buduje handlerow crona - Migracje i schemat bazy danych ## SCOPE LIMITS - Nie wprowadzamy DI container — to osobny temat (CONCERNS.md [MEDIUM] No DI Container) - Nie naprawiamy innych bugów z CONCERNS.md w tym planie - Nie przenosimy crona do routes/web.php — fabryka jest prostszym i bardziej przenośnym rozwiązaniem - Nie zmieniamy publicznego API CronHandlerFactory po jego stworzeniu bez potrzeby Przed deklaracją planu jako zakończonego: - [ ] `php -l src/Modules/Cron/CronHandlerFactory.php` — No syntax errors - [ ] `php -l src/Core/Application.php` — No syntax errors - [ ] `php -l bin/cron.php` — No syntax errors - [ ] Grep "new AllegroIntegrationRepository" w Application.php — 0 wyników w maybeRunCronOnWeb - [ ] Grep "new ShopproIntegrationsRepository" w Application.php — 0 wyników w maybeRunCronOnWeb - [ ] Grep "AllegroOrderSyncStateRepository" w bin/cron.php — 0 wyników - [ ] Grep "AllegroOAuthClient" w bin/cron.php — 0 wyników - [ ] Wszystkie kryteria akceptacji AC-1, AC-2, AC-3 spełnione - CronHandlerFactory istnieje i buduje kompletny, poprawny graf obiektów crona - Application::maybeRunCronOnWeb() liczy ≤25 linii (skrócone z 80+) - bin/cron.php liczy ≤25 linii (skrócone ze 123) - Dwa błędy w bin/cron.php naprawione (AllegroOAuthClient → AllegroTokenManager, AllegroOrderSyncStateRepository → ShopproOrderSyncStateRepository) - Brak błędów składni PHP we wszystkich zmienionych plikach - Brak duplikacji okablowania crona między Application.php a bin/cron.php Po zakończeniu utwórz `.paul/phases/02-bug-fixes/02-04-SUMMARY.md`