حقن الاعتماديات في XOOPS
نظرة عامة
Section titled “نظرة عامة”حقن الاعتماديات (DI) هو نمط تصميم يسمح للمكونات باستقبال اعتماديات من مصادر خارجية بدلاً من إنشاء بعضها داخلياً. يقدم XOOPS 4.0 دعم حاوية حقن الاعتماديات المتوافق مع PSR-11.
لماذا حقن الاعتماديات؟
Section titled “لماذا حقن الاعتماديات؟”بدون حقن الاعتماديات (الاقتران الوثيق)
Section titled “بدون حقن الاعتماديات (الاقتران الوثيق)”class ArticleService{ private ArticleRepository $repository; private EventDispatcher $dispatcher;
public function __construct() { // Hard dependencies - difficult to test and modify $this->repository = new ArticleRepository(new XoopsDatabase()); $this->dispatcher = new EventDispatcher(); }}مع حقن الاعتماديات (الاقتران الضعيف)
Section titled “مع حقن الاعتماديات (الاقتران الضعيف)”class ArticleService{ public function __construct( private readonly ArticleRepositoryInterface $repository, private readonly EventDispatcherInterface $dispatcher ) {}}حاوية PSR-11
Section titled “حاوية PSR-11”الاستخدام الأساسي
Section titled “الاستخدام الأساسي”use Psr\Container\ContainerInterface;
// Get the container$container = \Xmf\Module\Helper::getHelper('mymodule')->getContainer();
// Retrieve a service$articleService = $container->get(ArticleService::class);
// Check if service existsif ($container->has(ArticleService::class)) { // Use the service}تكوين الحاوية
Section titled “تكوين الحاوية”use Psr\Container\ContainerInterface;
return [ // Simple class instantiation ArticleRepository::class => ArticleRepository::class,
// Interface to implementation binding ArticleRepositoryInterface::class => ArticleRepository::class,
// Factory function ArticleService::class => function (ContainerInterface $c): ArticleService { return new ArticleService( $c->get(ArticleRepositoryInterface::class), $c->get(EventDispatcherInterface::class) ); },
// Shared instance (singleton) 'database' => function (): XoopsDatabase { return XoopsDatabaseFactory::getDatabaseConnection(); },];تسجيل الخدمات
Section titled “تسجيل الخدمات”السلك التلقائي
Section titled “السلك التلقائي”// The container automatically resolves dependencies// when type hints are available
class ArticleController{ public function __construct( private readonly ArticleService $service, private readonly ViewRenderer $renderer ) {}}
// Container creates ArticleController with its dependencies$controller = $container->get(ArticleController::class);التسجيل اليدوي
Section titled “التسجيل اليدوي”return [ ArticleService::class => [ 'class' => ArticleService::class, 'arguments' => [ ArticleRepositoryInterface::class, EventDispatcherInterface::class, ], 'shared' => true, // Singleton ],
'article.handler' => [ 'factory' => [ArticleHandlerFactory::class, 'create'], 'arguments' => ['@database'], // Reference other service ],];حقن المُنشِّئ
Section titled “حقن المُنشِّئ”الأسلوب المفضل
Section titled “الأسلوب المفضل”final class ArticleService{ public function __construct( private readonly ArticleRepositoryInterface $repository, private readonly EventDispatcherInterface $dispatcher, private readonly LoggerInterface $logger ) {}
public function create(CreateArticleDTO $dto): Article { $this->logger->info('Creating article', ['title' => $dto->title]);
$article = Article::create($dto); $this->repository->save($article); $this->dispatcher->dispatch(new ArticleCreatedEvent($article));
return $article; }}حقن الطريقة
Section titled “حقن الطريقة”للاعتماديات الاختيارية
Section titled “للاعتماديات الاختيارية”class ArticleController{ public function __construct( private readonly ArticleService $service ) {}
public function show(int $id, ?CacheInterface $cache = null): Response { $cacheKey = "article_{$id}";
if ($cache && $cached = $cache->get($cacheKey)) { return $this->render($cached); }
$article = $this->service->findById($id);
$cache?->set($cacheKey, $article, 3600);
return $this->render($article); }}ربط الواجهات
Section titled “ربط الواجهات”تحديد الواجهات
Section titled “تحديد الواجهات”interface ArticleRepositoryInterface{ public function findById(int $id): ?Article; public function save(Article $article): void; public function delete(Article $article): void;}ربط التطبيق
Section titled “ربط التطبيق”return [ ArticleRepositoryInterface::class => XoopsArticleRepository::class,
// Or with factory ArticleRepositoryInterface::class => function (ContainerInterface $c) { return new XoopsArticleRepository( $c->get('database') ); },];الاختبار مع حقن الاعتماديات
Section titled “الاختبار مع حقن الاعتماديات”السخرية السهلة
Section titled “السخرية السهلة”class ArticleServiceTest extends TestCase{ public function testCreateArticle(): void { // Create mocks $repository = $this->createMock(ArticleRepositoryInterface::class); $dispatcher = $this->createMock(EventDispatcherInterface::class); $logger = $this->createMock(LoggerInterface::class);
// Inject mocks $service = new ArticleService($repository, $dispatcher, $logger);
// Set expectations $repository->expects($this->once())->method('save'); $dispatcher->expects($this->once())->method('dispatch');
// Test $dto = new CreateArticleDTO('Title', 'Content'); $article = $service->create($dto);
$this->assertInstanceOf(Article::class, $article); }}تكامل XOOPS القديم
Section titled “تكامل XOOPS القديم”ربط القديم والجديد
Section titled “ربط القديم والجديد”// Get service from container in legacy codefunction mymodule_get_articles(int $limit): array{ $container = \Xmf\Module\Helper::getHelper('mymodule')->getContainer(); $service = $container->get(ArticleService::class);
return $service->findRecent($limit);}لف معالجات قديمة
Section titled “لف معالجات قديمة”return [ 'article.handler' => function () { return xoops_getModuleHandler('article', 'mymodule'); },
ArticleRepositoryInterface::class => function (ContainerInterface $c) { return new LegacyArticleRepository( $c->get('article.handler') ); },];أفضل الممارسات
Section titled “أفضل الممارسات”- حقن الواجهات - اعتمد على التجريدات وليس التطبيقات
- حقن المُنشِّئ - فضل حقن المُنشِّئ على حقن المُعيِّن
- المسؤولية الواحدة - يجب أن يكون لكل فئة عدد قليل من الاعتماديات
- تجنب الوعي بالحاوية - يجب ألا تعرف الخدمات عن الحاوية
- التكوين وليس الترميز - استخدم ملفات التكوين للأسلاك
الوثائق ذات الصلة
Section titled “الوثائق ذات الصلة”- ../07-XOOPS-4.0/Implementation-Guides/PSR-11-Dependency-Injection-Guide - تطبيق PSR-11
- ../03-Module-Development/Patterns/Service-Layer - نمط الخدمة
- ../03-Module-Development/Best-Practices/Testing - الاختبار مع حقن الاعتماديات
- ../07-XOOPS-4.0/XOOPS-4.0-Architecture - نظرة عامة على الهندسة المعمارية