Completed
Push — master ( 2b1385...7c6a84 )
by Thomas
07:21
created

RequestFsm::__invoke()   F

Complexity

Conditions 18
Paths 0

Size

Total Lines 112
Code Lines 73

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 112
rs 2
cc 18
eloc 73
nc 0
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace GuzzleHttp;
3
4
use GuzzleHttp\Event\BeforeEvent;
5
use GuzzleHttp\Event\ErrorEvent;
6
use GuzzleHttp\Event\CompleteEvent;
7
use GuzzleHttp\Event\EndEvent;
8
use GuzzleHttp\Exception\StateException;
9
use GuzzleHttp\Exception\RequestException;
10
use GuzzleHttp\Message\FutureResponse;
11
use GuzzleHttp\Message\MessageFactoryInterface;
12
use GuzzleHttp\Ring\Future\FutureInterface;
13
14
/**
15
 * Responsible for transitioning requests through lifecycle events.
16
 */
17
class RequestFsm
18
{
19
    private $handler;
20
    private $mf;
21
    private $maxTransitions;
22
23
    public function __construct(
24
        callable $handler,
25
        MessageFactoryInterface $messageFactory,
26
        $maxTransitions = 200
27
    ) {
28
        $this->mf = $messageFactory;
29
        $this->maxTransitions = $maxTransitions;
30
        $this->handler = $handler;
31
    }
32
33
    /**
34
     * Runs the state machine until a terminal state is entered or the
35
     * optionally supplied $finalState is entered.
36
     *
37
     * @param Transaction $trans      Transaction being transitioned.
38
     *
39
     * @throws \Exception if a terminal state throws an exception.
40
     */
41
    public function __invoke(Transaction $trans)
42
    {
43
        $trans->_transitionCount = 0;
44
45
        if (!$trans->state) {
46
            $trans->state = 'before';
47
        }
48
49
        transition:
50
51
        if (++$trans->_transitionCount > $this->maxTransitions) {
52
            throw new StateException("Too many state transitions were "
53
                . "encountered ({$trans->_transitionCount}). This likely "
54
                . "means that a combination of event listeners are in an "
55
                . "infinite loop.");
56
        }
57
58
        switch ($trans->state) {
59
            case 'before': goto before;
60
            case 'complete': goto complete;
61
            case 'error': goto error;
62
            case 'retry': goto retry;
63
            case 'send': goto send;
64
            case 'end': goto end;
65
            default: throw new StateException("Invalid state: {$trans->state}");
66
        }
67
68
        before: {
69
            try {
70
                $trans->request->getEmitter()->emit('before', new BeforeEvent($trans));
71
                $trans->state = 'send';
72
                if ((bool) $trans->response) {
73
                    $trans->state = 'complete';
74
                }
75
            } catch (\Exception $e) {
76
                $trans->state = 'error';
77
                $trans->exception = $e;
78
            }
79
            goto transition;
80
        }
81
82
        complete: {
83
            try {
84
                if ($trans->response instanceof FutureInterface) {
85
                    // Futures will have their own end events emitted when
86
                    // dereferenced.
87
                    return;
88
                }
89
                $trans->state = 'end';
90
                $trans->response->setEffectiveUrl($trans->request->getUrl());
91
                $trans->request->getEmitter()->emit('complete', new CompleteEvent($trans));
92
            } catch (\Exception $e) {
93
                $trans->state = 'error';
94
                $trans->exception = $e;
95
            }
96
            goto transition;
97
        }
98
99
        error: {
100
            try {
101
                // Convert non-request exception to a wrapped exception
102
                $trans->exception = RequestException::wrapException(
103
                    $trans->request, $trans->exception
104
                );
105
                $trans->state = 'end';
106
                $trans->request->getEmitter()->emit('error', new ErrorEvent($trans));
107
                // An intercepted request (not retried) transitions to complete
108
                if (!$trans->exception && $trans->state !== 'retry') {
109
                    $trans->state = 'complete';
110
                }
111
            } catch (\Exception $e) {
112
                $trans->state = 'end';
113
                $trans->exception = $e;
114
            }
115
            goto transition;
116
        }
117
118
        retry: {
119
            $trans->retries++;
120
            $trans->response = null;
121
            $trans->exception = null;
122
            $trans->state = 'before';
123
            goto transition;
124
        }
125
126
        send: {
127
            $fn = $this->handler;
128
            $trans->response = FutureResponse::proxy(
129
                $fn(RingBridge::prepareRingRequest($trans)),
130
                function ($value) use ($trans) {
131
                    RingBridge::completeRingResponse($trans, $value, $this->mf, $this);
132
                    $this($trans);
133
                    return $trans->response;
134
                }
135
            );
136
            return;
137
        }
138
139
        end: {
140
            $trans->request->getEmitter()->emit('end', new EndEvent($trans));
141
            // Throw exceptions in the terminal event if the exception
142
            // was not handled by an "end" event listener.
143
            if ($trans->exception) {
144
                if (!($trans->exception instanceof RequestException)) {
145
                    $trans->exception = RequestException::wrapException(
146
                        $trans->request, $trans->exception
147
                    );
148
                }
149
                throw $trans->exception;
150
            }
151
        }
152
    }
153
}
154