customize html and pdf exports with twig templates (#1582)

This commit is contained in:
Kevin Papst
2020-03-23 01:51:02 +01:00
committed by GitHub
parent 1ca1b00d11
commit 33f76f426c
32 changed files with 895 additions and 307 deletions

View File

@@ -17,6 +17,7 @@ use App\Event\ProjectMetaDisplayEvent;
use App\Event\TimesheetMetaDisplayEvent;
use App\Event\UserPreferenceDisplayEvent;
use App\Export\ExportItemInterface;
use App\Repository\ProjectRepository;
use App\Repository\Query\CustomerQuery;
use App\Repository\Query\TimesheetQuery;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
@@ -35,11 +36,24 @@ class HtmlRenderer
* @var EventDispatcherInterface
*/
protected $dispatcher;
/**
* @var ProjectRepository
*/
private $projectRepository;
/**
* @var string
*/
private $id = 'html';
/**
* @var string
*/
private $template = 'default.html.twig';
public function __construct(Environment $twig, EventDispatcherInterface $dispatcher)
public function __construct(Environment $twig, EventDispatcherInterface $dispatcher, ProjectRepository $projectRepository)
{
$this->twig = $twig;
$this->dispatcher = $dispatcher;
$this->projectRepository = $projectRepository;
}
/**
@@ -87,10 +101,13 @@ class HtmlRenderer
$this->dispatcher->dispatch($event);
$userPreferences = $event->getPreferences();
$content = $this->twig->render('export/renderer/default.html.twig', array_merge([
$summary = $this->calculateSummary($timesheets);
$content = $this->twig->render($this->getTemplate(), array_merge([
'entries' => $timesheets,
'query' => $query,
'summaries' => $this->calculateSummary($timesheets),
'summaries' => $summary,
'budgets' => $this->calculateProjectBudget($timesheets, $query, $this->projectRepository),
'timesheetMetaFields' => $timesheetMetaFields,
'customerMetaFields' => $customerMetaFields,
'projectMetaFields' => $projectMetaFields,
@@ -104,8 +121,27 @@ class HtmlRenderer
return $response;
}
protected function getTemplate(): string
{
return '@export/' . $this->template;
}
public function setTemplate(string $filename): HtmlRenderer
{
$this->template = $filename;
return $this;
}
public function setId(string $id): HtmlRenderer
{
$this->id = $id;
return $this;
}
public function getId(): string
{
return 'html';
return $this->id;
}
}

View File

@@ -10,6 +10,7 @@
namespace App\Export\Base;
use App\Export\ExportItemInterface;
use App\Repository\ProjectRepository;
use App\Repository\Query\TimesheetQuery;
use App\Timesheet\UserDateTimeFactory;
use App\Utils\HtmlToPdfConverter;
@@ -33,17 +34,30 @@ class PDFRenderer
* @var HtmlToPdfConverter
*/
private $converter;
/**
* @var ProjectRepository
*/
private $projectRepository;
/**
* @var string
*/
private $id = 'pdf';
/**
* @var string
*/
private $template = 'default.pdf.twig';
public function __construct(Environment $twig, UserDateTimeFactory $dateTime, HtmlToPdfConverter $converter)
public function __construct(Environment $twig, UserDateTimeFactory $dateTime, HtmlToPdfConverter $converter, ProjectRepository $projectRepository)
{
$this->twig = $twig;
$this->dateTime = $dateTime;
$this->converter = $converter;
$this->projectRepository = $projectRepository;
}
protected function getTemplate(): string
{
return 'export/renderer/pdf.html.twig';
return '@export/' . $this->template;
}
protected function getOptions(TimesheetQuery $query): array
@@ -68,11 +82,13 @@ class PDFRenderer
*/
public function render(array $timesheets, TimesheetQuery $query): Response
{
$summary = $this->calculateSummary($timesheets);
$content = $this->twig->render($this->getTemplate(), array_merge([
'entries' => $timesheets,
'query' => $query,
'now' => $this->dateTime->createDateTime(),
'summaries' => $this->calculateSummary($timesheets),
'summaries' => $summary,
'budgets' => $this->calculateProjectBudget($timesheets, $query, $this->projectRepository),
'decimal' => false,
], $this->getOptions($query)));
@@ -88,8 +104,22 @@ class PDFRenderer
return $response;
}
public function setTemplate(string $filename): PDFRenderer
{
$this->template = $filename;
return $this;
}
public function setId(string $id): PDFRenderer
{
$this->id = $id;
return $this;
}
public function getId(): string
{
return 'pdf';
return $this->id;
}
}

View File

