Completed
Push — master ( 31faa3...626087 )
by Aimeos
02:18
created

Base::addProduct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
cc 1
eloc 6
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * @license LGPLv3, http://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2016
6
 * @package Controller
7
 * @subpackage Frontend
8
 */
9
10
11
namespace Aimeos\Controller\Frontend\Basket\Decorator;
12
13
14
/**
15
 * Base for basket frontend controller decorators
16
 *
17
 * @package Controller
18
 * @subpackage Frontend
19
 */
20
abstract class Base
21
	extends \Aimeos\Controller\Frontend\Basket\Base
2 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
Coding Style introduced by
Expected 0 spaces between "Base" and comma; 1 found
Loading history...
22
	implements \Aimeos\Controller\Frontend\Common\Decorator\Iface
1 ignored issue
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
23
{
24
	private $controller;
25
26
27
	/**
28
	 * Initializes the controller decorator.
29
	 *
30
	 * @param \Aimeos\Controller\Frontend\Iface $controller Controller object
31
	 * @param \Aimeos\MShop\Context\Item\Iface $context Context object with required objects
32
	 */
33
	public function __construct( \Aimeos\Controller\Frontend\Iface $controller, \Aimeos\MShop\Context\Item\Iface $context )
34
	{
35
		$iface = '\Aimeos\Controller\Frontend\Basket\Iface';
36
		if( !( $controller instanceof $iface ) )
37
		{
38
			$msg = sprintf( 'Class "%1$s" does not implement interface "%2$s"', get_class( $controller ), $iface );
39
			throw new \Aimeos\Controller\Frontend\Exception( $msg );
40
		}
41
42
		$this->controller = $controller;
43
44
		parent::__construct( $context );
45
	}
46
47
48
	/**
49
	 * Passes unknown methods to wrapped objects.
50
	 *
51
	 * @param string $name Name of the method
52
	 * @param array $param List of method parameter
53
	 * @return mixed Returns the value of the called method
54
	 * @throws \Aimeos\Controller\Frontend\Exception If method call failed
55
	 */
56
	public function __call( $name, array $param )
57
	{
58
		return @call_user_func_array( array( $this->controller, $name ), $param );
59
	}
60
61
62
	/**
63
	 * Empties the basket and removing all products, addresses, services, etc.
64
	 * @return void
65
	 */
66
	public function clear()
67
	{
68
		$this->controller->clear();
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method clear() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
69
	}
70
71
72
	/**
73
	 * Returns the basket object.
74
	 *
75
	 * @return \Aimeos\MShop\Order\Item\Base\Iface Basket holding products, addresses and delivery/payment options
76
	 */
77
	public function get()
78
	{
79
		return $this->controller->get();
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method get() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
80
	}
81
82
83
	/**
84
	 * Explicitely persists the basket content
85
	 */
86
	public function save()
87
	{
88
		$this->controller->save();
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method save() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
89
	}
90
91
92
	/**
93
	 * Adds a categorized product to the basket of the user stored in the session.
94
	 *
95
	 * @param string $prodid ID of the base product to add
96
	 * @param integer $quantity Amount of products that should by added
97
	 * @param array $options Possible options are: 'stock'=>true|false and 'variant'=>true|false
98
	 * 	The 'stock'=>false option allows adding products without being in stock.
99
	 * 	The 'variant'=>false option allows adding the selection product to the basket
100
	 * 	instead of the specific sub-product if the variant-building attribute IDs
101
	 * 	doesn't match a specific sub-product or if the attribute IDs are missing.
102
	 * @param array $variantAttributeIds List of variant-building attribute IDs that identify a specific product
103
	 * 	in a selection products
104
	 * @param array $configAttributeIds  List of attribute IDs that doesn't identify a specific product in a
105
	 * 	selection of products but are stored together with the product (e.g. for configurable products)
106
	 * @param array $hiddenAttributeIds List of attribute IDs that should be stored along with the product in the order
107
	 * @param array $customAttributeValues Associative list of attribute IDs and arbitrary values that should be stored
108
	 * 	along with the product in the order
109
	 * @param string $stocktype Unique code of the stock type to deliver the products from
110
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If the product isn't available
111
	 * @return void
112
	 */
113
	public function addProduct( $prodid, $quantity = 1, array $options = array(), array $variantAttributeIds = array(),
114
		array $configAttributeIds = array(), array $hiddenAttributeIds = array(), array $customAttributeValues = array(),
115
		$stocktype = 'default' )
116
	{
117
		$this->controller->addProduct(
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method addProduct() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
118
			$prodid, $quantity, $options, $variantAttributeIds, $configAttributeIds,
119
			$hiddenAttributeIds, $customAttributeValues, $stocktype
120
		);
121
	}
122
123
124
	/**
125
	 * Deletes a product item from the basket.
126
	 *
127
	 * @param integer $position Position number (key) of the order product item
128
	 * @return void
129
	 */
130
	public function deleteProduct( $position )
131
	{
132
		$this->controller->deleteProduct( $position );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method deleteProduct() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
133
	}
134
135
136
	/**
137
	 * Edits the quantity of a product item in the basket.
138
	 *
139
	 * @param integer $position Position number (key) of the order product item
140
	 * @param integer $quantity New quantiy of the product item
141
	 * @param array $options Possible options are: 'stock'=>true|false
142
	 * @param array $configAttributeCodes Codes of the product config attributes that should be REMOVED
143
	 * @return void
144
	 */
145
	public function editProduct( $position, $quantity, array $options = array(), array $configAttributeCodes = array() )
146
	{
147
		$this->controller->editProduct( $position, $quantity, $options, $configAttributeCodes );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method editProduct() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
148
	}
149
150
151
	/**
152
	 * Adds the given coupon code and updates the basket.
153
	 *
154
	 * @param string $code Coupon code entered by the user
155
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception if the coupon code is invalid or not allowed
156
	 * @return void
157
	 */
158
	public function addCoupon( $code )
159
	{
160
		$this->controller->addCoupon( $code );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method addCoupon() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
161
	}
162
163
164
	/**
165
	 * Removes the given coupon code and its effects from the basket.
166
	 *
167
	 * @param string $code Coupon code entered by the user
168
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception if the coupon code is invalid
169
	 * @return void
170
	 */
171
	public function deleteCoupon( $code )
172
	{
173
		$this->controller->deleteCoupon( $code );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method deleteCoupon() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
174
	}
175
176
177
	/**
178
	 * Sets the address of the customer in the basket.
179
	 *
180
	 * @param string $type Address type constant from \Aimeos\MShop\Order\Item\Base\Address\Base
181
	 * @param \Aimeos\MShop\Common\Item\Address\Iface|array|null $value Address object or array with key/value pairs of address or null to remove address from basket
182
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If the billing or delivery address is not of any required type of
183
	 * 	if one of the keys is invalid when using an array with key/value pairs
184
	 * @return void
185
	 */
186
	public function setAddress( $type, $value )
187
	{
188
		$this->controller->setAddress( $type, $value );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method setAddress() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
189
	}
190
191
192
	/**
193
	 * Sets the delivery/payment service item based on the service ID.
194
	 *
195
	 * @param string $type Service type code like 'payment' or 'delivery'
196
	 * @param string $id Unique ID of the service item
197
	 * @param array $attributes Associative list of key/value pairs containing the attributes selected or
198
	 * 	entered by the customer when choosing one of the delivery or payment options
199
	 * @throws \Aimeos\Controller\Frontend\Basket\Exception If there is no price to the service item attached
200
	 * @return void
201
	 */
202
	public function setService( $type, $id, array $attributes = array() )
203
	{
204
		$this->controller->setService( $type, $id, $attributes );
1 ignored issue
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Aimeos\Controller\Frontend\Iface as the method setService() does only exist in the following implementations of said interface: Aimeos\Controller\Frontend\Basket\Decorator\Base, Aimeos\Controller\Frontend\Basket\Decorator\Bundle, Aimeos\Controller\Fronte...sket\Decorator\Category, Aimeos\Controller\Frontend\Basket\Decorator\Select, Aimeos\Controller\Frontend\Basket\Standard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
205
	}
206
207
208
	/**
209
	 * Returns the frontend controller
210
	 *
211
	 * @return \Aimeos\Controller\Frontend\Basket\Iface Frontend controller object
212
	 */
213
	protected function getController()
214
	{
215
		return $this->controller;
216
	}
217
}
218