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
Find and replace all ObjectManager::getInstance() calls in a module with proper dependency injection.
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?
2. What is the recommended replacement for ObjectManager::getInstance()?
3. How to check if a module uses deprecated APIs?
4. What stability flag allows installing dev versions?
Flashcards
Question
What does ^103.0 mean?
Click to reveal answer
Answer
>=103.0.0 <104.0.0 - compatible within major version
Question
How to find deprecated API usage?
Click to reveal answer
Answer
Search for @deprecated tags, ObjectManager usage, and deprecated class imports
Question
What replaces ObjectManager direct usage?
Click to reveal answer
Answer
Constructor injection with type hints
Question
What does composer why do?
Click to reveal answer
Answer
Shows why a specific package is installed (dependency tree)
Question
How to check module compatibility?
Click to reveal answer
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