Completed
Push — master ( 020c5c...9dbce5 )
by Julián
08:49
created

ApnsAdapter::getDefaultParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 6
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
/**
3
 * Push notification services abstraction (http://github.com/juliangut/tify)
4
 *
5
 * @link https://github.com/juliangut/tify for the canonical source repository
6
 *
7
 * @license https://github.com/juliangut/tify/blob/master/LICENSE
8
 */
9
10
namespace Jgut\Tify\Adapter\Apns;
11
12
use Jgut\Tify\Adapter\AbstractAdapter;
13
use Jgut\Tify\Adapter\FeedbackAdapter;
14
use Jgut\Tify\Adapter\PushAdapter;
15
use Jgut\Tify\Exception\AdapterException;
16
use Jgut\Tify\Exception\NotificationException;
17
use Jgut\Tify\Notification;
18
use Jgut\Tify\Receiver\ApnsReceiver;
19
use Jgut\Tify\Result;
20
use ZendService\Apple\Exception\RuntimeException as ApnsRuntimeException;
21
22
/**
23
 * Class ApnsAdapter
24
 */
25
class ApnsAdapter extends AbstractAdapter implements PushAdapter, FeedbackAdapter
26
{
27
    const RESULT_OK = 0;
28
    const RESULT_UNAVAILABLE = 2048;
29
30
    /**
31
     * Status codes mapping.
32
     *
33
     * @var array
34
     */
35
    protected static $statusCodes = [
36
        0 => 'OK',
37
        1 => 'Processing Error',
38
        2 => 'Missing Device Token',
39
        3 => 'Missing Topic',
40
        4 => 'Missing Payload',
41
        5 => 'Invalid Token Size',
42
        6 => 'Invalid Topic Size',
43
        7 => 'Invalid Payload Size',
44
        8 => 'Invalid Token',
45
        10 => 'Shutdown',
46
        255 => 'Unknown Error',
47
        self::RESULT_UNAVAILABLE => 'Server Unavailable',
48
    ];
49
50
    /**
51
     * APNS service builder.
52
     *
53
     * @var \Jgut\Tify\Adapter\Apns\ApnsBuilder
54
     */
55
    protected $builder;
56
57
    /**
58
     * @var \ZendService\Apple\Apns\Client\Message
59
     */
60
    protected $pushClient;
61
62
    /**
63
     * @var \ZendService\Apple\Apns\Client\Feedback
64
     */
65
    protected $feedbackClient;
66
67
    /**
68
     * @param array                                    $parameters
69
     * @param bool                                     $sandbox
70
     * @param \Jgut\Tify\Adapter\Apns\ApnsBuilder|null $builder
71
     *
72
     * @throws \Jgut\Tify\Exception\AdapterException
73
     */
74
    public function __construct(array $parameters = [], $sandbox = false, ApnsBuilder $builder = null)
75
    {
76
        parent::__construct($parameters, $sandbox);
77
78
        $certificatePath = $this->getParameter('certificate');
79
80
        if (!file_exists($certificatePath) || !is_readable($certificatePath)) {
81
            throw new AdapterException(
82
                sprintf('Certificate file "%s" does not exist or is not readable', $certificatePath)
83
            );
84
        }
85
86
        // @codeCoverageIgnoreStart
87
        if ($builder === null) {
88
            $builder = new ApnsBuilder;
89
        }
90
        // @codeCoverageIgnoreEnd
91
        $this->builder = $builder;
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     *
97
     * @throws \InvalidArgumentException
98
     * @throws \Jgut\Tify\Exception\AdapterException
99
     * @throws \ZendService\Apple\Exception\RuntimeException
100
     */
101
    public function push(Notification $notification)
102
    {
103
        $client = $this->getPushClient();
104
105
        $pushResults = [];
106
107
        /* @var \ZendService\Apple\Apns\Message $message */
108
        foreach ($this->getPushMessages($notification) as $message) {
109
            $pushResult = new Result($message->getToken());
110
111
            try {
112
                $pushResponse = $client->send($message);
113
114
                if ($pushResponse->getCode() !== static::RESULT_OK) {
115
                    $pushResult->setStatus(Result::STATUS_ERROR);
116
                    $pushResult->setStatusMessage(self::$statusCodes[$pushResponse->getCode()]);
117
                }
118
            // @codeCoverageIgnoreStart
119
            } catch (ApnsRuntimeException $exception) {
120
                $pushResult->setStatus(Result::STATUS_ERROR);
121
122
                if (preg_match('/^Server is unavailable/', $exception->getMessage())) {
123
                    $pushResult->setStatusMessage(self::$statusCodes[self::RESULT_UNAVAILABLE]);
124
                } else {
125
                    $pushResult->setStatusMessage($exception->getMessage());
126
                }
127
            }
128
            // @codeCoverageIgnoreEnd
129
130
            $pushResults[] = $pushResult;
131
        }
132
133
        $client->close();
134
        $this->pushClient = null;
135
136
        return $pushResults;
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     *
142
     * @throws \InvalidArgumentException
143
     * @throws \Jgut\Tify\Exception\AdapterException
144
     * @throws \Jgut\Tify\Exception\NotificationException
145
     */
146
    public function feedback()
147
    {
148
        $client = $this->getFeedbackClient();
149
150
        $feedbackResults = [];
151
152
        try {
153
            /* @var \ZendService\Apple\Apns\Response\Feedback[] $feedbackResponses */
154
            $feedbackResponses = $client->feedback();
155
        // @codeCoverageIgnoreStart
156
        } catch (ApnsRuntimeException $exception) {
157
            throw new NotificationException($exception->getMessage(), $exception->getCode(), $exception);
158
        }
159
        // @codeCoverageIgnoreEnd
160
161
        foreach ($feedbackResponses as $response) {
162
            $feedbackResults[] = new Result($response->getToken(), $response->getTime());
163
        }
164
165
        $client->close();
166
        $this->feedbackClient = null;
167
168
        return $feedbackResults;
169
    }
170
171
    /**
172
     * Get opened ServiceClient
173
     *
174
     * @throws \Jgut\Tify\Exception\AdapterException
175
     *
176
     * @return \ZendService\Apple\Apns\Client\Message
177
     */
178
    protected function getPushClient()
179
    {
180
        if ($this->pushClient === null) {
181
            $this->pushClient = $this->builder->buildPushClient(
182
                $this->getParameter('certificate'),
183
                $this->getParameter('pass_phrase'),
184
                $this->sandbox
185
            );
186
        }
187
188
        return $this->pushClient;
189
    }
190
191
    /**
192
     * Get opened ServiceFeedbackClient
193
     *
194
     * @throws \Jgut\Tify\Exception\AdapterException
195
     *
196
     * @return \ZendService\Apple\Apns\Client\Feedback
197
     */
198
    protected function getFeedbackClient()
199
    {
200
        if ($this->feedbackClient === null) {
201
            $this->feedbackClient = $this->builder->buildFeedbackClient(
202
                $this->getParameter('certificate'),
203
                $this->getParameter('pass_phrase'),
204
                $this->sandbox
205
            );
206
        }
207
208
        return $this->feedbackClient;
209
    }
210
211
    /**
212
     * Get service formatted push messages.
213
     *
214
     * @param \Jgut\Tify\Notification $notification
215
     *
216
     * @throws \ZendService\Apple\Exception\RuntimeException
217
     *
218
     * @return \Generator
219
     */
220
    protected function getPushMessages(Notification $notification)
221
    {
222
        foreach ($notification->getReceivers() as $receiver) {
223
            if ($receiver instanceof ApnsReceiver) {
224
                yield $this->builder->buildPushMessage($receiver, $notification);
225
            }
226
        }
227
    }
228
229
    /**
230
     * {@inheritdoc}
231
     */
232
    protected function getDefinedParameters()
233
    {
234
        return ['certificate', 'pass_phrase'];
235
    }
236
237
    /**
238
     * {@inheritdoc}
239
     */
240
    protected function getDefaultParameters()
241
    {
242
        return [
243
            'pass_phrase' => null,
244
        ];
245
    }
246
247
    /**
248
     * {@inheritdoc}
249
     */
250
    protected function getRequiredParameters()
251
    {
252
        return ['certificate'];
253
    }
254
}
255