Skip to content
advanced Phase 110 · Upgrades

Module Compatibility in Magento 2

Checking module compatibility, handling deprecated APIs, and managing version constraints during upgrades

45m
2 problems
Topic Progress 0%

Checking Compatibility

Module Compatibility Check Methods

Composer Validation

# Validate all modules
composer validate

# Check specific module
composer show magento/module-catalog

# Check version constraints
composer why magento/framework

Magento Module Status

# List all modules
php bin/magento module:status

# Check specific module status
php bin/magento module:status Vendor_Module

# Enable/disable module
php bin/magento module:enable Vendor_Module
php bin/magento module:disable Vendor_Module

Automated Compatibility Scan

// Script to check module compatibility
$modules = glob('app/code/Vendor/*/');
$issues = [];

foreach ($modules as $moduleDir) {
    $moduleName = basename($moduleDir);
    
    // Check for deprecated APIs
    $files = glob($moduleDir . '**/*.php');
    foreach ($files as $file) {
        $content = file_get_contents($file);
        
        if (preg_match('/ObjectManager::getInstance()/', $content)) {
            $issues[] = "$moduleName: Uses ObjectManager directly";
        }
        
        if (preg_match('/@deprecated/', $content)) {
            $issues[] = "$moduleName: Uses deprecated methods";
        }
    }
    
    // Check module.xml version
    $moduleXml = simplexml_load_file($moduleDir . 'etc/module.xml');
    if ($moduleXml) {
        $setupVersion = (string)$moduleXml->sequence->module['setup_version'] ?? 'unknown';
        // Compare against target version
    }
}

foreach ($issues as $issue) {
    echo $issue . "\n";
}

Integration Test for Compatibility

public function testModuleCompatibility(): void
{
    $moduleList = $this->objectManager->create(ModuleListInterface::class);
    $modules = $moduleList->getNames();
    
    foreach ($modules as $moduleName) {
        // Verify module can be loaded
        $this->assertTrue(
            $this->moduleManager->isEnabled($moduleName),
            "Module $moduleName should be enabled"
        );
    }
}

Deprecated APIs

Common Deprecated APIs in Magento

ObjectManager Direct Usage

// BAD: Direct ObjectManager usage (deprecated pattern)
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$product = $objectManager->create(\Magento\Catalog\Model\Product::class);

// GOOD: Constructor injection
class ProductProcessor
{
    public function __construct(
        private ProductFactory $productFactory
    ) {}
    
    public function process(): void
    {
        $product = $this->productFactory->create();
    }
}

Deprecated Class Methods

// Find deprecated methods in codebase
rg '@deprecated' app/code/ --include='*.php'

// Example deprecated patterns
$order->getShippingAddress();  // May be deprecated in favor of interface
$product->getResource();       // Use repository pattern instead
$helper->jsonEncode();         // Use native json_encode

Deprecated Configuration

<!-- Check for deprecated config paths -->
<!-- system.xml with deprecated sections -->
<config>
    <section id="deprecated_section" translate="label">
        <!-- This section may be removed in newer versions -->
    </section>
</config>

Migration Strategy for Deprecated APIs

// Step 1: Find all deprecated usage
rg -l '@deprecated' app/code/Vendor/Module/

// Step 2: Replace with modern equivalent
// Before
$order->getShippingAddress();

// After
$order->getShippingAddress(); // Check interface first
// If interface available:
$shippingAddress = $order->getExtensionAttributes()->getShippingAssignments()[0]->getAddress();

// Step 3: Add backward compatibility
/**
 * @deprecated Use getShippingAddressFromExtensionAttributes() instead
 */
public function getShippingAddressOld()
{
    @trigger_error(__METHOD__ . ' is deprecated', E_USER_DEPRECATED);
    return $this->getShippingAddress();
}

Removed APIs by Version

2.4.5 → 2.4.6:
- Removed support for PHP 7.4
- Elasticsearch required (no MySQL search)
- Removed CMS Page/Block direct load
- Deprecated Swagger (use REST API docs)

2.4.4 → 2.4.5:
- Removed support for MySQL 5.7
- Redis required for session/cache
- Removed custom theme inheritance

Finding Deprecated Usage

# Search for common deprecated patterns
grep -r 'ObjectManager::getInstance()' app/code/
grep -r 'getHelper(' app/code/
grep -r 'get面したModel()' app/code/
grep -r '@deprecated' app/code/

# Use PHPStan to catch deprecated calls
vendor/bin/phpstan analyse --level=6 app/code/Vendor/

Version Constraints

Composer Version Constraint Syntax

Exact Version

{
    "require": {
        "magento/module-catalog": "103.0.6"
    }
}

Range Constraints

{
    "require": {
        "magento/module-catalog": ">=103.0.0 <104.0.0",
        "magento/module-sales": ">=103.0.0 <103.1.0"
    }
}

Caret (^) - Compatible with version

{
    "require": {
        "magento/framework": "^103.0",
        "php": "^8.1"
    }
}
// ^103.0 means >=103.0.0 <104.0.0

Tilde (~) - Next significant release

{
    "require": {
        "magento/module-catalog": "~103.0.5"
    }
}
// ~103.0.5 means >=103.0.5 <103.1.0

Wildcard (*)

{
    "require": {
        "magento/module-*": "2.4.6"
    }
}

