refactor/update #30

Merged
TorstenHettstedt merged 15 commits from refactor/update into master 2025-06-16 15:48:34 +02:00
17 changed files with 125 additions and 151 deletions
Showing only changes of commit 6fa6b28af6 - Show all commits
+6 -1
View File
@@ -4,7 +4,9 @@ namespace TorstenHettstedt\TimekeepingApi\Controller;
use JsonSerializable;
use PDO;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Slim\Psr7\Response;
abstract class AbstractController
@@ -18,6 +20,8 @@ abstract class AbstractController
* @param ContainerInterface $container
*
* @throws NotDatabasesException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function __construct(ContainerInterface $container)
{
@@ -34,7 +38,8 @@ abstract class AbstractController
*
* @return Response
*/
protected function printResponse(Response $response, mixed $data, int $status_code): Response {
protected function printResponse(Response $response, mixed $data, int $status_code): Response
{
$payload = json_encode($data);
$response->getBody()->write($payload);
@@ -11,6 +11,7 @@ use TorstenHettstedt\TimekeepingApi\Middleware\OriginAccessControlHandler;
class PreflightController
{
/** @noinspection PhpUnused */
public function preflight(Request $request, Response $response): ResponseInterface
{
return (new OriginAccessControlHandler())->originAccessControl($request, $response);
+35 -19
View File
@@ -21,9 +21,9 @@ class WorkingHoursController extends AbstractController
{
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -44,9 +44,9 @@ class WorkingHoursController extends AbstractController
}
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -59,21 +59,29 @@ class WorkingHoursController extends AbstractController
$repository = new WorkingHoursRepository($this->databases);
$queryParams = $request->getQueryParams();
try {
return $this->printResponse($response, $repository->findFiltered(
$queryParams['start-date'] ?? null,
$queryParams['end-date'] ?? null
), StatusCodeInterface::STATUS_OK);
return $this->printResponse(
$response,
$repository->findFiltered(
$queryParams['start-date'] ?? null,
$queryParams['end-date'] ?? null
),
StatusCodeInterface::STATUS_OK
);
} catch (RepositoryBadWhereDataException $exception) {
throw new HttpBadRequestException($request, 'Ein Wert für das Datum im Query ist ungültig', $exception);
} catch (Exception $exception) {
throw new HttpInternalServerErrorException($request, 'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception);
throw new HttpInternalServerErrorException(
$request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank',
$exception
);
}
}
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -88,14 +96,18 @@ class WorkingHoursController extends AbstractController
} catch (RepositoryRecordNotFoundException $exception) {
throw new HttpNotFoundException($request, 'Der Eintrag ist nicht vorhanden.', $exception);
} catch (Exception $exception) {
throw new HttpInternalServerErrorException($request, 'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception);
throw new HttpInternalServerErrorException(
$request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank',
$exception
);
}
}
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -114,7 +126,11 @@ class WorkingHoursController extends AbstractController
} catch (RepositoryRecordAlreadyExistException $exception) {
throw new HttpConflictRequestException($request, 'Der Eintrag ist schon vorhanden.', $exception);
} catch (Exception $exception) {
throw new HttpInternalServerErrorException($request, 'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception);
throw new HttpInternalServerErrorException(
$request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank',
$exception
);
}
return $this->printResponse($response, $model, StatusCodeInterface::STATUS_CREATED);
}
@@ -15,9 +15,9 @@ use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursYearlyViewRepositor
class WorkingHoursViewController extends AbstractController
{
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -30,15 +30,17 @@ class WorkingHoursViewController extends AbstractController
try {
return $this->printResponse($response, $repository->findAll(), StatusCodeInterface::STATUS_OK);
} catch (Exception $exception) {
throw new HttpInternalServerErrorException($request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception);
throw new HttpInternalServerErrorException(
$request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception
);
}
}
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -51,15 +53,17 @@ class WorkingHoursViewController extends AbstractController
try {
return $this->printResponse($response, $repository->findAll(), StatusCodeInterface::STATUS_OK);
} catch (Exception $exception) {
throw new HttpInternalServerErrorException($request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception);
throw new HttpInternalServerErrorException(
$request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception
);
}
}
/**
* @param Request $request
* @param Response $response
* @param mixed[] $args
* @param Request $request
* @param Response $response
* @param array<string, mixed> $args
*
* @return Response
*
@@ -72,8 +76,10 @@ class WorkingHoursViewController extends AbstractController
try {
return $this->printResponse($response, $repository->findAll(), StatusCodeInterface::STATUS_OK);
} catch (Exception $exception) {
throw new HttpInternalServerErrorException($request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception);
throw new HttpInternalServerErrorException(
$request,
'Der Wert für das Datum oder die Zeit ist falsch in der Datenbank', $exception
);
}
}
+9 -5
View File
@@ -1,10 +1,12 @@
<?php /** @noinspection PhpUndefinedClassInspection */
<?php
/** @noinspection PhpUndefinedClassInspection */
namespace TorstenHettstedt\TimekeepingApi\Middleware;
use JetBrains\PhpStorm\ArrayShape;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
@@ -14,12 +16,15 @@ use Throwable;
class ErrorHandler
{
/**
* @var App<ContainerInterface>
*/
protected App $app;
/**
* ErrorHandler constructor.
*
* @param App $app
* @param App<ContainerInterface> $app
*/
public function __construct(App $app)
{
@@ -29,7 +34,7 @@ class ErrorHandler
/**
* @param Throwable $exception
*
* @return mixed[]
* @return array<string, mixed>
*/
#[ArrayShape([
'timestamp' => "false|string",
@@ -71,8 +76,7 @@ class ErrorHandler
bool $logErrors,
bool $logErrorDetails,
?LoggerInterface $logger = null
): ResponseInterface
{
): ResponseInterface {
if ($logger !== null && $logErrors === true) {
$logger->error($exception->getMessage());
}
@@ -13,7 +13,7 @@ class JsonBodyParserMiddleware implements MiddlewareInterface
{
$contentType = $request->getHeaderLine('Content-Type');
if (strstr($contentType, 'application/json')) {
if (str_contains($contentType, 'application/json')) {
$contents = json_decode(file_get_contents('php://input'), true);
if (json_last_error() === JSON_ERROR_NONE) {
$request = $request->withParsedBody($contents);
@@ -28,15 +28,14 @@ class OriginAccessControlHandler implements MiddlewareInterface
public function originAccessControl(Request $request, Response $response): Response
{
$routeContext = RouteContext::fromRequest($request);
$routingResults = $routeContext->getRoutingResults();
$methods = $routingResults->getAllowedMethods();
$requestHeaders = $request->getHeaderLine('Access-Control-Request-Headers');
if ($this->testRoute($request)) {
// Stunden Minuten Sekunden
$accessControlMaxAge = 24 * 60 * 60;
// Stunden Minuten Sekunden
$accessControlMaxAge = 24 * 60 * 60;
$response = $response->withHeader('Access-Control-Allow-Origin', $this->buildOrigin($request));
$response = $response->withHeader('Access-Control-Allow-Methods', implode(',', $methods));
$response = $response->withHeader('Access-Control-Allow-Headers', $requestHeaders);
@@ -53,6 +52,6 @@ class OriginAccessControlHandler implements MiddlewareInterface
protected function buildOrigin(Request $request): string
{
return $request->getHeaderLine('Origin') ?? '';
return $request->getHeaderLine('Origin');
}
}
+6 -13
View File
@@ -1,23 +1,16 @@
<?php /** @noinspection PhpUnusedPrivateFieldInspection */
<?php
/** @noinspection PhpUnusedPrivateFieldInspection */
namespace TorstenHettstedt\TimekeepingApi\Models;
use MyCLabs\Enum\Enum;
/**
* Enum-Klasse für die unterstützten Periode-Definitionen.
* Der Wert der Periode ist ein Format-String für {@link https://secure.php.net/manual/en/datetime.format.php}.
*
* @extends Enum<string>
*
* @method static PeriodDesignationEnum WEEKLY()
* @method static PeriodDesignationEnum MONTHLY()
* @method static PeriodDesignationEnum YEARLY()
*/
class PeriodDesignationEnum extends Enum
enum PeriodDesignationEnum: string
{
private const WEEKLY = 'Y#W';
private const MONTHLY = 'Y-m';
private const YEARLY = 'Y';
case WEEKLY = 'Y#W';
case MONTHLY = 'Y-m';
case YEARLY = 'Y';
}
+4 -20
View File
@@ -10,42 +10,26 @@ use JetBrains\PhpStorm\ArrayShape;
class WorkingHours implements ModelInterface
{
protected ?DateTime $workingDay = null;
protected ?DateTime $workingDay = null;
protected ?DateInterval $workingTime = null;
/**
* @return DateTime|null
*/
public function getWorkingDay(): ?DateTime
{
return $this->workingDay;
}
/**
* @param DateTime $workingDay
*
* @return WorkingHours
*/
public function setWorkingDay(DateTime $workingDay): WorkingHours
public function setWorkingDay(DateTime $workingDay): static
{
$this->workingDay = $workingDay;
return $this;
}
/**
* @return DateInterval|null
*/
public function getWorkingTime(): ?DateInterval
{
return $this->workingTime;
}
/**
* @param DateInterval $workingTime
*
* @return WorkingHours
*/
public function setWorkingTime(DateInterval $workingTime): WorkingHours
public function setWorkingTime(DateInterval $workingTime): static
{
$this->workingTime = $workingTime;
return $this;
@@ -58,7 +42,7 @@ class WorkingHours implements ModelInterface
public function jsonSerialize(): array
{
return [
'workingDay' => $this->getWorkingDay()->format('Y-m-d'),
'workingDay' => $this->getWorkingDay()->format('Y-m-d'),
'workingTime' => $this->getWorkingTime()->format('%H:%I:%S')
];
}
+12 -35
View File
@@ -10,21 +10,12 @@ use JetBrains\PhpStorm\ArrayShape;
class WorkingHoursView implements ModelInterface
{
protected DateTimeInterface $period;
protected DateTimeInterface $period;
protected PeriodDesignationEnum $periodDesignation;
protected int $workingDays;
protected DateInterval $totalHours;
protected DateInterval $overtime;
protected int $workingDays;
protected DateInterval $totalHours;
protected DateInterval $overtime;
/**
* WorkingHoursView constructor.
*
* @param DateTimeInterface $period
* @param PeriodDesignationEnum $periodDesignation
* @param int $workingDays
* @param DateInterval $totalHours
* @param DateInterval $overtime
*/
public function __construct(
TorstenHettstedt marked this conversation as resolved Outdated
Outdated
Review

ist es nicht besser, die ganzen Parameter über den Konstrukt zu bestimmen?

ist es nicht besser, die ganzen Parameter über den Konstrukt zu bestimmen?
DateTimeInterface $period,
PeriodDesignationEnum $periodDesignation,
@@ -39,41 +30,26 @@ class WorkingHoursView implements ModelInterface
$this->overtime = $overtime;
}
/**
* @return DateTimeInterface
*/
public function getPeriod(): DateTimeInterface
{
return $this->period;
}
/**
* @return PeriodDesignationEnum
*/
public function getPeriodDesignation(): PeriodDesignationEnum
{
return $this->periodDesignation;
}
/**
* @return int
*/
public function getWorkingDays(): int
{
return $this->workingDays;
}
/**
* @return DateInterval
*/
public function getTotalHours(): DateInterval
{
return $this->totalHours;
}
/**
* @return DateInterval
*/
public function getOvertime(): DateInterval
{
return $this->overtime;
@@ -84,17 +60,18 @@ class WorkingHoursView implements ModelInterface
*
* @return array<string, mixed>
*/
#[ArrayShape(['period' => "string",
'periodDesignation' => "string",
'totalHours' => "string",
'workingDays' => "int",
'overtime' => "string"
#[ArrayShape([
'period' => "string",
'periodDesignation' => "string",
'totalHours' => "string",
'workingDays' => "int",
'overtime' => "string"
])] public function jsonSerialize(): array
{
$formatOvertime = (($this->getOvertime()->invert === 1) ? '-' : '') . '%H:%I:%S';
return [
'period' => $this->getPeriod()->format($this->getPeriodDesignation()->getValue()),
'periodDesignation' => strtolower($this->getPeriodDesignation()->getKey()),
'period' => $this->getPeriod()->format($this->getPeriodDesignation()->value),
'periodDesignation' => strtolower($this->getPeriodDesignation()->name),
'workingDays' => $this->getWorkingDays(),
'totalHours' => $this->getTotalHours()->format('%H:%I:%S'),
'overtime' => $this->getOvertime()->format($formatOvertime)
@@ -18,9 +18,8 @@ abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInt
{
protected const SQL_SELECT = '';
protected const SQL_WHERE = '';
protected const SQL_WHERE = '';
protected PDO $database;
protected PeriodDesignationEnum $periodDesignation;
/**
@@ -28,9 +27,8 @@ abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInt
*
* @param PDO $database
*/
public function __construct(PDO $database)
public function __construct(protected PDO $database)
{
$this->database = $database;
$this->database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
@@ -51,7 +49,7 @@ abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInt
$model = new WorkingHoursView(
$this->buildDateFromPeriod($row['period']),
$this->periodDesignation,
(int) $row['workingDays'],
(int)$row['workingDays'],
$this->buildDateInterval($row['totalHours']),
$this->buildDateInterval($row['overtime'])
);
@@ -82,7 +80,7 @@ abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInt
return new WorkingHoursView(
$this->buildDateFromPeriod($row['period']),
$this->periodDesignation,
(int) $row['workingDays'],
(int)$row['workingDays'],
$this->buildDateInterval($row['totalHours']),
$this->buildDateInterval($row['overtime'])
);
@@ -3,8 +3,10 @@
namespace TorstenHettstedt\TimekeepingApi\Repositories;
use TorstenHettstedt\TimekeepingApi\Models\ModelInterface;
/**
* @template T of \TorstenHettstedt\TimekeepingApi\Models\ModelInterface
* @template T of ModelInterface
*/
interface RepositoryReaderInterface
{
@@ -3,8 +3,10 @@
namespace TorstenHettstedt\TimekeepingApi\Repositories;
use TorstenHettstedt\TimekeepingApi\Models\ModelInterface;
/**
* @template T of \TorstenHettstedt\TimekeepingApi\Models\ModelInterface
* @template T of ModelInterface
*/
interface RepositoryWriterInterface
{
@@ -20,15 +20,12 @@ class WorkingHoursMonthlyViewRepository extends AbstractWorkingHoursViewReposito
"Überstunden" as "overtime"
from "Arbeitszeiten - Monat"
SQL;
protected const SQL_WHERE = ' where "Monat" = ?';
protected PDO $database;
protected PeriodDesignationEnum $periodDesignation;
protected const SQL_WHERE = ' where "Monat" = ?';
public function __construct(PDO $database)
{
parent::__construct($database);
$this->periodDesignation = PeriodDesignationEnum::MONTHLY();
$this->periodDesignation = PeriodDesignationEnum::MONTHLY;
}
protected function buildDateFromPeriod(string $period): DateTimeInterface
@@ -21,16 +21,8 @@ use TorstenHettstedt\TimekeepingApi\Models\WorkingHours;
class WorkingHoursRepository implements RepositoryReaderInterface, RepositoryWriterInterface
{
protected PDO $database;
/**
* WorkingHoursRepository constructor.
*
* @param PDO $database
*/
public function __construct(PDO $database)
public function __construct(protected PDO $database)
{
$this->database = $database;
$this->database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
@@ -106,7 +98,7 @@ class WorkingHoursRepository implements RepositoryReaderInterface, RepositoryWri
if (is_string($end)) {
$stmt->bindParam(':end', $end);
}
return $stmt ?? null;
return $stmt ?: null;
}
/**
@@ -121,7 +113,9 @@ class WorkingHoursRepository implements RepositoryReaderInterface, RepositoryWri
*/
public function findByKey(mixed $primary_key): WorkingHours
{
TorstenHettstedt marked this conversation as resolved
Review

Here-Doc?

Here-Doc?
$stmt = $this->database->prepare('select "Datum" as "workingDay", "Arbeitszeit" as "workingTime" from public."Arbeitszeiten" where "Datum" = ?');
$stmt = $this->database->prepare(
'select "Datum" as "workingDay", "Arbeitszeit" as "workingTime" from public."Arbeitszeiten" where "Datum" = ?'
);
$stmt->bindParam(1, $primary_key);
$stmt->execute();
$row = $stmt->fetch();
@@ -155,7 +149,9 @@ class WorkingHoursRepository implements RepositoryReaderInterface, RepositoryWri
throw new RepositoryRecordAlreadyExistException();
} /** @noinspection PhpUnusedLocalVariableInspection */
catch (RepositoryRecordNotFoundException $exception) {
$stmt = $this->database->prepare('insert into public."Arbeitszeiten" ("Datum", "Arbeitszeit") values (?, ?) on conflict do nothing');
$stmt = $this->database->prepare(
'insert into public."Arbeitszeiten" ("Datum", "Arbeitszeit") values (?, ?) on conflict do nothing'
);
$stmt->bindParam(1, $workingDay);
$stmt->bindParam(2, $workingTime);
$stmt->execute();
@@ -19,15 +19,12 @@ class WorkingHoursWeeklyViewRepository extends AbstractWorkingHoursViewRepositor
"Überstunden" as "overtime"
from "Arbeitszeiten - Woche"
SQL;
protected const SQL_WHERE = ' where "Woche" = ?';
protected PDO $database;
protected PeriodDesignationEnum $periodDesignation;
protected const SQL_WHERE = ' where "Woche" = ?';
public function __construct(PDO $database)
{
parent::__construct($database);
$this->periodDesignation = PeriodDesignationEnum::WEEKLY();
$this->periodDesignation = PeriodDesignationEnum::WEEKLY;
}
protected function buildDateFromPeriod(string $period): DateTimeInterface
@@ -19,15 +19,12 @@ class WorkingHoursYearlyViewRepository extends AbstractWorkingHoursViewRepositor
"Überstunden" as "overtime"
from "Arbeitszeiten - Jahr"
SQL;
protected const SQL_WHERE = ' where "Jahr" = ?';
protected PDO $database;
protected PeriodDesignationEnum $periodDesignation;
protected const SQL_WHERE = ' where "Jahr" = ?';
public function __construct(PDO $database)
{
parent::__construct($database);
$this->periodDesignation = PeriodDesignationEnum::YEARLY();
$this->periodDesignation = PeriodDesignationEnum::YEARLY;
}
/**