Completed
Pull Request — master (#31)
by Rafał
04:29
created

ResolveNextUrlAction::execute()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.439
c 0
b 0
f 0
cc 6
eloc 13
nc 3
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PH\Bundle\PayumBundle\Action;
6
7
use Payum\Core\Action\ActionInterface;
8
use PH\Bundle\PayumBundle\Request\ResolveNextUrl;
9
use PH\Component\Core\Model\PaymentInterface;
10
11
final class ResolveNextUrlAction implements ActionInterface
12
{
13
    /**
14
     * @var string
15
     */
16
    private $thankYouUrl;
17
18
    /**
19
     * @var string
20
     */
21
    private $cancelUrl;
22
23
    /**
24
     * ResolveNextUrlAction constructor.
25
     *
26
     * @param string $thankYouUrl
27
     * @param string $cancelUrl
28
     */
29
    public function __construct(string $thankYouUrl, string $cancelUrl)
30
    {
31
        $this->thankYouUrl = $thankYouUrl;
32
        $this->cancelUrl = $cancelUrl;
33
    }
34
35
    /**
36
     * {@inheritdoc}
37
     *
38
     * @param ResolveNextUrl $request
39
     */
40
    public function execute($request): void
41
    {
42
        /** @var PaymentInterface $payment */
43
        $payment = $request->getFirstModel();
44
45
        if (
46
            PaymentInterface::STATE_COMPLETED === $payment->getState() ||
47
            PaymentInterface::STATE_AUTHORIZED === $payment->getState() ||
48
            PaymentInterface::STATE_PROCESSING === $payment->getState()
49
        ) {
50
            $request->setUrl($this->thankYouUrl);
51
52
            $params = ['token' => $payment->getSubscription()->getTokenValue()];
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface PH\Component\Subscriptio...l\SubscriptionInterface as the method getTokenValue() does only exist in the following implementations of said interface: PH\Component\Core\Model\Subscription.

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
54
            if (isset($payment->getDetails()['email']) && null !== ($email = $payment->getDetails()['email'])) {
55
                $params['email'] = $email;
56
            }
57
58
            $request->setUrlQueryParams($params);
59
60
            return;
61
        }
62
63
        $request->setUrl($this->cancelUrl);
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function supports($request): bool
70
    {
71
        return
72
            $request instanceof ResolveNextUrl &&
73
            $request->getFirstModel() instanceof PaymentInterface
74
        ;
75
    }
76
}
77