Files
PHP-App-Timekeeping/api/src/Repositories/WorkingHoursRepository.php
T

222 lines
6.7 KiB
PHP

<?php
namespace TorstenHettstedt\TimekeepingApi\Repositories;
use DateInterval;
use DateTime;
use Exception;
use InvalidArgumentException;
use PDO;
use PDOException;
use PDOStatement;
use TorstenHettstedt\TimekeepingApi\Models\ModelInterface;
use TorstenHettstedt\TimekeepingApi\Models\WorkingHours;
/**
* @implements RepositoryReaderInterface<WorkingHours>
* @implements RepositoryWriterInterface<WorkingHours>
*/
class WorkingHoursRepository implements RepositoryReaderInterface, RepositoryWriterInterface
{
protected const string SQL_SELECT = <<<'SQL'
select
"Datum" as "workingDay",
"Arbeitszeit" as "workingTime",
"HomeOffice" as "isHomeOfficeDay"
from public."Arbeitszeiten"
SQL;
public function __construct(protected PDO $database)
{
$this->database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/**
*
* Gibt alle vorhandenen Einträge zurück
*
* @return WorkingHours[]
* @throws Exception
* @throws PDOException
*/
public function findAll(): array
{
return $this->findFiltered(null, null);
}
/**
*
* Gibt alle vorhandenen Einträge zurück
*
* @param string|null $start
* @param string|null $end
*
* @return WorkingHours[]
* @throws Exception
*/
public function findFiltered(?string $start, ?string $end): array
{
$models = [];
$stmt = $this->buildFindFilteredStatement($start, $end);
try {
$stmt->execute();
} catch (PDOException $exception) {
if ($exception->getCode() === '22007' || $exception->getCode() === '22008') {
throw new RepositoryBadWhereDataException($exception);
}
throw $exception;
}
while ($row = $stmt->fetch()) {
$model = new WorkingHours();
$model
->setWorkingDay(new DateTime($row['workingDay']))
->setWorkingTime(new DateInterval('P0000-00-00T' . $row['workingTime']))
->setIsHomeOffice($row['isHomeOfficeDay']);
$models[] = $model;
}
return $models;
}
protected function buildFilterString(?string $start, ?string $end): string
{
if (is_string($start) && is_string($end)) {
return 'where "Datum" >= :start AND "Datum" <= :end ';
}
if (is_string($start)) {
return 'where "Datum" >= :start ';
}
if (is_string($end)) {
return 'where "Datum" <= :end ';
}
return '';
}
protected function buildFindFilteredStatement(?string $start, ?string $end): ?PDOStatement
{
$query = static::SQL_SELECT . ' ';
$query .= $this->buildFilterString($start, $end);
$query .= 'order by "Datum"';
$stmt = $this->database->prepare($query);
if (is_string($start)) {
$stmt->bindParam(':start', $start);
}
if (is_string($end)) {
$stmt->bindParam(':end', $end);
}
return $stmt ?: null;
}
/**
* Gibt den Eintrag zurück, der durch die ID
*
* @param mixed $primary_key
*
* @return WorkingHours
* @throws RepositoryRecordNotFoundException
* @throws Exception
* @throws PDOException
*/
public function findByKey(mixed $primary_key): WorkingHours
{
$stmt = $this->database->prepare(static::SQL_SELECT . ' where "Datum" = ?');
$stmt->bindParam(1, $primary_key);
$stmt->execute();
$row = $stmt->fetch();
if ($row === false) {
throw new RepositoryRecordNotFoundException();
}
$model = new WorkingHours();
$model
->setWorkingDay(new DateTime($row['workingDay']))
->setWorkingTime(new DateInterval('P0000-00-00T' . $row['workingTime']))
->setIsHomeOffice($row['isHomeOfficeDay']);
return $model;
}
/**
* @param WorkingHours|ModelInterface $model
*
* @throws RepositoryRecordAlreadyExistException
* @throws Exception
*/
public function insert(mixed $model): void
{
if ($model instanceof WorkingHours) {
$workingDay = $model->getWorkingDay()->format('Y-m-d');
$workingTime = $model->getWorkingTime()->format('%H:%I:%S');
$isHomeOffice = $model->isHomeOffice();
} else {
throw new InvalidArgumentException('Es wird ein Modell der Klasse "' . WorkingHours::class . '" verlangt.');
}
try {
$this->findByKey($workingDay);
throw new RepositoryRecordAlreadyExistException();
} /** @noinspection PhpUnusedLocalVariableInspection */
catch (RepositoryRecordNotFoundException $exception) {
$stmt = $this->database->prepare(<<<'SQL'
insert into public."Arbeitszeiten" ("Datum", "Arbeitszeit", "HomeOffice")
values (?, ?, ?)
on conflict do nothing
SQL
);
$stmt->bindParam(1, $workingDay);
$stmt->bindParam(2, $workingTime);
$stmt->bindParam(3, $isHomeOffice, PDO::PARAM_BOOL);
$stmt->execute();
}
}
/**
* @param WorkingHours|ModelInterface $model
*
* @throws RepositoryRecordNotFoundException
*/
public function update(mixed $model): void
{
if ($model instanceof WorkingHours) {
$workingDay = $model->getWorkingDay()->format('Y-m-d');
$workingTime = $model->getWorkingTime()->format('%H:%I:%S');
$isHomeOffice = $model->isHomeOffice();
} else {
throw new InvalidArgumentException('Es wird ein Modell der Klasse "' . WorkingHours::class . '" verlangt.');
}
$stmt = $this->database->prepare(<<<'SQL'
update public."Arbeitszeiten"
set "Arbeitszeit" = ?, "HomeOffice" = ?
where "Datum" = ?
SQL
);
$stmt->bindParam(1, $workingTime);
$stmt->bindParam(2, $isHomeOffice, PDO::PARAM_BOOL);
$stmt->bindParam(3, $workingDay);
$stmt->execute();
if ($stmt->rowCount() < 1) {
throw new RepositoryRecordNotFoundException();
}
}
/**
* @param WorkingHours|ModelInterface $model
*
* @throws RepositoryRecordNotFoundException
*/
public function delete(mixed $model): void
{
if ($model instanceof WorkingHours) {
$workingDay = $model->getWorkingDay()->format('Y-m-d');
} else {
throw new InvalidArgumentException('Es wird ein Modell der Klasse "' . WorkingHours::class . '" verlangt.');
}
$stmt = $this->database->prepare('delete from public."Arbeitszeiten" where "Datum" = ?');
$stmt->bindParam(1, $workingDay);
$stmt->execute();
if ($stmt->rowCount() < 1) {
throw new RepositoryRecordNotFoundException();
}
}
}