5
5
*/
6
6
namespace Magento \Checkout \Block \Checkout ;
7
7
8
+ use Magento \Checkout \Helper \Data ;
9
+ use Magento \Framework \App \ObjectManager ;
10
+
8
11
class LayoutProcessor implements \Magento \Checkout \Block \Checkout \LayoutProcessorInterface
9
12
{
10
13
/**
@@ -22,6 +25,16 @@ class LayoutProcessor implements \Magento\Checkout\Block\Checkout\LayoutProcesso
22
25
*/
23
26
protected $ merger ;
24
27
28
+ /**
29
+ * @var \Magento\Customer\Model\Options
30
+ */
31
+ private $ options ;
32
+
33
+ /**
34
+ * @var Data
35
+ */
36
+ private $ checkoutDataHelper ;
37
+
25
38
/**
26
39
* @param \Magento\Customer\Model\AttributeMetadataDataProvider $attributeMetadataDataProvider
27
40
* @param \Magento\Ui\Component\Form\AttributeMapper $attributeMapper
@@ -38,12 +51,22 @@ public function __construct(
38
51
}
39
52
40
53
/**
41
- * Process js Layout of block
42
- *
43
- * @param array $jsLayout
54
+ * @deprecated
55
+ * @return \Magento\Customer\Model\Options
56
+ */
57
+ private function getOptions ()
58
+ {
59
+ if (!is_object ($ this ->options )) {
60
+ $ this ->options = ObjectManager::getInstance ()->get (\Magento \Customer \Model \Options::class);
61
+ }
62
+ return $ this ->options ;
63
+ }
64
+
65
+ /**
66
+ * Get addresses attributes
44
67
* @return array
45
68
*/
46
- public function process ( $ jsLayout )
69
+ private function getAddressAttributes ( )
47
70
{
48
71
/** @var \Magento\Eav\Api\Data\AttributeInterface[] $attributes */
49
72
$ attributes = $ this ->attributeMetadataDataProvider ->loadAttributesCollection (
@@ -53,37 +76,77 @@ public function process($jsLayout)
53
76
54
77
$ elements = [];
55
78
foreach ($ attributes as $ attribute ) {
79
+ $ code = $ attribute ->getAttributeCode ();
56
80
if ($ attribute ->getIsUserDefined ()) {
57
81
continue ;
58
82
}
59
- $ elements [$ attribute -> getAttributeCode () ] = $ this ->attributeMapper ->map ($ attribute );
60
- if (isset ($ elements [$ attribute -> getAttributeCode () ]['label ' ])) {
61
- $ label = $ elements [$ attribute -> getAttributeCode () ]['label ' ];
62
- $ elements [$ attribute -> getAttributeCode () ]['label ' ] = __ ($ label );
83
+ $ elements [$ code ] = $ this ->attributeMapper ->map ($ attribute );
84
+ if (isset ($ elements [$ code ]['label ' ])) {
85
+ $ label = $ elements [$ code ]['label ' ];
86
+ $ elements [$ code ]['label ' ] = __ ($ label );
63
87
}
64
88
}
65
89
90
+ return $ elements ;
91
+ }
92
+
93
+ /**
94
+ * Convert elements(like prefix and suffix) from inputs to selects when necessary
95
+ *
96
+ * @param array $elements address attributes
97
+ * @param array $attributesToConvert fields and their callbacks
98
+ * @return array
99
+ */
100
+ private function convertElementsToSelect ($ elements , $ attributesToConvert )
101
+ {
102
+ $ codes = array_keys ($ attributesToConvert );
103
+ foreach (array_keys ($ elements ) as $ code ) {
104
+ if (!in_array ($ code , $ codes )) {
105
+ continue ;
106
+ }
107
+ $ options = call_user_func ($ attributesToConvert [$ code ]);
108
+ if (!is_array ($ options )) {
109
+ continue ;
110
+ }
111
+ $ elements [$ code ]['dataType ' ] = 'select ' ;
112
+ $ elements [$ code ]['formElement ' ] = 'select ' ;
113
+
114
+ foreach ($ options as $ key => $ value ) {
115
+ $ elements [$ code ]['options ' ][] = [
116
+ 'value ' => $ key ,
117
+ 'label ' => $ value ,
118
+ ];
119
+ }
120
+ }
121
+
122
+ return $ elements ;
123
+ }
124
+
125
+ /**
126
+ * Process js Layout of block
127
+ *
128
+ * @param array $jsLayout
129
+ * @return array
130
+ */
131
+ public function process ($ jsLayout )
132
+ {
133
+ $ attributesToConvert = [
134
+ 'prefix ' => [$ this ->getOptions (), 'getNamePrefixOptions ' ],
135
+ 'suffix ' => [$ this ->getOptions (), 'getNameSuffixOptions ' ],
136
+ ];
137
+
138
+ $ elements = $ this ->getAddressAttributes ();
139
+ $ elements = $ this ->convertElementsToSelect ($ elements , $ attributesToConvert );
66
140
// The following code is a workaround for custom address attributes
67
141
if (isset ($ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
68
142
['payment ' ]['children ' ]
69
143
)) {
70
- if (!isset ($ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
71
- ['payment ' ]['children ' ]['payments-list ' ]['children ' ])) {
72
- $ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
73
- ['payment ' ]['children ' ]['payments-list ' ]['children ' ] = [];
74
- }
75
-
76
144
$ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
77
- ['payment ' ]['children ' ]['payments-list ' ]['children ' ] =
78
- array_merge_recursive (
79
- $ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
80
- ['payment ' ]['children ' ]['payments-list ' ]['children ' ],
81
- $ this ->processPaymentConfiguration (
82
- $ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
83
- ['payment ' ]['children ' ]['renders ' ]['children ' ],
84
- $ elements
85
- )
86
- );
145
+ ['payment ' ]['children ' ] = $ this ->processPaymentChildrenComponents (
146
+ $ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['billing-step ' ]['children ' ]
147
+ ['payment ' ]['children ' ],
148
+ $ elements
149
+ );
87
150
}
88
151
89
152
if (isset ($ jsLayout ['components ' ]['checkout ' ]['children ' ]['steps ' ]['children ' ]['shipping-step ' ]
@@ -99,9 +162,48 @@ public function process($jsLayout)
99
162
$ fields
100
163
);
101
164
}
165
+
102
166
return $ jsLayout ;
103
167
}
104
168
169
+ /**
170
+ * Appends billing address form component to payment layout
171
+ * @param array $paymentLayout
172
+ * @param array $elements
173
+ * @return array
174
+ */
175
+ private function processPaymentChildrenComponents (array $ paymentLayout , array $ elements )
176
+ {
177
+ if (!isset ($ paymentLayout ['payments-list ' ]['children ' ])) {
178
+ $ paymentLayout ['payments-list ' ]['children ' ] = [];
179
+ }
180
+
181
+ if (!isset ($ paymentLayout ['afterMethods ' ]['children ' ])) {
182
+ $ paymentLayout ['afterMethods ' ]['children ' ] = [];
183
+ }
184
+
185
+ // The if billing address should be displayed on Payment method or page
186
+ if ($ this ->getCheckoutDataHelper ()->isDisplayBillingOnPaymentMethodAvailable ()) {
187
+ $ paymentLayout ['payments-list ' ]['children ' ] =
188
+ array_merge_recursive (
189
+ $ paymentLayout ['payments-list ' ]['children ' ],
190
+ $ this ->processPaymentConfiguration (
191
+ $ paymentLayout ['renders ' ]['children ' ],
192
+ $ elements
193
+ )
194
+ );
195
+ } else {
196
+ $ component ['billing-address-form ' ] = $ this ->getBillingAddressComponent ('shared ' , $ elements );
197
+ $ paymentLayout ['afterMethods ' ]['children ' ] =
198
+ array_merge_recursive (
199
+ $ component ,
200
+ $ paymentLayout ['afterMethods ' ]['children ' ]
201
+ );
202
+ }
203
+
204
+ return $ paymentLayout ;
205
+ }
206
+
105
207
/**
106
208
* Inject billing address component into every payment component
107
209
*
@@ -117,75 +219,102 @@ private function processPaymentConfiguration(array &$configuration, array $eleme
117
219
if (empty ($ paymentComponent ['isBillingAddressRequired ' ])) {
118
220
continue ;
119
221
}
120
- $ output [$ paymentCode . '-form ' ] = [
121
- 'component ' => 'Magento_Checkout/js/view/billing-address ' ,
122
- 'displayArea ' => 'billing-address-form- ' . $ paymentCode ,
123
- 'provider ' => 'checkoutProvider ' ,
124
- 'deps ' => 'checkoutProvider ' ,
125
- 'dataScopePrefix ' => 'billingAddress ' . $ paymentCode ,
126
- 'sortOrder ' => 1 ,
127
- 'children ' => [
128
- 'form-fields ' => [
129
- 'component ' => 'uiComponent ' ,
130
- 'displayArea ' => 'additional-fieldsets ' ,
131
- 'children ' => $ this ->merger ->merge (
132
- $ elements ,
133
- 'checkoutProvider ' ,
134
- 'billingAddress ' . $ paymentCode ,
135
- [
136
- 'country_id ' => [
137
- 'sortOrder ' => 115 ,
138
- ],
139
- 'region ' => [
140
- 'visible ' => false ,
141
- ],
142
- 'region_id ' => [
143
- 'component ' => 'Magento_Ui/js/form/element/region ' ,
144
- 'config ' => [
145
- 'template ' => 'ui/form/field ' ,
146
- 'elementTmpl ' => 'ui/form/element/select ' ,
147
- 'customEntry ' => 'billingAddress ' . $ paymentCode . '.region ' ,
148
- ],
149
- 'validation ' => [
150
- 'validate-select ' => true ,
151
- ],
152
- 'filterBy ' => [
153
- 'target ' => '${ $.provider }:${ $.parentScope }.country_id ' ,
154
- 'field ' => 'country_id ' ,
155
- ],
156
- ],
157
- 'postcode ' => [
158
- 'component ' => 'Magento_Ui/js/form/element/post-code ' ,
159
- 'validation ' => [
160
- 'required-entry ' => true ,
161
- ],
162
- ],
163
- 'company ' => [
164
- 'validation ' => [
165
- 'min_text_length ' => 0 ,
166
- ],
167
- ],
168
- 'fax ' => [
169
- 'validation ' => [
170
- 'min_text_length ' => 0 ,
171
- ],
172
- ],
173
- 'telephone ' => [
174
- 'config ' => [
175
- 'tooltip ' => [
176
- 'description ' => 'For delivery questions. ' ,
177
- ],
178
- ],
179
- ],
180
- ]
181
- ),
182
- ],
183
- ],
184
- ];
222
+ $ output [$ paymentCode . '-form ' ] = $ this ->getBillingAddressComponent ($ paymentCode , $ elements );
185
223
}
186
224
unset($ configuration [$ paymentGroup ]['methods ' ]);
187
225
}
188
226
189
227
return $ output ;
190
228
}
229
+
230
+ /**
231
+ * Gets billing address component details
232
+ *
233
+ * @param string $paymentCode
234
+ * @param array $elements
235
+ * @return array
236
+ */
237
+ private function getBillingAddressComponent ($ paymentCode , $ elements )
238
+ {
239
+ return [
240
+ 'component ' => 'Magento_Checkout/js/view/billing-address ' ,
241
+ 'displayArea ' => 'billing-address-form- ' . $ paymentCode ,
242
+ 'provider ' => 'checkoutProvider ' ,
243
+ 'deps ' => 'checkoutProvider ' ,
244
+ 'dataScopePrefix ' => 'billingAddress ' . $ paymentCode ,
245
+ 'sortOrder ' => 1 ,
246
+ 'children ' => [
247
+ 'form-fields ' => [
248
+ 'component ' => 'uiComponent ' ,
249
+ 'displayArea ' => 'additional-fieldsets ' ,
250
+ 'children ' => $ this ->merger ->merge (
251
+ $ elements ,
252
+ 'checkoutProvider ' ,
253
+ 'billingAddress ' . $ paymentCode ,
254
+ [
255
+ 'country_id ' => [
256
+ 'sortOrder ' => 115 ,
257
+ ],
258
+ 'region ' => [
259
+ 'visible ' => false ,
260
+ ],
261
+ 'region_id ' => [
262
+ 'component ' => 'Magento_Ui/js/form/element/region ' ,
263
+ 'config ' => [
264
+ 'template ' => 'ui/form/field ' ,
265
+ 'elementTmpl ' => 'ui/form/element/select ' ,
266
+ 'customEntry ' => 'billingAddress ' . $ paymentCode . '.region ' ,
267
+ ],
268
+ 'validation ' => [
269
+ 'required-entry ' => true ,
270
+ ],
271
+ 'filterBy ' => [
272
+ 'target ' => '${ $.provider }:${ $.parentScope }.country_id ' ,
273
+ 'field ' => 'country_id ' ,
274
+ ],
275
+ ],
276
+ 'postcode ' => [
277
+ 'component ' => 'Magento_Ui/js/form/element/post-code ' ,
278
+ 'validation ' => [
279
+ 'required-entry ' => true ,
280
+ ],
281
+ ],
282
+ 'company ' => [
283
+ 'validation ' => [
284
+ 'min_text_length ' => 0 ,
285
+ ],
286
+ ],
287
+ 'fax ' => [
288
+ 'validation ' => [
289
+ 'min_text_length ' => 0 ,
290
+ ],
291
+ ],
292
+ 'telephone ' => [
293
+ 'config ' => [
294
+ 'tooltip ' => [
295
+ 'description ' => __ ('For delivery questions. ' ),
296
+ ],
297
+ ],
298
+ ],
299
+ ]
300
+ ),
301
+ ],
302
+ ],
303
+ ];
304
+ }
305
+
306
+ /**
307
+ * Get checkout data helper instance
308
+ *
309
+ * @return Data
310
+ * @deprecated
311
+ */
312
+ private function getCheckoutDataHelper ()
313
+ {
314
+ if (!$ this ->checkoutDataHelper ) {
315
+ $ this ->checkoutDataHelper = ObjectManager::getInstance ()->get (Data::class);
316
+ }
317
+
318
+ return $ this ->checkoutDataHelper ;
319
+ }
191
320
}
0 commit comments