Completed
Pull Request — 23 (#431)
by Harald
10:27
created

CustomerGateway::sale()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
namespace Braintree;
3
4
use InvalidArgumentException;
5
6
/**
7
 * Braintree CustomerGateway module
8
 * Creates and manages Customers
9
 *
10
 * <b>== More information ==</b>
11
 *
12
 * For more detailed information on Customers, see {@link http://www.braintreepayments.com/gateway/customer-api http://www.braintreepaymentsolutions.com/gateway/customer-api}
13
 *
14
 * @package    Braintree
15
 * @category   Resources
16
 * @copyright  2015 Braintree, a division of PayPal, Inc.
17
 */
18
class CustomerGateway
19
{
20
    private $_gateway;
21
    private $_config;
22
    private $_http;
23
24
    public function __construct($gateway)
25
    {
26
        $this->_gateway = $gateway;
27
        $this->_config = $gateway->config;
28
        $this->_config->assertHasAccessTokenOrKeys();
29
        $this->_http = new Http($gateway->config);
30
    }
31
32 View Code Duplication
    public function all()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
33
    {
34
        $path = $this->_config->merchantPath() . '/customers/advanced_search_ids';
35
        $response = $this->_http->post($path);
36
        $pager = [
37
            'object' => $this,
38
            'method' => 'fetch',
39
            'methodArgs' => [[]]
40
            ];
41
42
        return new ResourceCollection($response, $pager);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $this->_http->post($path) on line 35 can also be of type null; however, Braintree\ResourceCollection::__construct() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
43
    }
44
45 View Code Duplication
    public function fetch($query, $ids)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
46
    {
47
        $criteria = [];
48
        foreach ($query as $term) {
49
            $criteria[$term->name] = $term->toparam();
50
        }
51
        $criteria["ids"] = CustomerSearch::ids()->in($ids)->toparam();
52
        $path = $this->_config->merchantPath() . '/customers/advanced_search';
53
        $response = $this->_http->post($path, ['search' => $criteria]);
54
55
        return Util::extractattributeasarray(
56
            $response['customers'],
57
            'customer'
58
        );
59
    }
60
61
    /**
62
     * Creates a customer using the given +attributes+. If <tt>:id</tt> is not passed,
63
     * the gateway will generate it.
64
     *
65
     * <code>
66
     *   $result = Customer::create(array(
67
     *     'first_name' => 'John',
68
     *     'last_name' => 'Smith',
69
     *     'company' => 'Smith Co.',
70
     *     'email' => '[email protected]',
71
     *     'website' => 'www.smithco.com',
72
     *     'fax' => '419-555-1234',
73
     *     'phone' => '614-555-1234'
74
     *   ));
75
     *   if($result->success) {
76
     *     echo 'Created customer ' . $result->customer->id;
77
     *   } else {
78
     *     echo 'Could not create customer, see result->errors';
79
     *   }
80
     * </code>
81
     *
82
     * @access public
83
     * @param array $attribs
84
     * @return Braintree_Result_Successful|Braintree_Result_Error
85
     */
86
    public function create($attribs = [])
87
    {
88
        Util::verifyKeys(self::createSignature(), $attribs);
89
        return $this->_doCreate('/customers', ['customer' => $attribs]);
90
    }
91
92
    /**
93
     * attempts the create operation assuming all data will validate
94
     * returns a Customer object instead of a Result
95
     *
96
     * @access public
97
     * @param array $attribs
98
     * @return Customer
99
     * @throws Exception\ValidationError
100
     */
101
    public function createNoValidate($attribs = [])
102
    {
103
        $result = $this->create($attribs);
104
        return Util::returnObjectOrThrowException(__CLASS__, $result);
105
    }
106
    /**
107
     * create a customer from a TransparentRedirect operation
108
     *
109
     * @deprecated since version 2.3.0
110
     * @access public
111
     * @param array $attribs
0 ignored issues
show
Bug introduced by
There is no parameter named $attribs. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
112
     * @return Customer
113
     */
114 View Code Duplication
    public function createFromTransparentRedirect($queryString)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        trigger_error("DEPRECATED: Please use TransparentRedirectRequest::confirm", E_USER_NOTICE);
117
        $params = TransparentRedirect::parseAndValidateQueryString(
118
                $queryString
119
                );
120
        return $this->_doCreate(
121
                '/customers/all/confirm_transparent_redirect_request',
122
                ['id' => $params['id']]
123
        );
124
    }
125
126
    /**
127
     *
128
     * @deprecated since version 2.3.0
129
     * @access public
130
     * @param none
131
     * @return string
132
     */
133
    public function createCustomerUrl()
134
    {
135
        trigger_error("DEPRECATED: Please use TransparentRedirectRequest::url", E_USER_NOTICE);
136
        return $this->_config->baseUrl() . $this->_config->merchantPath() .
137
                '/customers/all/create_via_transparent_redirect_request';
138
    }
139
140
141
    /**
142
     * creates a full array signature of a valid create request
143
     * @return array gateway create request format
144
     */
145
    public static function createSignature()
146
    {
147
148
        $creditCardSignature = CreditCardGateway::createSignature();
149
        unset($creditCardSignature[array_search('customerId', $creditCardSignature)]);
150
        $signature = [
151
            'id', 'company', 'email', 'fax', 'firstName',
152
            'lastName', 'phone', 'website', 'deviceData',
153
            'deviceSessionId', 'fraudMerchantId', 'paymentMethodNonce',
154
            ['riskData' =>
155
                ['customer_browser', 'customer_ip']
156
            ],
157
            ['creditCard' => $creditCardSignature],
158
            ['customFields' => ['_anyKey_']],
159
            ];
160
        return $signature;
161
    }
162
163
    /**
164
     * creates a full array signature of a valid update request
165
     * @return array update request format
166
     */
167
    public static function updateSignature()
168
    {
169
        $creditCardSignature = CreditCardGateway::updateSignature();
170
171
        foreach($creditCardSignature AS $key => $value) {
172
            if(is_array($value) and array_key_exists('options', $value)) {
173
                array_push($creditCardSignature[$key]['options'], 'updateExistingToken');
174
            }
175
        }
176
177
        $signature = [
178
            'id', 'company', 'email', 'fax', 'firstName',
179
            'lastName', 'phone', 'website', 'deviceData',
180
            'deviceSessionId', 'fraudMerchantId', 'paymentMethodNonce', 'defaultPaymentMethodToken',
181
            ['creditCard' => $creditCardSignature],
182
            ['customFields' => ['_anyKey_']],
183
            ];
184
        return $signature;
185
    }
186
187
188
    /**
189
     * find a customer by id
190
     *
191
     * @access public
192
     * @param string id customer Id
193
     * @return Customer|boolean The customer object or false if the request fails.
194
     * @throws Exception\NotFound
195
     */
196 View Code Duplication
    public function find($id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
197
    {
198
        $this->_validateId($id);
199
        try {
200
            $path = $this->_config->merchantPath() . '/customers/' . $id;
201
            $response = $this->_http->get($path);
202
            return Customer::factory($response['customer']);
203
        } catch (Exception\NotFound $e) {
204
            throw new Exception\NotFound(
205
            'customer with id ' . $id . ' not found'
206
            );
207
        }
208
    }
209
210
    /**
211
     * credit a customer for the passed transaction
212
     *
213
     * @access public
214
     * @param int $customerId
215
     * @param array $transactionAttribs
216
     * @return Result\Successful|Result\Error
217
     */
218
    public function credit($customerId, $transactionAttribs)
219
    {
220
        $this->_validateId($customerId);
221
        return Transaction::credit(
222
                array_merge($transactionAttribs,
223
                        ['customerId' => $customerId]
224
                        )
225
                );
226
    }
227
228
    /**
229
     * credit a customer, assuming validations will pass
230
     *
231
     * returns a Transaction object on success
232
     *
233
     * @access public
234
     * @param int $customerId
235
     * @param array $transactionAttribs
236
     * @return Transaction
237
     * @throws Exception\ValidationError
238
     */
239
    public function creditNoValidate($customerId, $transactionAttribs)
240
    {
241
        $result = $this->credit($customerId, $transactionAttribs);
242
        return Util::returnObjectOrThrowException('Braintree\Transaction', $result);
243
    }
244
245
    /**
246
     * delete a customer by id
247
     *
248
     * @param string $customerId
249
     */
250 View Code Duplication
    public function delete($customerId)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
251
    {
252
        $this->_validateId($customerId);
253
        $path = $this->_config->merchantPath() . '/customers/' . $customerId;
254
        $this->_http->delete($path);
255
        return new Result\Successful();
256
    }
257
258
    /**
259
     * create a new sale for a customer
260
     *
261
     * @param string $customerId
262
     * @param array $transactionAttribs
263
     * @return Result\Successful|Result\Error
264
     * @see Transaction::sale()
265
     */
266
    public function sale($customerId, $transactionAttribs)
267
    {
268
        $this->_validateId($customerId);
269
        return Transaction::sale(
270
                array_merge($transactionAttribs,
271
                        ['customerId' => $customerId]
272
                        )
273
                );
274
    }
275
276
    /**
277
     * create a new sale for a customer, assuming validations will pass
278
     *
279
     * returns a Transaction object on success
280
     * @access public
281
     * @param string $customerId
282
     * @param array $transactionAttribs
283
     * @return Transaction
284
     * @throws Exception\ValidationsFailed
285
     * @see Transaction::sale()
286
     */
287
    public function saleNoValidate($customerId, $transactionAttribs)
288
    {
289
        $result = $this->sale($customerId, $transactionAttribs);
290
        return Util::returnObjectOrThrowException('Braintree\Transaction', $result);
291
    }
292
293
    /**
294
     * Returns a ResourceCollection of customers matching the search query.
295
     *
296
     * If <b>query</b> is a string, the search will be a basic search.
297
     * If <b>query</b> is a hash, the search will be an advanced search.
298
     * For more detailed information and examples, see {@link http://www.braintreepayments.com/gateway/customer-api#searching http://www.braintreepaymentsolutions.com/gateway/customer-api}
299
     *
300
     * @param mixed $query search query
301
     * @return ResourceCollection
302
     * @throws InvalidArgumentException
303
     */
304
    public function search($query)
305
    {
306
        $criteria = [];
307
        foreach ($query as $term) {
308
            $result = $term->toparam();
309
            if(is_null($result) || empty($result)) {
310
                throw new InvalidArgumentException('Operator must be provided');
311
            }
312
313
            $criteria[$term->name] = $term->toparam();
314
        }
315
316
        $path = $this->_config->merchantPath() . '/customers/advanced_search_ids';
317
        $response = $this->_http->post($path, ['search' => $criteria]);
318
        $pager = [
319
            'object' => $this,
320
            'method' => 'fetch',
321
            'methodArgs' => [$query]
322
            ];
323
324
        return new ResourceCollection($response, $pager);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $this->_http->post($path...'search' => $criteria)) on line 317 can also be of type null; however, Braintree\ResourceCollection::__construct() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
325
    }
326
327
    /**
328
     * updates the customer record
329
     *
330
     * if calling this method in static context, customerId
331
     * is the 2nd attribute. customerId is not sent in object context.
332
     *
333
     * @access public
334
     * @param string $customerId (optional)
335
     * @param array $attributes
336
     * @return Result\Successful|Result\Error
337
     */
338
    public function update($customerId, $attributes)
339
    {
340
        Util::verifyKeys(self::updateSignature(), $attributes);
341
        $this->_validateId($customerId);
342
        return $this->_doUpdate(
343
            'put',
344
            '/customers/' . $customerId,
345
            ['customer' => $attributes]
346
        );
347
    }
348
349
    /**
350
     * update a customer record, assuming validations will pass
351
     *
352
     * if calling this method in static context, customerId
353
     * is the 2nd attribute. customerId is not sent in object context.
354
     * returns a Customer object on success
355
     *
356
     * @access public
357
     * @param string $customerId
358
     * @param array $attributes
359
     * @return Customer
360
     * @throws Exception\ValidationsFailed
361
     */
362
    public function updateNoValidate($customerId, $attributes)
363
    {
364
        $result = $this->update($customerId, $attributes);
365
        return Util::returnObjectOrThrowException(__CLASS__, $result);
366
    }
367
    /**
368
     *
369
     * @deprecated since version 2.3.0
370
     * @access public
371
     * @return string
372
     */
373
    public function updateCustomerUrl()
374
    {
375
        trigger_error("DEPRECATED: Please use TransparentRedirectRequest::url", E_USER_NOTICE);
376
        return $this->_config->baseUrl() . $this->_config->merchantPath() .
377
                '/customers/all/update_via_transparent_redirect_request';
378
    }
379
380
    /**
381
     * update a customer from a TransparentRedirect operation
382
     *
383
     * @deprecated since version 2.3.0
384
     * @access public
385
     * @param string $queryString
386
     * @return object
387
     */
388 View Code Duplication
    public function updateFromTransparentRedirect($queryString)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
389
    {
390
        trigger_error("DEPRECATED: Please use TransparentRedirectRequest::confirm", E_USER_NOTICE);
391
        $params = TransparentRedirect::parseAndValidateQueryString(
392
                $queryString
393
        );
394
        return $this->_doUpdate(
395
                'post',
396
                '/customers/all/confirm_transparent_redirect_request',
397
                ['id' => $params['id']]
398
        );
399
    }
400
401
    /* instance methods */
402
403
    /**
404
     * sets instance properties from an array of values
405
     *
406
     * @ignore
407
     * @access protected
408
     * @param array $customerAttribs array of customer data
409
     * @return void
410
     */
411
    protected function _initialize($customerAttribs)
412
    {
413
        // set the attributes
414
        $this->_attributes = $customerAttribs;
415
416
        // map each address into its own object
417
        $addressArray = [];
418 View Code Duplication
        if (isset($customerAttribs['addresses'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
419
420
            foreach ($customerAttribs['addresses'] AS $address) {
421
                $addressArray[] = Address::factory($address);
422
            }
423
        }
424
        $this->_set('addresses', $addressArray);
0 ignored issues
show
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
425
426
        // map each creditCard into its own object
427
        $creditCardArray = [];
428 View Code Duplication
        if (isset($customerAttribs['creditCards'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
429
            foreach ($customerAttribs['creditCards'] AS $creditCard) {
430
                $creditCardArray[] = CreditCard::factory($creditCard);
431
            }
432
        }
433
        $this->_set('creditCards', $creditCardArray);
0 ignored issues
show
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
434
435
        // map each coinbaseAccount into its own object
436
        $coinbaseAccountArray = [];
437 View Code Duplication
        if (isset($customerAttribs['coinbaseAccounts'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
438
            foreach ($customerAttribs['coinbaseAccounts'] AS $coinbaseAccount) {
439
                $coinbaseAccountArray[] = CoinbaseAccount::factory($coinbaseAccount);
440
            }
441
        }
442
        $this->_set('coinbaseAccounts', $coinbaseAccountArray);
0 ignored issues
show
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
443
444
        // map each paypalAccount into its own object
445
        $paypalAccountArray = [];
446 View Code Duplication
        if (isset($customerAttribs['paypalAccounts'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
447
            foreach ($customerAttribs['paypalAccounts'] AS $paypalAccount) {
448
                $paypalAccountArray[] = PayPalAccount::factory($paypalAccount);
449
            }
450
        }
451
        $this->_set('paypalAccounts', $paypalAccountArray);
0 ignored issues
show
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
452
453
        // map each applePayCard into its own object
454
        $applePayCardArray = [];
455 View Code Duplication
        if (isset($customerAttribs['applePayCards'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
456
            foreach ($customerAttribs['applePayCards'] AS $applePayCard) {
457
                $applePayCardArray[] = ApplePayCard::factory($applePayCard);
458
            }
459
        }
460
        $this->_set('applePayCards', $applePayCardArray);
0 ignored issues
show
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
461
462
        // map each androidPayCard into its own object
463
        $androidPayCardArray = [];
464 View Code Duplication
        if (isset($customerAttribs['androidPayCards'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
465
            foreach ($customerAttribs['androidPayCards'] AS $androidPayCard) {
466
                $androidPayCardArray[] = AndroidPayCard::factory($androidPayCard);
467
            }
468
        }
469
        $this->_set('androidPayCards', $androidPayCardArray);
0 ignored issues
show
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
470
471
        $this->_set('paymentMethods', array_merge($this->creditCards, $this->paypalAccounts, $this->applePayCards, $this->coinbaseAccounts, $this->androidPayCards));
0 ignored issues
show
Bug introduced by
The property creditCards does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property paypalAccounts does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property applePayCards does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property coinbaseAccounts does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The property androidPayCards does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
The method _set() does not seem to exist on object<Braintree\CustomerGateway>.

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...
472
    }
473
474
    /**
475
     * returns a string representation of the customer
476
     * @return string
477
     */
478
    public function  __toString()
479
    {
480
        return __CLASS__ . '[' .
481
                Util::attributesToString($this->_attributes) .']';
482
    }
483
484
    /**
485
     * returns false if comparing object is not a Customer,
486
     * or is a Customer with a different id
487
     *
488
     * @param object $otherCust customer to compare against
489
     * @return boolean
490
     */
491
    public function isEqual($otherCust)
492
    {
493
        return !($otherCust instanceof Customer) ? false : $this->id === $otherCust->id;
0 ignored issues
show
Bug introduced by
The property id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
494
    }
495
496
    /**
497
     * returns an array containt all of the customer's payment methods
498
     *
499
     * @return array
500
     */
501
    public function paymentMethods()
502
    {
503
        return $this->paymentMethods;
0 ignored issues
show
Bug introduced by
The property paymentMethods does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
504
    }
505
506
    /**
507
     * returns the customer's default payment method
508
     *
509
     * @return CreditCard|PayPalAccount|ApplePayCard|AndroidPayCard
510
     */
511
    public function defaultPaymentMethod()
512
    {
513
        $defaultPaymentMethods = array_filter($this->paymentMethods, 'Braintree\\Customer::_defaultPaymentMethodFilter');
514
        return current($defaultPaymentMethods);
515
    }
516
517
    public static function _defaultPaymentMethodFilter($paymentMethod)
518
    {
519
        return $paymentMethod->isDefault();
520
    }
521
522
    /* private class properties  */
523
524
    /**
525
     * @access protected
526
     * @var array registry of customer data
527
     */
528
    protected $_attributes = [
529
        'addresses'   => '',
530
        'company'     => '',
531
        'creditCards' => '',
532
        'email'       => '',
533
        'fax'         => '',
534
        'firstName'   => '',
535
        'id'          => '',
536
        'lastName'    => '',
537
        'phone'       => '',
538
        'createdAt'   => '',
539
        'updatedAt'   => '',
540
        'website'     => '',
541
        ];
542
543
    /**
544
     * sends the create request to the gateway
545
     *
546
     * @ignore
547
     * @param string $subPath
548
     * @param array $params
549
     * @return mixed
550
     */
551 View Code Duplication
    public function _doCreate($subPath, $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
552
    {
553
        $fullPath = $this->_config->merchantPath() . $subPath;
554
        $response = $this->_http->post($fullPath, $params);
555
556
        return $this->_verifyGatewayResponse($response);
0 ignored issues
show
Bug introduced by
It seems like $response defined by $this->_http->post($fullPath, $params) on line 554 can also be of type null; however, Braintree\CustomerGatewa...verifyGatewayResponse() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
557
    }
558
559
    /**
560
     * verifies that a valid customer id is being used
561
     * @ignore
562
     * @param string customer id
563
     * @throws InvalidArgumentException
564
     */
565 View Code Duplication
    private function _validateId($id = null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
566
        if (is_null($id)) {
567
            throw new InvalidArgumentException(
568
                'expected customer id to be set'
569
            );
570
        }
571
        if (!preg_match('/^[0-9A-Za-z_-]+$/', $id)) {
572
            throw new InvalidArgumentException(
573
                $id . ' is an invalid customer id.'
574
            );
575
        }
576
    }
577
578
579
    /* private class methods */
580
581
    /**
582
     * sends the update request to the gateway
583
     *
584
     * @ignore
585
     * @param string $subPath
586
     * @param array $params
587
     * @return mixed
588
     */
589 View Code Duplication
    private function _doUpdate($httpVerb, $subPath, $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
590
    {
591
        $fullPath = $this->_config->merchantPath() . $subPath;
592
        $response = $this->_http->$httpVerb($fullPath, $params);
593
594
        return $this->_verifyGatewayResponse($response);
595
    }
596
597
    /**
598
     * generic method for validating incoming gateway responses
599
     *
600
     * creates a new Customer object and encapsulates
601
     * it inside a Result\Successful object, or
602
     * encapsulates a Errors object inside a Result\Error
603
     * alternatively, throws an Unexpected exception if the response is invalid.
604
     *
605
     * @ignore
606
     * @param array $response gateway response values
607
     * @return Result\Successful|Result\Error
608
     * @throws Exception\Unexpected
609
     */
610 View Code Duplication
    private function _verifyGatewayResponse($response)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
611
    {
612
        if (isset($response['customer'])) {
613
            // return a populated instance of Customer
614
            return new Result\Successful(
615
                    Customer::factory($response['customer'])
0 ignored issues
show
Documentation introduced by
\Braintree\Customer::fac...($response['customer']) is of type object<Braintree\Customer>, but the function expects a array|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
616
            );
617
        } else if (isset($response['apiErrorResponse'])) {
618
            return new Result\Error($response['apiErrorResponse']);
619
        } else {
620
            throw new Exception\Unexpected(
621
            "Expected customer or apiErrorResponse"
622
            );
623
        }
624
    }
625
}
626
class_alias('Braintree\CustomerGateway', 'Braintree_CustomerGateway');
627