PluginProbe
Auto Alt Text / 2.7.0
Auto Alt Text v2.7.0
3.0.3 2.8.2 1.3.1 1.3.2 2.0.0 2.1.0 2.1.1 2.2.0 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.7.0 2.8.0 2.8.1 All 28 releases
auto-alt-text / src / App / Core / Container.php

Container.php in Auto Alt Text 2.7.0, at src/App/Core/Container.php

383 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace AATXT\App\Core;
6
7 use AATXT\App\Admin\MediaLibrary;
8 use AATXT\App\Admin\PluginOptions;
9 use AATXT\App\AIProviders\Anthropic\AnthropicResponse;
10 use AATXT\App\AIProviders\Azure\AzureComputerVisionCaptionsResponse;
11 use AATXT\App\AIProviders\Azure\AzureTranslator;
12 use AATXT\App\AIProviders\OpenAI\OpenAIVision;
13 use AATXT\App\Configuration\AnthropicConfig;
14 use AATXT\App\Configuration\AzureConfig;
15 use AATXT\App\Configuration\OpenAIConfig;
16 use AATXT\App\Infrastructure\Database\ErrorLogSchema;
17 use AATXT\App\Infrastructure\Http\HttpClientInterface;
18 use AATXT\App\Infrastructure\Http\WordPressHttpClient;
19 use AATXT\App\Infrastructure\Repositories\ConfigRepositoryInterface;
20 use AATXT\App\Infrastructure\Repositories\ErrorLogRepository;
21 use AATXT\App\Infrastructure\Repositories\ErrorLogRepositoryInterface;
22 use AATXT\App\Infrastructure\Repositories\WordPressConfigRepository;
23 use AATXT\App\Logging\DBLogger;
24 use AATXT\App\Services\AltTextGeneratorFactory;
25 use AATXT\App\Services\ConfigBasedGeneratorFactory;
26 use AATXT\App\Services\AltTextService;
27 use AATXT\App\Utilities\AssetsManager;
28 use AATXT\App\AIProviders\Decorators\DecoratorBuilder;
29 use AATXT\App\AltTextGeneratorAi;
30 use AATXT\App\AltTextGeneratorAttachmentTitle;
31 use AATXT\App\AltTextGeneratorParentPostTitle;
32 use AATXT\App\Events\EventDispatcherInterface;
33 use AATXT\App\Events\SimpleEventDispatcher;
34 use AATXT\App\Events\AltTextGenerationFailedEvent;
35 use AATXT\App\Events\Listeners\LogErrorListener;
36 use AATXT\App\Events\Listeners\NotifyAdminListener;
37 use AATXT\Config\Constants;
38 use DI\Container as DIContainer;
39 use DI\ContainerBuilder;
40
41 /**
42 * Dependency Injection Container configuration.
43 *
44 * This class sets up and configures the PHP-DI container with all
45 * service bindings for the plugin. It implements the Dependency Inversion
46 * Principle by binding interfaces to concrete implementations.
47 *
48 * Usage:
49 * ```php
50 * $container = Container::make();
51 * $service = $container->get(SomeService::class);
52 * ```
53 */
54 final class Container
55 {
56 private static ?DIContainer $instance = null;
57
58 /**
59 * Private constructor to prevent direct instantiation.
60 */
61 private function __construct()
62 {
63 }
64
65 /**
66 * Get or create the container instance.
67 *
68 * @return DIContainer The configured container
69 * @throws \Exception If container build fails
70 */
71 public static function make(): DIContainer
72 {
73 if (self::$instance === null) {
74 self::$instance = self::build();
75 }
76
77 return self::$instance;
78 }
79
80 /**
81 * Build and configure the container with all service bindings.
82 *
83 * @return DIContainer The configured container
84 * @throws \Exception If container build fails
85 */
86 private static function build(): DIContainer
87 {
88 $builder = new ContainerBuilder();
89
90 // Enable compilation for better performance in production
91 // Note: Disable in development if you need to modify bindings frequently
92 // $builder->enableCompilation(__DIR__ . '/../../../var/cache');
93
94 $builder->addDefinitions(self::getDefinitions());
95
96 return $builder->build();
97 }
98
99 /**
100 * Get all service definitions for the container.
101 *
102 * @return array<string, mixed> Array of service definitions
103 */
104 private static function getDefinitions(): array
105 {
106 return [
107 // WordPress database abstraction
108 // Maps wpdb class to the global WordPress database object
109 \wpdb::class => function () {
110 return $GLOBALS['wpdb'];
111 },
112
113 // Database Schema Management
114 // Manages error logs table schema
115 ErrorLogSchema::class => \DI\create(ErrorLogSchema::class)
116 ->constructor(\DI\get(\wpdb::class)),
117
118 // Error Log Repository
119 // Maps interface to concrete implementation for error log persistence
120 ErrorLogRepositoryInterface::class => \DI\create(ErrorLogRepository::class)
121 ->constructor(
122 \DI\get(\wpdb::class),
123 \DI\get(ErrorLogSchema::class)
124 ),
125
126 // Config Repository
127 // Maps interface to WordPress options implementation for configuration management
128 ConfigRepositoryInterface::class => \DI\create(WordPressConfigRepository::class),
129
130 // Database Logger
131 // Legacy logger refactored to use repository pattern
132 DBLogger::class => \DI\create(DBLogger::class)
133 ->constructor(
134 \DI\get(ErrorLogRepositoryInterface::class),
135 \DI\get(ErrorLogSchema::class)
136 ),
137
138 // HTTP Client abstraction
139 // Maps HttpClientInterface to WordPress HTTP client implementation
140 HttpClientInterface::class => \DI\create(WordPressHttpClient::class),
141
142 // OpenAI Configuration
143 // Factory that reads configuration from WordPress options
144 OpenAIConfig::class => function () {
145 return new OpenAIConfig(
146 PluginOptions::apiKeyOpenAI(),
147 PluginOptions::openAiPrompt(),
148 PluginOptions::openAiModel()
149 );
150 },
151
152 // Anthropic Configuration
153 // Factory that reads configuration from WordPress options
154 AnthropicConfig::class => function () {
155 return new AnthropicConfig(
156 PluginOptions::apiKeyAnthropic(),
157 PluginOptions::anthropicPrompt(),
158 PluginOptions::anthropicModel()
159 );
160 },
161
162 // Azure Configuration
163 // Factory that reads configuration from WordPress options
164 // Includes both Computer Vision and Translator settings
165 AzureConfig::class => function () {
166 return new AzureConfig(
167 PluginOptions::apiKeyAzureComputerVision(),
168 PluginOptions::endpointAzureComputerVision(),
169 '', // Azure doesn't use a model parameter
170 '', // Azure doesn't use a custom prompt
171 PluginOptions::apiKeyAzureTranslateInstance(),
172 PluginOptions::endpointAzureTranslateInstance(),
173 PluginOptions::regionAzureTranslateInstance(),
174 PluginOptions::languageAzureTranslateInstance()
175 );
176 },
177
178 // OpenAI Vision Provider
179 // Automatically injects HttpClientInterface and OpenAIConfig
180 OpenAIVision::class => \DI\create(OpenAIVision::class)
181 ->constructor(
182 \DI\get(HttpClientInterface::class),
183 \DI\get(OpenAIConfig::class)
184 ),
185
186 // Anthropic Claude Provider
187 // Automatically injects HttpClientInterface and AnthropicConfig
188 AnthropicResponse::class => \DI\create(AnthropicResponse::class)
189 ->constructor(
190 \DI\get(HttpClientInterface::class),
191 \DI\get(AnthropicConfig::class)
192 ),
193
194 // Azure Translator
195 // Automatically injects HttpClientInterface and AzureConfig
196 AzureTranslator::class => \DI\create(AzureTranslator::class)
197 ->constructor(
198 \DI\get(HttpClientInterface::class),
199 \DI\get(AzureConfig::class)
200 ),
201
202 // Azure Computer Vision Provider
203 // Automatically injects HttpClientInterface, AzureConfig, and AzureTranslator
204 AzureComputerVisionCaptionsResponse::class => \DI\create(AzureComputerVisionCaptionsResponse::class)
205 ->constructor(
206 \DI\get(HttpClientInterface::class),
207 \DI\get(AzureConfig::class),
208 \DI\get(AzureTranslator::class)
209 ),
210
211 // =============================================
212 // Decorated AI Providers (using Decorator Pattern)
213 // Order: Provider → Cleaning → Validation → Caching
214 // =============================================
215
216 // Decorated OpenAI Vision Provider
217 // Applies cleaning and validation decorators
218 'openai.vision.decorated' => function ($container) {
219 return DecoratorBuilder::wrap($container->get(OpenAIVision::class))
220 ->withCleaning()
221 ->withValidation(false)
222 ->build();
223 },
224
225 // Decorated Anthropic Provider
226 // Applies cleaning and validation decorators
227 'anthropic.decorated' => function ($container) {
228 return DecoratorBuilder::wrap($container->get(AnthropicResponse::class))
229 ->withCleaning()
230 ->withValidation(false)
231 ->build();
232 },
233
234 // Decorated Azure Provider
235 // Applies cleaning and validation decorators
236 // Note: Azure has built-in translation, so cleaning is important
237 'azure.decorated' => function ($container) {
238 return DecoratorBuilder::wrap($container->get(AzureComputerVisionCaptionsResponse::class))
239 ->withCleaning()
240 ->withValidation(false)
241 ->build();
242 },
243
244 // Alt Text Generator Factory
245 // Factory pattern for creating different types of alt text generators
246 // Uses decorated providers for cleaning and validation
247 AltTextGeneratorFactory::class => function ($container) {
248 $factory = new ConfigBasedGeneratorFactory();
249
250 // Register OpenAI Vision generator (decorated)
251 $factory->register(
252 Constants::AATXT_OPTION_TYPOLOGY_CHOICE_OPENAI,
253 function () use ($container) {
254 return AltTextGeneratorAi::make(
255 $container->get('openai.vision.decorated')
256 );
257 }
258 );
259
260 // Register Anthropic generator (decorated)
261 $factory->register(
262 Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ANTHROPIC,
263 function () use ($container) {
264 return AltTextGeneratorAi::make(
265 $container->get('anthropic.decorated')
266 );
267 }
268 );
269
270 // Register Azure generator (decorated)
271 $factory->register(
272 Constants::AATXT_OPTION_TYPOLOGY_CHOICE_AZURE,
273 function () use ($container) {
274 return AltTextGeneratorAi::make(
275 $container->get('azure.decorated')
276 );
277 }
278 );
279
280 // Register Parent Post Title generator
281 $factory->register(
282 Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ARTICLE_TITLE,
283 function () {
284 return AltTextGeneratorParentPostTitle::make();
285 }
286 );
287
288 // Register Attachment Title generator
289 $factory->register(
290 Constants::AATXT_OPTION_TYPOLOGY_CHOICE_ATTACHMENT_TITLE,
291 function () {
292 return AltTextGeneratorAttachmentTitle::make();
293 }
294 );
295
296 return $factory;
297 },
298
299
300 // =============================================
301 // Event System (Observer Pattern)
302 // =============================================
303
304 // Log Error Listener
305 // Listens for AltTextGenerationFailedEvent and logs errors to database
306 LogErrorListener::class => function ($container) {
307 return new LogErrorListener(
308 $container->get(ErrorLogRepositoryInterface::class)
309 );
310 },
311
312 // Notify Admin Listener
313 // Listens for failure events and can send email notifications
314 // Email notifications are disabled by default
315 NotifyAdminListener::class => function () {
316 return new NotifyAdminListener(
317 false, // Email disabled by default
318 5 // Threshold: 5 failures before notification
319 );
320 },
321
322 // Event Dispatcher
323 // Central event dispatcher with pre-registered listeners
324 EventDispatcherInterface::class => function ($container) {
325 $dispatcher = new SimpleEventDispatcher();
326
327 // Register LogErrorListener for failure events
328 // Note: We're using the listener via event system instead of direct logging
329 // This allows for decoupled error handling
330 $logErrorListener = $container->get(LogErrorListener::class);
331 $dispatcher->listen(
332 AltTextGenerationFailedEvent::class,
333 [$logErrorListener, 'handle']
334 );
335
336 // Register NotifyAdminListener for failure events
337 $notifyAdminListener = $container->get(NotifyAdminListener::class);
338 $dispatcher->listen(
339 AltTextGenerationFailedEvent::class,
340 [$notifyAdminListener, 'handleFailure']
341 );
342
343 return $dispatcher;
344 },
345
346 // Alt Text Service
347 // Main service for generating alt text, uses factory and handles errors
348 // Integrated with Event System for decoupled logging
349 AltTextService::class => function ($container) {
350 return new AltTextService(
351 $container->get(AltTextGeneratorFactory::class),
352 $container->get(ConfigRepositoryInterface::class),
353 $container->get(ErrorLogRepositoryInterface::class),
354 $container->get(EventDispatcherInterface::class)
355 );
356 },
357
358 // Assets Manager
359 // Handles Vite manifest loading for versioned assets
360 AssetsManager::class => \DI\create(AssetsManager::class),
361
362 // Media Library
363 // Handles media library UI customization and AJAX alt text generation
364 MediaLibrary::class => function ($container) {
365 return new MediaLibrary(
366 $container->get(AltTextService::class),
367 $container->get(AssetsManager::class)
368 );
369 },
370 ];
371 }
372
373 /**
374 * Reset the container instance (useful for testing).
375 *
376 * @return void
377 */
378 public static function reset(): void
379 {
380 self::$instance = null;
381 }
382 }
383