Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
123f5eef81 | ||
|
|
0e98a933e1 | ||
|
|
c2676abfa2 | ||
|
|
675c5cb9ae |
@@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace TorstenHettstedt\TimekeepingApi\Repositories;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use Exception;
|
||||||
|
use PDO;
|
||||||
|
use PDOException;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Models\PeriodDesignationEnum;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Models\WorkingHoursView;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @implements RepositoryReaderInterface<WorkingHoursView>
|
||||||
|
*/
|
||||||
|
abstract class AbstractWorkingHoursViewRepository implements RepositoryReaderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
protected const SQL_SELECT = '';
|
||||||
|
protected const SQL_WHERE = '';
|
||||||
|
|
||||||
|
protected PDO $database;
|
||||||
|
protected PeriodDesignationEnum $periodDesignation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WorkingHoursRepository constructor.
|
||||||
|
*
|
||||||
|
* @param PDO $database
|
||||||
|
*/
|
||||||
|
public function __construct(PDO $database)
|
||||||
|
{
|
||||||
|
$this->database = $database;
|
||||||
|
$this->database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Gibt alle vorhandenen Einträge zurück
|
||||||
|
*
|
||||||
|
* @return WorkingHoursView[]
|
||||||
|
* @throws Exception
|
||||||
|
* @throws PDOException
|
||||||
|
*/
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
$models = [];
|
||||||
|
$stmt = $this->database->prepare(static::SQL_SELECT);
|
||||||
|
$stmt->execute();
|
||||||
|
while ($row = $stmt->fetch()) {
|
||||||
|
$model = new WorkingHoursView(
|
||||||
|
$this->buildDateFromPeriod($row['period']),
|
||||||
|
$this->periodDesignation,
|
||||||
|
(int) $row['workingDays'],
|
||||||
|
$this->buildDateInterval($row['totalHours']),
|
||||||
|
$this->buildDateInterval($row['overtime'])
|
||||||
|
);
|
||||||
|
$models[] = $model;
|
||||||
|
}
|
||||||
|
return $models;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt den Eintrag zurück, der durch die ID
|
||||||
|
*
|
||||||
|
* @param mixed $primary_key
|
||||||
|
*
|
||||||
|
* @return WorkingHoursView
|
||||||
|
* @throws RepositoryRecordNotFoundException
|
||||||
|
* @throws Exception
|
||||||
|
* @throws PDOException
|
||||||
|
*/
|
||||||
|
public function findByKey(mixed $primary_key): WorkingHoursView
|
||||||
|
{
|
||||||
|
$stmt = $this->database->prepare(static::SQL_SELECT . static::SQL_WHERE);
|
||||||
|
$stmt->bindParam(1, $primary_key);
|
||||||
|
$stmt->execute();
|
||||||
|
$row = $stmt->fetch();
|
||||||
|
if ($row === false) {
|
||||||
|
throw new RepositoryRecordNotFoundException();
|
||||||
|
}
|
||||||
|
return new WorkingHoursView(
|
||||||
|
$this->buildDateFromPeriod($row['period']),
|
||||||
|
$this->periodDesignation,
|
||||||
|
(int) $row['workingDays'],
|
||||||
|
$this->buildDateInterval($row['totalHours']),
|
||||||
|
$this->buildDateInterval($row['overtime'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $time
|
||||||
|
*
|
||||||
|
* @return DateInterval
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function buildDateInterval(string $time): DateInterval
|
||||||
|
{
|
||||||
|
$time_array = explode(':', $time);
|
||||||
|
$hours = (int)$time_array[0];
|
||||||
|
$minutes = (int)$time_array[1];
|
||||||
|
$seconds = (int)$time_array[2];
|
||||||
|
$interval = new DateInterval(sprintf('PT%dH%dM%dS', abs($hours), abs($minutes), abs($seconds)));
|
||||||
|
if ($hours < 0) {
|
||||||
|
$interval->invert = 1;
|
||||||
|
}
|
||||||
|
if ($minutes < 0) {
|
||||||
|
$interval->invert = 1;
|
||||||
|
}
|
||||||
|
if ($seconds < 0) {
|
||||||
|
$interval->invert = 1;
|
||||||
|
}
|
||||||
|
return $interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $period
|
||||||
|
*
|
||||||
|
* @return DateTimeInterface
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
abstract protected function buildDateFromPeriod(string $period): DateTimeInterface;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace TorstenHettstedt\TimekeepingApi\Repositories;
|
||||||
|
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use PDO;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Models\PeriodDesignationEnum;
|
||||||
|
|
||||||
|
class WorkingHoursMonthlyViewRepository extends AbstractWorkingHoursViewRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
protected const SQL_SELECT = <<<SQL
|
||||||
|
select
|
||||||
|
"Monat" as "period",
|
||||||
|
"Gesamtarbeitszeit" as "totalHours",
|
||||||
|
"Arbeitstage" as "workingDays",
|
||||||
|
"Überstunden" as "overtime"
|
||||||
|
from "Arbeitszeiten - Monat"
|
||||||
|
SQL;
|
||||||
|
protected const SQL_WHERE = ' where "Monat" = ?';
|
||||||
|
|
||||||
|
protected PDO $database;
|
||||||
|
protected PeriodDesignationEnum $periodDesignation;
|
||||||
|
|
||||||
|
public function __construct(PDO $database)
|
||||||
|
{
|
||||||
|
parent::__construct($database);
|
||||||
|
$this->periodDesignation = PeriodDesignationEnum::MONTHLY();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildDateFromPeriod(string $period): DateTimeInterface
|
||||||
|
{
|
||||||
|
return new DateTime($period . '-01');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TorstenHettstedt\TimekeepingApi\Repositories;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use PDO;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Models\PeriodDesignationEnum;
|
||||||
|
|
||||||
|
class WorkingHoursWeeklyViewRepository extends AbstractWorkingHoursViewRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
protected const SQL_SELECT = <<<SQL
|
||||||
|
select
|
||||||
|
"Woche" as "period",
|
||||||
|
"Gesamtarbeitszeit" as "totalHours",
|
||||||
|
"Arbeitstage" as "workingDays",
|
||||||
|
"Überstunden" as "overtime"
|
||||||
|
from "Arbeitszeiten - Woche"
|
||||||
|
SQL;
|
||||||
|
protected const SQL_WHERE = ' where "Woche" = ?';
|
||||||
|
|
||||||
|
protected PDO $database;
|
||||||
|
protected PeriodDesignationEnum $periodDesignation;
|
||||||
|
|
||||||
|
public function __construct(PDO $database)
|
||||||
|
{
|
||||||
|
parent::__construct($database);
|
||||||
|
$this->periodDesignation = PeriodDesignationEnum::WEEKLY();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildDateFromPeriod(string $period): DateTimeInterface
|
||||||
|
{
|
||||||
|
$time_array = explode('#', $period);
|
||||||
|
$year = (int)$time_array[0];
|
||||||
|
$week = (int)$time_array[1] - 1;
|
||||||
|
$date = new DateTime('first day of January ' . $year);
|
||||||
|
$date->modify('monday this week');
|
||||||
|
$date->add(new DateInterval(sprintf('P%dW', $week)));
|
||||||
|
return $date;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace TorstenHettstedt\TimekeepingApi\Repositories;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use Exception;
|
||||||
|
use PDO;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Models\PeriodDesignationEnum;
|
||||||
|
|
||||||
|
class WorkingHoursYearlyViewRepository extends AbstractWorkingHoursViewRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
protected const SQL_SELECT = <<<SQL
|
||||||
|
select
|
||||||
|
"Jahr" as "period",
|
||||||
|
"Gesamtarbeitszeit" as "totalHours",
|
||||||
|
"Arbeitstage" as "workingDays",
|
||||||
|
"Überstunden" as "overtime"
|
||||||
|
from "Arbeitszeiten - Jahr"
|
||||||
|
SQL;
|
||||||
|
protected const SQL_WHERE = ' where "Jahr" = ?';
|
||||||
|
|
||||||
|
protected PDO $database;
|
||||||
|
protected PeriodDesignationEnum $periodDesignation;
|
||||||
|
|
||||||
|
public function __construct(PDO $database)
|
||||||
|
{
|
||||||
|
parent::__construct($database);
|
||||||
|
$this->periodDesignation = PeriodDesignationEnum::YEARLY();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $period
|
||||||
|
*
|
||||||
|
* @return DateTimeInterface
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function buildDateFromPeriod(string $period): DateTimeInterface
|
||||||
|
{
|
||||||
|
return new DateTime($period . '-01-01');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,24 +3,22 @@
|
|||||||
namespace TorstenHettstedt\TimekeepingApi\Tests\Unit\Repositories;
|
namespace TorstenHettstedt\TimekeepingApi\Tests\Unit\Repositories;
|
||||||
|
|
||||||
use Codeception\Test\Unit;
|
use Codeception\Test\Unit;
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
use PDO;
|
use PDO;
|
||||||
use TorstenHettstedt\TimekeepingApi\Models\PeriodDesignationEnum;
|
|
||||||
use TorstenHettstedt\TimekeepingApi\Models\WorkingHoursView;
|
use TorstenHettstedt\TimekeepingApi\Models\WorkingHoursView;
|
||||||
use TorstenHettstedt\TimekeepingApi\Repositories\RepositoryRecordNotFoundException;
|
use TorstenHettstedt\TimekeepingApi\Repositories\RepositoryRecordNotFoundException;
|
||||||
use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursViewRepository;
|
use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursWeeklyViewRepository;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursMonthlyViewRepository;
|
||||||
|
use TorstenHettstedt\TimekeepingApi\Repositories\WorkingHoursYearlyViewRepository;
|
||||||
|
|
||||||
class WorkingHoursViewRepositoryTest extends Unit
|
class WorkingHoursViewRepositoryTest extends Unit
|
||||||
{
|
{
|
||||||
const EXISTING_DATE = '2020-01-28';
|
|
||||||
const EXISTING_INTERVAL = 'PT7H20M';
|
|
||||||
const NEW_DATE = '2020-04-01';
|
|
||||||
const NEW_INTERVAL = 'PT7H59M';
|
|
||||||
const RECORDS_COUNT = 61;
|
|
||||||
|
|
||||||
protected PDO $pdoObject;
|
protected PDO $pdoObject;
|
||||||
|
|
||||||
protected function _before(): void
|
protected function _before(): void
|
||||||
{
|
{
|
||||||
|
/** @noinspection SpellCheckingInspection */
|
||||||
$this->pdoObject = new PDO('pgsql:host=psql.torsten-hettstedt.net;port=5432;dbname=testdb;user=bruce;password=mypass');
|
$this->pdoObject = new PDO('pgsql:host=psql.torsten-hettstedt.net;port=5432;dbname=testdb;user=bruce;password=mypass');
|
||||||
parent::_before();
|
parent::_before();
|
||||||
}
|
}
|
||||||
@@ -31,9 +29,9 @@ class WorkingHoursViewRepositoryTest extends Unit
|
|||||||
public function listObjectProvider(): array
|
public function listObjectProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[PeriodDesignationEnum::YEARLY(), 1],
|
[WorkingHoursYearlyViewRepository::class, 1],
|
||||||
[PeriodDesignationEnum::MONTHLY(), 3],
|
[WorkingHoursMonthlyViewRepository::class, 3],
|
||||||
[PeriodDesignationEnum::WEEKLY(), 13],
|
[WorkingHoursWeeklyViewRepository::class, 13],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,9 +41,9 @@ class WorkingHoursViewRepositoryTest extends Unit
|
|||||||
public function existingObjectProvider(): array
|
public function existingObjectProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[PeriodDesignationEnum::YEARLY(), '2020', 61],
|
[WorkingHoursYearlyViewRepository::class, '2020', 61, new DateTime('2020-01-01', new DateTimeZone('UCT'))],
|
||||||
[PeriodDesignationEnum::MONTHLY(), '2020-02', 20],
|
[WorkingHoursMonthlyViewRepository::class, '2020 February', 20, new DateTime('2020-02-01', new DateTimeZone('UCT'))],
|
||||||
[PeriodDesignationEnum::WEEKLY(), '2020#3', 5],
|
[WorkingHoursWeeklyViewRepository::class, '2020#03', 5, new DateTime('2020-01-13', new DateTimeZone('UCT'))],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,54 +53,56 @@ class WorkingHoursViewRepositoryTest extends Unit
|
|||||||
public function notExistingObjectProvider(): array
|
public function notExistingObjectProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
[PeriodDesignationEnum::YEARLY(), '2022',],
|
[WorkingHoursYearlyViewRepository::class, '2022',],
|
||||||
[PeriodDesignationEnum::MONTHLY(), '2020-05',],
|
[WorkingHoursMonthlyViewRepository::class, '2020 May',],
|
||||||
[PeriodDesignationEnum::WEEKLY(), '2020#30',],
|
[WorkingHoursWeeklyViewRepository::class, '2020#30',],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param PeriodDesignationEnum $period
|
* @param string $period_class
|
||||||
* @param int $count_records
|
* @param int $count_records
|
||||||
*
|
*
|
||||||
* @dataProvider listObjectProvider
|
* @dataProvider listObjectProvider
|
||||||
*/
|
*/
|
||||||
public function testFindAll(PeriodDesignationEnum $period, int $count_records): void
|
public function testFindAll(string $period_class, int $count_records): void
|
||||||
{
|
{
|
||||||
$repository = new WorkingHoursViewRepository($this->pdoObject, $period);
|
$repository = new $period_class($this->pdoObject);
|
||||||
$models = $repository->findAll();
|
$models = $repository->findAll();
|
||||||
$this->assertIsArray($models);
|
$this->assertIsArray($models);
|
||||||
$this->assertContainsOnly(WorkingHoursView::class, $models);
|
$this->assertContainsOnly(WorkingHoursView::class, $models);
|
||||||
$this->assertCount(self::RECORDS_COUNT, $models);
|
$this->assertCount($count_records, $models);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @dataProvider existingObjectProvider
|
* @dataProvider existingObjectProvider
|
||||||
*
|
*
|
||||||
* @param PeriodDesignationEnum $period
|
* @param string $period_class
|
||||||
* @param string $search
|
* @param string $search
|
||||||
|
* @param int $workingDays
|
||||||
|
* @param DateTime $period
|
||||||
*/
|
*/
|
||||||
public function testExistingFindByKey(PeriodDesignationEnum $period, string $search, int $workingDays): void
|
public function testExistingFindByKey(string $period_class, string $search, int $workingDays, DateTime $period): void
|
||||||
{
|
{
|
||||||
$repository = new WorkingHoursViewRepository($this->pdoObject, $period);
|
$repository = new $period_class($this->pdoObject);
|
||||||
$model = $repository->findByKey(self::EXISTING_DATE);
|
$model = $repository->findByKey($search);
|
||||||
$this->assertInstanceOf(WorkingHoursView::class, $model);
|
$this->assertInstanceOf(WorkingHoursView::class, $model);
|
||||||
$this->assertEquals($workingDays, $model->getWorkingDays());
|
$this->assertEquals($workingDays, $model->getWorkingDays());
|
||||||
|
$this->assertEquals($period->format('Ymd'), $model->getPeriod()->format('Ymd'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param PeriodDesignationEnum $period
|
* @param string $period_class
|
||||||
* @param string $search
|
* @param string $search
|
||||||
*
|
*
|
||||||
* @dataProvider notExistingObjectProvider
|
* @dataProvider notExistingObjectProvider
|
||||||
*
|
*
|
||||||
* @throws RepositoryRecordNotFoundException
|
|
||||||
*/
|
*/
|
||||||
public function testNotExistingFindByKey(PeriodDesignationEnum $period, string $search): void
|
public function testNotExistingFindByKey(string $period_class, string $search): void
|
||||||
{
|
{
|
||||||
$repository = new WorkingHoursViewRepository($this->pdoObject, $period);
|
$repository = new $period_class($this->pdoObject);
|
||||||
$this->expectException(RepositoryRecordNotFoundException::class);
|
$this->expectException(RepositoryRecordNotFoundException::class);
|
||||||
$repository->findByKey(self::NEW_DATE);
|
$repository->findByKey($search);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user