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;
}