Skip to content

Commit

Permalink
[Demo] Statistics chart
Browse files Browse the repository at this point in the history
  • Loading branch information
loic425 committed Feb 14, 2025
1 parent e1b6dc3 commit 43846c9
Show file tree
Hide file tree
Showing 22 changed files with 591 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ composer.lock
.phpunit.result.cache
/phpunit.xml
###< symfony/phpunit-bridge ###

###> symfony/asset-mapper ###
/public/assets/
/assets/vendor/
###< symfony/asset-mapper ###
58 changes: 58 additions & 0 deletions app/Doctrine/Day.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Doctrine;

use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\TokenType;

final class Day extends FunctionNode
{
/** @var Node|string|null */
public $date;

public function parse(Parser $parser): void
{
$parser->match(TokenType::T_IDENTIFIER);
$parser->match(TokenType::T_OPEN_PARENTHESIS);

$this->date = $parser->ArithmeticPrimary();

$parser->match(TokenType::T_CLOSE_PARENTHESIS);
}

public function getSql(SqlWalker $sqlWalker): string
{
$platform = $sqlWalker->getConnection()->getDatabasePlatform();

if ($platform instanceof MySQLPlatform) {
return sprintf('DAY(%s)', $sqlWalker->walkArithmeticPrimary($this->date));
}

if ($platform instanceof PostgreSQLPlatform) {
return sprintf('EXTRACT(DAY FROM %s)', $sqlWalker->walkArithmeticPrimary($this->date));
}

if ($platform instanceof SqlitePlatform) {
return sprintf('CAST(STRFTIME("%%d", %s) AS NUMBER)', $sqlWalker->walkArithmeticPrimary($this->date));
}

throw new \RuntimeException(sprintf('Platform "%s" is not supported!', $platform::class));
}
}
58 changes: 58 additions & 0 deletions app/Doctrine/Month.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Doctrine;

use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\TokenType;

final class Month extends FunctionNode
{
/** @var Node|string|null */
public $date;

public function parse(Parser $parser): void
{
$parser->match(TokenType::T_IDENTIFIER);
$parser->match(TokenType::T_OPEN_PARENTHESIS);

$this->date = $parser->ArithmeticPrimary();

$parser->match(TokenType::T_CLOSE_PARENTHESIS);
}

public function getSql(SqlWalker $sqlWalker): string
{
$platform = $sqlWalker->getConnection()->getDatabasePlatform();

if ($platform instanceof MySQLPlatform) {
return sprintf('MONTH(%s)', $sqlWalker->walkArithmeticPrimary($this->date));
}

if ($platform instanceof PostgreSQLPlatform) {
return sprintf('EXTRACT(MONTH FROM %s)', $sqlWalker->walkArithmeticPrimary($this->date));
}

if ($platform instanceof SqlitePlatform) {
return sprintf('CAST(STRFTIME("%%m", %s) AS NUMBER)', $sqlWalker->walkArithmeticPrimary($this->date));
}

throw new \RuntimeException(sprintf('Platform "%s" is not supported!', $platform::class));
}
}
58 changes: 58 additions & 0 deletions app/Doctrine/Year.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Doctrine;

use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\TokenType;

final class Year extends FunctionNode
{
/** @var Node|string|null */
public $date;

public function parse(Parser $parser): void
{
$parser->match(TokenType::T_IDENTIFIER);
$parser->match(TokenType::T_OPEN_PARENTHESIS);

$this->date = $parser->ArithmeticPrimary();

$parser->match(TokenType::T_CLOSE_PARENTHESIS);
}

public function getSql(SqlWalker $sqlWalker): string
{
$platform = $sqlWalker->getConnection()->getDatabasePlatform();

if ($platform instanceof MySQLPlatform) {
return sprintf('YEAR(%s)', $sqlWalker->walkArithmeticPrimary($this->date));
}

if ($platform instanceof PostgreSQLPlatform) {
return sprintf('EXTRACT(YEAR FROM %s)', $sqlWalker->walkArithmeticPrimary($this->date));
}

if ($platform instanceof SqlitePlatform) {
return sprintf('CAST(STRFTIME("%%Y", %s) AS NUMBER)', $sqlWalker->walkArithmeticPrimary($this->date));
}

throw new \RuntimeException(sprintf('Platform "%s" is not supported!', $platform::class));
}
}
43 changes: 43 additions & 0 deletions app/Repository/TalkRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,47 @@ public function findTotalTalks(\DatePeriod $datePeriod): int