Stability Flags

{
    "require": {
        "magento/module-catalog": "2.4.6@stable",
        "vendor/experimental": "dev-main@dev"
    }
}
// Options: @stable, @RC, @beta, @alpha, @dev

Best Practices

1. Use ^ for minor version flexibility
   ^103.0 allows 103.0.x, 103.1.x, etc.

2. Pin exact versions for critical dependencies
   "magento/framework": "103.0.6"

3. Use ranges for third-party modules
   "vendor/module": ">=2.0 <3.0"

4. Document why specific versions are required
   Add comments in README or lock file

5. Test with minimum supported versions
   Don't just test with latest

Version Locking Strategy

{
    "require": {
        "php": ">=8.1 <8.3",
        "magento/product-community-edition": "2.4.6-p2",
        "magento/framework": "103.0.6-p2"
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}

Updating Modules for Compatibility

Module Update Workflow

Step 1: Assess Current State

# Check current module version
composer show vendor/module

# Check for updates
composer show --available vendor/module

# View changelog
composer changelog vendor/module

Step 2: Update Code

// Replace deprecated interface usage
// BEFORE
use Magento\Catalog\Model\Product;

// AFTER
use Magento\Catalog\Api\Data\ProductInterface;

// Update constructor injection
public function __construct(
    private ProductRepositoryInterface $productRepository
) {}

Step 3: Update configuration

<!-- Update di.xml for new interfaces -->
<config>
    <type name="Vendor\Module\Service\ProductService">
        <arguments>
            <argument name="productRepository" xsi:type="object">
                Magento\Catalog\Api\ProductRepositoryInterface
            </argument>
        </arguments>
    </type>
</config>

Step 4: Update tests

// Update test to use mock instead of ObjectManager
public function testProductSave(): void
{
    $productRepository = $this->createMock(ProductRepositoryInterface::class);
    $productRepository->expects($this->once())
        ->method('save')
        ->willReturnArgument(0);
    
    $service = new ProductService($productRepository);
    $service->saveProduct($product);
}

Step 5: Version bump

// Update composer.json
{
    "name": "vendor/module",
    "version": "2.0.0",
    "require": {
        "php": ">=8.1",
        "magento/framework": "^103.0",
        "magento/module-catalog": "^103.0"
    }
}

Module Compatibility Checklist

Code:
- [ ] No ObjectManager direct usage
- [ ] All deprecated APIs replaced
- [ ] PHP 8.1+ compatible syntax
- [ ] Return types added
- [ ] Property types added

Configuration:
- [ ] di.xml uses interfaces
- [ ] events.xml references valid events
- [ ] routes.xml compatible with new routing
- [ ] system.xml fields valid

Dependencies:
- [ ] composer.json constraints updated
- [ ] All dependencies available in target version
- [ ] No conflicting dependencies

Tests:
- [ ] Unit tests passing
- [ ] Integration tests passing
- [ ] No deprecation warnings in test output

Practice Problems

0 / 2 solved
Fix Deprecated API Usage

Find and replace all ObjectManager::getInstance() calls in a module with proper dependency injection.

Module Version Upgrade

Upgrade a module's composer.json constraints to be compatible with Magento 2.4.6 while maintaining backward compatibility.

Quiz

1. What does ^103.0 mean in composer version constraints?

Question 1 options

2. What is the recommended replacement for ObjectManager::getInstance()?

Question 2 options

3. How to check if a module uses deprecated APIs?

Question 3 options

4. What stability flag allows installing dev versions?

Question 4 options

Flashcards

Question

What does ^103.0 mean?

Answer

>=103.0.0 <104.0.0 - compatible within major version

Question

How to find deprecated API usage?

Answer

Search for @deprecated tags, ObjectManager usage, and deprecated class imports

Question

What replaces ObjectManager direct usage?

Answer

Constructor injection with type hints

Question

What does composer why do?

Answer

Shows why a specific package is installed (dependency tree)

Question

How to check module compatibility?

Answer

composer validate, module:status, PHPStan analysis, integration tests

Revision Notes

Key Takeaways

  • 1. Use composer validate and why/why-not to check compatibility
  • 2. ObjectManager direct usage is deprecated - use constructor injection
  • 3. Caret (^) allows compatible updates within same major version
  • 4. Always test with minimum supported PHP and package versions
  • 5. Document deprecated APIs and provide migration path for users
  • 6. Update version constraints in composer.json for new Magento versions

Interview Tips

  • How do you check if a module is compatible with a new Magento version?
  • Explain composer version constraint syntax with examples
  • How do you handle deprecated API usage in your modules?
  • Describe your module update workflow
  • What is the difference between ^ and ~ in composer constraints?

Cheat Sheet

Module Compatibility Cheat Sheet

Check Compatibility:

  • composer validate
  • composer why/why-not
  • PHPStan analysis
  • Integration tests

Version Constraints:

  • ^103.0 = >=103.0 <104.0
  • ~103.0.5 = >=103.0.5 <103.1.0
  • 103.0.6 = exact version
  • @dev = development version

Deprecated APIs:

  • ObjectManager::getInstance() → constructor injection
  • Direct model load → repository pattern
  • Helper methods → service classes

Checklist:
No ObjectManager, PHP 8.1+, interfaces in di.xml, tests passing