Api::getPropertiesByDevices()   C
last analyzed

Complexity

Conditions 13
Paths 48

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 2 Features 0
Metric Value
cc 13
eloc 23
c 3
b 2
f 0
nc 48
nop 2
dl 0
loc 37
rs 6.6166

How to fix   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
/**
3
 * Created by PhpStorm.
4
 * User: sheldon
5
 * Date: 18-6-14
6
 * Time: 下午4:39.
7
 */
8
9
namespace MiotApi\Api;
10
11
use MiotApi\Contract\Instance\Instance;
12
use MiotApi\Exception\ApiErrorException;
13
14
/**
15
 * 更方便的API调用.
16
 *
17
 * Class Api
18
 */
19
class Api extends BaseApi
20
{
21
    /**
22
     * 一次性获取到包含了 serialNumber (原did)的设备列表.
23
     *
24
     * @return array|mixed
25
     */
26
    public function devicesList()
27
    {
28
        $devicesList = [];
29
        $devices = $this->devices();
30
31
        if (isset($devices['devices'])) {
32
            if (!empty($devices['devices'])) {
33
                foreach ($devices['devices'] as $device) {
34
                    $dids[] = $device['did'];
35
                    $device['serialNumber'] = null;
36
                    $devicesList[$device['did']] = $device;
37
                }
38
39
                $deviceInformations = $this->deviceInformation($dids);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dids seems to be defined by a foreach iteration on line 33. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
40
41
                if (isset($deviceInformations['device-information'])) {
42
                    foreach ($deviceInformations['device-information'] as $deviceInformation) {
43
                        if (isset($devicesList[$deviceInformation['id']])) {
44
                            $devicesList[$deviceInformation['id']]['serialNumber'] = $deviceInformation['serialNumber'];
45
                        }
46
                    }
47
                }
48
49
                return array_values($devicesList);
50
            } else {
51
                // 没有设备的情况
52
                return [];
53
            }
54
        } else {
55
            // 获取设备出错
56
            return $devices;
57
        }
58
    }
59
60
    /**
61
     * 按照名称获取属性.
62
     *
63
     * @param $did
64
     * @param $type
65
     * @param $data | $data = ['brightness', 'on']
0 ignored issues
show
Documentation Bug introduced by
The doc comment $data | at position 0 could not be parsed: Unknown type name '$data' at position 0 in $data |.
Loading history...
66
     *
67
     * @throws ApiErrorException
68
     * @throws \MiotApi\Exception\SpecificationErrorException
69
     *
70
     * @return array|bool|mixed
71
     */
72
    public function getPropertyGraceful($did, $type, $data)
73
    {
74
        $propertyData = [
75
            $did => [
76
                'type' => $type,
77
                'data' => $data,
78
            ],
79
        ];
80
81
        return $this->getPropertiesGraceful($propertyData);
82
    }
83
84
    /**
85
     * 按照名称获取多个设备属性.
86
     *
87
     * @param $data
88
     * $data = ['AABBCD-did' =>
89
     * ['type' => 'urn:miot-spec-v2:device:light:0000A001:yeelink-color1:1', data => ['brightness', 'on']]
90
     * ]
91
     *
92
     * @throws ApiErrorException
93
     * @throws \MiotApi\Exception\SpecificationErrorException
94
     *
95
     * @return array|bool|mixed
96
     */
97
    public function getPropertiesGraceful($data)
98
    {
99
        if (!empty($data)) {
100
            $properties = [];
101
            $attributes = [];
102
            $instances = [];
103
            foreach ($data as $did => $datum) {
104
                if (isset($datum['type'])) {
105
                    $instance = new Instance($datum['type']);
106
                    $propertiesNodes = $instance->getPropertiesNodes();
107
                    $instances[$did] = $propertiesNodes;
108
109
                    if (!empty($datum['data'])) {
110
                        foreach ($datum['data'] as $name) {
111
                            list($sids, $pids) = $instance->getSidPidByName($name);
112
113
                            if (!$sids || !$pids) {
114
                                throw new ApiErrorException('Invalid property! did:'.$did.',name: '.$name);
115
                            }
116
117
                            foreach ($sids as $sindex => $sid) {
118
                                $property = $propertiesNodes[($sid.'.'.$pids[$sindex])];
119
120
                                if (!$property->canRead()) {
121
                                    throw new ApiErrorException(
122
                                        'The property does\'t has the read access! did:'.$did.',name: '.$name
123
                                    );
124
                                }
125
126
                                $properties[] = $did.'.'.$sid.'.'.$pids[$sindex];
127
                            }
128
                        }
129
                    } else {
130
                        foreach ($propertiesNodes as $property) {
131
                            $name = $property->getUrn()->getName();
132
                            list($sids, $pids) = $instance->getSidPidByName($name);
133
134
                            if (!$sids || !$pids) {
135
                                throw new ApiErrorException('Invalid property! did:'.$did.',name: '.$name);
136
                            }
137
138
                            foreach ($sids as $sindex => $sid) {
139
                                $property = $propertiesNodes[($sid.'.'.$pids[$sindex])];
140
141
                                if ($property->canRead()) {
142
                                    $properties[] = $did.'.'.$sid.'.'.$pids[$sindex];
143
                                }
144
                            }
145
                        }
146
                    }
147
                } else {
148
                    throw new ApiErrorException('Properties data and device type required');
149
                }
150
            }
151
152
            $response = $this->properties(array_unique($properties));
153
            if (isset($response['properties']) && !empty($response['properties'])) {
154
                foreach ($response['properties'] as $res) {
155
                    $pidArr = explode('.', $res['pid']);
156
                    if (isset($res['value']) // 是否获取到了值
157
                        && isset($res['status']) // 是否有返回状态
158
                        && $res['status'] == 0 // 是否正常返回
159
                        && isset($pidArr[0]) // did
160
                        && isset($pidArr[1]) // sid
161
                        && isset($pidArr[2]) // pid
162
                        && isset($instances[$pidArr[0]][($pidArr[1].'.'.$pidArr[2])])) {
163
                        $attributeName = $instances[$pidArr[0]][($pidArr[1].'.'.$pidArr[2])]->getUrn()->getName();
164
165
                        if (isset($attributes[$pidArr[0]][$attributeName])) {
166
                            if (is_array($attributes[$pidArr[0]][$attributeName])) {
167
                                $attributes[$pidArr[0]][$attributeName][] = $res['value'];
168
                            } else {
169
                                $attributes[$pidArr[0]][$attributeName] = [
170
                                    $attributes[$pidArr[0]][$attributeName],
171
                                    $res['value'],
172
                                ];
173
                            }
174
                        } else {
175
                            $attributes[$pidArr[0]][$attributeName] = $res['value'];
176
                        }
177
                    }
178
                }
179
            }
180
181
            return $attributes;
182
        } else {
183
            throw new ApiErrorException('devices data required');
184
        }
185
    }
186
187
    /**
188
     * 按照名称设置属性.
189
     *
190
     * @param $did
191
     * @param $type
192
     * @param $data | $data = ['brightness' => 75, 'on' => true]
0 ignored issues
show
Documentation Bug introduced by
The doc comment $data | at position 0 could not be parsed: Unknown type name '$data' at position 0 in $data |.
Loading history...
193
     *
194
     * @throws ApiErrorException
195
     * @throws \MiotApi\Exception\JsonException
196
     * @throws \MiotApi\Exception\SpecificationErrorException
197
     *
198
     * @return array|bool|mixed
199
     */
200
    public function setPropertyGraceful($did, $type, $data)
201
    {
202
        if (!empty($data)) {
203
            $propertyData = [
204
                $did => [
205
                    'type' => $type,
206
                    'data' => $data,
207
                ],
208
            ];
209
210
            return $this->setPropertiesGraceful($propertyData);
211
        } else {
212
            throw new ApiErrorException('Properties data required');
213
        }
214
    }
215
216
    /**
217
     * 按照名称设置多个设备属性.
218
     *
219
     * @param $data
220
     * $data = ['AABBCD-did' =>
221
     * ['type' => 'urn:miot-spec-v2:device:light:0000A001:yeelink-color1:1', data => ['brightness' => 75, 'on' => true]]
222
     * ]
223
     *
224
     * @throws ApiErrorException
225
     * @throws \MiotApi\Exception\JsonException
226
     * @throws \MiotApi\Exception\SpecificationErrorException
227
     *
228
     * @return array|bool|mixed
229
     */
230
    public function setPropertiesGraceful($data)
231
    {
232
        if (!empty($data)) {
233
            $properties = [];
234
            foreach ($data as $did => $datum) {
235
                if (!empty($datum['data']) && isset($datum['type'])) {
236
                    $instance = new Instance($datum['type']);
237
                    $propertiesNodes = $instance->getPropertiesNodes();
238
239
                    foreach ($datum['data'] as $name => $value) {
240
                        list($sids, $pids) = $instance->getSidPidByName($name);
241
242
                        if (!$sids || !$pids) {
243
                            throw new ApiErrorException('Invalid property! did:'.$did.',name: '.$name);
244
                        }
245
246
                        foreach ($sids as $sindex => $sid) {
247
                            $property = $propertiesNodes[($sid.'.'.$pids[$sindex])];
248
249
                            if (!is_array($value)) {
250
                                $tmpValue = $value;
251
                            } else {
252
                                if (!isset($value[$sindex])) {
253
                                    continue;
254
                                }
255
                                $tmpValue = $value[$sindex];
256
                            }
257
258
                            if (!$property->verify($tmpValue)) {
259
                                throw new ApiErrorException('Invalid property value! did:'.$did.',name: '.$name);
260
                            }
261
262
                            if (!$property->canWrite()) {
263
                                throw new ApiErrorException(
264
                                    'The property does\'t has the write access! did:'.$did.',name: '.$name
265
                                );
266
                            }
267
268
                            $properties[] = [
269
                                'pid'   => $did.'.'.$sid.'.'.$pids[$sindex],
270
                                'value' => $tmpValue,
271
                            ];
272
                        }
273
                    }
274
                } else {
275
                    throw new ApiErrorException('Properties data and device type required');
276
                }
277
            }
278
279
            return $this->setProperties([
280
                'properties' => $properties,
281
            ]);
282
        } else {
283
            throw new ApiErrorException('devices data required');
284
        }
285
    }
286
287
    /**
288
     * 根据 devicesList 方法获取到的设备列表信息 订阅设备属性变化.
289
     *
290
     * @param $devices
291
     * @param $customData
292
     * @param $receiverUrl
293
     *
294
     * @throws \MiotApi\Exception\SpecificationErrorException
295
     *
296
     * @return array|bool|mixed
297
     */
298
    public function subscriptByDevices($devices, $customData, $receiverUrl)
299
    {
300
        $subscriptProperties = $this->getPropertiesByDevices($devices, ['notify']);
301
302
        return $this->subscript($subscriptProperties, $customData, $receiverUrl);
303
    }
304
305
    /**
306
     * 根据 devicesList 方法获取到的设备列表信息 退订设备属性变化.
307
     *
308
     * @param $devices
309
     *
310
     * @throws \MiotApi\Exception\SpecificationErrorException
311
     *
312
     * @return array|bool|mixed
313
     */
314
    public function unSubscriptByDevices($devices)
315
    {
316
        $subscriptProperties = $this->getPropertiesByDevices($devices, ['notify']);
317
318
        return $this->unSubscript($subscriptProperties);
319
    }
320
321
    /**
322
     * 根据设备列表和 access列表 获取对于访问方式的属性.
323
     *
324
     * @param $devices
325
     * @param array $access | ['read'] ['read', 'notify'] ['read', 'write', 'notify']
326
     *
327
     * @throws \MiotApi\Exception\SpecificationErrorException
328
     *
329
     * @return array|bool
330
     */
331
    protected function getPropertiesByDevices($devices, $access = [])
332
    {
333
        try {
334
            $properties = [];
335
            if (!empty($devices) && !isset($devices['status'])) {
336
                foreach ($devices as $device) {
337
                    $instance = new Instance($device['type']);
338
                    $propertiesNodes = $instance->getPropertiesNodes();
339
                    if (!empty($propertiesNodes)) {
340
                        foreach ($propertiesNodes as $index => $property) {
341
                            if (in_array('read', $access)) {
342
                                if ($property->canRead()) {
343
                                    $properties[] = $device['did'].'.'.$index;
344
                                }
345
                            }
346
                            if (in_array('write', $access)) {
347
                                if ($property->canWrite()) {
348
                                    $properties[] = $device['did'].'.'.$index;
349
                                }
350
                            }
351
                            if (in_array('notify', $access)) {
352
                                if ($property->canNotify()) {
353
                                    $properties[] = $device['did'].'.'.$index;
354
                                }
355
                            }
356
                        }
357
                    }
358
                }
359
            } else {
360
                throw new ApiErrorException('invalid devices lists');
361
            }
362
363
            return $properties;
364
        } catch (ApiErrorException $exception) {
365
            throw new ApiErrorException('Could not get properties by devices:'.$exception->getMessage());
366
367
            return false;
0 ignored issues
show
Unused Code introduced by
return false is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
368
        }
369
    }
370
}
371