Completed
Push — 1.2-symfony-4.1 ( 9574a4 )
by Kamil
40:20
created

PayumController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 17
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
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Bundle\PayumBundle\Controller;
15
16
use FOS\RestBundle\View\View;
17
use Payum\Core\Model\GatewayConfigInterface;
18
use Payum\Core\Payum;
19
use Payum\Core\Security\GenericTokenFactoryInterface;
20
use Payum\Core\Security\HttpRequestVerifierInterface;
21
use Payum\Core\Security\TokenInterface;
22
use Sylius\Bundle\PayumBundle\Factory\GetStatusFactoryInterface;
23
use Sylius\Bundle\PayumBundle\Factory\ResolveNextRouteFactoryInterface;
24
use Sylius\Bundle\ResourceBundle\Controller\RequestConfigurationFactoryInterface;
25
use Sylius\Bundle\ResourceBundle\Controller\ViewHandlerInterface;
26
use Sylius\Component\Core\Model\OrderInterface;
27
use Sylius\Component\Order\Repository\OrderRepositoryInterface;
28
use Sylius\Component\Payment\Model\PaymentInterface;
29
use Sylius\Component\Resource\Metadata\MetadataInterface;
30
use Symfony\Component\HttpFoundation\RedirectResponse;
31
use Symfony\Component\HttpFoundation\Request;
32
use Symfony\Component\HttpFoundation\Response;
33
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
34
use Symfony\Component\Routing\RouterInterface;
35
36
final class PayumController
37
{
38
    /**
39
     * @var Payum
40
     */
41
    private $payum;
42
43
    /**
44
     * @var OrderRepositoryInterface
45
     */
46
    private $orderRepository;
47
48
    /**
49
     * @var MetadataInterface
50
     */
51
    private $orderMetadata;
52
53
    /**
54
     * @var RequestConfigurationFactoryInterface
55
     */
56
    private $requestConfigurationFactory;
57
58
    /**
59
     * @var ViewHandlerInterface
60
     */
61
    private $viewHandler;
62
63
    /**
64
     * @var RouterInterface
65
     */
66
    private $router;
67
68
    /** @var GetStatusFactoryInterface */
69
    private $getStatusRequestFactory;
70
71
    /** @var ResolveNextRouteFactoryInterface */
72
    private $resolveNextRouteRequestFacotry;
73
74
    public function __construct(
75
        Payum $payum,
76
        OrderRepositoryInterface $orderRepository,
77
        MetadataInterface $orderMetadata,
78
        RequestConfigurationFactoryInterface $requestConfigurationFactory,
79
        ViewHandlerInterface $viewHandler,
80
        RouterInterface $router,
81
        GetStatusFactoryInterface $getStatusFactory,
82
        ResolveNextRouteFactoryInterface $resolveNextRouteFactory
83
    ) {
84
        $this->payum = $payum;
85
        $this->orderRepository = $orderRepository;
86
        $this->orderMetadata = $orderMetadata;
87
        $this->requestConfigurationFactory = $requestConfigurationFactory;
88
        $this->viewHandler = $viewHandler;
89
        $this->router = $router;
90
        $this->getStatusRequestFactory = $getStatusFactory;
91
        $this->resolveNextRouteRequestFacotry = $resolveNextRouteFactory;
92
    }
93
94
    public function prepareCaptureAction(Request $request, $tokenValue): Response
95
    {
96
        $configuration = $this->requestConfigurationFactory->create($this->orderMetadata, $request);
97
98
        /** @var OrderInterface $order */
99
        $order = $this->orderRepository->findOneByTokenValue($tokenValue);
100
101
        if (null === $order) {
102
            throw new NotFoundHttpException(sprintf('Order with token "%s" does not exist.', $tokenValue));
103
        }
104
105
        $request->getSession()->set('sylius_order_id', $order->getId());
106
        $payment = $order->getLastPayment(PaymentInterface::STATE_NEW);
107
108
        if (null === $payment) {
109
            $url = $this->router->generate('sylius_shop_order_thank_you');
110
111
            return new RedirectResponse($url);
112
        }
113
114
        $token = $this->provideTokenBasedOnPayment($payment, $configuration->getParameters()->get('redirect'));
115
116
        $view = View::createRedirect($token->getTargetUrl());
117
118
        return $this->viewHandler->handle($configuration, $view);
119
    }
120
121
    public function afterCaptureAction(Request $request): Response
122
    {
123
        $configuration = $this->requestConfigurationFactory->create($this->orderMetadata, $request);
124
125
        $token = $this->getHttpRequestVerifier()->verify($request);
126
127
        $status = $this->getStatusRequestFactory->createNewWithModel($token);
128
        $this->payum->getGateway($token->getGatewayName())->execute($status);
129
        $resolveNextRoute = $this->resolveNextRouteRequestFacotry->createNewWithModel($status->getFirstModel());
130
        $this->payum->getGateway($token->getGatewayName())->execute($resolveNextRoute);
131
132
        $this->getHttpRequestVerifier()->invalidate($token);
133
134
        if (PaymentInterface::STATE_NEW !== $status->getValue()) {
135
            $request->getSession()->getBag('flashes')->add('info', sprintf('sylius.payment.%s', $status->getValue()));
136
        }
137
138
        return $this->viewHandler->handle(
139
            $configuration,
140
            View::createRouteRedirect($resolveNextRoute->getRouteName(), $resolveNextRoute->getRouteParameters())
141
        );
142
    }
143
144
    private function getTokenFactory(): GenericTokenFactoryInterface
145
    {
146
        return $this->payum->getTokenFactory();
147
    }
148
149
    private function getHttpRequestVerifier(): HttpRequestVerifierInterface
150
    {
151
        return $this->payum->getHttpRequestVerifier();
152
    }
153
154
    private function provideTokenBasedOnPayment(PaymentInterface $payment, array $redirectOptions): TokenInterface
155
    {
156
        /** @var GatewayConfigInterface $gatewayConfig */
157
        $gatewayConfig = $payment->getMethod()->getGatewayConfig();
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Sylius\Component\Payment...\PaymentMethodInterface as the method getGatewayConfig() does only exist in the following implementations of said interface: Sylius\Component\Core\Model\PaymentMethod.

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...
158
159
        if (isset($gatewayConfig->getConfig()['use_authorize']) && $gatewayConfig->getConfig()['use_authorize'] == true) {
160
            $token = $this->getTokenFactory()->createAuthorizeToken(
161
                $gatewayConfig->getGatewayName(),
162
                $payment,
163
                $redirectOptions['route']
164
                    ?? null,
165
                $redirectOptions['parameters']
166
                    ?? []
167
            );
168
        } else {
169
            $token = $this->getTokenFactory()->createCaptureToken(
170
                $gatewayConfig->getGatewayName(),
171
                $payment,
172
                $redirectOptions['route']
173
                    ?? null,
174
                $redirectOptions['parameters']
175
                    ?? []
176
            );
177
        }
178
179
        return $token;
180
    }
181
}
182