Completed
Push — master ( 7f0e8c...703bff )
by
unknown
08:31 queued 06:54
created

DbDriver   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 91.43%

Importance

Changes 3
Bugs 2 Features 0
Metric Value
wmc 28
lcom 1
cbo 6
dl 0
loc 225
ccs 96
cts 105
cp 0.9143
rs 10
c 3
b 2
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A setDestination() 0 10 2
A getDestination() 0 8 2
A getContent() 0 8 2
A getSendersArray() 0 10 2
B generateUDH() 0 26 1
A send() 0 18 4
A setContent() 0 16 3
A setSender() 0 16 3
A getSender() 0 8 2
A getDefaultSender() 0 18 3
B parseLongMessage() 0 38 3
1
<?php
2
3
namespace NotificationChannels\Gammu\Drivers;
4
5
use Illuminate\Contracts\Config\Repository;
6
use NotificationChannels\Gammu\Models\Outbox;
7
use NotificationChannels\Gammu\Models\OutboxMultipart;
8
use NotificationChannels\Gammu\Models\Phone;
9
use NotificationChannels\Gammu\Exceptions\CouldNotSendNotification;
10
use Exception;
11
12
class DbDriver extends DriverAbstract
13
{
14
    protected $config;
15
16
    protected $outbox;
17
18
    protected $multipart;
19
20
    protected $phone;
21
22
    protected $data = [];
23
24
    protected $chunks = [];
25
26
    public $isLongSms = false;
27
28
    public $sender;
29
30
    private $minLongSmsChar = 160;
31
32 20
    public function __construct(
33
        Repository $config, Outbox $outbox, OutboxMultipart $multipart, Phone $phone
34
    ) {
35 20
        $this->config = $config;
36 20
        $this->outbox = $outbox;
37 20
        $this->multipart = $multipart;
38 20
        $this->phone = $phone;
39
40 20
        $this->data['CreatorID'] = $this->getSignature();
41 20
    }
42
43 1
    public function send($phoneNumber, $content, $sender = null, $callback = null)
44
    {
45 1
        $this->setDestination($phoneNumber);
46 1
        $this->setContent($content);
47 1
        $this->setSender($sender);
48
49
        // Check Destination
50 1
        $this->getDestination();
51
52 1
        $outbox = $this->outbox->create($this->data);
53
54 1
        if (! empty($this->chunks) && ! empty($outbox->ID)) {
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<NotificationChannels\Gammu\Models\Outbox>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
55
            foreach ($this->chunks as $chunk) {
56
                $chunk['ID'] = $outbox->ID;
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<NotificationChannels\Gammu\Models\Outbox>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
57
                $this->multipart->create($chunk);
58
            }
59
        }
60 1
    }
61
62 3
    public function setDestination($phoneNumber)
63
    {
64 3
        if (empty($phoneNumber)) {
65 1
            throw CouldNotSendNotification::destinationNotProvided();
66
        }
67
68 2
        $this->data['DestinationNumber'] = $this->destination = trim($phoneNumber);
69
70 2
        return $this;
71
    }
72
73 3
    public function getDestination()
74
    {
75 3
        if (empty($this->data['DestinationNumber'])) {
76 1
            throw CouldNotSendNotification::destinationNotProvided();
77
        }
78
79 2
        return $this->destination;
80
    }
81
82 5
    public function setContent($content)
83
    {
84 5
        if (empty($content)) {
85 1
            throw CouldNotSendNotification::contentNotProvided();
86
        }
87
88 4
        $this->content = $content;
89
90 4
        if (strlen($content) > $this->minLongSmsChar) {
91 1
            $this->parseLongMessage($content);
92 1
        } else {
93 3
            $this->data['TextDecoded'] = $content;
94
        }
95
96 4
        return $this;
97
    }
98
99 3
    public function getContent()
100
    {
101 3
        if (empty($this->content)) {
102 1
            throw CouldNotSendNotification::contentNotProvided();
103
        }
104
105 2
        return $this->content;
106
    }
107
108 2
    public function setSender($sender = null)
109
    {
110 2
        if (empty($sender)) {
111 1
            $sender = $this->getDefaultSender();
112
        }
113
114 1
        $senders = $this->getSendersArray();
115
116 1
        if (! in_array($sender, $senders)) {
117
            return $this->getSender();
118
        }
119
120 1
        $this->data['SenderID'] = $this->sender = $sender;
121
122 1
        return $this;
123
    }
124
125 9
    public function getSender()
126
    {
127 9
        if (empty($this->sender)) {
128 8
            $this->sender = $this->getDefaultSender();
129 6
        }
130
131 7
        return $this->sender;
132
    }
133
134 9
    private function getDefaultSender()
135
    {
136 9
        $sender = $this->config->get('services.gammu.sender');
137
138 9
        $senders = $this->getSendersArray();
139
140 6
        if (in_array($sender, $senders)) {
141 2
            $this->sender = $sender;
142
143 2
            return $this->sender;
144
        }
145
146
        try {
147 4
            return $this->phone->where('Send', 'yes')->firstOrFail()->ID;
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<NotificationChannels\Gammu\Models\Phone>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
148
        } catch (Exception $e) {
149
            throw CouldNotSendNotification::senderNotProvided();
150
        }
151
    }
152
153 10
    private function getSendersArray()
154
    {
155 10
        $senders = $this->phone->where('Send', 'yes')->get()->pluck('ID')->toArray();
0 ignored issues
show
Documentation Bug introduced by
The method where does not exist on object<NotificationChannels\Gammu\Models\Phone>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
156
157 10
        if (empty($senders)) {
158 3
            throw CouldNotSendNotification::senderNotProvided();
159
        }
160
161 7
        return $senders;
162
    }
163
164
    /**
165
     * Generate UDH part for long SMS.
166
     *
167
     * @link https://en.wikipedia.org/wiki/Concatenated_SMS#Sending_a_concatenated_SMS_using_a_User_Data_Header
168
     *
169
     * @return string
170
     */
171 2
    private function generateUDH($total = 2, $sequence = 2, $ref = 0)
172
    {
173
        // Length of User Data Header, in this case 05
174 2
        $octet1 = '05';
175
176
        // Information Element Identifier, equal to 00 (Concatenated short messages, 8-bit reference number)
177 2
        $octet2 = '00';
178
179
        // Length of the header, excluding the first two fields; equal to 03
180 2
        $octet3 = '03';
181
182
        // CSMS reference number, must be same for all the SMS parts in the CSMS
183 2
        $octet4 = str_pad(dechex($ref), 2, '0', STR_PAD_LEFT);
184
185
        // Total number of parts
186 2
        $octet5 = str_pad(dechex($total), 2, '0', STR_PAD_LEFT);
187
188
        // Part sequence
189 2
        $octet6 = str_pad(dechex($sequence), 2, '0', STR_PAD_LEFT);
190
191 2
        $udh = collect([
192 2
            $octet1, $octet2, $octet3, $octet4, $octet5, $octet6,
193 2
        ])->implode('');
194
195 2
        return strtoupper($udh);
196
    }
197
198 3
    protected function parseLongMessage($content)
199
    {
200 3
        if (strlen($content) <= $this->minLongSmsChar) {
201 1
            return $this;
202
        }
203
204
        // Parse message to chunks
205
        // @ref: http://www.nowsms.com/long-sms-text-messages-and-the-160-character-limit
206 2
        $messages = str_split($content, 153);
207 2
        $messages = collect($messages);
208 2
        $messagesCount = $messages->count();
209
210
        // Get first message
211 2
        $firstChunk = $messages->shift();
212
213
        // Generate UDH
214 2
        $ref = mt_rand(0, 255);
215 2
        $i = 1;
216 2
        $firstUDH = $this->generateUDH($messagesCount, $i, $ref);
217 2
        ++$i;
218
219 2
        $this->data['TextDecoded'] = $firstChunk;
220 2
        $this->data['UDH'] = $firstUDH;
221 2
        $this->data['MultiPart'] = 'true';
222
223 2
        foreach ($messages as $chunk) {
224 2
            array_push($this->chunks, [
225 2
                'UDH' => $this->generateUDH($messagesCount, $i, $ref),
226 2
                'TextDecoded' => $chunk,
227 2
                'SequencePosition' => $i,
228 2
            ]);
229 2
            ++$i;
230 2
        }
231
232 2
        $this->isLongSms = true;
233
234 2
        return $this;
235
    }
236
}
237