ba69001f4d7e2ab9c5f68eb72a8e70585f3b72e6
[yaffs-website] / web / core / lib / Drupal / Core / Config / Development / ConfigSchemaChecker.php
1 <?php
2
3 namespace Drupal\Core\Config\Development;
4
5 use Drupal\Component\Utility\Crypt;
6 use Drupal\Component\Utility\SafeMarkup;
7 use Drupal\Core\Config\ConfigCrudEvent;
8 use Drupal\Core\Config\ConfigEvents;
9 use Drupal\Core\Config\Schema\SchemaCheckTrait;
10 use Drupal\Core\Config\Schema\SchemaIncompleteException;
11 use Drupal\Core\Config\StorageInterface;
12 use Drupal\Core\Config\TypedConfigManagerInterface;
13 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
14
15 /**
16  * Listens to the config save event and validates schema.
17  *
18  * If tests have the $strictConfigSchema property set to TRUE this event
19  * listener will be added to the container and throw exceptions if configuration
20  * is invalid.
21  *
22  * @see \Drupal\KernelTests\KernelTestBase::register()
23  * @see \Drupal\simpletest\WebTestBase::setUp()
24  * @see \Drupal\simpletest\KernelTestBase::containerBuild()
25  */
26 class ConfigSchemaChecker implements EventSubscriberInterface {
27   use SchemaCheckTrait;
28
29   /**
30    * The typed config manger.
31    *
32    * @var \Drupal\Core\Config\TypedConfigManagerInterface
33    */
34   protected $typedManager;
35
36   /**
37    * An array of config checked already. Keyed by config name and a checksum.
38    *
39    * @var array
40    */
41   protected $checked = [];
42
43   /**
44    * An array of config object names that are excluded from schema checking.
45    *
46    * @var string[]
47    */
48   protected $exclude = [];
49
50   /**
51    * Constructs the ConfigSchemaChecker object.
52    *
53    * @param \Drupal\Core\Config\TypedConfigManagerInterface $typed_manager
54    *   The typed config manager.
55    * @param string[] $exclude
56    *   An array of config object names that are excluded from schema checking.
57    */
58   public function __construct(TypedConfigManagerInterface $typed_manager, array $exclude = []) {
59     $this->typedManager = $typed_manager;
60     $this->exclude = $exclude;
61   }
62
63   /**
64    * Checks that configuration complies with its schema on config save.
65    *
66    * @param \Drupal\Core\Config\ConfigCrudEvent $event
67    *   The configuration event.
68    *
69    * @throws \Drupal\Core\Config\Schema\SchemaIncompleteException
70    *   Exception thrown when configuration does not match its schema.
71    */
72   public function onConfigSave(ConfigCrudEvent $event) {
73     // Only validate configuration if in the default collection. Other
74     // collections may have incomplete configuration (for example language
75     // overrides only). These are not valid in themselves.
76     $saved_config = $event->getConfig();
77     if ($saved_config->getStorage()->getCollectionName() != StorageInterface::DEFAULT_COLLECTION) {
78       return;
79     }
80
81     $name = $saved_config->getName();
82     $data = $saved_config->get();
83     $checksum = Crypt::hashBase64(serialize($data));
84     if (!in_array($name, $this->exclude) && !isset($this->checked[$name . ':' . $checksum])) {
85       $this->checked[$name . ':' . $checksum] = TRUE;
86       $errors = $this->checkConfigSchema($this->typedManager, $name, $data);
87       if ($errors === FALSE) {
88         throw new SchemaIncompleteException("No schema for $name");
89       }
90       elseif (is_array($errors)) {
91         $text_errors = [];
92         foreach ($errors as $key => $error) {
93           $text_errors[] = SafeMarkup::format('@key @error', ['@key' => $key, '@error' => $error]);
94         }
95         throw new SchemaIncompleteException("Schema errors for $name with the following errors: " . implode(', ', $text_errors));
96       }
97     }
98   }
99
100   /**
101    * {@inheritdoc}
102    */
103   public static function getSubscribedEvents() {
104     $events[ConfigEvents::SAVE][] = ['onConfigSave', 255];
105     return $events;
106   }
107
108 }