Skip to content

Commit

Permalink
Merge pull request #17 from christoph-kluge/relationships
Browse files Browse the repository at this point in the history
Add support for relationships
  • Loading branch information
AlexVanderbist authored Mar 4, 2022
2 parents 72b18d5 + 12ab30b commit 0ca7b61
Show file tree
Hide file tree
Showing 15 changed files with 750 additions and 138 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

All notable changes to `laravel-stats` will be documented in this file

## 2.0.0 - 2022-02-20

### Added

- Added `StatsWriter` with classname support (`StatsWriter::for(MyModel::class)`)
- Added `StatsWriter` with eloquent-model support (`StatsWriter::for($eloquent)`)
- Added `StatsWriter` with "has-many"-relationship support (`StatsWriter::for($model->relationship())`) - other relationships are untested yet
- Added `StatsWriter` with custom-attribute support (`StatsWriter::for(MyModel::class, ['custom_column' => 'orders])`)
- Extended `StatsQuery` with relationship-support (`StatsQuery::for($model->relationship())`)
- Extended `StatsQuery` with additional attributes (`StatsQuery::for(StatsEvent::class, ['name' => 'OrderStats'])`)
- Extended `BaseStats` with direct writer access (`OrderStats::writer()` as addition to `OrderStats::query()`)

### Changed (breaks BC)

- Changed visibility of `StatsQuery::for($model)->generatePeriods()` from `public` to `protected`
- Replaced `StatsQuery::for($model)->getStatistic()` with `StatsQuery::for($model)->getAttributes()`
- Removed `BaseStats->createEvent()`

### Migrations

- Replace `StatsQuery::for(OrderStats::class)` with `OrderStats::query()`
- Replace `StatsEvent::TYPE_SET` use `DataPoint::TYPE_SET` instead
- Replace `StatsEvent::TYPE_CHANGE` use `DataPoint::TYPE_CHANGE` instead

## 1.0.1 - 2022-02-02

- Add support for Laravel 9
Expand Down
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ grouped by week.
```php
use Spatie\Stats\StatsQuery;

$stats = StatsQuery::for(SubscriptionStats::class)
$stats = SubscriptionStats::query()
->start(now()->subMonths(2))
->end(now()->subSecond())
->groupByWeek()
Expand Down Expand Up @@ -171,6 +171,47 @@ This will return an array containing arrayable `Spatie\Stats\DataPoint` objects.
]
```

## Extended Use-Cases

### Read and Write from a custom Model

* Create a new table with `type (string)`, `value (bigInt)`, `created_at`, `updated_at` fields
* Create a model and add `HasStats`-trait

```php
StatsWriter::for(MyCustomModel::class)->set(123)
StatsWriter::for(MyCustomModel::class, ['custom_column' => '123'])->increment(1)
StatsWriter::for(MyCustomModel::class, ['another_column' => '234'])->decrement(1, now()->subDay())

$stats = StatsQuery::for(MyCustomModel::class)
->start(now()->subMonths(2))
->end(now()->subSecond())
->groupByWeek()
->get();

// OR

$stats = StatsQuery::for(MyCustomModel::class, ['additional_column' => '123'])
->start(now()->subMonths(2))
->end(now()->subSecond())
->groupByWeek()
->get();
```

### Read and Write from a HasMany-Relationship

```php
$tenant = Tenant::find(1)

StatsWriter::for($tenant->orderStats(), ['payment_type_column' => 'recurring'])->increment(1)

$stats = StatsQuery::for($tenant->orderStats(), , ['payment_type_column' => 'recurring'])
->start(now()->subMonths(2))
->end(now()->subSecond())
->groupByWeek()
->get();
```

## Testing

``` bash
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"spatie/laravel-package-tools": "^1.9.2"
},
"require-dev": {
"doctrine/dbal": "^3.3",
"orchestra/testbench": "^6.23|^7.0",
"phpunit/phpunit": "^9.4",
"vimeo/psalm": "^4.12"
Expand Down
37 changes: 13 additions & 24 deletions src/BaseStats.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,30 @@ public function getName(): string

public static function query(): StatsQuery
{
return new StatsQuery(static::class);
return StatsQuery::for(StatsEvent::class, [
'name' => (new static)->getName(),
]);
}

public static function increase(mixed $number = 1, ?DateTimeInterface $timestamp = null)
public static function writer(): StatsWriter
{
$number = is_int($number) ? $number : 1;

$stats = new static;

$stats->createEvent(StatsEvent::TYPE_CHANGE, $number, $timestamp);
return StatsWriter::for(StatsEvent::class, [
'name' => (new static)->getName(),
]);
}

public static function decrease(mixed $number = 1, ?DateTimeInterface $timestamp = null)
public static function increase(mixed $number = 1, ?DateTimeInterface $timestamp = null)
{
$number = is_int($number) ? $number : 1;

$stats = new static;

$stats->createEvent(StatsEvent::TYPE_CHANGE, -$number, $timestamp);
static::writer()->increase($number, $timestamp);
}

public static function set(int $value, ?DateTimeInterface $timestamp = null)
public static function decrease(mixed $number = 1, ?DateTimeInterface $timestamp = null)
{
$stats = new static;

$stats->createEvent(StatsEvent::TYPE_SET, $value, $timestamp);
static::writer()->decrease($number, $timestamp);
}

protected function createEvent($type, $value, ?DateTimeInterface $timestamp = null): StatsEvent
public static function set(int $value, ?DateTimeInterface $timestamp = null)
{
return StatsEvent::create([
'name' => $this->getName(),
'type' => $type,
'value' => $value,
'created_at' => $timestamp ?? now(),
]);
static::writer()->set($value, $timestamp);
}
}
4 changes: 4 additions & 0 deletions src/DataPoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

class DataPoint implements Arrayable
{

const TYPE_SET = 'set';
const TYPE_CHANGE = 'change';

public function __construct(
public Carbon $start,
public Carbon $end,
Expand Down
45 changes: 13 additions & 32 deletions src/Models/StatsEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,27 @@

namespace Spatie\Stats\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Spatie\Stats\DataPoint;
use Spatie\Stats\Traits\HasStats;

class StatsEvent extends Model
{
const TYPE_SET = 'set';
const TYPE_CHANGE = 'change';
use HasStats;

/**
* @deprecated use DataPoint::TYPE_SET
*/
const TYPE_SET = DataPoint::TYPE_SET;

/**
* @deprecated use DataPoint::TYPE_CHANGE
*/
const TYPE_CHANGE = DataPoint::TYPE_CHANGE;

protected $casts = [
'value' => 'integer',
];

protected $guarded = [];

public function scopeGroupByPeriod(Builder $query, string $period): void
{
$periodGroupBy = static::getPeriodDateFormat($period);

$query->groupByRaw($periodGroupBy)->selectRaw("{$periodGroupBy} as period");
}

public static function getPeriodDateFormat(string $period): string
{
return match ($period) {
'year' => "date_format(created_at,'%Y')",
'month' => "date_format(created_at,'%Y-%m')",
'week' => "yearweek(created_at, 3)", // see https://stackoverflow.com/questions/15562270/php-datew-vs-mysql-yearweeknow
'day' => "date_format(created_at,'%Y-%m-%d')",
'hour' => "date_format(created_at,'%Y-%m-%d %H')",
'minute' => "date_format(created_at,'%Y-%m-%d %H:%i')",
};
}

public function scopeIncrements(Builder $query): void
{
$query->where('value', '>', 0);
}

public function scopeDecrements(Builder $query): void
{
$query->where('value', '<', 0);
}
}
Loading

0 comments on commit 0ca7b61

Please sign in to comment.