Issues (28)

src/Visits.php (2 issues)

1
<?php
2
3
namespace Awssat\Visits;
4
5
use Awssat\Visits\Models\Visit;
6
use Awssat\Visits\Traits\{Lists, Periods, Record, Setters};
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Support\Arr;
9
use Illuminate\Support\Str;
10
use Jaybizzle\CrawlerDetect\CrawlerDetect;
11
12
class Visits
13
{
14
    use Record, Lists, Periods, Setters;
15
16
    /**
17
     * @var mixed
18
     */
19
    protected $ipSeconds;
20
    /**
21
     * @var null
22
     */
23
    protected $subject;
24
    /**
25
     * @var bool|mixed
26
     */
27
    protected $fresh = false;
28
    /**
29
     * @var null|string
30
     */
31
    protected $country = null;
32
    /**
33
     * @var null|string
34
     */
35
    protected $referer = null;
36
    /**
37
     * @var null|string
38
     */
39
    protected $operatingSystem = null;
40
    /**
41
     * @var null|string
42
     */
43
    protected $language = null;
44
    /**
45
     * @var mixed
46
     */
47
    protected $periods;
48
    /**
49
     * @var Keys
50
     */
51
    protected $keys;
52
53
    /**
54
     * @var \Awssat\DataEngines\DataEngine
0 ignored issues
show
The type Awssat\DataEngines\DataEngine was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
55
     */
56
    protected $connection;
57
58
    /**
59
     * @var boolean
60
     */
61
    public $ignoreCrawlers = false;
62
    /**
63
     * @var array
64
     */
65
    public $globalIgnore = [];
66
67
    /**
68
     * @var array
69
     */
70
    public $config = [];
71
72
    /**
73
     * @param \Illuminate\Database\Eloquent\Model $subject any model
74
     * @param string $tag use only if you want to use visits on multiple models
75
     */
76
    public function __construct($subject = null, $tag = 'visits')
77
    {
78
        $this->config = config('visits');
79
80
        $this->connection = $this->determineConnection($this->config['engine'] ?? 'redis')
81
                                ->connect($this->config['connection'])
0 ignored issues
show
The method connect() does not exist on Illuminate\Contracts\Foundation\Application. ( Ignorable by Annotation )

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

81
                                ->/** @scrutinizer ignore-call */ connect($this->config['connection'])

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...
82
                                ->setPrefix($this->config['keys_prefix'] ?? $this->config['redis_keys_prefix'] ?? 'visits');
83
84
        if(! $this->connection) {
85
            return;
86
        }
87
88
        $this->periods = $this->config['periods'];
89
        $this->ipSeconds = $this->config['remember_ip'];
90
        $this->fresh = $this->config['always_fresh'];
91
        $this->ignoreCrawlers = $this->config['ignore_crawlers'];
92
        $this->globalIgnore = $this->config['global_ignore'];
93
        $this->subject = $subject;
94
        $this->keys = new Keys($subject, preg_replace('/[^a-z0-9_]/i', '', $tag));
95
96
        if (! empty($this->keys->id)) {
97
            $this->periodsSync();
98
        }
99
    }
100
101
    protected function determineConnection($name)
102
    {
103
        $connections = [
104
            'redis' => \Awssat\Visits\DataEngines\RedisEngine::class,
105
            'eloquent' => \Awssat\Visits\DataEngines\EloquentEngine::class
106
        ];
107
108
        if(! array_key_exists($name, $connections)) {
109
            throw new \Exception("(Laravel-Visits) The selected engine `{$name}` is not supported! Please correct this issue from config/visits.php.");
110
        }
111
112
        return app($connections[$name]);
113
    }
114
115
    /**
116
     * @param $subject
117
     * @return self
118
     */
119
    public function by($subject)
120
    {
121
        if($subject instanceof Model) {
122
            $this->keys->append($this->keys->modelName($subject), $subject->{$subject->getKeyName()});
123
        } else if (is_array($subject)) {
124
            $this->keys->append(array_keys($subject)[0], Arr::first($subject));
125
        }
126
127
        return $this;
128
    }
129
130
    /**
131
     * Reset methods
132
     *
133
     * @param $method
134
     * @param string $args
135
     * @return \Awssat\Visits\Reset
136
     */
137
    public function reset($method = 'visits', $args = '')
138
    {
139
        return new Reset($this, $method, $args);
140
    }
141
142
    /**
143
     * Check for the ip is has been recorded before
144
     * @return bool
145
     */
146
    public function recordedIp()
147
    {
148
        if(! $this->connection->exists($this->keys->ip(request()->ip()))) {
149
            $this->connection->set($this->keys->ip(request()->ip()), true);
150
            $this->connection->setExpiration($this->keys->ip(request()->ip()), $this->ipSeconds);
151
152
            return false;
153
        }
154
155
        return true;
156
    }
157
158
    /**
159
     * Get visits of model incount(stance.
160
     * @return mixed
161
     */
162
    public function count()
163
    {
164
        if ($this->country) {
165
            return $this->connection->get($this->keys->visits."_countries:{$this->keys->id}", $this->country);
166
        } else if ($this->referer) {
167
            return $this->connection->get($this->keys->visits."_referers:{$this->keys->id}", $this->referer);
168
        } else if ($this->operatingSystem) {
169
            return $this->connection->get($this->keys->visits."_OSes:{$this->keys->id}", $this->operatingSystem);
170
        } else if ($this->language) {
171
            return $this->connection->get($this->keys->visits."_languages:{$this->keys->id}", $this->language);
172
        }
173
174
        return intval(
175
            $this->keys->instanceOfModel
176
                    ? $this->connection->get($this->keys->visits, $this->keys->id)
177
                    : $this->connection->get($this->keys->visitsTotal())
178
        );
179
    }
180
181
    /**
182
     * @return integer time left in seconds
183
     */
184
    public function timeLeft()
185
    {
186
        return $this->connection->timeLeft($this->keys->visits);
187
    }
188
189
    /**
190
     * @return integer time left in seconds
191
     */
192
    public function ipTimeLeft()
193
    {
194
        return $this->connection->timeLeft($this->keys->ip(request()->ip()));
195
    }
196
197
    protected function isCrawler()
198
    {
199
        return $this->ignoreCrawlers && app(CrawlerDetect::class)->isCrawler();
200
    }
201
202
    /**
203
     * @param int $inc value to increment
204
     * @param bool $force force increment, skip time limit
205
     * @param array $ignore to ignore recording visits of periods, country, refer, language and operatingSystem. pass them on this array.
206
     * @return bool
207
     */
208
    public function increment($inc = 1, $force = false, $ignore = [])
209
    {
210
        if ($force || (!$this->isCrawler() && !$this->recordedIp())) {
211
   
212
            $this->connection->increment($this->keys->visits, $inc, $this->keys->id);
213
            $this->connection->increment($this->keys->visitsTotal(), $inc);
214
215
            if(is_array($this->globalIgnore) && sizeof($this->globalIgnore) > 0) {
216
                $ignore = array_merge($ignore, $this->globalIgnore);
217
            }
218
219
            //NOTE: $$method is parameter also .. ($periods,$country,$refer)
220
            foreach (['country', 'refer', 'periods', 'operatingSystem', 'language'] as $method) {
221
                if(! in_array($method, $ignore))  {
222
                    $this->{'record'.Str::studly($method)}($inc);
223
                }
224
            }
225
226
            return true;
227
        }
228
229
        return false;
230
    }
231
232
    /**
233
     * @param int $inc
234
     * @param array $ignore to ignore recording visits like country, periods ...
235
     * @return bool
236
     */
237
    public function forceIncrement($inc = 1, $ignore = [])
238
    {
239
        return $this->increment($inc, true, $ignore);
240
    }
241
242
    /**
243
     * Decrement a new/old subject to the cache cache.
244
     *
245
     * @param int $dec
246
     * @param array $ignore to ignore recording visits like country, periods ...
247
     * @return bool
248
     */
249
    public function decrement($dec = 1, $force = false, $ignore = [])
250
    {
251
        return $this->increment(-$dec, $force, $ignore);
252
    }
253
254
    /**
255
     * @param int $dec
256
     * @param array $ignore to ignore recording visits like country, periods ...
257
     * @return bool
258
     */
259
    public function forceDecrement($dec = 1, $ignore = [])
260
    {
261
        return $this->decrement($dec, true, $ignore);
262
    }
263
264
    /**
265
     * @param $period
266
     * @param int $time
267
     * @return bool
268
     */
269
    public function expireAt($period, $time)
270
    {
271
        $periodKey = $this->keys->period($period);
272
        return $this->connection->setExpiration($periodKey, $time);
273
    }
274
275
    /**
276
     * To be used with models to integrate relationship with visits model.
277
     * @return \Illuminate\Database\Eloquent\Relations\Relation 
278
     */
279
    public function relation()
280
    {
281
        $prefix = $this->config['keys_prefix'] ?? $this->config['redis_keys_prefix'] ?? 'visits';
282
        
283
        return $this->subject->hasOne(Visit::class, 'secondary_key')->where('primary_key', $prefix.':'.$this->keys->visits);
284
    }
285
}
286