تزریق وابستگی در XOOPS
بررسی اجمالی
Section titled “بررسی اجمالی”تزریق وابستگی (DI) یک الگوی طراحی است که به اجزا اجازه می دهد تا وابستگی های خود را از منابع خارجی دریافت کنند نه اینکه آنها را در داخل ایجاد کنند. XOOPS 4.0 پشتیبانی از کانتینر DI سازگار با PSR-11 را معرفی می کند.
چرا تزریق وابستگی؟
Section titled “چرا تزریق وابستگی؟”بدون DI (کوپلینگ محکم)
Section titled “بدون DI (کوپلینگ محکم)”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(); }}با DI (کوپلینگ شل)
Section titled “با DI (کوپلینگ شل)”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;}پیاده سازی Bind
Section titled “پیاده سازی Bind”return [ ArticleRepositoryInterface::class => XoopsArticleRepository::class,
// Or with factory ArticleRepositoryInterface::class => function (ContainerInterface $c) { return new XoopsArticleRepository( $c->get('database') ); },];تست با DI
Section titled “تست با DI”مسخره کردن آسان
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 Legacy ادغام
Section titled “XOOPS Legacy ادغام”پل زدن قدیم و جدید
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);}Wrapping Legacy Handlers
Section titled “Wrapping Legacy Handlers”return [ 'article.handler' => function () { return xoops_getModuleHandler('article', 'mymodule'); },
ArticleRepositoryInterface::class => function (ContainerInterface $c) { return new LegacyArticleRepository( $c->get('article.handler') ); },];بهترین شیوه ها
Section titled “بهترین شیوه ها”- Inject Interfaces - به انتزاعات بستگی دارد، نه پیاده سازی
- تزریق سازنده - سازنده را به تزریق ستر ترجیح دهید
- ** مسئولیت منفرد ** - هر کلاس باید وابستگی های کمی داشته باشد
- اجتناب از آگاهی از کانتینر - سرویس ها نباید از کانتینر اطلاع داشته باشند
- پیکربندی، کد نویسی نکنید - از فایل های پیکربندی برای سیم کشی استفاده کنید
مستندات مرتبط
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 - تست با DI
- ../07-XOOPS-4.0/XOOPS-4.0-Architecture - نمای کلی معماری