calendar logic

Provide data structure for month, weeks and days.
Provide controller to open month, week and day.

Relates: #7887
This commit is contained in:
Daniel Siepmann 2020-10-22 16:31:54 +02:00
parent 10d6e94c4d
commit 98762332f5
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
23 changed files with 1782 additions and 1 deletions

163
.github/workflows/ci.yaml vendored Normal file
View file

@ -0,0 +1,163 @@
name: CI
on: [push]
jobs:
check-composer:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Validate composer.json
run: composer validate
php-linting:
runs-on: ubuntu-latest
strategy:
matrix:
php-version:
- 7.3
- 7.4
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-version }}"
- name: PHP lint
run: "find *.php Classes Tests -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l"
check-dependencies:
runs-on: ubuntu-latest
needs: [check-composer]
steps:
- uses: actions/checkout@v2
- name: Keep composer at 1.x
run: sudo composer selfupdate --1
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest --no-plugins
- name: Missing composer requirements
run: ./vendor/bin/composer-require-checker check
xml-linting:
runs-on: ubuntu-latest
needs: [check-composer]
steps:
- uses: actions/checkout@v2
- name: Install xmllint
run: sudo apt-get install libxml2-utils
- name: Keep composer at 1.x
run: sudo composer selfupdate --1
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: PHPUnit configuration file
run: xmllint --schema vendor/phpunit/phpunit/phpunit.xsd --noout phpunit.xml.dist
- name: PHPCodeSniffer configuration file
run: xmllint --schema vendor/squizlabs/php_codesniffer/phpcs.xsd --noout phpcs.xml.dist
- name: Fetch schema for xliff
run: wget https://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd --output-document=.Build/xliff-core-1.2-strict.xsd
- name: TYPO3 language files
run: xmllint --schema .Build/xliff-core-1.2-strict.xsd --noout $(find Resources -name '*.xlf')
coding-guideline:
runs-on: ubuntu-latest
needs:
- check-dependencies
- xml-linting
steps:
- uses: actions/checkout@v2
- name: Keep composer at 1.x
run: sudo composer selfupdate --1
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: Coding Guideline
run: ./vendor/bin/phpcs
tests:
runs-on: ubuntu-latest
needs:
- check-dependencies
- xml-linting
strategy:
matrix:
php-version:
- 7.3
- 7.4
steps:
- uses: actions/checkout@v2
- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php-version }}"
- name: Keep composer at 1.x
run: sudo composer selfupdate --1
- name: Get Composer Cache Directory
id: composer-cache
run: |
echo "::set-output name=dir::$(composer config cache-files-dir)"
- uses: actions/cache@v1
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: PHPUnit Tests
run: ./vendor/bin/phpunit --testdox

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
/.Build/
/vendor/
/composer.lock

View file

@ -0,0 +1,115 @@
<?php
namespace WerkraumMedia\Calendar\Controller\Frontend;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Extbase\Annotation as Extbase;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
use WerkraumMedia\Calendar\Domain\Model\Day;
use WerkraumMedia\Calendar\Domain\Model\Month;
use WerkraumMedia\Calendar\Domain\Model\Week;
class CalendarController extends ActionController
{
public function initializeMonthAction()
{
if ($this->request->hasArgument('month') === false) {
$this->request->setArguments([
'month' => [
'month' => date('m'),
'year' => date('Y'),
],
]);
}
$this->arguments->getArgument('month')
->getPropertyMappingConfiguration()
->allowAllProperties();
}
/**
* @Extbase\IgnoreValidation("month")
*/
public function monthAction(Month $month)
{
$this->view->assignMultiple([
'month' => $month,
]);
}
public function initializeWeekAction()
{
if ($this->request->hasArgument('week') === false) {
$this->request->setArguments([
'week' => [
'week' => date('W'),
'year' => date('Y'),
],
]);
}
$this->arguments->getArgument('week')
->getPropertyMappingConfiguration()
->allowAllProperties();
}
/**
* @Extbase\IgnoreValidation("week")
*/
public function weekAction(Week $week)
{
$this->view->assignMultiple([
'week' => $week,
]);
}
public function initializeDayAction()
{
if ($this->request->hasArgument('day') === false) {
$this->request->setArguments([
'day' => new \DateTimeImmutable(),
]);
}
$propertyMappingConfiguration = $this->arguments->getArgument('day')
->getPropertyMappingConfiguration();
$propertyMappingConfiguration->allowAllProperties();
$propertyMappingConfiguration
->forProperty('day')
->setTypeConverterOption(
DateTimeConverter::class,
DateTimeConverter::CONFIGURATION_DATE_FORMAT,
'Y-m-d'
);
}
/**
* @Extbase\IgnoreValidation("day")
*/
public function dayAction(Day $day)
{
$this->view->assignMultiple([
'day' => $day,
]);
}
}

