├── .gitignore
├── composer.json
├── readme.md
└── src
├── Console
├── MetricsMakeCommand.php
├── MetricsTableCommand.php
└── stubs
│ ├── metrics.count.stub
│ ├── metrics.stub
│ └── metrics.time.stub
├── Exceptions
└── NotUserClassException.php
├── Metricable.php
├── Metrics.php
├── MetricsServiceProvider.php
├── MetricsStatistics.php
├── Types
├── CountMetrics.php
└── TimeMetrics.php
└── config
└── config.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | /node_modules
3 | composer.lock
4 |
5 |
6 | # Laravel
7 | /bootstrap/compiled.php
8 | .env.*.php
9 | .env.php
10 | .env
11 |
12 | # Windows image file caches
13 | Thumbs.db
14 | ehthumbs.db
15 |
16 | # Folder config file
17 | Desktop.ini
18 |
19 | # Recycle Bin used on file shares
20 | $RECYCLE.BIN/
21 |
22 | # Windows Installer files
23 | *.cab
24 | *.msi
25 | *.msm
26 | *.msp
27 |
28 | # Windows shortcuts
29 | *.lnk
30 |
31 | # Netbeans
32 | nbproject/private/
33 | build/
34 | nbbuild/
35 | dist/
36 | nbdist/
37 | nbactions.xml
38 | nb-configuration.xml
39 | .nb-gradle/
40 |
41 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
42 |
43 | *.iml
44 |
45 | ## Directory-based project format:
46 | .idea/
47 | # if you remove the above rule, at least ignore the following:
48 |
49 | # User-specific stuff:
50 | # .idea/workspace.xml
51 | # .idea/tasks.xml
52 | # .idea/dictionaries
53 |
54 | # Sensitive or high-churn files:
55 | # .idea/dataSources.ids
56 | # .idea/dataSources.xml
57 | # .idea/sqlDataSources.xml
58 | # .idea/dynamic.xml
59 | # .idea/uiDesigner.xml
60 |
61 | # Gradle:
62 | # .idea/gradle.xml
63 | # .idea/libraries
64 |
65 | # Mongo Explorer plugin:
66 | # .idea/mongoSettings.xml
67 |
68 | ## File-based project format:
69 | *.ipr
70 | *.iws
71 |
72 | ## Plugin-specific files:
73 |
74 | # IntelliJ
75 | /out/
76 |
77 | # mpeltonen/sbt-idea plugin
78 | .idea_modules/
79 |
80 | # JIRA plugin
81 | atlassian-ide-plugin.xml
82 |
83 | # Crashlytics plugin (for Android Studio and IntelliJ)
84 | com_crashlytics_export_strings.xml
85 | crashlytics.properties
86 | crashlytics-build.properties
87 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gurmanalexander/laravel-metrics",
3 | "description": "Managable metrics",
4 | "keywords": ["laravel", "metrics", "statistics", "stats"],
5 | "license": "MIT",
6 | "type": "library",
7 | "authors": [
8 | {
9 | "name": "Alexander Gurman",
10 | "email": "gurmanalexander@gmail.com"
11 | }
12 | ],
13 | "require": {
14 | "php": ">=5.5.0",
15 | "illuminate/support": "5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.*"
16 | },
17 | "autoload": {
18 | "psr-4": {
19 | "GurmanAlexander\\Metrics\\": "src/"
20 | }
21 | },
22 | "extra": {
23 | "laravel": {
24 | "providers": [
25 | "GurmanAlexander\\Metrics\\MetricsServiceProvider"
26 | ]
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Laravel Metrics
2 | This package helps you to manage your application metrics (e.g. Time, Count, Money)
3 |
4 | ## Table of Contents
5 | - Installation
6 | - Usage
7 | - Create Metrics
8 | - Metrics usage
9 | - Start Metrics
10 | - Stop Metrics
11 | - Once Metrics
12 | - Statistics
13 | - Methods
14 | - user()
15 | - admin()
16 | - startAt()
17 | - endAt()
18 | - betweenAt()
19 | - period
20 | - getBuilder()
21 | - Results
22 | - count()
23 | - sum()
24 | - avg()
25 | - min()
26 | - max()
27 |
28 |
29 | ## Installation
30 |
31 | Require this package with composer:
32 |
33 | ```shell
34 | composer require gurmanalexander/laravel-metrics:1.*
35 | ```
36 |
37 | After updating composer, add the ServiceProvider to the providers array in config/app.php
38 |
39 | > Laravel 5.5 uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider
40 |
41 |
42 | ### Laravel 5.x:
43 |
44 | ```php
45 | GurmanAlexander\Metrics\MetricsServiceProvider::class,
46 | ```
47 |
48 | Copy the package config to your local config with the publish command:
49 |
50 | ```shell
51 | php artisan vendor:publish --provider="GurmanAlexander\Metrics\MetricsServiceProvider"
52 | ```
53 |
54 | You may use the `metrics:table` command to generate a migration with the proper table schema:
55 |
56 | ```shell
57 | php artisan metrics:table
58 | ```
59 |
60 | And then migrate:
61 |
62 | ```shell
63 | php artisan migrate
64 | ```
65 |
66 | ## Usage
67 | ### Create Metrics
68 | You can crete new Metrics (default CountMetrics), but you can change it to TimeMetrics with parameter `--time`
69 | ```shell
70 | php artisan make:metrics PageViewCountMetrics
71 | ```
72 |
73 | Creating TimeMetrics example:
74 | ```shell
75 | php artisan make:metrics FirstPaymentMetrics
76 | ```
77 |
78 | This will create new class in `app/Metrics/` folder
79 | ```php
80 | class FirstPaymentMetrics extends CountMetrics
81 | {
82 |
83 | }
84 | ```
85 |
86 | ### Metrics usage
87 | Now you can start watching your Metrics. You need to add trait `Metricable` to your Model (e.g. User), that you want watching
88 | ```php
89 | use GurmanAlexander\Metrics\Metricable;
90 | class User extends Model
91 | {
92 | use Metricable;
93 | ...
94 | }
95 | ```
96 |
97 | ### Start metrics
98 | To start Metrics:
99 | > In CountMetrics first parameter - `$user` (The user to which the metrics belongs, default `null`),
100 | > second parameter - `admin` (The user who called the metrics, default `null`),
101 | > third parameter - `$count` (How much to increase the metrics. For example, you can use money metrics. default `1`)
102 |
103 | > In TimeMetrics only two parameters - `$user` and `$admin`
104 | ```php
105 | // For example, when creating user start Metrics
106 | $user = User::create(['email', 'password']);
107 | $user->startMetrics(new FirstPaymentMetrics($user));
108 | ```
109 | or
110 | ```php
111 | // when user view some news
112 | $user = auth()->user();
113 | $news->startMetrics(new PageViewCountMetrics($user));
114 | ```
115 |
116 | ### Stop metrics
117 | To stop Metrics:
118 | ```php
119 | // when user make some payment
120 | $user->paySomething();
121 | $user->closeMetrics(new FirstPaymentMetrics($user));
122 | ```
123 | or
124 | ```php
125 | // when user logout
126 | $user = auth()->user();
127 | $news->closeMetrics(new PageViewCountMetrics($user));
128 | auth()->logout();
129 | ```
130 |
131 | ### Once metrics
132 | To fire once Metrics:
133 | ```php
134 | $user = auth()->user();
135 | $user->onceMetrics(new SomeOnceMetrics());
136 | ```
137 |
138 | ## Statistics
139 | To get statistics you can use `MetricsStatistics` class
140 |
141 | Example:
142 | ```php
143 | // to get total payments
144 | $stats = new MetricsStatistics(new FirstPaymentMetrics());
145 | ```
146 |
147 | ### Methods
148 |
149 | #### user
150 | Filter statistics by `$user` (user Model, array of users or Collection of users)
151 | > `$user` - The user to which the metrics belongs.
152 | ```php
153 | // model
154 | $stats->user(auth()->user());
155 |
156 | // array
157 | $stats->user([auth()->user(), User:first()]);
158 |
159 | // collection
160 | $stats->user(User::where('is_active', 1)->get());
161 | ```
162 |
163 | #### admin
164 | Filter by **admin** like by **user**
165 | > `admin` - The user who called the metrics.
166 |
167 | #### startAt
168 | Filter from `$start_at` date
169 | > The metrics stats calculating by `end_at` field (when metrics stops)
170 | ```php
171 | $start_at = Carbon::now()->startOfMonth();
172 | $stats->startAt($start_at);
173 | ```
174 |
175 | #### endAt
176 | Filter to `$end_at` date
177 | > The metrics stats calculating by `end_at` field (when metrics stops)
178 | ```php
179 | $end_at = Carbon::now()->endOfMonth();
180 | $stats->endAt($end_at);
181 | ```
182 |
183 | #### betweenAt
184 | Filter from `$start_at` to `$end_at` date
185 | > The metrics stats calculating by `end_at` field (when metrics stops)
186 | ```php
187 | $start_at = Carbon::now()->startOfMonth();
188 | $end_at = Carbon::now()->endOfMonth();
189 | $stats->betweenAt($start_at, $end_at);
190 | ```
191 |
192 | #### period
193 | Calculating statistics grouped by periods
194 | ```php
195 | $stats->hourly();
196 | $stats->daily();
197 | $stats->weekly();
198 | $stats->monthly();
199 | $stats->yearly();
200 |
201 | // result example
202 | $stats->hourly()->count()->toArray();
203 |
204 | // [
205 | // 0 => [
206 | // "count" => 23,
207 | // "date" => "2017-06-30",
208 | // "period" => "hour",
209 | // "hour" => 9
210 | // ],
211 | // 1 => [
212 | // "count" => 15,
213 | // "date" => "2017-06-30",
214 | // "period" => "hour",
215 | // "hour" => 8
216 | // ],
217 | // 2 => [
218 | // "count" => 32,
219 | // "date" => "2017-06-30",
220 | // "period" => "hour",
221 | // "hour" => 7
222 | // ],
223 | // ]
224 | ```
225 |
226 | #### getBuilder
227 | return Builder to your custom calculating
228 |
229 | ### Results
230 | to get results
231 |
232 | #### count
233 | return **Count** of all filtered Metrics in DB
234 | > return Collection of Metrics
235 |
236 | #### sum
237 | return **Sum** of all filtered Metrics in DB
238 | > if this is TimeMetrics - total seconds for metrics
239 |
240 | #### avg
241 | return **Average** of all filtered Metrics in DB
242 | > if this is TimeMetrics - average seconds for metrics
243 |
244 | #### min
245 | return **Min** of all filtered Metrics in DB
246 | > if this is TimeMetrics - min seconds for metrics
247 |
248 | #### max
249 | return **Max** of all filtered Metrics in DB
250 | > if this is TimeMetrics - max seconds for metrics
251 |
252 |
253 |
254 | ### Example:
255 | ```php
256 | // to get total payments
257 | $stats = new MetricsStatistics(new FirstPaymentMetrics());
258 |
259 | // to get average time from user registration to first payment (in seconds)
260 | $stats = new MetricsStatistics(new FirstPaymentMetrics())->hourly()->avg()->toArray();
261 |
262 | // [
263 | // 0 => [
264 | // "avg" => 12.13,
265 | // "date" => "2017-06-30",
266 | // "period" => "hour",
267 | // "hour" => 9
268 | // ],
269 | // 1 => [
270 | // "avg" => 8.00,
271 | // "date" => "2017-06-30",
272 | // "period" => "hour",
273 | // "hour" => 8
274 | // ],
275 | // 2 => [
276 | // "avg" => 5.34,
277 | // "date" => "2017-06-30",
278 | // "period" => "hour",
279 | // "hour" => 7
280 | // ],
281 | // ]
282 | ```
283 |
284 |
--------------------------------------------------------------------------------
/src/Console/MetricsMakeCommand.php:
--------------------------------------------------------------------------------
1 | option('time')) {
37 | return __DIR__.'/stubs/metrics.time.stub';
38 | } elseif ($this->option('count')) {
39 | return __DIR__.'/stubs/metrics.count.stub';
40 | }
41 |
42 | return __DIR__.'/stubs/metrics.count.stub';
43 | }
44 |
45 | /**
46 | * Get the default namespace for the class.
47 | *
48 | * @param string $rootNamespace
49 | * @return string
50 | */
51 | protected function getDefaultNamespace($rootNamespace)
52 | {
53 | return $rootNamespace.'\Metrics';
54 | }
55 |
56 | /**
57 | * Get the console command options.
58 | *
59 | * @return array
60 | */
61 | protected function getOptions()
62 | {
63 | return [
64 | ['time', 't', InputOption::VALUE_NONE, 'Generate a Timer metrics class.'],
65 |
66 | ['count', 'c', InputOption::VALUE_NONE, 'Generate a Counter metrics class.'],
67 | ];
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Console/MetricsTableCommand.php:
--------------------------------------------------------------------------------
1 | files = $files;
46 | $this->composer = $composer;
47 | }
48 |
49 | /**
50 | * Execute the console command.
51 | *
52 | * @return void
53 | */
54 | public function fire()
55 | {
56 | $fullPath = $this->createBaseMigration();
57 |
58 | $this->files->put($fullPath, $this->files->get(__DIR__.'/stubs/metrics.stub'));
59 |
60 | $this->info('Migration created successfully!');
61 |
62 | $this->composer->dumpAutoloads();
63 | }
64 |
65 | /**
66 | * Create a base migration file for the notifications.
67 | *
68 | * @return string
69 | */
70 | protected function createBaseMigration()
71 | {
72 | $name = 'create_metrics_table';
73 |
74 | $path = $this->laravel->databasePath().'/migrations';
75 |
76 | return $this->laravel['migration.creator']->create($name, $path);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/Console/stubs/metrics.count.stub:
--------------------------------------------------------------------------------
1 | uuid('id')->primary();
19 | $table->boolean('is_failed')->default(false);
20 |
21 | $table->integer('user_id')->unsigned()->nullable();
22 | $table->foreign('user_id')->references('id')->on(Config::get('metrics.users_table', 'users'))->onDelete('cascade')->onUpdate('cascade');
23 |
24 | $table->integer('admin_id')->unsigned()->nullable();
25 | $table->foreign('admin_id')->references('id')->on(Config::get('metrics.users_table', 'users'))->onDelete('set null')->onUpdate('cascade');
26 |
27 | $table->string('type')->index();
28 | $table->morphs('metricable');
29 |
30 | $table->json('data');
31 | $table->integer('count')->default(0)->index();
32 | $table->timestamp('start_at')->default(DB::raw('CURRENT_TIMESTAMP'))->index();
33 | $table->timestamp('end_at')->nullable()->index();
34 | $table->timestamps();
35 | });
36 | }
37 |
38 | /**
39 | * Reverse the migrations.
40 | *
41 | * @return void
42 | */
43 | public function down()
44 | {
45 | Schema::dropIfExists('metrics');
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Console/stubs/metrics.time.stub:
--------------------------------------------------------------------------------
1 | addMetrics($metrics);
15 | }
16 |
17 | /**
18 | * Fire once metrics
19 | *
20 | * @param Metrics $metrics
21 | * @return boolean
22 | */
23 | public function onceMetrics(Metrics $metrics)
24 | {
25 | return $metrics->onceMetrics($this);
26 | }
27 |
28 | /**
29 | * Add or start metrics to existing metrics
30 | *
31 | * @param Metrics $metrics
32 | * @return boolean
33 | */
34 | public function addMetrics(Metrics $metrics)
35 | {
36 | return $metrics->addMetrics($this);
37 | }
38 |
39 | /**
40 | * Stop watching metrics
41 | *
42 | * @param Metrics $metrics
43 | * @return boolean
44 | */
45 | public function closeMetrics(Metrics $metrics)
46 | {
47 | return $metrics->closeMetrics($this);
48 | }
49 | }
--------------------------------------------------------------------------------
/src/Metrics.php:
--------------------------------------------------------------------------------
1 | 'array',
36 | 'is_failed' => 'boolean',
37 | 'count' => 'integer',
38 | 'type' => 'string',
39 | ];
40 |
41 | protected $guarded = [];
42 |
43 | protected $userModel;
44 | protected $adminModel;
45 |
46 | public abstract function addMetrics($metricable);
47 | public abstract function onceMetrics($metricable);
48 | public abstract function closeMetrics($metricable);
49 |
50 | public function __construct(array $attributes = [])
51 | {
52 | $this->id = Uuid::uuid4()->toString();
53 | parent::__construct($attributes);
54 | }
55 |
56 | public function user()
57 | {
58 | return $this->belongsTo(Config::get('metrics.user', '\App\User'),'user_id');
59 | }
60 |
61 | public function admin()
62 | {
63 | return $this->belongsTo(Config::get('metrics.user', '\App\User'),'admin_id');
64 | }
65 |
66 | public function metricable()
67 | {
68 | return $this->morphTo();
69 | }
70 |
71 | /**
72 | * Find opened metrics if exists
73 | *
74 | * @param $metricable
75 | * @return Metrics|null - child class
76 | */
77 | protected function findCurrentMetrics($metricable)
78 | {
79 | $metrics = static::where('metricable_id', $metricable->id)
80 | ->where('metricable_type', get_class($metricable))
81 | ->where('type', static::class)
82 | ->whereNull('end_at')
83 | ;
84 | if (!empty($this->userModel)) {
85 | $metrics->where('user_id', $this->userModel->id);
86 | }
87 | return $metrics->first();
88 | }
89 |
90 | /**
91 | * Check if $user instance of User Model
92 | *
93 | * @param $user
94 | * @return mixed - User Model
95 | */
96 | public function checkUserInstance($user)
97 | {
98 | if ($user && get_class($user) !== Config::get('metrics.user')) {
99 | throw new NotUserClassException(
100 | 'Argument passed to ' . static::class .
101 | ' must be an instance of ' . Config::get('metrics.user') .
102 | ', instance of ' . get_class($user) . ' given, called in ' . __FILE__ .
103 | ' on line ' . __LINE__ . ' and defined'
104 | );
105 | }
106 | return $user;
107 | }
108 |
109 | /**
110 | * Write history of metrics to data
111 | */
112 | protected function fired()
113 | {
114 | $data = $this->data;
115 | $data['fired_at'][] = Carbon::now()->toDateTimeString();
116 | $this->data = $data;
117 | }
118 |
119 | /**
120 | * Write user and admin (if exists) to metrics
121 | * Write user activity (history) to data:
122 | * [
123 | * 'user' => [user_id => [...dates]],
124 | * 'admin' => [admin_id => [...dates]],
125 | * ]
126 | *
127 | * @param Metrics $metrics
128 | */
129 | protected function fillUsers(Metrics &$metrics)
130 | {
131 |
132 | foreach (['user', 'admin'] as $userType) {
133 | if ($metrics->{$userType . 'Model'}) {
134 | if (!$metrics->{$userType}) {
135 | $metrics->{$userType}()->associate($metrics->{$userType . 'Model'});
136 | }
137 | }
138 | if (!empty($metrics->{$userType})) {
139 | $data = $this->data;
140 | if (empty($data[$userType])) {
141 | $data[$userType] = [];
142 | }
143 | if (empty($data[$userType][$metrics->{$userType}->id])) {
144 | $data[$userType][$metrics->{$userType}->id] = [];
145 | }
146 | $data[$userType][$metrics->{$userType}->id][] = Carbon::now()->toDateTimeString();
147 | $this->data = $data;
148 | }
149 | }
150 |
151 | }
152 |
153 | /**
154 | * Build period selectors for SQL query to get stats data for needed period
155 | * For week example:
156 | * 'week' as `period`,
157 | * WEEK(`end_at`, 1) as `week`
158 | *
159 | * @param $period
160 | * @return array
161 | */
162 | protected static function getPeriodSqlColumns($period)
163 | {
164 | $result = [
165 | DB::raw('"' . $period . '" as period')
166 | ];
167 | switch ($period) {
168 | case 'week': {
169 | $result[] = DB::raw(strtoupper($period) . '(end_at, 1) as ' . $period);
170 | }break;
171 | default: {
172 | $result[] = DB::raw(strtoupper($period) . '(end_at) as ' . $period);
173 | }
174 | }
175 | return $result;
176 | }
177 |
178 | /**
179 | * Build complete SQL select
180 | *
181 | * @param Builder $builder
182 | * @param $period
183 | * @param $raw
184 | * @return Builder
185 | */
186 | protected static function statsBuilder(Builder $builder, $period, $raw)
187 | {
188 | return $builder->select(
189 | array_merge([
190 | $raw,
191 | DB::raw('DATE_FORMAT(end_at, "%Y-%m-%d") as date'),
192 | ], self::getPeriodSqlColumns($period))
193 | );
194 | }
195 |
196 | /**
197 | * Get COUNT stats for Metrics divided into periods
198 | *
199 | * @param Builder $builder
200 | * @param $period
201 | * @return \Illuminate\Database\Eloquent\Collection
202 | */
203 | public static function statsCount(Builder $builder, $period)
204 | {
205 | return self::statsBuilder($builder, $period, DB::raw('COUNT(*) as count'))->get();
206 | }
207 |
208 | /**
209 | * Get AVG stats for Metrics divided into periods
210 | *
211 | * @param Builder $builder
212 | * @param $period
213 | * @return \Illuminate\Database\Eloquent\Collection
214 | */
215 | public static function statsAvg(Builder $builder, $period)
216 | {
217 | return self::statsBuilder($builder, $period, DB::raw('AVG(count) as avg'))->get();
218 | }
219 |
220 | /**
221 | * Get SUM stats for Metrics divided into periods
222 | *
223 | * @param Builder $builder
224 | * @param $period
225 | * @return \Illuminate\Database\Eloquent\Collection
226 | */
227 | public static function statsSum(Builder $builder, $period)
228 | {
229 | return self::statsBuilder($builder, $period, DB::raw('SUM(count) as sum'))->get();
230 | }
231 |
232 | /**
233 | * Get MIN stats for Metrics divided into periods
234 | *
235 | * @param Builder $builder
236 | * @param $period
237 | * @return \Illuminate\Database\Eloquent\Collection
238 | */
239 | public static function statsMin(Builder $builder, $period)
240 | {
241 | return self::statsBuilder($builder, $period, DB::raw('MIN(count) as min'))->get();
242 | }
243 |
244 | /**
245 | * Get MAX stats for Metrics divided into periods
246 | *
247 | * @param Builder $builder
248 | * @param $period
249 | * @return \Illuminate\Database\Eloquent\Collection
250 | */
251 | public static function statsMax(Builder $builder, $period)
252 | {
253 | return self::statsBuilder($builder, $period, DB::raw('MAX(count) as max'))->get();
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/src/MetricsServiceProvider.php:
--------------------------------------------------------------------------------
1 | publishes([
17 | __DIR__.'/config/config.php' => config_path('metrics.php'),
18 | ]);
19 | }
20 |
21 | /**
22 | * Register the application services.
23 | *
24 | * @return void
25 | */
26 | public function register()
27 | {
28 | if ($this->app->runningInConsole()) {
29 |
30 | $this->commands([
31 | MetricsTableCommand::class,
32 | MetricsMakeCommand::class,
33 | ]);
34 | }
35 |
36 | $this->mergeConfigFrom(
37 | __DIR__.'/config/config.php', 'metrics'
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/MetricsStatistics.php:
--------------------------------------------------------------------------------
1 | metricsClass = get_class($metrics);
25 | $this->metricsModel = $metrics;
26 |
27 | $this->metrics = call_user_func(get_class($metrics) . '::where', ['type' => get_class($metrics)]);
28 | $this->metrics
29 | ->where('type', get_class($metrics))
30 | ->whereNotNull('end_at')
31 | ->orderBy('end_at', 'desc')
32 | ;
33 |
34 | $this->startAt = Carbon::now()->startOfMonth();
35 | $this->endAt = Carbon::now();
36 | }
37 |
38 | /**
39 | * Filter by date "start from" calculating statistics
40 | *
41 | * @param Carbon|null $start_at
42 | * @return MetricsStatistics
43 | */
44 | public function startAt(Carbon $start_at = null)
45 | {
46 | if ($start_at) $this->startAt = $start_at;
47 |
48 | $this->metrics->where('end_at', '>=', $this->startAt);
49 |
50 | return $this;
51 | }
52 |
53 | /**
54 | * Filter by date "end to" calculating statistics
55 | *
56 | * @param Carbon|null $end_at
57 | * @return MetricsStatistics
58 | */
59 | public function endAt(Carbon $end_at = null)
60 | {
61 | if ($end_at) $this->endAt = $end_at;
62 |
63 | $this->metrics->where('end_at', '<=', $this->endAt);
64 |
65 | return $this;
66 | }
67 |
68 | /**
69 | * Filter by date "start from" to "end to" calculating statistics
70 | *
71 | * @param Carbon|null $start_at
72 | * @param Carbon|null $end_at
73 | * @return MetricsStatistics
74 | */
75 | public function betweenAt(Carbon $start_at = null, Carbon $end_at = null)
76 | {
77 | if ($start_at) $this->startAt = $start_at;
78 | if ($end_at) $this->endAt = $end_at;
79 | $this->metrics->whereBetween('end_at', [$this->startAt, $this->endAt]);
80 |
81 | return $this;
82 | }
83 |
84 | /**
85 | * Filter by user
86 | *
87 | * @param \App\User|array|null $user
88 | * @return MetricsStatistics
89 | */
90 | public function user($user = null)
91 | {
92 | $this->filterUser($user, 'user_id');
93 |
94 | return $this;
95 | }
96 |
97 | /**
98 | * Filter by admin
99 | *
100 | * @param \App\User|array|null $user
101 | * @return MetricsStatistics
102 | */
103 | public function admin($user = null)
104 | {
105 | $this->filterUser($user, 'admin_id');
106 |
107 | return $this;
108 | }
109 |
110 | protected function period($period)
111 | {
112 | if (in_array($period, [self::HOURLY, self::DAILY, self::WEEKLY, self::MONTHLY, self::YEARLY])) {
113 | $this->period = $period;
114 | }
115 |
116 |
117 | switch ($this->period) {
118 | case self::WEEKLY: {
119 | $groupBy = 'WEEK(end_at, 1)';
120 | } break;
121 | default: {
122 | $groupBy = strtoupper($this->period) . '(end_at)';
123 | }
124 | }
125 |
126 | $this->metrics->groupBy(DB::raw($groupBy));
127 |
128 | return $this;
129 | }
130 |
131 | /**
132 | * Calculating result hourly
133 | *
134 | * @return MetricsStatistics
135 | */
136 | public function hourly()
137 | {
138 | return $this->period(self::HOURLY);
139 | }
140 |
141 | /**
142 | * Calculating result daily
143 | *
144 | * @return MetricsStatistics
145 | */
146 | public function daily()
147 | {
148 | return $this->period(self::DAILY);
149 | }
150 |
151 | /**
152 | * Calculating result weekly
153 | *
154 | * @return MetricsStatistics
155 | */
156 | public function weekly()
157 | {
158 | return $this->period(self::WEEKLY);
159 | }
160 |
161 | /**
162 | * Calculating result monthly
163 | *
164 | * @return MetricsStatistics
165 | */
166 | public function monthly()
167 | {
168 | return $this->period(self::MONTHLY);
169 | }
170 |
171 | /**
172 | * Calculating result yearly
173 | *
174 | * @return MetricsStatistics
175 | */
176 | public function yearly()
177 | {
178 | return $this->period(self::YEARLY);
179 | }
180 |
181 | /**
182 | * @param \App\User|array|null $user
183 | * @param string $foreign_key
184 | * @return MetricsStatistics
185 | */
186 | protected function filterUser($user = null, $foreign_key = 'user_id')
187 | {
188 | if (!$user) return $this;
189 |
190 | if (is_array($user) || $user instanceof \Illuminate\Support\Collection) {
191 | $user_ids = [];
192 | foreach ($user as $item) {
193 | $this->metrics->checkUserInstance($item);
194 | $user_ids[] = $item->id;
195 | }
196 | $this->metrics->whereIn($foreign_key, $user_ids);
197 | return $this;
198 | }
199 |
200 | $this->metricsModel->checkUserInstance($user);
201 | $this->metrics->where($foreign_key, $user->id);
202 | return $this;
203 | }
204 |
205 | /**
206 | * Get statistics Eloquent Builder for custom queries
207 | *
208 | * @return mixed
209 | */
210 | public function getBuilder()
211 | {
212 | return $this->metrics;
213 | }
214 |
215 | /**
216 | * Call magic methods
217 | * Example:
218 | * - count calls Metrics::statsCount()
219 | * - avg calls Metrics::statsAvg()
220 | * - sum calls Metrics::statsSum()
221 | * - min calls Metrics::statsMin()
222 | * - max calls Metrics::statsMax()
223 | *
224 | * you can add yur own methods in Metrics child classes to get custom stats
225 | *
226 | * @param $name
227 | * @param $arguments
228 | * @return mixed
229 | */
230 | function __call($name, $arguments)
231 | {
232 | $methodName = ('stats' . strtoupper(substr($name, 0, 1)) . strtolower(substr($name, 1)));
233 | if (method_exists($this->metricsClass, $methodName)) {
234 | return call_user_func_array([$this->metricsClass, $methodName], [$this->metrics, $this->period]);
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/src/Types/CountMetrics.php:
--------------------------------------------------------------------------------
1 | userModel = $this->checkUserInstance($user);
26 | $this->adminModel = $this->checkUserInstance($admin);
27 |
28 | $this->countMetricsCount = $count;
29 |
30 | parent::__construct([]);
31 | }
32 |
33 | public function addMetrics($metricable)
34 | {
35 | $metrics = $this->findCurrentMetrics($metricable);
36 |
37 | if (!$metrics) $metrics = $this;
38 |
39 | $metrics->type = static::class;
40 | $metrics->count+= $this->countMetricsCount;
41 |
42 | $metrics->fired();
43 |
44 | $metrics->metricable()->associate($metricable);
45 |
46 | $metrics->fillUsers($this);
47 |
48 | return $metrics->save();
49 | }
50 |
51 | public function closeMetrics($metricable)
52 | {
53 | $metrics = $this->findCurrentMetrics($metricable);
54 |
55 | if (!$metrics) {
56 | Log::error('trying to close unstarted metrics');
57 | return false;
58 | }
59 |
60 | $metrics->type = static::class;
61 | $metrics->end_at = Carbon::now();
62 | $metrics->metricable()->associate($metricable);
63 |
64 | $metrics->fired();
65 |
66 | $metrics->fillUsers($this);
67 |
68 | return $metrics->save();
69 | }
70 |
71 | public function onceMetrics($metricable)
72 | {
73 | $this->addMetrics($metricable);
74 | return $this->closeMetrics($metricable);
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Types/TimeMetrics.php:
--------------------------------------------------------------------------------
1 | userModel = $this->checkUserInstance($user);
22 | $this->adminModel = $this->checkUserInstance($admin);
23 |
24 | parent::__construct([]);
25 | }
26 |
27 | public function addMetrics($metricable)
28 | {
29 | $metrics = $this->findCurrentMetrics($metricable);
30 |
31 | if ($metrics) return false;
32 |
33 | $metrics = $this;
34 | $metrics->type = static::class;
35 | $metrics->metricable()->associate($metricable);
36 |
37 | $metrics->fired();
38 |
39 | $metrics->fillUsers($metrics);
40 |
41 | return $metrics->save();
42 | }
43 |
44 | public function closeMetrics($metricable)
45 | {
46 | $metrics = $this->findCurrentMetrics($metricable);
47 |
48 | if (!$metrics) {
49 | Log::error('trying to close unstarted metrics');
50 | return false;
51 | }
52 |
53 | $metrics->type = static::class;
54 | $metrics->end_at = Carbon::now();
55 | $metrics->count = $metrics->end_at->diffInSeconds($metrics->start_at);
56 | $metrics->metricable()->associate($metricable);
57 |
58 | $metrics->fired();
59 |
60 | $metrics->fillUsers($this);
61 |
62 | return $metrics->save();
63 | }
64 |
65 | public function onceMetrics($metricable)
66 | {
67 | return false;
68 | }
69 | }
--------------------------------------------------------------------------------
/src/config/config.php:
--------------------------------------------------------------------------------
1 | '\App\User',
15 |
16 | /*
17 | |--------------------------------------------------------------------------
18 | | Application Users Table
19 | |--------------------------------------------------------------------------
20 | |
21 | | This is the users table used by the application to save users to the
22 | | database.
23 | |
24 | */
25 | 'users_table' => 'users',
26 |
27 | ];
28 |
--------------------------------------------------------------------------------