Completed
Push — master ( 27ba4c...6ae628 )
by Elf
02:02
created

Client::instance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
3
namespace ElfSundae\Laravel\Agent;
4
5
use Jenssegers\Agent\Agent;
6
use Illuminate\Support\Fluent;
7
use ElfSundae\Laravel\Helper\Traits\FluentArrayAccess;
8
9
/**
10
 * The app client.
11
 *
12
 * @property string os
13
 * @property string osVersion
14
 * @property string platform
15
 * @property string locale
16
 * @property string app
17
 * @property string appVersion
18
 * @property string appChannel
19
 * @property string network
20
 * @property string udid
21
 */
22
class Client extends Fluent
23
{
24
    use FluentArrayAccess;
25
26
    /**
27
     * The Agent instance.
28
     *
29
     * @var \Jenssegers\Agent\Agent
30
     */
31
    protected $agent;
32
33
    /**
34
     * Return this instance.
35
     *
36
     * @return $this
37
     */
38
    public function instance()
39
    {
40
        return $this;
41
    }
42
43
    /**
44
     * Get the Agent instance.
45
     *
46
     * @return \Jenssegers\Agent\Agent
47
     */
48
    public function agent()
49
    {
50
        return $this->agent;
51
    }
52
53
    /**
54
     * Set the Agent instance.
55
     *
56
     * @param  \Jenssegers\Agent\Agent  $agent
57
     * @return $this
58
     */
59
    public function setAgent(Agent $agent)
60
    {
61
        $this->agent = $agent;
62
63
        return $this->parseAgent();
64
    }
65
66
    /**
67
     * Merge new data into the current attributes.
68
     *
69
     * @param  array  ...$data
70
     * @return $this
71
     */
72
    public function add(array ...$data)
73
    {
74
        $this->attributes = array_replace($this->attributes, ...$data);
75
76
        return $this;
77
    }
78
79
    /**
80
     * Set a given attribute value.
81
     *
82
     * @param  array|string  $key
83
     * @param  mixed   $value
84
     * @return $this
85
     */
86
    public function set($key, $value = null)
87
    {
88
        $data = is_array($key) ? $key : [$key => $value];
89
90
        return $this->add($data);
91
    }
92
93
    /**
94
     * Check the version of the given property in the User-Agent.
95
     *
96
     * @param  string  $propertyName
97
     * @return string|float|false
98
     *
99
     * @see \Jenssegers\Agent\Agent::version()
100
     */
101
    public function version($propertyName, $type = Agent::VERSION_TYPE_STRING)
102
    {
103
        $version = $this->agent->version($propertyName, $type);
104
105
        return is_string($version) ? str_replace(['_', '+'], '.', $version) : $version;
106
    }
107
108
    /**
109
     * Check a certain value exists, case insensitived.
110
     *
111
     * @param  string  $value
112
     * @return bool
113
     */
114
    public function is($value)
115
    {
116
        return in_arrayi($value, $this->attributes) ||
117
            in_arrayi('is'.$value, array_keys($this->attributes)) ||
118
            $this->agent->is($value);
119
    }
120
121
    /**
122
     * Get or check the current app channel.
123
     *
124
     * @return string|bool
125
     */
126
    public function appChannel()
127
    {
128
        $appChannel = $this->get('appChannel');
129
130
        if (func_num_args() > 0) {
131
            $checks = is_array(func_get_arg(0)) ? func_get_arg(0) : func_get_args();
132
133
            return $appChannel ? in_arrayi($appChannel, $checks) : false;
134
        }
135
136
        return $appChannel;
137
    }
138
139
    /**
140
     * Set the User-Agent to be used.
141
     *
142
     * @param  string  $userAgent
143
     * @return $this
144
     */
145
    public function setUserAgent($userAgent = null)
146
    {
147
        $this->agent->setUserAgent($userAgent);
148
149
        return $this->parseAgent();
150
    }
151
152
    /**
153
     * Parse Agent information.
154
     *
155
     * @return $this
156
     */
157
    protected function parseAgent()
158
    {
159
        return $this->add(
160
            $this->parseCommonClient(),
161
            $this->parseAppClient()
162
        );
163
    }
164
165
    /**
166
     * Parse common client.
167
     *
168
     * @return array
169
     */
170
    protected function parseCommonClient()
171
    {
172
        $info = [
173
            'os' => $this->agent->platform(),
174
            'osVersion' => $this->version($this->agent->platform()),
175
            'platform' => $this->agent->device(),
176
            'locale' => head($this->agent->languages()),
177
        ];
178
179
        if ($this->agent->is('iOS')) {
180
            $info['os'] = 'iOS';
181
        }
182
183
        if ($this->agent->is('AndroidOS')) {
184
            $info['os'] = 'Android';
185
        }
186
187
        if (is_string($this->version('MicroMessenger'))) {
188
            $info['isWechat'] = true;
189
        } else {
190
            unset($info['isWechat']);
191
        }
192
193
        return array_filter($info);
194
    }
195
196
    /**
197
     * Parse app client from the User-Agent.
198
     *
199
     * @example `Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12H143 _ua(eyJuZXQiOiJXaUZpIiwib3MiOiJpT1MiLCJhcHBWIjoiMC4xLjIiLCJvc1YiOiI4LjQiLCJhcHAiOiJndXBpYW8iLCJhcHBDIjoiRGVidWciLCJ0ZGlkIjoiaDNiYjFmNTBhYzBhMzdkYmE4ODhlMTgyNjU3OWJkZmZmIiwiYWNpZCI6IjIxZDNmYmQzNDNmMjViYmI0MzU2ZGEyMmJmZjUxZDczZjg0YWQwNmQiLCJsb2MiOiJ6aF9DTiIsInBmIjoiaVBob25lNywxIn0)`
200
     *
201
     * @return array
202
     */
203
    protected function parseAppClient()
204
    {
205
        $data = $this->getAppClientAttributes(
206
            $this->getAppClientData($this->agent->getUserAgent())
207
        );
208
209
        if (empty($data)) {
210
            $this->resetAppClientAttributes();
211
        }
212
213
        return $data;
214
    }
215
216
    /**
217
     * Get app client information from the User-Agent.
218
     *
219
     * @param  string  $userAgent
220
     * @return array
221
     */
222
    protected function getAppClientData($userAgent)
223
    {
224
        if (preg_match('#client\((.+)\)#is', $userAgent, $matches)) {
225
            if ($info = json_decode(urlsafe_base64_decode($matches[1]), true)) {
226
                if (is_array($info) && ! empty($info)) {
227
                    return $info;
228
                }
229
            }
230
        }
231
232
        return [];
233
    }
234
235
    /**
236
     * Get app client attributes.
237
     *
238
     * @param  array  $info
239
     * @return array
240
     */
241
    protected function getAppClientAttributes($info)
242
    {
243
        $info = array_filter($info);
244
        $data = [];
245
246
        if (
247
            ($data['os'] = array_get($info, 'os')) &&
248
            ($data['osVersion'] = array_get($info, 'osV')) &&
249
            ($data['platform'] = array_get($info, 'pf')) &&
250
            ($data['locale'] = array_get($info, 'loc')) &&
251
            ($data['app'] = array_get($info, 'app')) &&
252
            ($data['appVersion'] = array_get($info, 'appV')) &&
253
            ($data['appChannel'] = array_get($info, 'appC')) &&
254
            ($data['network'] = array_get($info, 'net')) &&
255
            ($data['udid'] = array_get($info, 'udid'))
256
        ) {
257
            if ($data['os'] === 'iPhone OS') {
258
                $data['os'] = 'iOS';
259
            }
260
261
            $data['isAppClient'] = true;
262
263
            return array_filter($data);
264
        }
265
266
        return [];
267
    }
268
269
    /**
270
     * Reset app client attributes.
271
     */
272
    protected function resetAppClientAttributes()
273
    {
274
        unset(
275
            $this->attributes['app'],
276
            $this->attributes['appVersion'],
277
            $this->attributes['appChannel'],
278
            $this->attributes['network'],
279
            $this->attributes['udid'],
280
            $this->attributes['isAppClient']
281
        );
282
    }
283
284
    /**
285
     * Handle dynamic calls to the Agent instance.
286
     *
287
     * @param  string  $method
288
     * @param  array  $parameters
289
     * @return mixed
290
     */
291
    public function __call($method, $parameters)
292
    {
293
        return call_user_func_array([$this->agent, $method], $parameters);
294
    }
295
}
296