Standard::setAddress()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 57
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 23
nc 6
nop 1
dl 0
loc 57
rs 8.4444
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2015-2025
6
 * @package Client
7
 * @subpackage Html
8
 */
9
10
11
namespace Aimeos\Client\Html\Checkout\Standard\Address\Delivery;
12
13
14
/**
15
 * Default implementation of checkout billing address HTML client.
16
 *
17
 * @package Client
18
 * @subpackage Html
19
 */
20
class Standard
21
	extends \Aimeos\Client\Html\Common\Client\Factory\Base
22
	implements \Aimeos\Client\Html\Common\Client\Factory\Iface
23
{
24
	/**
25
	 * Stores the given or fetched billing address in the basket.
26
	 *
27
	 * A view must be available and this method doesn't generate any output
28
	 * besides setting view variables if necessary.
29
	 */
30
	public function init()
31
	{
32
		$context = $this->context();
33
		$view = $this->view();
34
35
		try
36
		{
37
			if( ( $id = $view->param( 'ca_delivery_delete', null ) ) !== null )
38
			{
39
				$cntl = \Aimeos\Controller\Frontend::create( $context, 'customer' );
40
41
				if( ( $item = $cntl->uses( ['customer/address'] )->get()->getAddressItem( $id ) ) !== null )
42
				{
43
					$cntl->deleteAddressItem( $item )->store();
44
					throw new \Aimeos\Client\Html\Exception( sprintf( 'Delivery address deleted successfully' ) );
45
				}
46
			}
47
48
			// only start if there's something to do
49
			if( $view->param( 'ca_deliveryoption' ) === null ) {
50
				return;
51
			}
52
53
			$this->setAddress( $view );
54
55
			parent::init();
56
		}
57
		catch( \Aimeos\Controller\Frontend\Exception $e )
58
		{
59
			$view->addressDeliveryError = $e->getErrorList();
60
			throw $e;
61
		}
62
	}
63
64
65
	/**
66
	 * Checks the address fields for missing data and sanitizes the given parameter list.
67
	 *
68
	 * @param array $params Associative list of address keys (order.address.* or customer.address.*) and their values
69
	 * @return array List of missing field names
70
	 */
71
	protected function checkFields( array $params ) : array
72
	{
73
		$view = $this->view();
74
75
		/** client/html/common/address/delivery/mandatory
76
		 * List of delivery address input fields that are required
77
		 *
78
		 * You can configure the list of delivery address fields that are
79
		 * necessary and must be filled by the customer before he can
80
		 * continue the checkout process. Available field keys are:
81
		 *
82
		 * * company
83
		 * * vatid
84
		 * * salutation
85
		 * * firstname
86
		 * * lastname
87
		 * * address1
88
		 * * address2
89
		 * * address3
90
		 * * postal
91
		 * * city
92
		 * * state
93
		 * * languageid
94
		 * * countryid
95
		 * * telephone
96
		 * * telefax
97
		 * * email
98
		 * * website
99
		 *
100
		 * @param array List of field keys
101
		 * @since 2015.02
102
		 * @see client/html/checkout/standard/address/delivery/disable-new
103
		 * @see client/html/common/address/delivery/optional
104
		 * @see client/html/common/address/delivery/hidden
105
		 * @see client/html/common/address/salutations
106
		 * @see client/html/common/address/validate
107
		 * @see common/countries
108
		 * @see common/states
109
		 */
110
		$mandatory = $view->config( 'client/html/common/address/delivery/mandatory', [] );
111
112
		/** client/html/common/address/delivery/optional
113
		 * List of delivery address input fields that are optional
114
		 *
115
		 * You can configure the list of delivery address fields that
116
		 * customers can fill but don't have to before they can
117
		 * continue the checkout process. Available field keys are:
118
		 *
119
		 * * company
120
		 * * vatid
121
		 * * salutation
122
		 * * firstname
123
		 * * lastname
124
		 * * address1
125
		 * * address2
126
		 * * address3
127
		 * * postal
128
		 * * city
129
		 * * state
130
		 * * languageid
131
		 * * countryid
132
		 * * telephone
133
		 * * telefax
134
		 * * email
135
		 * * website
136
		 * * nostore
137
		 *
138
		 * Using the "nostore" field displays the option to avoid storing the
139
		 * delivery address permanently in the customer account.
140
		 *
141
		 * @param array List of field keys
142
		 * @since 2015.02
143
		 * @see client/html/checkout/standard/address/delivery/disable-new
144
		 * @see client/html/common/address/delivery/mandatory
145
		 * @see client/html/common/address/delivery/hidden
146
		 * @see client/html/common/address/salutations
147
		 * @see client/html/common/address/validate
148
		 * @see common/countries
149
		 * @see common/states
150
		 */
151
		$optional = $view->config( 'client/html/common/address/delivery/optional', [] );
152
153
		/** client/html/common/address/delivery/hidden
154
		 * List of delivery address input fields that are optional
155
		 *
156
		 * You can configure the list of delivery address fields that
157
		 * are hidden when a customer enters his delivery address.
158
		 * Available field keys are:
159
		 *
160
		 * * company
161
		 * * vatid
162
		 * * salutation
163
		 * * firstname
164
		 * * lastname
165
		 * * address1
166
		 * * address2
167
		 * * address3
168
		 * * postal
169
		 * * city
170
		 * * state
171
		 * * languageid
172
		 * * countryid
173
		 * * telephone
174
		 * * telefax
175
		 * * email
176
		 * * website
177
		 *
178
		 * Caution: Only hide fields that don't require any input
179
		 *
180
		 * @param array List of field keys
181
		 * @since 2015.02
182
		 * @see client/html/checkout/standard/address/delivery/disable-new
183
		 * @see client/html/common/address/delivery/mandatory
184
		 * @see client/html/common/address/delivery/optional
185
		 * @see client/html/common/address/salutations
186
		 * @see common/countries
187
		 * @see common/states
188
		 */
189
		$hidden = $view->config( 'client/html/common/address/delivery/hidden', [] );
190
191
		/** client/html/common/address/validate
192
		 *
193
		 * @see client/html/common/address/delivery/mandatory
194
		 * @see client/html/common/address/delivery/optional
195
		 */
196
197
		$allFields = array_flip( array_merge( $mandatory, $optional, $hidden ) );
198
		$invalid = $this->validateFields( $params, $allFields );
199
		$this->checkSalutation( $params, $mandatory );
200
201
		$msg = $view->translate( 'client', 'Delivery address part "%1$s" is invalid' );
202
203
		foreach( $invalid as $key => $name ) {
204
			$invalid[$key] = sprintf( $msg, $name );
205
		}
206
207
		$msg = $view->translate( 'client', 'Delivery address part "%1$s" is missing' );
208
209
		foreach( $mandatory as $key )
210
		{
211
			if( !isset( $params['order.address.' . $key] ) || $params['order.address.' . $key] == '' ) {
212
				$invalid[$key] = sprintf( $msg, $key );
213
			}
214
		}
215
216
		return $invalid;
217
	}
218
219
220
	/**
221
	 * Additional checks for the salutation
222
	 *
223
	 * @param array $params Associative list of address keys (order.address.*) and their values
224
	 * @param array &$mandatory List of mandatory field names
225
	 * @since 2016.05
226
	 */
227
	protected function checkSalutation( array $params, array &$mandatory )
228
	{
229
		if( isset( $params['order.address.salutation'] )
230
				&& $params['order.address.salutation'] === 'company'
231
				&& in_array( 'company', $mandatory ) === false
232
		) {
233
			$mandatory[] = 'company';
234
		}
235
	}
236
237
238
	/**
239
	 * Returns the address as string
240
	 *
241
	 * @param \Aimeos\Base\View\Iface $view The view object which generates the HTML output
242
	 * @param \Aimeos\MShop\Order\Item\Address\Iface $addr Order address item
243
	 * @return string Address as string
244
	 */
245
	protected function getAddressString( \Aimeos\Base\View\Iface $view, \Aimeos\MShop\Order\Item\Address\Iface $addr )
246
	{
247
		return preg_replace( "/\n+/m", "\n", trim( sprintf(
248
			/// Address format with company (%1$s), salutation (%2$s), title (%3$s), first name (%4$s), last name (%5$s),
249
			/// address part one (%6$s, e.g street), address part two (%7$s, e.g house number), address part three (%8$s, e.g additional information),
250
			/// postal/zip code (%9$s), city (%10$s), state (%11$s), country (%12$s), language (%13$s),
251
			/// e-mail (%14$s), phone (%15$s), facsimile/telefax (%16$s), web site (%17$s), vatid (%18$s)
252
			$view->translate( 'client', '%1$s
253
%2$s %3$s %4$s %5$s
254
%6$s %7$s
255
%8$s
256
%9$s %10$s
257
%11$s
258
%12$s
259
%13$s
260
%14$s
261
%15$s
262
%16$s
263
%17$s
264
%18$s
265
'
266
			),
267
			$addr->getCompany(),
268
			$view->translate( 'mshop/code', (string) $addr->getSalutation() ),
269
			$addr->getTitle(),
270
			$addr->getFirstName(),
271
			$addr->getLastName(),
272
			$addr->getAddress1(),
273
			$addr->getAddress2(),
274
			$addr->getAddress3(),
275
			$addr->getPostal(),
276
			$addr->getCity(),
277
			$addr->getState(),
278
			$view->translate( 'country', (string) $addr->getCountryId() ),
279
			$view->translate( 'language', (string) $addr->getLanguageId() ),
280
			$addr->getEmail(),
281
			$addr->getTelephone(),
282
			$addr->getTelefax(),
283
			$addr->getWebsite(),
284
			$addr->getVatID()
285
		) ) );
286
	}
287
288
289
	/**
290
	 * Sets the new address
291
	 *
292
	 * @param \Aimeos\Base\View\Iface $view View object
293
	 * @throws \Aimeos\Client\Html\Exception If an error occurs
294
	 * @since 2016.05
295
	 */
296
	protected function setAddress( \Aimeos\Base\View\Iface $view )
297
	{
298
		$address = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $address is dead and can be removed.
Loading history...
299
		$context = $this->context();
300
		$ctrl = \Aimeos\Controller\Frontend::create( $context, 'basket' );
301
302
		/** client/html/checkout/standard/address/delivery/disable-new
303
		 * Disables the option to enter a different delivery address for an order
304
		 *
305
		 * Besides the billing address, customers can usually enter a different
306
		 * delivery address as well. To suppress displaying the form fields for
307
		 * a delivery address, you can set this configuration option to "1".
308
		 *
309
		 * @param boolean A value of "1" to disable, "0" enables the delivery address form
310
		 * @since 2015.02
311
		 * @see client/html/common/address/salutations
312
		 * @see client/html/common/address/delivery/mandatory
313
		 * @see client/html/common/address/delivery/optional
314
		 * @see client/html/common/address/delivery/hidden
315
		 */
316
		$disable = $view->config( 'client/html/checkout/standard/address/delivery/disable-new', false );
317
		$type = \Aimeos\MShop\Order\Item\Address\Base::TYPE_DELIVERY;
318
319
		if( ( $option = $view->param( 'ca_deliveryoption', 'null' ) ) === 'null' && $disable === false ) // new address
0 ignored issues
show
Unused Code introduced by
The assignment to $option is dead and can be removed.
Loading history...
320
		{
321
			$params = $view->param( 'ca_delivery', [] );
322
323
			if( ( $view->addressDeliveryError = $this->checkFields( $params ) ) !== [] ) {
324
				throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one delivery address part is missing or invalid' ) );
325
			}
326
327
			$ctrl->addAddress( $type, $params, 0 );
328
		}
329
		else if( ( $option = $view->param( 'ca_deliveryoption' ) ) !== 'like' ) // existing address
330
		{
331
			$params = $view->param( 'ca_delivery_' . $option, [] );
332
333
			if( !empty( $params ) && ( $view->addressDeliveryError = $this->checkFields( $params ) ) !== [] ) {
334
				throw new \Aimeos\Client\Html\Exception( sprintf( 'At least one delivery address part is missing or invalid' ) );
335
			}
336
337
			$custCntl = \Aimeos\Controller\Frontend::create( $context, 'customer' );
338
339
			if( ( $address = $custCntl->uses( ['customer/address'] )->get()->getAddressItem( $option ) ) !== null )
340
			{
341
				$params = array_replace( $address->toArray(), $params + ['order.address.addressid' => $option] );
342
				$addr = $ctrl->addAddress( $type, $params, 0 )->get()->getAddress( $type, 0 ); // sanitize address first
343
				$custCntl->addAddressItem( $address->copyFrom( $addr ), $option )->store(); // update existing address
344
			}
345
			else
346
			{
347
				$ctrl->addAddress( $type, $params, 0 );
348
			}
349
		}
350
		else
351
		{
352
			$ctrl->deleteAddress( $type );
353
		}
354
	}
355
356
357
	/**
358
	 * Sets the necessary parameter values in the view.
359
	 *
360
	 * @param \Aimeos\Base\View\Iface $view The view object which generates the HTML output
361
	 * @param array &$tags Result array for the list of tags that are associated to the output
362
	 * @param string|null &$expire Result variable for the expiration date of the output (null for no expiry)
363
	 * @return \Aimeos\Base\View\Iface Modified view object
364
	 */
365
	public function data( \Aimeos\Base\View\Iface $view, array &$tags = [], ?string &$expire = null ) : \Aimeos\Base\View\Iface
366
	{
367
		$context = $this->context();
368
		$manager = \Aimeos\MShop::create( $context, 'order' );
369
		$basketCntl = \Aimeos\Controller\Frontend::create( $context, 'basket' );
370
371
		$addrStrings = $addrValues = [];
372
		$addrMap = map( $basketCntl->get()->getAddress( 'delivery' ) );
373
374
		foreach( $view->get( 'addressDeliveryItems', [] ) as $id => $address )
375
		{
376
			$params = $view->param( 'ca_delivery_' . $id, [] );
377
			$basketValues = $addrMap->get( $id, map() )->toArray();
378
			$addr = $manager->createAddress()->copyFrom( $address )->fromArray( $basketValues )->fromArray( $params );
0 ignored issues
show
Bug introduced by
The method createAddress() does not exist on Aimeos\MShop\Common\Manager\Iface. Did you maybe mean create()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

378
			$addr = $manager->/** @scrutinizer ignore-call */ createAddress()->copyFrom( $address )->fromArray( $basketValues )->fromArray( $params );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
379
380
			$addrStrings[$id] = $this->getAddressString( $view, $addr );
381
			$addrValues[$id] = $addr->toArray();
382
		}
383
384
		$values = !$addrMap->isEmpty() ? $addrMap->first()->toArray() : [];
385
		$values = array_merge( $values, $view->param( 'ca_delivery', [] ) );
386
		$addrNew = $manager->createAddress()->fromArray( $values );
387
388
		$addrStringNew = $this->getAddressString( $view, $addrNew );
389
		$option = $addrNew->getAddressId() ?: ( $addrMap->isEmpty() ? 'like' : 'null' );
390
391
		$view->addressDeliveryOption = $view->param( 'ca_deliveryoption', $option );
392
		$view->addressDeliveryValuesNew = $addrNew->toArray();
393
		$view->addressDeliveryStringNew = $addrStringNew;
394
		$view->addressDeliveryStrings = $addrStrings;
395
		$view->addressDeliveryValues = $addrValues;
396
		$view->addressDeliveryCss = $this->cssDelivery();
397
398
		return parent::data( $view, $tags, $expire );
399
	}
400
401
402
	/**
403
	 * Returns the CSS classes for the delivery address fields
404
	 *
405
	 * @return array Associative list of CSS classes for the delivery address fields
406
	 */
407
	protected function cssDelivery() : array
408
	{
409
		$config = $this->context()->config();
410
411
		$mandatory = $config->get( 'client/html/common/address/delivery/mandatory', [] );
412
		$optional = $config->get( 'client/html/common/address/delivery/optional', [] );
413
		$hidden = $config->get( 'client/html/common/address/delivery/hidden', [] );
414
415
		$css = [];
416
417
		foreach( $mandatory as $name ) {
418
			$css[$name][] = 'mandatory';
419
		}
420
421
		foreach( $optional as $name ) {
422
			$css[$name][] = 'optional';
423
		}
424
425
		foreach( $hidden as $name ) {
426
			$css[$name][] = 'hidden';
427
		}
428
429
		return $css;
430
	}
431
432
433
	/**
434
	 * Validate the address key/value pairs using regular expressions
435
	 *
436
	 * @param array &$params Associative list of address keys (order.address.*) and their values
437
	 * @param array $fields List of field names to validate
438
	 * @return array List of invalid address keys
439
	 * @since 2016.05
440
	 */
441
	protected function validateFields( array $params, array $fields ) : array
442
	{
443
		$config = $this->context()->config();
444
445
		/** client/html/common/address/validate/company
446
		 * Regular expression to check the "company" address value
447
		 *
448
		 * @see client/html/common/address/validate
449
		 */
450
451
		/** client/html/common/address/validate/vatid
452
		 * Regular expression to check the "vatid" address value
453
		 *
454
		 * @see client/html/common/address/validate
455
		 */
456
457
		/** client/html/common/address/validate/salutation
458
		 * Regular expression to check the "salutation" address value
459
		 *
460
		 * @see client/html/common/address/validate
461
		 */
462
463
		/** client/html/common/address/validate/firstname
464
		 * Regular expression to check the "firstname" address value
465
		 *
466
		 * @see client/html/common/address/validate
467
		 */
468
469
		/** client/html/common/address/validate/lastname
470
		 * Regular expression to check the "lastname" address value
471
		 *
472
		 * @see client/html/common/address/validate
473
		 */
474
475
		/** client/html/common/address/validate/address1
476
		 * Regular expression to check the "address1" address value
477
		 *
478
		 * @see client/html/common/address/validate
479
		 */
480
481
		/** client/html/common/address/validate/address2
482
		 * Regular expression to check the "address2" address value
483
		 *
484
		 * @see client/html/common/address/validate
485
		 */
486
487
		/** client/html/common/address/validate/address3
488
		 * Regular expression to check the "address3" address value
489
		 *
490
		 * @see client/html/common/address/validate
491
		 */
492
493
		/** client/html/common/address/validate/postal
494
		 * Regular expression to check the "postal" address value
495
		 *
496
		 * @see client/html/common/address/validate
497
		 */
498
499
		/** client/html/common/address/validate/city
500
		 * Regular expression to check the "city" address value
501
		 *
502
		 * @see client/html/common/address/validate
503
		 */
504
505
		/** client/html/common/address/validate/state
506
		 * Regular expression to check the "state" address value
507
		 *
508
		 * @see client/html/common/address/validate
509
		 */
510
511
		/** client/html/common/address/validate/languageid
512
		 * Regular expression to check the "languageid" address value
513
		 *
514
		 * @see client/html/common/address/validate
515
		 */
516
517
		/** client/html/common/address/validate/countryid
518
		 * Regular expression to check the "countryid" address value
519
		 *
520
		 * @see client/html/common/address/validate
521
		 */
522
523
		/** client/html/common/address/validate/telephone
524
		 * Regular expression to check the "telephone" address value
525
		 *
526
		 * @see client/html/common/address/validate
527
		 */
528
529
		/** client/html/common/address/validate/telefax
530
		 * Regular expression to check the "telefax" address value
531
		 *
532
		 * @see client/html/common/address/validate
533
		 */
534
535
		/** client/html/common/address/validate/email
536
		 * Regular expression to check the "email" address value
537
		 *
538
		 * @see client/html/common/address/validate
539
		 */
540
541
		/** client/html/common/address/validate/website
542
		 * Regular expression to check the "website" address value
543
		 *
544
		 * @see client/html/common/address/validate
545
		 */
546
547
		$invalid = [];
548
549
		foreach( $params as $key => $value )
550
		{
551
			$name = ( $pos = strrpos( $key, '.' ) ) ? substr( $key, $pos + 1 ) : $key;
552
553
			if( isset( $fields[$name] ) )
554
			{
555
				$regex = $config->get( 'client/html/common/address/validate/' . $name );
556
557
				if( $regex && preg_match( '/' . $regex . '/', $value ) !== 1 ) {
558
					$invalid[$name] = $name;
559
				}
560
			}
561
		}
562
563
		return $invalid;
564
	}
565
566
567
	/** client/html/checkout/standard/address/delivery/template-body
568
	 * Relative path to the HTML body template of the checkout standard address delivery client.
569
	 *
570
	 * The template file contains the HTML code and processing instructions
571
	 * to generate the result shown in the body of the frontend. The
572
	 * configuration string is the path to the template file relative
573
	 * to the templates directory (usually in templates/client/html).
574
	 *
575
	 * You can overwrite the template file configuration in extensions and
576
	 * provide alternative templates. These alternative templates should be
577
	 * named like the default one but suffixed by
578
	 * an unique name. You may use the name of your project for this. If
579
	 * you've implemented an alternative client class as well, it
580
	 * should be suffixed by the name of the new class.
581
	 *
582
	 * @param string Relative path to the template creating code for the HTML page body
583
	 * @since 2014.03
584
	 * @see client/html/checkout/standard/address/delivery/template-header
585
	 */
586
}
587