🆙 Add cms i using 🆙

This commit is contained in:
2025-11-25 22:42:56 +01:00
parent 94704e0925
commit d44196149e
35591 changed files with 3601123 additions and 0 deletions
@@ -0,0 +1,8 @@
<?php
namespace Flowframe\Trend\Adapters;
abstract class AbstractAdapter
{
abstract public function format(string $column, string $interval): string;
}
@@ -0,0 +1,23 @@
<?php
namespace Flowframe\Trend\Adapters;
use Error;
class MySqlAdapter extends AbstractAdapter
{
public function format(string $column, string $interval): string
{
$format = match ($interval) {
'minute' => '%Y-%m-%d %H:%i:00',
'hour' => '%Y-%m-%d %H:00',
'day' => '%Y-%m-%d',
'week' => '%Y-%u',
'month' => '%Y-%m',
'year' => '%Y',
default => throw new Error('Invalid interval.'),
};
return "date_format({$column}, '{$format}')";
}
}
@@ -0,0 +1,23 @@
<?php
namespace Flowframe\Trend\Adapters;
use Error;
class PgsqlAdapter extends AbstractAdapter
{
public function format(string $column, string $interval): string
{
$format = match ($interval) {
'minute' => 'YYYY-MM-DD HH24:MI:00',
'hour' => 'YYYY-MM-DD HH24:00:00',
'day' => 'YYYY-MM-DD',
'week' => 'IYYY-IW',
'month' => 'YYYY-MM',
'year' => 'YYYY',
default => throw new Error('Invalid interval.'),
};
return "to_char(\"{$column}\", '{$format}')";
}
}
@@ -0,0 +1,23 @@
<?php
namespace Flowframe\Trend\Adapters;
use Error;
class SqliteAdapter extends AbstractAdapter
{
public function format(string $column, string $interval): string
{
$format = match ($interval) {
'minute' => '%Y-%m-%d %H:%M:00',
'hour' => '%Y-%m-%d %H:00',
'day' => '%Y-%m-%d',
'week' => '%Y-%W',
'month' => '%Y-%m',
'year' => '%Y',
default => throw new Error('Invalid interval.'),
};
return "strftime('{$format}', {$column})";
}
}
@@ -0,0 +1,195 @@
<?php
namespace Flowframe\Trend;
use Carbon\CarbonInterface;
use Carbon\CarbonPeriod;
use Error;
use Flowframe\Trend\Adapters\MySqlAdapter;
use Flowframe\Trend\Adapters\PgsqlAdapter;
use Flowframe\Trend\Adapters\SqliteAdapter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
class Trend
{
public string $interval;
public CarbonInterface $start;
public CarbonInterface $end;
public string $dateColumn = 'created_at';
public string $dateAlias = 'date';
public function __construct(public Builder $builder)
{
}
public static function query(Builder $builder): self
{
return new static($builder);
}
public static function model(string $model): self
{
return new static($model::query());
}
public function between($start, $end): self
{
$this->start = $start;
$this->end = $end;
return $this;
}
public function interval(string $interval): self
{
$this->interval = $interval;
return $this;
}
public function perMinute(): self
{
return $this->interval('minute');
}
public function perHour(): self
{
return $this->interval('hour');
}
public function perDay(): self
{
return $this->interval('day');
}
public function perWeek(): self
{
return $this->interval('week');
}
public function perMonth(): self
{
return $this->interval('month');
}
public function perYear(): self
{
return $this->interval('year');
}
public function dateColumn(string $column): self
{
$this->dateColumn = $column;
return $this;
}
public function dateAlias(string $alias): self
{
$this->dateAlias = $alias;
return $this;
}
public function aggregate(string $column, string $aggregate): Collection
{
$values = $this->builder
->toBase()
->selectRaw("
{$this->getSqlDate()} as {$this->dateAlias},
{$aggregate}({$column}) as aggregate
")
->whereBetween($this->dateColumn, [$this->start, $this->end])
->groupBy($this->dateAlias)
->orderBy($this->dateAlias)
->get();
return $this->mapValuesToDates($values);
}
public function average(string $column): Collection
{
return $this->aggregate($column, 'avg');
}
public function min(string $column): Collection
{
return $this->aggregate($column, 'min');
}
public function max(string $column): Collection
{
return $this->aggregate($column, 'max');
}
public function sum(string $column): Collection
{
return $this->aggregate($column, 'sum');
}
public function count(string $column = '*'): Collection
{
return $this->aggregate($column, 'count');
}
public function mapValuesToDates(Collection $values): Collection
{
$values = $values->map(fn ($value) => new TrendValue(
date: $value->{$this->dateAlias},
aggregate: $value->aggregate,
));
$placeholders = $this->getDatePeriod()->map(
fn (CarbonInterface $date) => new TrendValue(
date: $date->format($this->getCarbonDateFormat()),
aggregate: 0,
)
);
return $values
->merge($placeholders)
->unique('date')
->sort()
->flatten();
}
protected function getDatePeriod(): Collection
{
return collect(
CarbonPeriod::between(
$this->start,
$this->end,
)->interval("1 {$this->interval}")
);
}
protected function getSqlDate(): string
{
$adapter = match ($this->builder->getConnection()->getDriverName()) {
'mysql', 'mariadb' => new MySqlAdapter(),
'sqlite' => new SqliteAdapter(),
'pgsql' => new PgsqlAdapter(),
default => throw new Error('Unsupported database driver.'),
};
return $adapter->format($this->dateColumn, $this->interval);
}
protected function getCarbonDateFormat(): string
{
return match ($this->interval) {
'minute' => 'Y-m-d H:i:00',
'hour' => 'Y-m-d H:00',
'day' => 'Y-m-d',
'week' => 'Y-W',
'month' => 'Y-m',
'year' => 'Y',
default => throw new Error('Invalid interval.'),
};
}
}
@@ -0,0 +1,14 @@
<?php
namespace Flowframe\Trend;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
class TrendServiceProvider extends PackageServiceProvider
{
public function configurePackage(Package $package): void
{
$package->name('laravel-trend');
}
}
@@ -0,0 +1,12 @@
<?php
namespace Flowframe\Trend;
class TrendValue
{
public function __construct(
public string $date,
public mixed $aggregate,
) {
}
}