diff --git a/app/config/config.php b/app/config/config.php index 9519612..0ece9e4 100644 --- a/app/config/config.php +++ b/app/config/config.php @@ -8,6 +8,9 @@ use Interop\Container\ContainerInterface; use Maintained\Badge\BadgeGenerator; use Maintained\Badge\BadgeProvider; use Maintained\Badge\CachedBadgeProvider; +use Maintained\Statistics\CachedStatisticsProvider; +use Maintained\Statistics\StatisticsComputer; +use Maintained\Statistics\StatisticsProvider; use PUGX\Poser\Poser; use PUGX\Poser\Render\SvgRender; use function DI\factory; @@ -39,8 +42,12 @@ return [ }), Cache::class => object(FilesystemCache::class) - ->constructor(__DIR__ . '/../../app/cache/badges'), + ->constructor(__DIR__ . '/../../app/cache/app') + ->method('setNamespace', 'Maintained'), BadgeProvider::class => object(CachedBadgeProvider::class) ->constructorParameter('wrapped', link(BadgeGenerator::class)), + + StatisticsProvider::class => object(CachedStatisticsProvider::class) + ->constructorParameter('wrapped', link(StatisticsComputer::class)), ]; diff --git a/app/config/routes.php b/app/config/routes.php index e313bb8..6a58a01 100644 --- a/app/config/routes.php +++ b/app/config/routes.php @@ -2,13 +2,18 @@ use Maintained\Application\Controller\BadgeController; use Maintained\Application\Controller\HomeController; +use Maintained\Application\Controller\ProjectController; return [ - 'home' => [ + 'home' => [ 'pattern' => '/', 'controller' => HomeController::class, ], - 'badge' => [ + 'project' => [ + 'pattern' => '/project/{user}/{repository}', + 'controller' => ProjectController::class, + ], + 'badge' => [ 'pattern' => '/badge/{user}/{repository}.svg', 'controller' => BadgeController::class, ], diff --git a/src/Maintained/Application/Controller/ProjectController.php b/src/Maintained/Application/Controller/ProjectController.php new file mode 100644 index 0000000..6995276 --- /dev/null +++ b/src/Maintained/Application/Controller/ProjectController.php @@ -0,0 +1,33 @@ + + */ +class ProjectController +{ + /** + * @Inject + * @var \Twig_Environment + */ + private $twig; + + /** + * @Inject + * @var StatisticsProvider + */ + private $statisticsProvider; + + public function __invoke($user, $repository) + { + $statistics = $this->statisticsProvider->getStatistics($user, $repository); + + echo $this->twig->render('project.twig', [ + 'repository' => $user . '/' . $repository, + 'resolutionTime' => $statistics->resolutionTime, + ]); + } +} diff --git a/src/Maintained/Application/View/layout.twig b/src/Maintained/Application/View/layout.twig index cbd4193..26c3271 100644 --- a/src/Maintained/Application/View/layout.twig +++ b/src/Maintained/Application/View/layout.twig @@ -32,25 +32,27 @@ - Is it maintained? + Is it maintained? diff --git a/src/Maintained/Application/View/project.twig b/src/Maintained/Application/View/project.twig new file mode 100644 index 0000000..ef003bf --- /dev/null +++ b/src/Maintained/Application/View/project.twig @@ -0,0 +1,28 @@ +{% extends 'layout.twig' %} + +{% block content %} + +
+
+ +
+
+

{{ repository }}

+
+
+
+ +
+
+ +

+ Resolution time: {{ resolutionTime.formatLong() }} +

+ +
+
+ +
+
+ +{% endblock %} \ No newline at end of file diff --git a/src/Maintained/Badge/CachedBadgeProvider.php b/src/Maintained/Badge/CachedBadgeProvider.php index 8c46128..628eb87 100644 --- a/src/Maintained/Badge/CachedBadgeProvider.php +++ b/src/Maintained/Badge/CachedBadgeProvider.php @@ -11,7 +11,7 @@ use Doctrine\Common\Cache\Cache; */ class CachedBadgeProvider implements BadgeProvider { - const CACHE_NAMESPACE = 'maintained/'; + const CACHE_NAMESPACE = 'badge/'; /** * @var Cache diff --git a/src/Maintained/Diagnostic.php b/src/Maintained/Diagnostic.php index 58c5343..b8ad0ba 100644 --- a/src/Maintained/Diagnostic.php +++ b/src/Maintained/Diagnostic.php @@ -55,7 +55,7 @@ class Diagnostic } /** - * @return float + * @return TimeInterval */ public function computeAverage() { @@ -67,6 +67,9 @@ class Diagnostic return new TimeInterval($average); } + /** + * @return TimeInterval + */ public function computeMedian() { $durations = array_map(function (Issue $issue) { diff --git a/src/Maintained/Statistics/CachedStatisticsProvider.php b/src/Maintained/Statistics/CachedStatisticsProvider.php new file mode 100644 index 0000000..b142d67 --- /dev/null +++ b/src/Maintained/Statistics/CachedStatisticsProvider.php @@ -0,0 +1,46 @@ + + */ +class CachedStatisticsProvider implements StatisticsProvider +{ + const CACHE_NAMESPACE = 'statistics/'; + + /** + * @var Cache + */ + private $cache; + + /** + * @var StatisticsProvider + */ + private $wrapped; + + public function __construct(Cache $cache, StatisticsProvider $wrapped) + { + $this->cache = $cache; + $this->wrapped = $wrapped; + } + + public function getStatistics($user, $repository) + { + $key = self::CACHE_NAMESPACE . $user . '/' . $repository; + + $statistics = $this->cache->fetch($key); + + if ($statistics === false) { + $statistics = $this->wrapped->getStatistics($user, $repository); + + $this->cache->save($key, $statistics); + } + + return $statistics; + } +} diff --git a/src/Maintained/Statistics/Statistics.php b/src/Maintained/Statistics/Statistics.php new file mode 100644 index 0000000..5446cc6 --- /dev/null +++ b/src/Maintained/Statistics/Statistics.php @@ -0,0 +1,18 @@ + + */ +class Statistics +{ + /** + * @var TimeInterval + */ + public $resolutionTime; +} diff --git a/src/Maintained/Statistics/StatisticsComputer.php b/src/Maintained/Statistics/StatisticsComputer.php new file mode 100644 index 0000000..0973e50 --- /dev/null +++ b/src/Maintained/Statistics/StatisticsComputer.php @@ -0,0 +1,23 @@ + + */ +class StatisticsComputer implements StatisticsProvider +{ + public function getStatistics($user, $repository) + { + $diagnostic = new Diagnostic($user . '/' . $repository); + + $statistics = new Statistics(); + $statistics->resolutionTime = $diagnostic->computeMedian(); + + return $statistics; + } +} diff --git a/src/Maintained/Statistics/StatisticsProvider.php b/src/Maintained/Statistics/StatisticsProvider.php new file mode 100644 index 0000000..4b3c1d6 --- /dev/null +++ b/src/Maintained/Statistics/StatisticsProvider.php @@ -0,0 +1,18 @@ + + */ +interface StatisticsProvider +{ + /** + * @param string $user + * @param string $repository + * @return Statistics + */ + public function getStatistics($user, $repository); +} diff --git a/src/Maintained/TimeInterval.php b/src/Maintained/TimeInterval.php index 611f06d..4ab9e4e 100644 --- a/src/Maintained/TimeInterval.php +++ b/src/Maintained/TimeInterval.php @@ -54,6 +54,25 @@ class TimeInterval } } + /** + * Format to a long display string. + * + * @return string + */ + public function formatLong() + { + switch (true) { + case $this->seconds < self::TO_MINUTE: + return sprintf('%d second(s)', $this->seconds); + case $this->seconds < self::TO_HOUR: + return sprintf('%d minute(s)', $this->toMinutes()); + case $this->seconds < self::TO_DAY: + return sprintf('%d hour(s)', $this->toHours()); + default: + return sprintf('%d day(s)', $this->toDays()); + } + } + /** * @return int */ diff --git a/web/css/theme.css b/web/css/theme.css index c395265..cde9383 100755 --- a/web/css/theme.css +++ b/web/css/theme.css @@ -27,6 +27,7 @@ body { line-height: 1.42857143; color: #2c3e50; background-color: #ffffff; + padding-top: 50px; } p { @@ -107,7 +108,7 @@ header { } header .container { - padding-top: 100px; + padding-top: 40px; padding-bottom: 50px; } @@ -130,8 +131,10 @@ header .intro-text .skills { } @media(min-width:768px) { + body { + padding-top: 100px; + } header .container { - padding-top: 140px; padding-bottom: 100px; }