Index

PeriodStatistic

MMO\core\helpers · 1 symbol · generated 30 Sep 2026

class

PeriodStatistic

PeriodStatistic.php:19

Accumulates counters (e.g. "sales", "signups") across multiple years, bucketed by calendar period (day/week/month/trimester/semester/year), for year-over-year comparison charts. getCount is CUMULATIVE: it sums every included period from the finest granularity up to (and including) the one asked for -- e.g.

class MMO\core\helpers\PeriodStatistic
Namespace
MMO\core\helpers
asking for Month returns day+week+month combined, not the month bucket alone.
$stat = new PeriodStatistic(2); // track 2 years, default periods (day/week/month/year) $stat->addCategory('sales'); $stat->add('sales', 5, cDatePeriod::Day, 0); // year index 0 $stat->add('sales', 3, cDatePeriod::Week, 0); $stat->getCount('sales', cDatePeriod::Week, 0); // 8 (day + week)

Index

INCLUDE_ALL
INCLUDE_DAY
INCLUDE_DEFAULT
INCLUDE_MONTH
INCLUDE_SEMESTER
INCLUDE_TRIMESTER
INCLUDE_WEEK
INCLUDE_YEAR
counts
includedPeriods
period
periods
yearCount
yearIndex
add($title, $count, $period, $yearIndex)Add $count to $title's bucket for the given period/year.
addCategory($title)Register a counter title, pre-filled with zeros for every tracked year/period.
excludePeriod($period)
getCount($title, $period, $yearIndex)
getPeriods()
includePeriod($period)
loopCollection($collection, $date, $filters, $dateField)Convenience driver: for each of the setYearCount tracked years (going backward one year at a time from $date), queries $collection for entities matching $filters within that year's largest tra…
loopCounts()Iterate every registered counter title, yielding its full year x period grid of CUMULATIVE counts (see
periodIndex($period)
PeriodToFlag($period) static
resetCounts()Reset every registered counter back to all-zeros (keeping the same titles).
setYearCount($yearCount)Change how many years are tracked, resetting every counter's data (resetCounts).
__construct($yearCount, $includedPeriods)

Constants8

INCLUDE_ALL

const INCLUDE_ALL = 63

INCLUDE_DAY

const INCLUDE_DAY = 1

INCLUDE_DEFAULT

const INCLUDE_DEFAULT = 39

INCLUDE_MONTH

const INCLUDE_MONTH = 4

INCLUDE_SEMESTER

const INCLUDE_SEMESTER = 16

INCLUDE_TRIMESTER

const INCLUDE_TRIMESTER = 8

INCLUDE_WEEK

const INCLUDE_WEEK = 2

INCLUDE_YEAR

const INCLUDE_YEAR = 32

Properties6

counts

protected array $counts = []
Type
array

includedPeriods

protected int $includedPeriods = 39
Type
int

period

protected ?MMO\core\helpers\cDatePeriod $period = null
Type
null | cDatePeriod

periods

protected array $periods = []
Type
array

yearCount

protected int $yearCount
Type
int

yearIndex

protected ?int $yearIndex = null
Type
null | int

Methods13

add($title, $count, $period, $yearIndex)

PeriodStatistic.php:118

Add $count to $title's bucket for the given period/year.

function add( string $title, int|float $count = 1, MMO\core\helpers\cDatePeriod|string|null $period = null, ?int $yearIndex = null ): self
$titlestringthe counter's name (e.g. 'sales') -- need not have been addCategory-d first
$count = 1int | float
$period = nullcDatePeriod | string | nulldefaults to whatever period loopCollection last set as "current"
$yearIndex = nullnull | int0 = the most recent year; defaults to whatever loopCollection last set as "current"
returnsself$this, for chaining
$stat->add('sales', 5, cDatePeriod::Day, 0);

addCategory($title)

PeriodStatistic.php:137

Register a counter title, pre-filled with zeros for every tracked year/period. Not strictly required before add (which lazily creates the entry), but ensures the title appears (with zeros) in

function addCategory(string $title): void
See
loopCounts even if nothing was ever added to it.
$titlestring
returnsvoid

excludePeriod($period)

PeriodStatistic.php:86
function excludePeriod(MMO\core\helpers\cDatePeriod $period): self
$periodcDatePeriod
returnsself$this, for chaining
$stat->excludePeriod(cDatePeriod::Week);

getCount($title, $period, $yearIndex)

PeriodStatistic.php:179
function getCount( string $title, MMO\core\helpers\cDatePeriod|string|null $period = null, ?int $yearIndex = null ): int
$titlestring
$period = nullcDatePeriod | string | nulldefaults to whatever period loopCollection last set as "current"
$yearIndex = nullnull | intdefaults to whatever loopCollection last set as "current"
returnsintthe CUMULATIVE count from the finest tracked period up to and including $period (0 if $title or $yearIndex was never populated)
$stat->getCount('sales', cDatePeriod::Month, 0); // day + week + month, for year index 0

includePeriod($period)

PeriodStatistic.php:76
function includePeriod(MMO\core\helpers\cDatePeriod $period): self
$periodcDatePeriod
returnsself$this, for chaining
$stat->includePeriod(cDatePeriod::Trimester);

loopCollection($collection, $date, $filters, $dateField)

PeriodStatistic.php:240

Convenience driver: for each of the setYearCount tracked years (going backward one year at a time from $date), queries $collection for entities matching $filters within that year's largest tracked period window, and yields each one tagged with which period it falls into -- while also updating the internal "current" period/year ($period / $yearIndex) so a plain add(title, count) call inside the loop body (with no explicit period/year) lands in the right bucket.

function loopCollection( MMO\core\entities\Collection $collection, DateTimeInterface $date, array $filters = [], string $dateField = 'ctime' ): Generator
$collectionCollection
$dateDateTimeInterfacethe reference "now" for year 0
$filters = []arrayextra filters merged into the query
$dateField = 'ctime'stringthe entity field used to bucket by period
returnsGeneratorperiodName => iEntity, one at a time, across every tracked year
foreach ($stat->loopCollection($orders, new DateTime(), [], 'ctime') as $period => $order) { $stat->add('revenue', $order['amount']); // period/year are inferred from the current loop position }

loopCounts()

PeriodStatistic.php:201

Iterate every registered counter title, yielding its full year x period grid of CUMULATIVE counts (see

function loopCounts(): Generator
See
getCount) -- ready to feed straight into a chart.
returnsGeneratortitle => [yearIndex => [count per tracked period, finest first], ...]
foreach ($stat->loopCounts() as $title => $byYear) {...}

periodIndex($period)

PeriodStatistic.php:96
protected function periodIndex(MMO\core\helpers\cDatePeriod $period): int
$periodcDatePeriod
returnsintthis period's position among the currently-tracked granularities (0 = finest)
throwsif $period is Second/Minute/Hour (not trackable -- see PeriodToFlag)

PeriodToFlag($period)

staticPeriodStatistic.php:58
static function PeriodToFlag(MMO\core\helpers\cDatePeriod $period): int
$periodcDatePeriod
returnsintthe matching self::INCLUDE_* bit, or 0 for a period this class doesn't track (Second/Minute/Hour)

resetCounts()

PeriodStatistic.php:160

Reset every registered counter back to all-zeros (keeping the same titles).

function resetCounts(): void
returnsvoid

setYearCount($yearCount)

PeriodStatistic.php:150

Change how many years are tracked, resetting every counter's data (resetCounts).

function setYearCount(int $yearCount): self
$yearCountint
returnsself$this, for chaining

__construct($yearCount, $includedPeriods)

PeriodStatistic.php:41
function __construct(int $yearCount = 2, int $includedPeriods = self::INCLUDE_DEFAULT)
$yearCount = 2inthow many years of history to track (setYearCount)
$includedPeriods = self::INCLUDE_DEFAULTinta bitmask of self::INCLUDE_* (default: day/week/month/year)