一键导入
module-di
Configure Magento 2 dependency injection — preferences, virtual types, constructor arguments, and proxy generation via di.xml
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Configure Magento 2 dependency injection — preferences, virtual types, constructor arguments, and proxy generation via di.xml
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Build Magento 2 admin grids using UI Component listing XML, data providers, and admin controllers with proper ACL integration
Implement Magento 2 GraphQL resolvers — define schema.graphqls types, write query and mutation resolvers, and handle authorization
Run Magento 2 CLI commands through Warden's Docker environment: warden shell, bin/magento, composer, Redis/Valkey, Varnish, OpenSearch, RabbitMQ, n98-magerun2, mutagen sync, and env lifecycle.
Adapt Luma-oriented Magento 2 modules to work with Hyva themes — replace RequireJS and Knockout with Alpine.js, Tailwind CSS, and ViewModels
Implement Magento 2 plugins (interceptors) following best practices for before, after, and around method interception
Create a new Magento 2 module with the required directory structure, registration files, composer autoloading, and module sequence declarations
| name | module-di |
| description | Configure Magento 2 dependency injection — preferences, virtual types, constructor arguments, and proxy generation via di.xml |
| installed_version | 1.0.0 |
| magehub_version | 0.1.13 |
Magento's object manager resolves all class dependencies through constructor
injection configured in etc/di.xml. Understanding this system is essential
because every service, model, and controller receives its collaborators
through the DI container — never through manual instantiation.
Declare all dependencies as constructor parameters with interface type hints.
The object manager automatically resolves concrete implementations based on
di.xml preferences. Avoid requesting concrete classes directly — interface
injection keeps your code decoupled and allows other modules to substitute
implementations via preferences.
Use <preference> to bind an interface to its default concrete implementation.
Preferences are global unless scoped to a specific area (etc/frontend/di.xml,
etc/adminhtml/di.xml). Only one preference per interface can be active at a
time — later-loaded modules override earlier ones based on sequence order.
Create <virtualType> entries when you need a class with a different set of
constructor arguments but no behavioral changes. Virtual types avoid creating
empty subclasses solely to change injected values. They are resolved only by
the DI container — they have no real PHP class file and cannot be used with
instanceof checks.
Declare <proxy> types for expensive dependencies that are not always used.
Proxies defer instantiation until the first method call, reducing the cost of
object graph construction. Use proxies on optional collaborators in commands,
cron jobs, and observers where the dependency is invoked conditionally.
Place di.xml in etc/ for global scope, etc/frontend/ for storefront,
and etc/adminhtml/ for admin. Area-scoped configuration overrides global
configuration. Keep preferences and type configurations in the narrowest scope
that applies to prevent unintended side effects in other areas.
Bind an interface to its concrete implementation so the object manager resolves the correct class for all constructor injections
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Vendor\Module\Api\DataProviderInterface"
type="Vendor\Module\Model\DataProvider"/>
</config>
Create a virtual logger instance with a custom handler without writing a PHP subclass
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="Vendor\Module\Model\VirtualDebugLogger"
type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="name" xsi:type="string">vendor_module</argument>
<argument name="handlers" xsi:type="array">
<item name="debug" xsi:type="object">Vendor\Module\Logger\DebugHandler</item>
</argument>
</arguments>
</virtualType>
<type name="Vendor\Module\Model\ImportProcessor">
<arguments>
<argument name="logger" xsi:type="object">Vendor\Module\Model\VirtualDebugLogger</argument>
</arguments>
</type>
</config>
Production-ready service class demonstrating proper constructor injection with interface type hints
<?php
declare(strict_types=1);
namespace Vendor\Module\Model;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Psr\Log\LoggerInterface;
class ProductDataExporter
{
public function __construct(
private readonly ProductRepositoryInterface $productRepository,
private readonly SearchCriteriaBuilder $searchCriteriaBuilder,
private readonly LoggerInterface $logger
) {
}
public function getActiveProducts(int $storeId): array
{
$criteria = $this->searchCriteriaBuilder
->addFilter('status', 1)
->addFilter('store_id', $storeId)
->create();
try {
$result = $this->productRepository->getList($criteria);
} catch (\Exception $e) {
$this->logger->error('Failed to load products', [
'store_id' => $storeId,
'exception' => $e->getMessage(),
]);
return [];
}
return $result->getItems();
}
}
Direct ObjectManager usage in models, services, or controllers: Hidden dependencies make the class impossible to unit test in isolation. Other modules cannot substitute implementations via di.xml because the dependency is resolved at call time, bypassing the DI container. Solution: Replace all ObjectManager::getInstance()->get() and create() calls with constructor-injected dependencies: public function __construct( private readonly ProductRepositoryInterface $productRepository ) {}
Creating empty PHP subclasses only to change constructor arguments: Pollutes the codebase with classes that contain no logic. Each empty subclass is another file to maintain and adds confusion about where behavior lives. Solution: Use a virtualType in di.xml instead:
custom_valuePath template:
etc/di.xml
Global dependency injection configuration with preferences and type argument overrides
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="{{vendor}}\{{module}}\Api\{{interfaceName}}"
type="{{vendor}}\{{module}}\Model\{{className}}"/>
</config>
Path template:
Api/{{interfaceName}}.php
Service contract interface for the module's primary API
<?php
declare(strict_types=1);
namespace {{vendor}}\{{module}}\Api;
interface {{interfaceName}}
{
/**
* @return mixed
*/
public function execute(): mixed;
}