Test Setup Failed
Push — master ( 4c62c0...259020 )
by Bruce Pinheiro de
02:12
created

CustomerClient::request()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 40
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 27
nc 6
nop 4
dl 0
loc 40
rs 8.5806
c 0
b 0
f 0
1
<?php
2
namespace BPCI\SumUp\Customer;
3
4
use BPCI\SumUp\ContextInterface;
5
use BPCI\SumUp\Customer\Card\CardInterface;
6
use BPCI\SumUp\Exception\BadRequestException;
7
use BPCI\SumUp\Exception\InvalidCustomerException;
8
use BPCI\SumUp\OAuth\AccessToken;
9
use BPCI\SumUp\OAuth\AuthenticationHelper;
10
use BPCI\SumUp\SumUp;
11
use BPCI\SumUp\Utils\Hydrator;
0 ignored issues
show
Bug introduced by
The type BPCI\SumUp\Utils\Hydrator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use Psr\Http\Message\ResponseInterface;
13
14
class CustomerClient implements CustomerClientInterface
15
{
16
    const ENDPOINT = 'customers';
17
    protected $context;
18
    protected $lastResponse;
19
20
    /**
21
	 * CheckoutClientInterface constructor.
22
	 * @param ContextInterface $context
23
	 */
24
	public function __construct(ContextInterface $context)
25
	{
26
		$this->context = $context;
27
	}
28
29
    /**
30
     * @inheritDoc
31
     * @throws BadRequestException
32
     */
33
    public function createCard(CustomerInterface $customer, CardInterface $card, AccessToken $accessToken): ?CardInterface
34
    {
35
        //TODO Implement this method
36
37
    }
38
39
    /**
40
     * @inheritDoc
41
     * @throws BadRequestException
42
     */
43
    public function getCards(CustomerInterface $custome, AccessToken $accessToken): array
44
    {
45
        //TODO Implement this method
46
    }
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return array. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
47
48
    /**
49
     * @inheritDoc
50
     * @throws BadRequestException
51
     */
52
    public function deleteCard(CustomerInterface $customer, CardInterface $card, AccessToken $accessToken): void
53
    {
54
        //TODO Implement this method
55
    }
56
57
    /**
58
     * @inheritDoc
59
     * @throws BadRequestException
60
     * @throws InvalidCustomerException
61
     */
62
    public function create(CustomerInterface $customer, AccessToken $accessToken): ?CustomerInterface
63
    {
64
        $accessToken = AuthenticationHelper::getValidToken($this->context, $accessToken, self::getScopes());
65
        self::validateCustomer($customer);
66
        $client = SumUp::getClient();
67
        $headers = AuthenticationHelper::getOAuthHeader($accessToken);
68
        $body = self::getCustomerBody($customer);
69
        try {
70
            $response = $client->post(self::ENDPOINT, [
71
                'headers' => $headers
72
            ], $body);
0 ignored issues
show
Unused Code introduced by
The call to GuzzleHttp\Client::post() has too many arguments starting with $body. ( Ignorable by Annotation )

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

72
            /** @scrutinizer ignore-call */ 
73
            $response = $client->post(self::ENDPOINT, [

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
73
            $successul = $response->getStatusCode() === 201;
74
        } catch(\GuzzleHttp\Exception\RequestException $e){
75
            throw new BadRequestException(
76
                $e->getMessage(),
77
                $e->getRequest(),
0 ignored issues
show
Bug introduced by
$e->getRequest() of type Psr\Http\Message\RequestInterface is incompatible with the type integer expected by parameter $code of BPCI\SumUp\Exception\Bad...xception::__construct(). ( Ignorable by Annotation )

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

77
                /** @scrutinizer ignore-type */ $e->getRequest(),
Loading history...
78
                $e->getResponse()
0 ignored issues
show
Bug introduced by
$e->getResponse() of type Psr\Http\Message\ResponseInterface is incompatible with the type Throwable|null expected by parameter $previous of BPCI\SumUp\Exception\Bad...xception::__construct(). ( Ignorable by Annotation )

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

78
                /** @scrutinizer ignore-type */ $e->getResponse()
Loading history...
79
            );
80
        }
81
82
        if ($successul) {
83
            $wrapper = new Hydrator($response);
84
            $customer = $wrapper->hydrate($customer);
85
            return $customer;
86
        }
87
88
        return null;
89
    }
90
91
	private function request(string $action, CustomerInterface $customer, AccessToken $accessToken, array $scopes):? CustomerInterface
92
	{
93
		$accessToken = AuthenticationHelper::getValidToken(
94
			$this->context,
95
			$accessToken,
96
			$scopes??self::getScopes()
97
		);
98
99
		$client = SumUp::getClient();
100
		$options = AuthenticationHelper::getOAuthHeader($accessToken);
101
		$options['form_params'] = self::getCustomerBody($customer);
102
103
		$successCode=200;
104
		$uri = self::ENDPOINT . '/' . $customer->getCustomerId();
105
		switch (true){
106
			case $action==='create': {
107
				$action='post';
108
				$successCode=201;
109
				$uri = self::ENDPOINT;
110
				break;
111
			}
112
			case $action==='complete': {
113
				$action='put';
114
				break;
115
			}
116
			default:{
117
				$action='get';
118
				break;
119
			}
120
		}
121
122
		/** @var ResponseInterface $response */
123
		$response = $client->{$action}($uri, $options);
124
		$this->lastResponse = $response;
125
		if($successCode===$response->getStatusCode()){
126
			$wrapper = new Hydrator($response);
127
			return $wrapper->hydrate($customer);
128
		}
129
130
		return null;
131
	}
132
133
    /**
134
     * Validate an customer
135
     *
136
     * @param CustomerInterface $customer
137
     * @return void
138
     * @throws InvalidCustomerException
139
     */
140
    private static function validateCustomer(CustomerInterface $customer): void
141
    {
142
        if (!$customer->isValid()) {
143
            throw new InvalidCustomerException('Ops! Something is wrong with this CustomerInterface Instance');
144
        }
145
    }
146
147
    public static function getCustomerBody(CustomerInterface $customer): array
148
    {
149
        $customerBody = [
150
            'personal_details' => [
151
                'name' => $customer->getName(),
152
                'phone' => $customer->getPhone(),
153
                'address' => [
154
                    'line1' => $customer->getAddress()->getLine1(),
155
                    'line2' => $customer->getAddress()->getLine2(),
156
                    'country' => $customer->getAddress()->getCountry(),
157
                    'postal_code' => $customer->getAddress()->getPostalCode(),
158
                    'city' => $customer->getAddress()->getCity(),
159
                    'state' => $customer->getAddress()->getState(),
160
                ],
161
            ],
162
        ];
163
164
        if ($customer->getCustomerId() !== null) {
165
            $customerBody['customer_id'] = $customer->getCustomerId();
166
        }
167
168
        return $customerBody;
169
    }
170
171
    public function setContext(ContextInterface $context): CustomerClientInterface
172
	{
173
		$this->context = $context;
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return BPCI\SumUp\Customer\CustomerClientInterface. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
174
	}
175
176
    /**
177
     * @inheritDoc
178
     */
179
    public static function getScopes(): array
180
    {
181
        return [
182
            'payment_instruments',
183
        ];
184
    }
185
186
	function getLastResponse(): ResponseInterface
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
187
	{
188
		return $this->lastResponse;
189
	}
190
191
192
	/**
193
	 * return the context used to created the client.
194
	 * @return ContextInterface
195
	 */
196
	function getContext(): ContextInterface
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
197
	{
198
		// TODO: Implement getContext() method.
199
	}
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return BPCI\SumUp\ContextInterface. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
200
}
201