return (int) $queryBuilder->getQuery()->getSingleScalarResult();
}

public function findTalkStatisticsPerDay(\DatePeriod $datePeriod): array
{
return $this->findTalkStatistics($datePeriod, [
'year' => 'YEAR(o.startsAt) AS year',
'month' => 'MONTH(o.startsAt) AS month',
'day' => 'DAY(o.startsAt) AS day',
]);
}

public function findTalkStatisticsPerMonth(\DatePeriod $datePeriod): array
{
return $this->findTalkStatistics($datePeriod, [
'year' => 'YEAR(o.startsAt) AS year',
'month' => 'MONTH(o.startsAt) AS month',
]);
}

private function findTalkStatistics(\DatePeriod $datePeriod, array $groupBy): array
{
$queryBuilder = $this->createQueryBuilder('o');

$queryBuilder
->select('COUNT(o.id) AS total')
->andWhere(
$queryBuilder->expr()->gte('o.startsAt', ':start_date'),
)
->andWhere(
$queryBuilder->expr()->lt('o.startsAt', ':end_date'),
)
->setParameter('start_date', $datePeriod->getStartDate())
->setParameter('end_date', $datePeriod->getEndDate())
;

foreach ($groupBy as $name => $select) {
$queryBuilder
->addSelect($select)
->addGroupBy($name)
;
}

return $queryBuilder->getQuery()->getArrayResult();
}
}
56 changes: 56 additions & 0 deletions app/Statistics/Provider/DayTalksProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Statistics\Provider;

use App\Repository\TalkRepository;

final class DayTalksProvider
{
public function __construct(
private readonly TalkRepository $talkRepository,
) {
}

/**
* @return array<array{period: \DateTimeInterface, total: int}>
*/
public function provide(\DatePeriod $datePeriod): array
{
$talkStatistics = $this->talkRepository->findTalkStatisticsPerDay($datePeriod);

$talks = [];
foreach ($datePeriod as $date) {
$talks[] = [
'period' => $date,
'total' => $this->getTotalForDate($talkStatistics, $date),
];
}

return $talks;
}

/** @param array<array{total: string|int, year: int, month: int, day: int}> $totals */
private function getTotalForDate(array $totals, \DateTimeInterface $date): int
{
$formattedPeriodDate = $date->format('Y-n-j');

foreach ($totals as $entry) {
if ($entry['year'] . '-' . $entry['month'] . '-' . $entry['day'] === $formattedPeriodDate) {
return (int) $entry['total'];
}
}

return 0;
}
}
57 changes: 57 additions & 0 deletions app/Statistics/Provider/MonthTalksProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Statistics\Provider;

use App\Repository\TalkRepository;

final class MonthTalksProvider
{
public function __construct(
private readonly TalkRepository $talkRepository,
) {
}

/**
* @return array<array{period: \DateTimeInterface, total: int}>
*/
public function provide(\DatePeriod $datePeriod): array
{
$talkStatistics = $this->talkRepository->findTalkStatisticsPerMonth($datePeriod);

$talks = [];
foreach ($datePeriod as $date) {
$talks[] = [
'period' => $date,
'total' => $this->getTotalForDate($talkStatistics, $date),
];
}

return $talks;
}

/** @param array<array{total: string|int, year: int, month: int}> $totals */
private function getTotalForDate(array $totals, \DateTimeInterface $date): int
{
$formattedPeriodDate = $date->format('Y-n');

foreach ($totals as $entry) {
$entryDate = $entry['year'] . '-' . $entry['month'];
if ($formattedPeriodDate === $entryDate) {
return (int) $entry['total'];
}
}

return 0;
}
}
Loading

0 comments on commit 43846c9

Please sign in to comment.