Scope Hierarchy
Configuration Scope Levels
Default (app/etc/config.php)
│
├── Website
│ ├── Store
│ │ ├── Store View (en_US)
│ │ └── Store View (fr_FR)
│ └── Store
│ └── Store View (de_DE)
└── Website
└── Store
└── Store View (en_GB)
Scope Constants
namespace Magento\Framework\App\Config;
interface ScopeInterface
{
const SCOPE_DEFAULT = 'default';
const SCOPE_WEBSITES = 'websites';
const SCOPE_STORES = 'stores';
const SCOPE_STORE = 'store';
}
Scope Resolver
namespace Vendor\Config\Scope;
class ScopeResolver
{
private StoreManagerInterface $storeManager;
public function resolve(int $storeId): array
{
$store = $this->storeManager->getStore($storeId);
$website = $store->getWebsite();
return [
'default' => null,
'website' => $website->getId(),
'store' => $store->getId(),
'store_view' => $storeId,
];
}
}
Scope Configuration
Reading Config by Scope
namespace Vendor\Config\Reader;
class ScopedConfigReader
{
private ConfigInterface $config;
public function getValue(
string $path,
string $scope,
int $scopeId
): mixed {
return $this->config->getValue($path, $scope, $scopeId);
}
public function getWebsiteValue(string $path, int $websiteId): mixed
{
return $this->config->getValue(
$path,
ScopeInterface::SCOPE_WEBSITES,
$websiteId
);
}
public function getStoreValue(string $path, int $storeId): mixed
{
return $this->config->getValue(
$path,
ScopeInterface::SCOPE_STORES,
$storeId
);
}
}
Scope-Aware Service
namespace Vendor\Config\Service;
class ScopeAwareService
{
private ConfigInterface $config;
private ScopeResolverInterface $scopeResolver;
public function getConfigValue(
string $path,
int $storeId
): mixed {
// Try store view scope first
$value = $this->config->getValue(
$path,
ScopeInterface::SCOPE_STORES,
$storeId
);
if ($value !== null) {
return $value;
}
// Fall back to website scope
$scopes = $this->scopeResolver->resolve($storeId);
$value = $this->config->getValue(
$path,
ScopeInterface::SCOPE_WEBSITES,
$scopes['website']
);
if ($value !== null) {
return $value;
}
// Fall back to default
return $this->config->getValue(
$path,
ScopeInterface::SCOPE_DEFAULT
);
}
}
Scope Inheritance
Config Value Resolution
namespace Vendor\Config\Inheritance;
class ConfigValueResolver
{
private ConfigInterface $config;
public function resolve(
string $path,
int $storeId
): ResolvedValue {
$storeValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_STORES,
$storeId
);
$websiteId = $this->getWebsiteId($storeId);
$websiteValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_WEBSITES,
$websiteId
);
$defaultValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_DEFAULT
);
return new ResolvedValue([
'value' => $storeValue ?? $websiteValue ?? $defaultValue,
'scope' => $storeValue !== null ? 'store' : (
$websiteValue !== null ? 'website' : 'default'
),
]);
}
}
Scope Override Check
namespace Vendor\Config\Override;
class ScopeOverrideChecker
{
public function hasOverride(
string $path,
int $storeId
): bool {
$storeValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_STORES,
$storeId
);
return $storeValue !== null;
}
public function getOverrides(int $websiteId): array
{
$overrides = [];
$allPaths = $this->config->getAllPaths();
foreach ($allPaths as $path) {
$websiteValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_WEBSITES,
$websiteId
);
if ($websiteValue !== null) {
$overrides[$path] = $websiteValue;
}
}
return $overrides;
}
}
Scope in Admin
Admin Scope Selector
<!-- system.xml scope attributes -->
<field id="field_name" translate="label" type="text" sortOrder="10"
showInDefault="1" showInWebsite="1" showInStore="1">
<label>Field Label</label>
</field>
Scope-Aware Save
namespace Vendor\Config\Admin\Save;
class ScopedConfigSaver
{
private ConfigInterface $config;
public function save(
string $path,
mixed $value,
string $scope,
int $scopeId
): void {
$this->config->setValue(
$path,
$value,
$scope,
$scopeId
);
$this->config->save();
}
}
Scope Display in Admin
namespace Vendor\Config\Admin\Display;
class ScopeAwareRenderer
{
public function renderValue(
string $path,
int $storeId
): array {
$storeValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_STORES,
$storeId
);
$websiteValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_WEBSITES,
$this->getWebsiteId($storeId)
);
$defaultValue = $this->config->getValue(
$path,
ScopeInterface::SCOPE_DEFAULT
);
return [
'current' => $storeValue ?? $websiteValue ?? $defaultValue,
'inherited' => $storeValue === null,
'scope' => $storeValue !== null ? 'Store' : (
$websiteValue !== null ? 'Website' : 'Default'
),
];
}
}
Quiz
1. What is scope inheritance?
2. How do you read store-specific config?
3. What does showInStore='1' mean in system.xml?
Flashcards
Question
What are the scope levels?
Click to reveal answer
Answer
Default → Website → Store → Store View
Question
How does scope inheritance work?
Click to reveal answer
Answer
More specific scope overrides broader scope
Question
How to read store config?
Click to reveal answer
Answer
getValue(path, SCOPE_STORES, storeId)
Question
What is showInStore?
Click to reveal answer
Answer
system.xml attribute allowing store view scope override
Revision Notes
Key Takeaways
- 1. Scope hierarchy: Default → Website → Store → Store View
- 2. More specific scopes override broader ones
- 3. showInStore/Website/Default controls admin field visibility
- 4. Config values resolve by checking most specific scope first
- 5. Scope-aware services read config at correct level
Interview Tips
- • Explain scope hierarchy and inheritance order
- • Discuss when to use each scope level
- • Describe how to read config at different scopes
- • Talk about scope-aware design patterns
Cheat Sheet
Scopes:
Default → global fallback
Website → payment/shipping
Store → catalog
Store View → language/display
Inheritance:
Store View → Website → Default
First non-null value wins
Reading:
getValue($path, $scope, $scopeId)
$scope = 'default'/'websites'/'stores'