Extension points, event subscriptions, and DI preferences
The Payment module declares 2 plugins that modify checkout behavior.
| Plugin Name | Target Class | Area | Purpose |
|---|---|---|---|
| PaymentMethodProcess | Block\Form\Container | global | Processes payment method forms in container |
| ProcessPaymentConfiguration | Checkout\Block\Checkout\LayoutProcessor | frontend | Injects payment config into checkout layout |
Located in Plugin\PaymentMethodProcess. Handles Braintree CC Vault integration.
// di.xml configuration
<type name="Magento\Payment\Block\Form\Container">
<plugin name="PaymentMethodProcess"
type="Magento\Payment\Plugin\PaymentMethodProcess"/>
</type>
<type name="Magento\Payment\Plugin\PaymentMethodProcess">
<arguments>
<argument name="braintreeCCVault" xsi:type="string">braintree_cc_vault</argument>
</arguments>
</type>
Located in Plugin\PaymentConfigurationProcess. Adds payment configuration to checkout JS config.
// frontend/di.xml
<type name="Magento\Checkout\Block\Checkout\LayoutProcessor">
<plugin name="ProcessPaymentConfiguration"
type="Magento\Payment\Plugin\PaymentConfigurationProcess"/>
</type>
// Plugin adds payment component config to:
// jsLayout > components > checkout > children > steps >
// children > billing-step > children > payment
The Payment module subscribes to 2 events in the global area.
| Event | Observer Name | Class |
|---|---|---|
| sales_order_save_before | payment_sales_order_save_before | Observer\SalesOrderBeforeSaveObserver |
| sales_order_status_unassign | sales_order_status_update | Observer\UpdateOrderStatusForPaymentMethodsObserver |
Validates payment data integrity before order is saved to database.
// Observer\SalesOrderBeforeSaveObserver::execute()
public function execute(Observer $observer)
{
$order = $observer->getEvent()->getOrder();
$payment = $order->getPayment();
// Validates payment method is still available
// Checks payment additional information
// Ensures required data is present
}
Updates payment method configuration when order status is unassigned.
// Observer\UpdateOrderStatusForPaymentMethodsObserver::execute()
public function execute(Observer $observer)
{
$status = $observer->getEvent()->getStatus();
$state = $observer->getEvent()->getState();
// Updates payment/method/order_status config
// when a status is unassigned from a state
}
The Payment module declares 8 interface-to-implementation preferences.
| Interface | Implementation |
|---|---|
| Api\Data\PaymentMethodInterface | Model\PaymentMethod |
| Api\Data\PaymentAdditionalInfoInterface | Model\PaymentAdditionalInfo |
| Api\PaymentMethodListInterface | Model\PaymentMethodList |
| Gateway\Validator\ResultInterface | Gateway\Validator\Result |
| Gateway\ConfigFactoryInterface | Gateway\Config\ConfigFactory |
| Gateway\Command\CommandManagerPoolInterface | Gateway\Command\CommandManagerPool |
| Gateway\Data\PaymentDataObjectFactoryInterface | Gateway\Data\PaymentDataObjectFactory |
| Gateway\ErrorMapper\ErrorMessageMapperInterface | Gateway\ErrorMapper\ErrorMessageMapper |
Virtual types are extensively used to configure payment logging and error mapping.
<!-- Dedicated payment log file -->
<virtualType name="Magento\Payment\Model\Method\VirtualDebug"
type="Magento\Framework\Logger\Handler\Base">
<arguments>
<argument name="fileName" xsi:type="string">/var/log/payment.log</argument>
</arguments>
</virtualType>
<virtualType name="Magento\Payment\Model\Method\VirtualLogger"
type="Magento\Framework\Logger\Monolog">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="debug" xsi:type="object">
Magento\Payment\Model\Method\VirtualDebug
</item>
</argument>
</arguments>
</virtualType>
<!-- Error mapping reader and schema -->
<virtualType name="Magento\Payment\Gateway\ErrorMapper\VirtualSchemaLocator"
type="Magento\Framework\Config\GenericSchemaLocator">
<arguments>
<argument name="moduleName" xsi:type="string">Magento_Payment</argument>
<argument name="schema" xsi:type="string">error_mapping.xsd</argument>
</arguments>
</virtualType>
<virtualType name="Magento\Payment\Gateway\ErrorMapper\VirtualConfigReader"
type="Magento\Framework\Config\Reader\Filesystem">
<arguments>
<argument name="converter" xsi:type="object">
Magento\Payment\Gateway\ErrorMapper\XmlToArrayConverter
</argument>
<argument name="schemaLocator" xsi:type="object">
Magento\Payment\Gateway\ErrorMapper\VirtualSchemaLocator
</argument>
<argument name="fileName" xsi:type="string">error_mapping.xml</argument>
</arguments>
</virtualType>
Minimum configuration required to add a Gateway-based payment method:
<!-- etc/di.xml -->
<!-- 1. Method Facade -->
<virtualType name="MyPaymentFacade" type="Magento\Payment\Model\Method\Adapter">
<arguments>
<argument name="code" xsi:type="const">My\Payment\Model\Ui\ConfigProvider::CODE</argument>
<argument name="formBlockType" xsi:type="string">Magento\Payment\Block\Form</argument>
<argument name="infoBlockType" xsi:type="string">Magento\Payment\Block\Info</argument>
<argument name="valueHandlerPool" xsi:type="object">MyPaymentValueHandlerPool</argument>
<argument name="commandPool" xsi:type="object">MyPaymentCommandPool</argument>
</arguments>
</virtualType>
<!-- 2. Command Pool -->
<virtualType name="MyPaymentCommandPool" type="Magento\Payment\Gateway\Command\CommandPool">
<arguments>
<argument name="commands" xsi:type="array">
<item name="authorize" xsi:type="string">MyPaymentAuthorizeCommand</item>
</argument>
</arguments>
</virtualType>
<!-- 3. Value Handler Pool -->
<virtualType name="MyPaymentValueHandlerPool" type="Magento\Payment\Gateway\Config\ValueHandlerPool">
<arguments>
<argument name="handlers" xsi:type="array">
<item name="default" xsi:type="string">MyPaymentConfigValueHandler</item>
</argument>
</arguments>
</virtualType>
<!-- etc/config.xml -->
<config>
<default>
<payment>
<mypayment>
<active>1</active>
<model>MyPaymentFacade</model>
<title>My Payment Method</title>
<payment_action>authorize</payment_action>
</mypayment>
</payment>
</default>
</config>