Request   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Test Coverage

Coverage 96%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 16
eloc 52
c 2
b 0
f 0
dl 0
loc 138
ccs 24
cts 25
cp 0.96
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A setRequest() 0 6 3
A getApplicationId() 0 10 6
A checkSignature() 0 4 4
A fromAmazonRequest() 0 17 3
1
<?php
2
3
namespace MaxBeckers\AmazonAlexa\Request;
4
5
use MaxBeckers\AmazonAlexa\Exception\MissingRequestDataException;
6
use MaxBeckers\AmazonAlexa\Exception\MissingRequiredHeaderException;
7
use MaxBeckers\AmazonAlexa\Helper\PropertyHelper;
8
use MaxBeckers\AmazonAlexa\Request\Request\AbstractRequest;
9
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillAccountLinkedRequest;
10
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillDisabledRequest;
11
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillEnabledRequest;
12
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillPermissionAcceptedRequest;
13
use MaxBeckers\AmazonAlexa\Request\Request\AlexaSkillEvent\SkillPermissionChangedRequest;
14
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackFailedRequest;
15
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackFinishedRequest;
16
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackNearlyFinishedRequest;
17
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackStartedRequest;
18
use MaxBeckers\AmazonAlexa\Request\Request\AudioPlayer\PlaybackStoppedRequest;
19
use MaxBeckers\AmazonAlexa\Request\Request\CanFulfill\CanFulfillIntentRequest;
20
use MaxBeckers\AmazonAlexa\Request\Request\Display\ElementSelectedRequest;
21
use MaxBeckers\AmazonAlexa\Request\Request\GameEngine\InputHandlerEvent;
22
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\NextCommandIssued;
23
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\PauseCommandIssued;
24
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\PlayCommandIssued;
25
use MaxBeckers\AmazonAlexa\Request\Request\PlaybackController\PreviousCommandIssued;
26
use MaxBeckers\AmazonAlexa\Request\Request\Standard\IntentRequest;
27
use MaxBeckers\AmazonAlexa\Request\Request\Standard\LaunchRequest;
28
use MaxBeckers\AmazonAlexa\Request\Request\Standard\SessionEndedRequest;
29
use MaxBeckers\AmazonAlexa\Request\Request\System\ConnectionsResponseRequest;
30
use MaxBeckers\AmazonAlexa\Request\Request\System\ExceptionEncounteredRequest;
31
32
/**
33
 * @author Maximilian Beckers <[email protected]>
34
 */