View file

@ -0,0 +1,89 @@
<?php
namespace WerkraumMedia\Calendar\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class Day
{
/**
* @var \DateTimeImmutable
*/
private $day;
/**
* @var mixed
*/
private $foreignData;
/**
* @var bool
*/
private $initialized = false;
public function __construct(
\DateTime $day
) {
$this->periods = new ObjectStorage();
$this->day = \DateTimeImmutable::createFromMutable($day)->modify('midnight');
}
public function isActive(): bool
{
$foreignData = $this->getForeignData();
if ($foreignData instanceof IsDayActive) {
return $foreignData->isActive($this->getDateTimeInstance());
}
return false;
}
public function getForeignData()
{
$this->initializeForeignData();
return $this->foreignData;
}
public function getDateTimeInstance(): \DateTimeImmutable
{
return $this->day;
}
public function getAsUrlArgument(): array
{
return [
'day' => $this->day->format('Y-m-d'),
];
}
private function initializeForeignData(): void
{
if ($this->initialized) {
return;
}
$this->foreignData = GeneralUtility::makeInstance(ForeignDataFactory::class)
->getData($this);
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace WerkraumMedia\Calendar\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
interface ForeignDataFactory
{
/**
*
*/
public function getData(Day $day);
}

View file

@ -0,0 +1,27 @@
<?php
namespace WerkraumMedia\Calendar\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
interface IsDayActive
{
public function isActive(\DateTimeImmutable $dateTime): bool;
}

View file

@ -0,0 +1,129 @@
<?php
namespace WerkraumMedia\Calendar\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class Month
{
/**
* @var int
*/
private $month;
/**
* @var int
*/
private $year;
/**
* @var Week[]
*/
private $weeks = [];
public function __construct(
int $month,
int $year
) {
$this->month = $month;
$this->year = $year;
}
public function isActive(): bool
{
foreach ($this->getWeeks() as $week) {
if ($week->isActive()) {
return true;
}
}
return false;
}
public function getWeeks(): array
{
if ($this->weeks !== []) {
return $this->weeks;
}
$month = $this->getDateTimeInstance();
$lastDay = $month->modify('last day of this month')->modify('sunday this week');
$currentDay = $month->modify('monday this week');
while ($currentDay <= $lastDay) {
$this->weeks[] = new Week(
(int) $currentDay->format('W'),
(int) $currentDay->format('Y')
);
$currentDay = $currentDay->modify('+7 days');
}
return $this->weeks;
}
public function getPreviousMonth(): Month
{
$previousMonth = $this->month - 1;
$previousYear = $this->year;
if ($previousMonth <= 0) {
$previousMonth = 12;
--$previousYear;
}
return new self(
$previousMonth,
$previousYear
);
}
public function getNextMonth(): Month
{
$nextMonth = $this->month + 1;
$nextYear = $this->year;
if ($nextMonth > 12) {
$nextMonth = 1;
++$nextYear;
}
return new self(
$nextMonth,
$nextYear
);
}
public function getAsUrlArgument(): array
{
return [
'month' => $this->month,
'year' => $this->year,
];
}
public function getDateTimeInstance(): \DateTimeImmutable
{
return new \DateTimeImmutable($this->year . '-' . $this->month . '-01');
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace WerkraumMedia\Calendar\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
class NullDataFactory implements ForeignDataFactory
{
public function getData(Day $day)
{
return null;
}
}

View file

@ -0,0 +1,118 @@
<?php
namespace WerkraumMedia\Calendar\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
class Week
{
/**
* @var int
*/
private $week;
/**
* @var int
*/
private $year;
/**
* @var Day[]
*/
private $days = [];
public function __construct(
int $week,
int $year
) {
$this->week = $week;
$this->year = $year;
}
public function isActive(): bool
{
foreach ($this->getDays() as $day) {
if ($day->isActive()) {
return true;
}
}
return false;
}
public function getDays(): array
{
if ($this->days !== []) {
return $this->days;
}
$currentDay = $this->getWeek()->modify('monday this week');
$endOfWeek = $currentDay->modify('sunday this week');
while ($currentDay <= $endOfWeek) {
$this->days[] = new Day(\DateTime::createFromImmutable($currentDay));
$currentDay = $currentDay->modify('+1 day');
}
return $this->days;
}
public function getPreviousWeek(): Week
{
$newDay = $this->getWeek()->modify('-1 week');
return new self(
(int) $newDay->format('W'),
(int) $newDay->format('Y')
);
}
public function getNextWeek(): Week
{
$newDay = $this->getWeek()->modify('+1 week');
return new self(
(int) $newDay->format('W'),
(int) $newDay->format('Y')
);
}
public function getDateTimeInstance(): \DateTimeImmutable
{
return $this->getWeek();
}
public function getAsUrlArgument(): array
{
return [
'week' => $this->week,
'year' => $this->year,
];
}
private function getWeek(): \DateTimeImmutable
{
$week = new \DateTimeImmutable();
$week = $week->setISODate($this->year, $this->week);
$week = $week->modify('thursday');
return $week;
}
}

View file

@ -0,0 +1,8 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false
WerkraumMedia\Calendar\:
resource: '../Classes/*'

View file

@ -0,0 +1,8 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true">
<h2>{day.dateTimeInstance -> f:format.date(format: 'd.m.Y')}</h2>
TODO: Show periods
Maybe remove and instead link to filtered list
</html>

View file

@ -0,0 +1,42 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true">
<h2>{month.dateTimeInstance -> f:format.date(format: '%B %Y')}</h2>
<f:link.action action="month" controller="Frontend\Calendar" arguments="{month: month.previousMonth}">
Prev Month
</f:link.action>
<f:link.action action="month" controller="Frontend\Calendar" arguments="{month: month.nextMonth}">
Next Month
</f:link.action>
<table>
<tr>
<th>KW</th>
<th>Mo</th>
<th>Di</th>
<th>Mi</th>
<th>Do</th>
<th>Fr</th>
<th>Sa</th>
<th>So</th>
</tr>
<f:for each="{month.weeks}" as="week">
<tr class="{f:if(condition: week.active, then: 'active', else: 'inactive')}">
<td>
<f:link.action action="week" controller="Frontend\Calendar" arguments="{week: week.asUrlArgument}">
{week.dateTimeInstance -> f:format.date(format: '%V')}
</f:link.action>
</td>
<f:for each="{week.days}" as="day">
<td class="{f:if(condition: day.active, then: 'active', else: 'inactive')}">
<f:link.action action="day" controller="Frontend\Calendar" arguments="{day: day.asUrlArgument}">
{day.dateTimeInstance -> f:format.date(format: 'd')}
</f:link.action>
</td>
</f:for>
</tr>
</f:for>
</table>
</html>

View file

@ -0,0 +1,33 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true">
<h2>{week.dateTimeInstance -> f:format.date(format: '%V %Y')}</h2>
<f:link.action action="week" controller="Frontend\Calendar" arguments="{week: week.previousWeek}">
Prev Week
</f:link.action>
<f:link.action action="week" controller="Frontend\Calendar" arguments="{week: week.nextWeek}">
Next Week
</f:link.action>
<table>
<tr>
<th>Mo</th>
<th>Di</th>
<th>Mi</th>
<th>Do</th>
<th>Fr</th>
<th>Sa</th>
<th>So</th>
</tr>
<tr>
<f:for each="{week.days}" as="day">
<td class="{f:if(condition: day.active, then: 'active', else: 'inactive')}">
<f:link.action action="day" controller="Frontend\Calendar" arguments="{day: day.asUrlArgument}">
{day.dateTimeInstance -> f:format.date(format: 'd')}
</f:link.action>
</td>
</f:for>
</tr>
</table>
</html>

View file

@ -0,0 +1,33 @@
<?php
namespace WerkraumMedia\Calendar\Tests;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
trait ForcePropertyTrait
{
protected function forceProperty($subject, string $name, $value)
{
$objectReflection = new \ReflectionObject($subject);
$property = $objectReflection->getProperty($name);
$property->setAccessible(true);
$property->setValue($subject, $value);
}
}

View file

@ -0,0 +1,275 @@
<?php
namespace WerkraumMedia\Calendar\Tests\Unit\Controller\Frontend;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\Argument as ProphetArgument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;
use TYPO3\CMS\Extbase\Mvc\Controller\Argument;
use TYPO3\CMS\Extbase\Mvc\Controller\Arguments;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Extbase\Mvc\Web\Request;
use TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration;
use WerkraumMedia\Calendar\Controller\Frontend\CalendarController;
use WerkraumMedia\Calendar\Domain\Model\Day;
use WerkraumMedia\Calendar\Domain\Model\Month;
use WerkraumMedia\Calendar\Domain\Model\Week;
use WerkraumMedia\Calendar\Tests\ForcePropertyTrait;
/**
* @covers WerkraumMedia\Calendar\Controller\Frontend\CalendarController
* @testdox The calendar controller
*/
class CalendarControllerTest extends TestCase
{
use ProphecyTrait;
use ForcePropertyTrait;
/**
* @test
*/
public function setsCurrentMonthAsDefaultArgument(): void
{
$subject = new CalendarController();
$arguments = $this->allowsMappingOfAllPropertiesForArgument('month')['arguments'];
$request = $this->prophesize(Request::class);
$request->hasArgument('month')->willReturn(false);
$request->setArguments([
'month' => [
'month' => date('m'),
'year' => date('Y'),
],
])->shouldBeCalled();
$this->forceProperty($subject, 'request', $request->reveal());
$this->forceProperty($subject, 'arguments', $arguments->reveal());
$subject->initializeMonthAction();
$request->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function allowsMonthToBeMapped(): void
{
$subject = new CalendarController();
$arguments = $this->allowsMappingOfAllPropertiesForArgument('month')['arguments'];
$request = $this->prophesize(Request::class);
$request->hasArgument('month')->willReturn(true);
$this->forceProperty($subject, 'request', $request->reveal());
$this->forceProperty($subject, 'arguments', $arguments->reveal());
$subject->initializeMonthAction();
$arguments->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function addsMonthToView(): void
{
$subject = new CalendarController();
$month = $this->prophesize(Month::class);
$view = $this->prophesize(ViewInterface::class);
$view->assignMultiple([
'month' => $month->reveal(),
])->shouldBeCalled();
$this->forceProperty($subject, 'view', $view->reveal());
$subject->monthAction($month->reveal());
$view->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function setsCurrentWeekAsDefaultArgument(): void
{
$subject = new CalendarController();
$arguments = $this->allowsMappingOfAllPropertiesForArgument('week')['arguments'];
$request = $this->prophesize(Request::class);
$request->hasArgument('week')->willReturn(false);
$request->setArguments([
'week' => [
'week' => date('W'),
'year' => date('Y'),
],
])->shouldBeCalled();
$this->forceProperty($subject, 'request', $request->reveal());
$this->forceProperty($subject, 'arguments', $arguments->reveal());
$subject->initializeWeekAction();
$request->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function allowsWeekToBeMapped(): void
{
$subject = new CalendarController();
$arguments = $this->allowsMappingOfAllPropertiesForArgument('week')['arguments'];
$request = $this->prophesize(Request::class);
$request->hasArgument('week')->willReturn(true);
$this->forceProperty($subject, 'request', $request->reveal());
$this->forceProperty($subject, 'arguments', $arguments->reveal());
$subject->initializeWeekAction();
$arguments->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function addsWeekToView(): void
{
$subject = new CalendarController();
$week = $this->prophesize(Week::class);
$view = $this->prophesize(ViewInterface::class);
$view->assignMultiple([
'week' => $week->reveal(),
])->shouldBeCalled();
$this->forceProperty($subject, 'view', $view->reveal());
$subject->weekAction($week->reveal());
$view->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function setsCurrentDayAsDefaultArgument(): void
{
$subject = new CalendarController();
$prophecies = $this->allowsMappingOfAllPropertiesForArgument('day');
$propertyConfiguration = $prophecies['propertyMappingConfiguration'];
$arguments = $prophecies['arguments'];
$request = $this->prophesize(Request::class);
$request->hasArgument('day')->willReturn(false);
$request->setArguments(ProphetArgument::that(function (array $arguments) {
return count($arguments) === 1
&& isset($arguments['day'])
&& $arguments['day'] instanceof \DateTimeImmutable
&& $arguments['day']->format('Y-m-d') === date('Y-m-d')
;
}))->shouldBeCalled();
$configuration = $this->prophesize(PropertyMappingConfiguration::class);
$configuration->setTypeConverterOption(
'',
'',
'Y-m-d'
);
$propertyConfiguration->forProperty('day')->willReturn($configuration);
$this->forceProperty($subject, 'request', $request->reveal());
$this->forceProperty($subject, 'arguments', $arguments->reveal());
$subject->initializeDayAction();
$request->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function configuredMappingForDay(): void
{
$subject = new CalendarController();
$prophecies = $this->allowsMappingOfAllPropertiesForArgument('day');
$propertyConfiguration = $prophecies['propertyMappingConfiguration'];
$arguments = $prophecies['arguments'];
$request = $this->prophesize(Request::class);
$request->hasArgument('day')->willReturn(true);
$configuration = $this->prophesize(PropertyMappingConfiguration::class);
$configuration->setTypeConverterOption(
'',
'',
'Y-m-d'
);
$propertyConfiguration->forProperty('day')->willReturn($configuration);
$this->forceProperty($subject, 'request', $request->reveal());
$this->forceProperty($subject, 'arguments', $arguments->reveal());
$subject->initializeDayAction();
$arguments->checkProphecyMethodsPredictions();
}
/**
* @test
*/
public function addsDayToView(): void
{
$subject = new CalendarController();
$day = $this->prophesize(Day::class);
$view = $this->prophesize(ViewInterface::class);
$view->assignMultiple([
'day' => $day->reveal(),
])->shouldBeCalled();
$this->forceProperty($subject, 'view', $view->reveal());
$subject->dayAction($day->reveal());
$view->checkProphecyMethodsPredictions();
}
private function allowsMappingOfAllPropertiesForArgument(string $argumentName): array
{
$propertyMappingConfiguration = $this->prophesize(PropertyMappingConfiguration::class);
$propertyMappingConfiguration->allowAllProperties()->shouldBeCalled();
$argument = $this->prophesize(Argument::class);
$argument->getPropertyMappingConfiguration()->willReturn($propertyMappingConfiguration);
$arguments = $this->prophesize(Arguments::class);
$arguments->getArgument($argumentName)->willReturn($argument->reveal());
return [
'propertyMappingConfiguration' => $propertyMappingConfiguration,
'argument' => $argument,
'arguments' => $arguments,
];
}
}

View file

@ -0,0 +1,144 @@
<?php
namespace WerkraumMedia\Calendar\Tests\Unit\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use WerkraumMedia\Calendar\Domain\Model\Day;
use WerkraumMedia\Calendar\Domain\Model\ForeignDataFactory;
use WerkraumMedia\Calendar\Domain\Model\IsDayActive;
use WerkraumMedia\Calendar\Domain\Model\NullDataFactory;
use WerkraumMedia\Calendar\Tests\ForcePropertyTrait;
/**
* @covers WerkraumMedia\Calendar\Domain\Model\Day
* @testdox A day
*/
class DayTest extends TestCase
{
use ProphecyTrait;
use ForcePropertyTrait;
public function tearDown(): void
{
GeneralUtility::purgeInstances();
parent::tearDown();
}
/**
* @test
*/
public function canBeCreated(): void
{
$subject = new Day(
new \DateTime()
);
self::assertInstanceOf(Day::class, $subject);
}
/**
* @test
*/
public function providesDateTimeInstance(): void
{
$dateTimeInstance = new \DateTime();
$subject = new Day(
$dateTimeInstance
);
self::assertInstanceOf(\DateTimeImmutable::class, $subject->getDateTimeInstance());
self::assertSame($dateTimeInstance->format('U'), $subject->getDateTimeInstance()->format('U'));
}
/**
* @test
*/
public function providedDateTimeInstanceHasMidnight(): void
{
$dateTimeInstance = new \DateTime();
$subject = new Day(
$dateTimeInstance
);
self::assertSame('00:00:00', $subject->getDateTimeInstance()->format('H:i:s'));
}
/**
* @test
*/
public function providesItselfAsUrlArgument(): void
{
$subject = new Day(new \DateTime('2020-10-19'));
self::assertSame(['day' => '2020-10-19'], $subject->getAsUrlArgument());
}
/**
* @test
*/
public function isNotActiveIfNoForeignDataWithInterfaceExists(): void
{
$subject = new Day(new \DateTime('2020-10-19'));
$this->forceProperty($subject, 'initialized', true);
self::assertFalse($subject->isActive());
}
/**
* @test
*/
public function isNotActiveIfForeignDataIsNotActive(): void
{
$subject = new Day(new \DateTime('2020-10-19'));
$foreignData = $this->prophesize(IsDayActive::class);
$foreignData->isActive(Argument::any())->willReturn(false);
$this->forceProperty($subject, 'initialized', true);
$this->forceProperty($subject, 'foreignData', $foreignData->reveal());
self::assertFalse($subject->isActive());
}
/**
* @test
*/
public function initializesForeignDataViaFactory(): void
{
$subject = new Day(new \DateTime('2020-10-19'));
$foreignData = $this->prophesize(IsDayActive::class);
$foreignData->isActive(Argument::any())->willReturn(true);
$factory = $this->prophesize(ForeignDataFactory::class);
$factory->getData($subject)->willReturn($foreignData->reveal());
GeneralUtility::addInstance(ForeignDataFactory::class, $factory->reveal());
self::assertTrue($subject->isActive());
}
}

View file

@ -0,0 +1,183 @@
<?php
namespace WerkraumMedia\Calendar\Tests\Unit\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use PHPUnit\Framework\TestCase;
use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\Calendar\Domain\Model\Month;
use WerkraumMedia\Calendar\Domain\Model\Week;
use WerkraumMedia\Calendar\Tests\ForcePropertyTrait;
/**
* @covers WerkraumMedia\Calendar\Domain\Model\Month
* @testdox A month
*/
class MonthTest extends TestCase
{
use ProphecyTrait;
use ForcePropertyTrait;
/**
* @test
*/
public function canBeCreated(): void
{
$subject = new Month(1, 2020);
self::assertInstanceOf(Month::class, $subject);
}
/**
* @test
*/
public function returnsPreviousMonthForSameYear(): void
{
$subject = new Month(2, 2020);
self::assertSame('01', $subject->getPreviousMonth()->getDateTimeInstance()->format('m'));
self::assertSame('2020', $subject->getPreviousMonth()->getDateTimeInstance()->format('Y'));
}
/**
* @test
*/
public function returnsPreviousMonthForPreviousYear(): void
{
$subject = new Month(1, 2020);
self::assertSame('12', $subject->getPreviousMonth()->getDateTimeInstance()->format('m'));
self::assertSame('2019', $subject->getPreviousMonth()->getDateTimeInstance()->format('Y'));
}
/**
* @test
*/
public function returnsNextMonthForSameYear(): void
{
$subject = new Month(1, 2020);
self::assertSame('02', $subject->getNextMonth()->getDateTimeInstance()->format('m'));
self::assertSame('2020', $subject->getNextMonth()->getDateTimeInstance()->format('Y'));
}
/**
* @test
*/
public function returnsNextMonthForNextYear(): void
{
$subject = new Month(12, 2020);
self::assertSame('01', $subject->getNextMonth()->getDateTimeInstance()->format('m'));
self::assertSame('2021', $subject->getNextMonth()->getDateTimeInstance()->format('Y'));
}
/**
* @test
*/
public function returnsFiveWeeksForDecember2020(): void
{
$subject = new Month(12, 2020);
$weeks = $subject->getWeeks();
self::assertCount(5, $weeks);
self::assertSame('2020-11-30', $weeks[0]->getDays()[0]->getDateTimeInstance()->format('Y-m-d'));
self::assertSame('2021-01-03', $weeks[4]->getDays()[6]->getDateTimeInstance()->format('Y-m-d'));
}
/**
* @test
*/
public function returnsSixWeeksForNovember2020(): void
{
$subject = new Month(11, 2020);
$weeks = $subject->getWeeks();
self::assertCount(6, $weeks);
self::assertSame('2020-10-26', $weeks[0]->getDays()[0]->getDateTimeInstance()->format('Y-m-d'));
self::assertSame('2020-12-06', $weeks[5]->getDays()[6]->getDateTimeInstance()->format('Y-m-d'));
}
/**
* @test
*/
public function returnsSameWeeksOnSecondCall(): void
{
$subject = new Month(11, 2020);
self::assertSame($subject->getWeeks(), $subject->getWeeks());
}
/**
* @test
*/
public function providesDateTimeInstance(): void
{
$subject = new Month(02, 2018);
self::assertSame('2018-02-01', $subject->getDateTimeInstance()->format('Y-m-d'));
}
/**
* @test
*/
public function returnsAsUrlArguments(): void
{
$subject = new Month(02, 2018);
self::assertSame([
'month' => 2,
'year' => 2018,
], $subject->getAsUrlArgument());
}
/**
* @test
*/
public function returnsNotActiveIfAllWeeksAreInactive(): void
{
$subject = new Month(02, 2018);
$week = $this->prophesize(Week::class);
$week->isActive()->willReturn(false);
$weeks = [$week->reveal()];
$this->forceProperty($subject, 'weeks', $weeks);
self::assertFalse($subject->isActive());
}
/**
* @test
*/
public function returnsActiveIfASingleWeekIsActive(): void
{
$subject = new Month(02, 2018);
$week = $this->prophesize(Week::class);
$week->isActive()->willReturn(true);
$week2 = $this->prophesize(Week::class);
$week2->isActive()->willReturn(false);
$weeks = [$week->reveal(), $week2->reveal()];
$this->forceProperty($subject, 'weeks', $weeks);
self::assertTrue($subject->isActive());
}
}

View file

@ -0,0 +1,45 @@
<?php
namespace WerkraumMedia\Calendar\Tests\Unit\Domain\Model;
/*
* Copyright (C) 2020 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
use Prophecy\PhpUnit\ProphecyTrait;
use WerkraumMedia\Calendar\Domain\Model\Day;
use WerkraumMedia\Calendar\Domain\Model\NullDataFactory;
use PHPUnit\Framework\TestCase;
/**
* @covers WerkraumMedia\Calendar\Domain\Model\NullDataFactory
*/
class NullDataFactoryTest extends TestCase
{
use ProphecyTrait;
/**
* @test
*/
public function returnsNull(): void
{
$subject = new NullDataFactory();
$day =