@@ -10,6 +10,8 @@
namespace App\Export\Base;
use App\Export\ExportItemInterface;
use App\Repository\ProjectRepository;
use App\Repository\Query\TimesheetQuery;
trait RendererTrait
{
@@ -80,4 +82,52 @@ trait RendererTrait
return $summary;
}
/**
* @param ExportItemInterface[] $exportItems
* @param TimesheetQuery $query
* @param ProjectRepository $projectRepository
* @return array
*/
protected function calculateProjectBudget(array $exportItems, TimesheetQuery $query, ProjectRepository $projectRepository)
{
$summary = [];
foreach ($exportItems as $exportItem) {
$customer = null;
$customerId = 'none';
$project = null;
$projectId = 'none';
if (null !== ($project = $exportItem->getProject())) {
$customer = $project->getCustomer();
$customerId = $customer->getId();
$projectId = $project->getId();
}
$id = $customerId . '_' . $projectId;
if (!isset($summary[$id])) {
$summary[$id] = [
'time' => $project->getTimeBudget(),
'money' => $project->getBudget(),
'time_left' => null,
'money_left' => null,
];
if (null !== $project && ($project->getTimeBudget() > 0 || $project->getBudget() > 0)) {
$projectStats = $projectRepository->getProjectStatistics($project, null, $query->getEnd());
if ($project->getTimeBudget() > 0) {
$summary[$id]['time_left'] = $project->getTimeBudget() - $projectStats->getRecordDuration();
}
if ($project->getBudget() > 0) {
$summary[$id]['money_left'] = $project->getBudget() - $projectStats->getRecordRate();
}
}
}
}
return $summary;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Export;
use App\Repository\Query\TimesheetQuery;
use Symfony\Component\HttpFoundation\Response;
interface ExportRendererInterface
{
/**
* @param ExportItemInterface[] $exportItems
* @param TimesheetQuery $query
* @return Response
*/
public function render(array $exportItems, TimesheetQuery $query): Response;
/**
* @return string
*/
public function getId(): string;
/**
* @return string
*/
public function getIcon(): string;
/**
* @return string
*/
public function getTitle(): string;
}

View File

@@ -10,9 +10,9 @@
namespace App\Export\Renderer;
use App\Export\Base\HtmlRenderer as BaseHtmlRenderer;
use App\Export\RendererInterface;
use App\Export\ExportRendererInterface;
final class HtmlRenderer extends BaseHtmlRenderer implements RendererInterface
final class HtmlRenderer extends BaseHtmlRenderer implements ExportRendererInterface
{
public function getIcon(): string
{

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Export\Renderer;
use App\Repository\ProjectRepository;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Twig\Environment;
final class HtmlRendererFactory
{
/**
* @var Environment
*/
private $twig;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @var ProjectRepository
*/
private $projectRepository;
public function __construct(Environment $twig, EventDispatcherInterface $dispatcher, ProjectRepository $projectRepository)
{
$this->twig = $twig;
$this->dispatcher = $dispatcher;
$this->projectRepository = $projectRepository;
}
public function create(string $id, string $template): HtmlRenderer
{
$renderer = new HtmlRenderer($this->twig, $this->dispatcher, $this->projectRepository);
$renderer->setId($id);
$renderer->setTemplate($template);
return $renderer;
}
}

View File

@@ -10,9 +10,9 @@
namespace App\Export\Renderer;
use App\Export\Base\PDFRenderer as BasePDFRenderer;
use App\Export\RendererInterface;
use App\Export\ExportRendererInterface;
final class PDFRenderer extends BasePDFRenderer implements RendererInterface
final class PDFRenderer extends BasePDFRenderer implements ExportRendererInterface
{
public function getIcon(): string
{

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Export\Renderer;
use App\Repository\ProjectRepository;
use App\Timesheet\UserDateTimeFactory;
use App\Utils\HtmlToPdfConverter;
use Twig\Environment;
final class PdfRendererFactory
{
/**
* @var Environment
*/
private $twig;
/**
* @var UserDateTimeFactory
*/
private $dateTime;
/**
* @var HtmlToPdfConverter
*/
private $converter;
/**
* @var ProjectRepository
*/
private $projectRepository;
public function __construct(Environment $twig, UserDateTimeFactory $dateTime, HtmlToPdfConverter $converter, ProjectRepository $projectRepository)
{
$this->twig = $twig;
$this->dateTime = $dateTime;
$this->converter = $converter;
$this->projectRepository = $projectRepository;
}
public function create(string $id, string $template): PDFRenderer
{
$renderer = new PDFRenderer($this->twig, $this->dateTime, $this->converter, $this->projectRepository);
$renderer->setId($id);
$renderer->setTemplate($template);
return $renderer;
}
}

View File

@@ -9,30 +9,6 @@
namespace App\Export;
use App\Repository\Query\TimesheetQuery;
use Symfony\Component\HttpFoundation\Response;
interface RendererInterface
interface RendererInterface extends ExportRendererInterface
{
/**
* @param ExportItemInterface[] $exportItems
* @param TimesheetQuery $query
* @return Response
*/
public function render(array $exportItems, TimesheetQuery $query): Response;
/**
* @return string
*/
public function getId(): string;
/**
* @return string
*/
public function getIcon(): string;
/**
* @return string
*/
public function getTitle(): string;
}

View File

@@ -12,7 +12,7 @@ namespace App\Export;
final class ServiceExport
{
/**
* @var RendererInterface[]
* @var ExportRendererInterface[]
*/
private $renderer = [];
@@ -21,7 +21,7 @@ final class ServiceExport
*/
private $exporter = [];
public function addRenderer(RendererInterface $renderer): ServiceExport
public function addRenderer(ExportRendererInterface $renderer): ServiceExport
{
$this->renderer[] = $renderer;
@@ -29,14 +29,14 @@ final class ServiceExport
}
/**
* @return RendererInterface[]
* @return ExportRendererInterface[]
*/
public function getRenderer(): array
{
return $this->renderer;
}
public function getRendererById(string $id): ?RendererInterface
public function getRendererById(string $id): ?ExportRendererInterface
{
foreach ($this->renderer as $renderer) {
if ($renderer->getId() === $id) {