Test Failed
Pull Request — master (#12)
by
unknown
02:12
created

ResultObjectMapper::transformThreeDS2DataValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace Cardinity\Method;
4
5
use Cardinity\Exception;
6
use Cardinity\Method\Payment\AuthorizationInformation;
7
use Cardinity\Method\Payment\PaymentInstrumentCard;
8
use Cardinity\Method\Payment\PaymentInstrumentRecurring;
9
use Cardinity\Method\Payment\ThreeDS2AuthorizationInformation;
10
11
class ResultObjectMapper implements ResultObjectMapperInterface
12
{
13
    /**
14
     * Map each item in response data to instance of ResultObjectInterface
15
     * @param array $response
16
     * @param MethodResultCollectionInterface $method
17
     *
18
     * @return array
19
     */
20
    public function mapCollection(array $response, MethodResultCollectionInterface $method)
21
    {
22
        $return = [];
23
24
        foreach ($response as $item) {
25
            $return[] = $this->map($item, $method->createResultObject());
26
        }
27
28
        return $return;
29
    }
30
31
    /**
32
     * Map response data to instance of ResultObjectInterface
33
     * @param array $response
34
     * @param ResultObjectInterface $result
35
     *
36
     * @return ResultObjectInterface
37
     */
38
    public function map(array $response, ResultObjectInterface $result)
39
    {
40
        foreach ($response as $field => $value) {
41
            $method = $this->getSetterName($field);
42
43
            if (!method_exists($result, $method)) {
44
                continue;
45
            }
46
47
            if ($field == 'payment_instrument') {
48
                $value = $this->transformPaymentInstrumentValue($value, $response['payment_method']);
49
            } elseif ($field == 'authorization_information') {
50
                $value = $this->transformAuthorizationInformationValue($value);
51
            } elseif ($field == 'threeds2_data') {
52
                $result->setThreeDS2AuthorizationInformation($this->transformThreeDS2DataValue($value));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Cardinity\Method\ResultObjectInterface as the method setThreeDS2AuthorizationInformation() does only exist in the following implementations of said interface: Cardinity\Method\Payment\Payment.

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...
53
                continue;
54
            }
55
56
            $result->$method($value);
57
        }
58
59
        return $result;
60
    }
61
62
    /**
63
     * Extracts camelCased setter name from underscore notation.
64
     * Eg. my_field_name => myFieldName
65
     * @param string $field
66
     * @return string
67
     */
68 View Code Duplication
    private function getSetterName($field)
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...
69
    {
70
        $parts = explode('_', $field);
71
        array_map('ucfirst', $parts);
72
        $name = 'set' . implode('', $parts);
73
74
        return $name;
75
    }
76
77
    /**
78
     * Transform PaymentInstrument result array to object
79
     * @param array $data
80
     * @param string $method
81
     * @return PaymentInstrumentCard|PaymentInstrumentRecurring
82
     * @throws Exception\Runtime for unsupported methods
83
     */
84
    private function transformPaymentInstrumentValue(array $data, $method)
85
    {
86
        if ($method == 'card') {
87
            $instrument = new PaymentInstrumentCard();
88
        } elseif ($method == 'recurring') {
89
            $instrument = new PaymentInstrumentRecurring();
90
        } else {
91
            throw new Exception\Runtime(sprintf('Method "%s" is not supported', $method));
92
        }
93
94
        $this->map($data, $instrument);
95
96
        return $instrument;
97
    }
98
99
    /**
100
     * Transform AuthorizationInformation result array to object
101
     * @param array $data
102
     * @return AuthorizationInformation
103
     */
104
    private function transformAuthorizationInformationValue($data)
105
    {
106
        $info = new AuthorizationInformation();
107
        $this->map($data, $info);
108
109
        return $info;
110
    }
111
112
    /**
113
     * @param ARRAY $data
114
     * @return ThreeDS2AuthorizationInformation
115
     */
116
    private function transformThreeDS2DataValue($data)
117
    {
118
        $threeds2 = new ThreeDS2AuthorizationInformation();
119
        $this->map($data, $threeds2);
120
        return $threeds2;
121
    }
122
}
123