typedManager = $typed_manager; $this->exclude = $exclude; } /** * Checks that configuration complies with its schema on config save. * * @param \Drupal\Core\Config\ConfigCrudEvent $event * The configuration event. * * @throws \Drupal\Core\Config\Schema\SchemaIncompleteException * Exception thrown when configuration does not match its schema. */ public function onConfigSave(ConfigCrudEvent $event) { // Only validate configuration if in the default collection. Other // collections may have incomplete configuration (for example language // overrides only). These are not valid in themselves. $saved_config = $event->getConfig(); if ($saved_config->getStorage()->getCollectionName() != StorageInterface::DEFAULT_COLLECTION) { return; } $name = $saved_config->getName(); $data = $saved_config->get(); $checksum = Crypt::hashBase64(serialize($data)); if (!in_array($name, $this->exclude) && !isset($this->checked[$name . ':' . $checksum])) { $this->checked[$name . ':' . $checksum] = TRUE; $errors = $this->checkConfigSchema($this->typedManager, $name, $data); if ($errors === FALSE) { throw new SchemaIncompleteException("No schema for $name"); } elseif (is_array($errors)) { $text_errors = []; foreach ($errors as $key => $error) { $text_errors[] = new FormattableMarkup('@key @error', ['@key' => $key, '@error' => $error]); } throw new SchemaIncompleteException("Schema errors for $name with the following errors: " . implode(', ', $text_errors)); } } } /** * {@inheritdoc} */ public static function getSubscribedEvents() { $events[ConfigEvents::SAVE][] = ['onConfigSave', 255]; return $events; } }