resolveRepository( $registry ); $factory = $this->resolveViewModelFactory( $registry ); $renderer = $this->resolveProductCardRenderer( $registry ); $settings = $this->resolveSettingsRepository( $registry ); $shortcode = new AmazonDiscountShortcodeRenderer( $repository, $factory, $renderer, $settings ); $adminCard = new AmazonDiscountShortcodeCardRenderer( $repository, $shortcode ); $registry->bind( self::BINDING_SHORTCODE_RENDERER, $shortcode ); $registry->bind( self::BINDING_ADMIN_CARD_RENDERER, $adminCard ); $catalog = $this->resolveOptionalCatalog( $registry ); if ( $catalog !== null ) { $this->syncService = new AmazonDiscountSyncService( $catalog, $repository ); $registry->bind( self::BINDING_SYNC_SERVICE, $this->syncService ); } } /** * Register scheduling and cron callbacks. * * @param HookRegistrar $hooks Hook registrar. */ public function boot( HookRegistrar $hooks ): void { $hooks->addAction( 'affilun_activate', array( $this, 'ensureScheduled' ) ); $hooks->addAction( 'init', array( $this, 'ensureScheduled' ) ); $sync = $this->syncService; $hooks->addAction( self::HOOK_DAILY_SYNC, static function () use ( $sync ): void { if ( $sync === null ) { return; } try { $result = $sync->sync(); if ( $result->errorsByCategory() !== array() && function_exists( 'error_log' ) ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Cron partial-failure surface. error_log( 'AFFILUN Amazon discount sync partial failure: ' . wp_json_encode( $result->errorsByCategory() ) ); } } catch ( Throwable $error ) { if ( function_exists( 'error_log' ) ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Cron failure surface. error_log( 'AFFILUN Amazon discount sync failed: ' . $error->getMessage() ); } } } ); } /** * Ensure the daily synchronization event exists. */ public function ensureScheduled(): void { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_event' ) ) { return; } if ( ! wp_next_scheduled( self::HOOK_DAILY_SYNC ) ) { wp_schedule_event( time() + 300, 'daily', self::HOOK_DAILY_SYNC ); } } /** * Resolve the discount repository. * * @param ServiceProviderRegistry $registry Service registry. */ private function resolveRepository( ServiceProviderRegistry $registry ): AmazonDiscountRepository { $key = PersistenceServiceProvider::BINDING_AMAZON_DISCOUNT_REPOSITORY; if ( ! $registry->has( $key ) ) { throw new LogicException( 'AmazonDiscountServiceProvider requires AmazonDiscountRepository.' ); } $value = $registry->get( $key ); if ( ! $value instanceof AmazonDiscountRepository ) { throw new LogicException( 'AmazonDiscountServiceProvider expected AmazonDiscountRepository.' ); } return $value; } /** * Resolve the standard card view-model factory. * * @param ServiceProviderRegistry $registry Service registry. */ private function resolveViewModelFactory( ServiceProviderRegistry $registry ): ProductCardViewModelFactory { $key = RenderServiceProvider::BINDING_PRODUCT_CARD_VIEW_MODEL_FACTORY; $value = $registry->has( $key ) ? $registry->get( $key ) : null; if ( ! $value instanceof ProductCardViewModelFactory ) { throw new LogicException( 'AmazonDiscountServiceProvider requires ProductCardViewModelFactory.' ); } return $value; } /** * Resolve the standard card renderer. * * @param ServiceProviderRegistry $registry Service registry. */ private function resolveProductCardRenderer( ServiceProviderRegistry $registry ): ProductCardRenderer { $key = RenderServiceProvider::BINDING_PRODUCT_CARD_RENDERER; $value = $registry->has( $key ) ? $registry->get( $key ) : null; if ( ! $value instanceof ProductCardRenderer ) { throw new LogicException( 'AmazonDiscountServiceProvider requires ProductCardRenderer.' ); } return $value; } /** * Resolve the same option-backed settings used by normal product cards. * * @param ServiceProviderRegistry $registry Service registry. */ private function resolveSettingsRepository( ServiceProviderRegistry $registry ): SettingsRepository { $key = PersistenceServiceProvider::BINDING_OPTION_STORE; $value = $registry->has( $key ) ? $registry->get( $key ) : null; if ( ! $value instanceof OptionStore ) { throw new LogicException( 'AmazonDiscountServiceProvider requires OptionStore.' ); } return new OptionStoreSettingsRepository( $value ); } /** * Resolve Amazon discount discovery when credentials are available. * * @param ServiceProviderRegistry $registry Service registry. */ private function resolveOptionalCatalog( ServiceProviderRegistry $registry ): ?AmazonDiscountCatalog { $key = ProviderServiceProvider::BINDING_PROVIDER_REGISTRY; $value = $registry->has( $key ) ? $registry->get( $key ) : null; if ( ! $value instanceof ProviderRegistry || ! $value->has( 'amazon' ) ) { return null; } $provider = $value->get( 'amazon' ); return $provider instanceof AmazonDiscountCatalog ? $provider : null; } }