35
class Request
36
{
37
    /**
38
     * List of all supported amazon request types.
39
     */
40
    const REQUEST_TYPES = [
41
        // Standard types
42
        IntentRequest::TYPE                  => IntentRequest::class,
43
        LaunchRequest::TYPE                  => LaunchRequest::class,
44
        SessionEndedRequest::TYPE            => SessionEndedRequest::class,
45
        // AudioPlayer types
46
        PlaybackStartedRequest::TYPE         => PlaybackStartedRequest::class,
47
        PlaybackNearlyFinishedRequest::TYPE  => PlaybackNearlyFinishedRequest::class,
48
        PlaybackFinishedRequest::TYPE        => PlaybackFinishedRequest::class,
49
        PlaybackStoppedRequest::TYPE         => PlaybackStoppedRequest::class,
50
        PlaybackFailedRequest::TYPE          => PlaybackFailedRequest::class,
51
        // PlaybackController types
52
        NextCommandIssued::TYPE              => NextCommandIssued::class,
53
        PauseCommandIssued::TYPE             => PauseCommandIssued::class,
54
        PlayCommandIssued::TYPE              => PlayCommandIssued::class,
55
        PreviousCommandIssued::TYPE          => PreviousCommandIssued::class,
56
        // System types
57
        ExceptionEncounteredRequest::TYPE    => ExceptionEncounteredRequest::class,
58
        // Display types
59
        ElementSelectedRequest::TYPE         => ElementSelectedRequest::class,
60
        // Game engine types
61
        InputHandlerEvent::TYPE              => InputHandlerEvent::class,
62
        // can fulfill intent
63
        CanFulfillIntentRequest::TYPE        => CanFulfillIntentRequest::class,
64
        // Connections Response Request
65
        ConnectionsResponseRequest::TYPE     => ConnectionsResponseRequest::class,
66
        // Skill event types
67
        SkillAccountLinkedRequest::TYPE      => SkillAccountLinkedRequest::class,
68
        SkillEnabledRequest::TYPE            => SkillEnabledRequest::class,
69
        SkillDisabledRequest::TYPE           => SkillDisabledRequest::class,
70
        SkillPermissionAcceptedRequest::TYPE => SkillPermissionAcceptedRequest::class,
71
        SkillPermissionChangedRequest::TYPE  => SkillPermissionChangedRequest::class,
72
    ];
73
74
    /**
75
     * @var string|null
76
     */
77
    public $version;
78
79
    /**
80
     * @var Session|null
81
     */
82
    public $session;
83
84
    /**
85
     * @var Context|null
86
     */
87
    public $context;
88
89
    /**
90
     * @var AbstractRequest|null
91
     */
92
    public $request;
93
94
    /**
95
     * @var string
96
     */
97
    public $amazonRequestBody;
98
99
    /**
100
     * @var string
101
     */
102
    public $signatureCertChainUrl;
103
104
    /**
105
     * @var string
106
     */
107
    public $signature;
108
109
    /**
110
     * @param string $amazonRequestBody
111
     * @param string $signatureCertChainUrl
112
     * @param string $signature
113
     *
114
     * @throws MissingRequiredHeaderException
115
     * @throws MissingRequestDataException
116
     *
117
     * @return Request
118
     */
119 44
    public static function fromAmazonRequest(string $amazonRequestBody, string $signatureCertChainUrl, string $signature): self
120
    {
121 44
        $request = new self();
122
123 44
        $request->signatureCertChainUrl = $signatureCertChainUrl;
124 44
        $request->signature             = $signature;
125 44
        $request->amazonRequestBody     = $amazonRequestBody;
126 44
        $amazonRequest                  = (array) json_decode($amazonRequestBody, true);
127
128 44
        $request->version = PropertyHelper::checkNullValueString($amazonRequest, 'version');
129 44
        $request->session = isset($amazonRequest['session']) ? Session::fromAmazonRequest($amazonRequest['session']) : null;
130 44
        $request->context = isset($amazonRequest['context']) ? Context::fromAmazonRequest($amazonRequest['context']) : null;
131
132 44
        $request->setRequest($amazonRequest);
133 43
        $request->checkSignature();
134
135 42
        return $request;
136
    }
137
138
    /**
139
     * @return string|null
140
     */
141 3
    public function getApplicationId()
142
    {
143
        // workaround for developer console
144 3
        if ($this->session && $this->session->application) {
145 1
            return $this->session->application->applicationId;
146 2
        } elseif ($this->context && ($system = $this->context->system) && $system->application) {
147 2
            return $system->application->applicationId;
148
        }
149
150
        return null;
151
    }
152
153
    /**
154
     * @param array $amazonRequest
155
     *
156
     * @throws MissingRequestDataException
157
     */
158 44
    private function setRequest(array $amazonRequest)
159
    {
160 44
        if (!isset($amazonRequest['request']['type']) || !isset(self::REQUEST_TYPES[$amazonRequest['request']['type']])) {
161 1
            throw new MissingRequestDataException();
162
        }
163 43
        $this->request = (self::REQUEST_TYPES[$amazonRequest['request']['type']])::fromAmazonRequest($amazonRequest['request']);
164
    }
165
166
    /**
167
     * @throws MissingRequiredHeaderException
168
     */
169 43
    private function checkSignature()
170
    {
171 43
        if ($this->request->validateSignature() && (!$this->signatureCertChainUrl || !$this->signature)) {
0 ignored issues
show
Bug introduced by
The method validateSignature() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

171
        if ($this->request->/** @scrutinizer ignore-call */ validateSignature() && (!$this->signatureCertChainUrl || !$this->signature)) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
172 1
            throw new MissingRequiredHeaderException();
173
        }
174
    }
175
}
176