7
7
8
8
namespace Drupal \rules \Engine ;
9
9
10
+ use Drupal \Core \Plugin \Context \ContextDefinitionInterface ;
10
11
use Drupal \Core \Plugin \ContextAwarePluginInterface as CoreContextAwarePluginInterface ;
11
- use Drupal \rules \Context \ContextDefinitionInterface ;
12
+ use Drupal \Core \TypedData \ComplexDataInterface ;
13
+ use Drupal \Core \TypedData \DataDefinitionInterface ;
14
+ use Drupal \Core \TypedData \ListInterface ;
15
+ use Drupal \Core \TypedData \PrimitiveInterface ;
16
+ use Drupal \rules \Context \ContextDefinitionInterface as RulesContextDefinitionInterface ;
12
17
use Drupal \rules \Context \ContextProviderInterface ;
13
18
use Drupal \rules \Exception \RulesIntegrityException ;
14
19
@@ -33,52 +38,62 @@ protected function doCheckIntegrity(CoreContextAwarePluginInterface $plugin, Exe
33
38
$ violation_list = new IntegrityViolationList ();
34
39
$ context_definitions = $ plugin ->getContextDefinitions ();
35
40
36
- foreach ($ context_definitions as $ name => $ definition ) {
41
+ foreach ($ context_definitions as $ name => $ context_definition ) {
37
42
// Check if a data selector is configured that maps to the state.
38
43
if (isset ($ this ->configuration ['context_mapping ' ][$ name ])) {
39
44
try {
40
45
$ data_definition = $ metadata_state ->fetchDefinitionByPropertyPath ($ this ->configuration ['context_mapping ' ][$ name ]);
46
+
47
+ $ this ->checkDataTypeCompatible ($ context_definition , $ data_definition , $ name , $ violation_list );
41
48
}
42
49
catch (RulesIntegrityException $ e ) {
43
50
$ violation = new IntegrityViolation ();
44
51
$ violation ->setMessage ($ this ->t ('Data selector %selector for context %context_name is invalid. @message ' , [
45
52
'%selector ' => $ this ->configuration ['context_mapping ' ][$ name ],
46
- '%context_name ' => $ definition ->getLabel (),
53
+ '%context_name ' => $ context_definition ->getLabel (),
47
54
'@message ' => $ e ->getMessage (),
48
55
]));
49
56
$ violation ->setContextName ($ name );
50
57
$ violation_list ->add ($ violation );
51
58
}
52
59
53
- if ($ definition instanceof ContextDefinitionInterface
54
- && $ definition ->getAssignmentRestriction () === ContextDefinitionInterface ::ASSIGNMENT_RESTRICTION_INPUT
60
+ if ($ context_definition instanceof RulesContextDefinitionInterface
61
+ && $ context_definition ->getAssignmentRestriction () === RulesContextDefinitionInterface ::ASSIGNMENT_RESTRICTION_INPUT
55
62
) {
56
63
$ violation = new IntegrityViolation ();
57
64
$ violation ->setMessage ($ this ->t ('The context %context_name may not be configured using a selector. ' , [
58
- '%context_name ' => $ definition ->getLabel (),
65
+ '%context_name ' => $ context_definition ->getLabel (),
59
66
]));
60
67
$ violation ->setContextName ($ name );
61
68
$ violation_list ->add ($ violation );
62
69
}
63
70
}
64
71
elseif (isset ($ this ->configuration ['context_values ' ][$ name ])) {
65
- if ($ definition instanceof ContextDefinitionInterface
66
- && $ definition ->getAssignmentRestriction () === ContextDefinitionInterface ::ASSIGNMENT_RESTRICTION_SELECTOR
72
+ if ($ context_definition instanceof RulesContextDefinitionInterface
73
+ && $ context_definition ->getAssignmentRestriction () === RulesContextDefinitionInterface ::ASSIGNMENT_RESTRICTION_SELECTOR
67
74
) {
68
75
$ violation = new IntegrityViolation ();
69
76
$ violation ->setMessage ($ this ->t ('The context %context_name may only be configured using a selector. ' , [
70
- '%context_name ' => $ definition ->getLabel (),
77
+ '%context_name ' => $ context_definition ->getLabel (),
71
78
]));
72
79
$ violation ->setContextName ($ name );
73
80
$ violation_list ->add ($ violation );
74
81
}
75
82
}
83
+ elseif ($ context_definition ->isRequired ()) {
84
+ $ violation = new IntegrityViolation ();
85
+ $ violation ->setMessage ($ this ->t ('The required context %context_name is missing. ' , [
86
+ '%context_name ' => $ context_definition ->getLabel (),
87
+ ]));
88
+ $ violation ->setContextName ($ name );
89
+ $ violation_list ->add ($ violation );
90
+ }
76
91
}
77
92
78
93
if ($ plugin instanceof ContextProviderInterface) {
79
94
$ provided_context_definitions = $ plugin ->getProvidedContextDefinitions ();
80
95
81
- foreach ($ provided_context_definitions as $ name => $ definition ) {
96
+ foreach ($ provided_context_definitions as $ name => $ context_definition ) {
82
97
if (isset ($ this ->configuration ['provides_mapping ' ][$ name ])) {
83
98
if (!preg_match ('/^[0-9a-zA-Z_]*$/ ' , $ this ->configuration ['provides_mapping ' ][$ name ])) {
84
99
$ violation = new IntegrityViolation ();
@@ -92,15 +107,63 @@ protected function doCheckIntegrity(CoreContextAwarePluginInterface $plugin, Exe
92
107
// Populate the state with the new variable that is provided by this
93
108
// plugin. That is necessary so that the integrity check in subsequent
94
109
// actions knows about the variable and does not throw violations.
95
- $ metadata_state ->setDataDefinition ($ this ->configuration ['provides_mapping ' ][$ name ], $ definition ->getDataDefinition ());
110
+ $ metadata_state ->setDataDefinition (
111
+ $ this ->configuration ['provides_mapping ' ][$ name ],
112
+ $ context_definition ->getDataDefinition ()
113
+ );
96
114
}
97
115
else {
98
- $ metadata_state ->setDataDefinition ($ name , $ definition ->getDataDefinition ());
116
+ $ metadata_state ->setDataDefinition ($ name , $ context_definition ->getDataDefinition ());
99
117
}
100
118
}
101
119
}
102
120
103
121
return $ violation_list ;
104
122
}
105
123
124
+ /**
125
+ * Checks that the data type of a mapped variable matches the expectation.
126
+ *
127
+ * @param \Drupal\Core\Plugin\Context\ContextDefinitionInterface $context_definition
128
+ * The context definition of the context on the plugin.
129
+ * @param \Drupal\Core\TypedData\DataDefinitionInterface $provided
130
+ * The data definition of the mapped variable to the context.
131
+ * @param string $context_name
132
+ * The name of the context on the plugin.
133
+ * @param \Drupal\rules\Engine\IntegrityViolationList $violation_list
134
+ * The list of violations where new ones will be added.
135
+ */
136
+ protected function checkDataTypeCompatible (ContextDefinitionInterface $ context_definition , DataDefinitionInterface $ provided , $ context_name , IntegrityViolationList $ violation_list ) {
137
+ $ expected_class = $ context_definition ->getDataDefinition ()->getClass ();
138
+ $ provided_class = $ provided ->getClass ();
139
+ $ expected_type_problem = NULL ;
140
+
141
+ if (is_subclass_of ($ expected_class , PrimitiveInterface::class)
142
+ && !is_subclass_of ($ provided_class , PrimitiveInterface::class)
143
+ ) {
144
+ $ expected_type_problem = $ this ->t ('primitive ' );
145
+ }
146
+ elseif (is_subclass_of ($ expected_class , ListInterface::class)
147
+ && !is_subclass_of ($ provided_class , ListInterface::class)
148
+ ) {
149
+ $ expected_type_problem = $ this ->t ('list ' );
150
+ }
151
+ elseif (is_subclass_of ($ expected_class , ComplexDataInterface::class)
152
+ && !is_subclass_of ($ provided_class , ComplexDataInterface::class)
153
+ ) {
154
+ $ expected_type_problem = $ this ->t ('complex ' );
155
+ }
156
+
157
+ if ($ expected_type_problem ) {
158
+ $ violation = new IntegrityViolation ();
159
+ $ violation ->setMessage ($ this ->t ('Expected a @expected_type data type for context %context_name but got a @provided_type data type instead. ' , [
160
+ '@expected_type ' => $ expected_type_problem ,
161
+ '%context_name ' => $ context_definition ->getLabel (),
162
+ '@provided_type ' => $ provided ->getDataType (),
163
+ ]));
164
+ $ violation ->setContextName ($ context_name );
165
+ $ violation_list ->add ($ violation );
166
+ }
167
+ }
168
+
106
169
}
0 commit comments