Completed
Push — master ( 1bbaa3...197cbb )
by Ehsan
08:36
created

AbstractBaseListener   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 93.24%

Importance

Changes 0
Metric Value
wmc 30
lcom 2
cbo 2
dl 0
loc 234
ccs 69
cts 74
cp 0.9324
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A listen() 0 21 3
extractRequest() 0 1 ?
getChannelId() 0 1 ?
B getRequest() 0 16 5
A setRequest() 0 4 1
A getConfig() 0 8 2
A setConfig() 0 4 1
verifyOrigin() 0 1 ?
isThisBot() 0 1 ?
A getRequestUtility() 0 8 2
A setRequestUtility() 0 4 1
B respondOK() 0 36 3
A verifyRequest() 0 18 4
A determineAction() 0 15 4
A getMessage() 0 12 4
1
<?php
2
3
namespace Botonomous\listener;
4
5
use Botonomous\Config;
6
use Botonomous\Event;
7
use Botonomous\utility\RequestUtility;
8
9
abstract class AbstractBaseListener
10
{
11
    private $config;
12
    private $request;
13
    private $requestUtility;
14
15
    /**
16
     * listen.
17
     *
18
     * @return mixed
19
     */
20 9
    public function listen()
21
    {
22
        // This is needed otherwise timeout error is displayed
23 9
        $this->respondOK();
24
25 9
        $request = $this->extractRequest();
26
27 9
        if (empty($request)) {
28
            /* @noinspection PhpInconsistentReturnPointsInspection */
29 5
            return;
30
        }
31
32 4
        $this->setRequest($request);
33
34 4
        if ($this->isThisBot() !== false) {
35
            /* @noinspection PhpInconsistentReturnPointsInspection */
36 2
            return;
37
        }
38
39 2
        return $request;
40
    }
41
42
    /**
43
     * @return mixed
44
     */
45
    abstract public function extractRequest();
46
47
    /**
48
     * @return string
49
     */
50
    abstract public function getChannelId();
51
52
    /**
53
     * @param null|string $key
54
     *
55
     * @return mixed
56
     */
57 36
    public function getRequest($key = null)
58
    {
59 36
        if (!isset($this->request)) {
60
            // each listener has its own way of extracting the request
61 10
            $this->setRequest($this->extractRequest());
62
        }
63
64 36
        if ($key === null) {
65
            // return the entire request since key is null
66 18
            return $this->request;
67
        }
68
69 26
        if (is_array($this->request) && array_key_exists($key, $this->request)) {
70 24
            return $this->request[$key];
71
        }
72 9
    }
73
74
    /**
75
     * @param array $request
76
     */
77 44
    public function setRequest($request)
78
    {
79 44
        $this->request = $request;
80 44
    }
81
82
    /**
83
     * @return Config
84
     */
85 8
    public function getConfig()
86
    {
87 8
        if (!isset($this->config)) {
88 5
            $this->setConfig(new Config());
89
        }
90
91 8
        return $this->config;
92
    }
93
94
    /**
95
     * @param Config $config
96
     */
97 12
    public function setConfig($config)
98
    {
99 12
        $this->config = $config;
100 12
    }
101
102
    /**
103
     * Verify the request comes from Slack
104
     * Each listener must have have this and has got its own way to check the request.
105
     *
106
     * @throws \Exception
107
     *
108
     * @return array
109
     */
110
    abstract public function verifyOrigin();
111
112
    /**
113
     * Check if the request belongs to the bot itself.
114
     *
115
     * @throws \Exception
116
     *
117
     * @return bool
118
     */
119
    abstract public function isThisBot();
120
121
    /**
122
     * @return RequestUtility
123
     */
124 23
    public function getRequestUtility()
125
    {
126 23
        if (!isset($this->requestUtility)) {
127 7
            $this->setRequestUtility((new RequestUtility()));
128
        }
129
130 23
        return $this->requestUtility;
131
    }
132
133
    /**
134
     * @param RequestUtility $requestUtility
135
     */
136 24
    public function setRequestUtility(RequestUtility $requestUtility)
137
    {
138 24
        $this->requestUtility = $requestUtility;
139 24
    }
140
141
    /**
142
     * respondOK.
143
     */
144 9
    protected function respondOK()
145
    {
146
        // check if fastcgi_finish_request is callable
147 9
        if (is_callable('fastcgi_finish_request')) {
148
            /*
149
             * http://stackoverflow.com/a/38918192
150
             * This works in Nginx but the next approach not
151
             */
152
            session_write_close();
153
            fastcgi_finish_request();
154
155
            /* @noinspection PhpInconsistentReturnPointsInspection */
156
            return;
157
        }
158
159 9
        ignore_user_abort(true);
160
161 9
        ob_start();
162 9
        header($this->getRequestUtility()->getServerProtocol().' 200 OK');
163
        // Disable compression (in case content length is compressed).
164 9
        header('Content-Encoding: none');
165 9
        header('Content-Length: '.ob_get_length());
166
167
        // Close the connection.
168 9
        header('Connection: close');
169
170 9
        ob_end_flush();
171
        // only if an output buffer is active do ob_flush
172 9
        if (ob_get_level() > 0) {
173 9
            ob_flush();
174
        }
175
176 9
        flush();
177
178
        /* @noinspection PhpInconsistentReturnPointsInspection */
179 9
    }
180
181
    /**
182
     * @throws \Exception
183
     *
184
     * @return array<string,boolean|string>
185
     */
186 4
    public function verifyRequest()
187
    {
188 4
        $originCheck = $this->verifyOrigin();
189
190 4
        if (!isset($originCheck['success'])) {
191
            throw new \Exception('Success must be provided in verifyOrigin response');
192
        }
193
194 4
        if ($originCheck['success'] !== true) {
195
            return ['success' => false, 'message' => $originCheck['message']];
196
        }
197
198 4
        if ($this->isThisBot() !== false) {
199 1
            return ['success' => false, 'message' => 'Request comes from the bot'];
200
        }
201
202 3
        return ['success' => true, 'message' => 'Yay!'];
203
    }
204
205
    /**
206
     * @return string|null
207
     */
208 7
    public function determineAction()
209
    {
210 7
        $utility = $this->getRequestUtility();
211 7
        $getRequest = $utility->getGet();
212
213 7
        if (!empty($getRequest['action'])) {
214 2
            return strtolower($getRequest['action']);
215
        }
216
217 5
        $request = $utility->getPostedBody();
218
219 5
        if (isset($request['type']) && $request['type'] === 'url_verification') {
220 1
            return 'url_verification';
221
        }
222 4
    }
223
224
    /**
225
     * Return message based on the listener
226
     * If listener is event and event text is empty, fall back to request text.
227
     *
228
     * @return mixed|string
229
     */
230 11
    public function getMessage()
231
    {
232 11
        if ($this instanceof EventListener && $this->getEvent() instanceof Event) {
233 1
            $message = $this->getEvent()->getText();
234
235 1
            if (!empty($message)) {
236 1
                return $message;
237
            }
238
        }
239
240 10
        return $this->getRequest('text');
241
    }
242
}
243