Problem/Motivation

The performance pattern save_in_loop (modules/audit_performance/src/Plugin/AuditAnalyzer/PerformanceAnalyzer.php) matches any ->save() inside a loop and reports "Entity save() inside a loop - each save triggers hooks and cache invalidation", recommending batch operations or queue workers.

The pattern does not look at the receiver. A loop over configuration names that updates each config object, for example

foreach ($names as $name) {
$config = $this->configFactory->reset($name)->getEditable($name);
...
$config->save();
}

(the code core's LocaleConfigManager::updateDefaultConfigLangcodes() uses), or a config form saving several settings, is reported as an entity save. Config::save() does not run entity hooks or entity access, invalidates only the config: cache tag, and there is no bulk alternative: saving each config object is the normal way to update several of them.

Steps to reproduce

1. Add a loop calling $this->configFactory->getEditable($name)->set('langcode', $langcode)->save(); to a custom module.
2. Run drush audit:run performance --format=json.
3. SAVE_IN_LOOP is reported.

Proposed resolution

Add a skip_config_save flag to the save_in_loop pattern, handled in isContextualPerfIssue() by a new isConfigObjectSave() helper that skips the save() when it is made on a configuration object:
- a ->getEditable( or $this->config( call chained to the save(), also when the chain is split over the two previous lines (only a chain that ends on the reported line counts);
- or a variable or property whose closest assignment above is such a call ($config = ...->getEditable($name)).

The receiver is resolved from the code, not guessed from the variable name: a $config variable that is reassigned to an entity before the save() is still reported. Entity saves in loops are reported as before.

Remaining tasks

- Implement the flag and the helper.
- Unit test with a data provider (none covered SAVE_IN_LOOP before): config chained, chained over several lines, through a variable, and $this->config() in a config form => not reported; an entity save, a $config variable reassigned to an entity, an entity save after a config line, all in a loop => reported; an entity save outside a loop => not reported.

User interface changes

Configuration object saves inside loops no longer produce SAVE_IN_LOOP warnings.

API changes

None.

Data model changes

None.

Comments

trebormc created an issue. See original summary.

  • trebormc committed f0eb9d29 on 1.x
    Issue #3630472 by trebormc: Skip configuration object saves in the...
trebormc’s picture

Status: Active » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.