DI & Configuration

Dependency injection preferences, virtual types, and configuration

Module Characteristics

The Magento_Shipping module has a notably minimal plugin footprint. It defines no plugins or observers internally. Instead, it relies heavily on:

  • • DI preferences to swap implementations
  • • Virtual types for logging configuration
  • • Area-specific preferences (adminhtml vs global)
  • • Extension by carrier modules (UPS, FedEx, etc.)

DI Preferences (Global)

Source: etc/di.xml

Interface Implementation Purpose
Quote\Model\Quote\Address\
RateCollectorInterface
Shipping\Model\Shipping Main rate collection implementation
Shipping\Model\
CarrierFactoryInterface
Shipping\Model\CarrierFactory Creates carrier instances by code
Shipping\Model\Carrier\
Source\GenericInterface
Shipping\Model\Carrier\
Source\GenericDefault
Generic config source model

DI Preferences (Admin Area)

Source: etc/adminhtml/di.xml

Interface Implementation Purpose
Shipping\Model\Shipping Shipping\Model\Shipping\Labels Adds label generation capabilities in admin
Shipping\Model\
ShipmentProviderInterface
Shipping\Model\
ShipmentProvider
Provides current shipment in admin context

Why Admin-Only Labels?

The Shipping\Labels class extends the base Shipping class and adds requestToShipment() functionality. This is only available in the admin area because label generation requires secure API credentials and should not be exposed to frontend code.

Virtual Types

The module defines virtual types for carrier-specific logging:

Carrier Debug Handler

<virtualType name="Magento\Shipping\Model\Carrier\VirtualDebug"
             type="Magento\Framework\Logger\Handler\Base">
    <arguments>
        <argument name="fileName" xsi:type="string">
            /var/log/shipping.log
        </argument>
    </arguments>
</virtualType>

Carrier Virtual Logger

<virtualType name="Magento\Shipping\Model\Method\VirtualLogger"
             type="Magento\Framework\Logger\Monolog">
    <arguments>
        <argument name="handlers" xsi:type="array">
            <item name="debug" xsi:type="object">
                Magento\Shipping\Model\Carrier\VirtualDebug
            </item>
        </argument>
    </arguments>
</virtualType>

Logger Injection into Carriers

<type name="Magento\Shipping\Model\Carrier\AbstractCarrier">
    <arguments>
        <argument name="logger" xsi:type="object">
            Magento\Shipping\Model\Method\VirtualLogger
        </argument>
    </arguments>
</type>

This configuration injects a specialized logger into all carrier classes that extends AbstractCarrier. All carrier debug output goes to var/log/shipping.log.

Type Argument Configuration

Source: etc/adminhtml/di.xml

<type name="Magento\Shipping\Helper\Data">
    <arguments>
        <!-- Use frontend URL model in admin context -->
        <argument name="url" xsi:type="object">
            Magento\Framework\Url
        </argument>
    </arguments>
</type>

The Helper\Data class is injected with the frontend URL model even in admin context. This ensures tracking URLs generated in admin emails point to the frontend store.

Plugins Targeting Shipping Classes

While Magento_Shipping defines no plugins itself, other modules extend its functionality:

Source Module Target Class Plugin Purpose
Magento_Ups Block\DataProviders\
Tracking\DeliveryDateTitle
Updates delivery date title for UPS tracking
Magento_Fedex Block\DataProviders\
Tracking\DeliveryDateTitle
Updates delivery date title for FedEx tracking
Magento_Fedex Block\Tracking\Popup Updates delivery date value for FedEx
Magento_Inventory
ShippingAdminUi
Block\Adminhtml\Create Modifies back button URL for MSI
Magento_InventoryIn
StorePickupShippingAdminUi
Controller\Adminhtml\
Order\Shipment\View
Adds store pickup tracking info
Magento_InventoryIn
StorePickupShippingAdminUi
Block\Adminhtml\View Adds store pickup tracking button

Preferences Overriding Shipping Classes

Source Module Original Class Replacement Class
Magento_Inventory
Shipping
Controller\Adminhtml\
Order\Shipment\NewAction
InventoryShipping\
Controller\...\NewAction

MSI Override: When Multi-Source Inventory is enabled, the shipment creation controller is replaced to support source selection during shipping.

Cron Configuration

Source: etc/crontab.xml

<config>
    <group id="default">
        <job name="aggregate_sales_report_shipment_data"
             instance="Magento\Shipping\Model\Observer"
             method="aggregateSalesReportShipmentData">
            <schedule>0 0 * * *</schedule>
        </job>
    </group>
</config>
Job Name Schedule Purpose
aggregate_sales_report_
shipment_data
0 0 * * * (midnight daily) Aggregates shipment data for sales reports

ACL Configuration

Source: etc/acl.xml

<acl>
    <resources>
        <resource id="Magento_Backend::admin">
            <resource id="Magento_Backend::stores">
                <resource id="Magento_Backend::stores_settings">
                    <resource id="Magento_Config::config">
                        <resource id="Magento_Shipping::config_shipping"
                                  title="Shipping Settings"
                                  sortOrder="30" />
                        <resource id="Magento_Shipping::carriers"
                                  title="Shipping Methods"
                                  sortOrder="40" />
                    </resource>
                </resource>
            </resource>
        </resource>
    </resources>
</acl>

config_shipping

Controls access to Shipping Settings (origin address, policy)

carriers

Controls access to Shipping Methods configuration

Extension Best Practices

DO

  • Create new carriers by extending AbstractCarrier or AbstractCarrierOnline
  • Register carriers via config.xml under carriers/[code]/model
  • Use plugins on Block\DataProviders classes for tracking customization
  • Log carrier debug output using $this->_debug($debugData)
  • Return proper Error objects when carrier is unavailable

DON'T

  • Override the Shipping class with a preference (use plugins instead)
  • Modify carrier factory directly (register carriers via config)
  • Skip validation in collectRates() (always check country/weight limits)
  • Return null from collectRates() without explanation
  • Store API credentials in code (use encrypted config)