From 883dec188b31f28572bd254d3458ea7dfa77fd3d Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Tue, 23 Feb 2021 13:04:29 +0100 Subject: [PATCH] Add support for years Add new action and model. Also allow to get days of year and month. Not always a week is helpful, sometimes all days of year or month are more helpful. --- .../Frontend/CalendarController.php | 26 +++ Classes/Domain/Model/ForeignDataFactory.php | 3 +- Classes/Domain/Model/Month.php | 22 +++ Classes/Domain/Model/Year.php | 109 ++++++++++++ .../Frontend/CalendarControllerTest.php | 63 +++++++ Tests/Unit/Domain/Model/MonthTest.php | 38 +++++ Tests/Unit/Domain/Model/YearTest.php | 158 ++++++++++++++++++ 7 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 Classes/Domain/Model/Year.php create mode 100644 Tests/Unit/Domain/Model/YearTest.php diff --git a/Classes/Controller/Frontend/CalendarController.php b/Classes/Controller/Frontend/CalendarController.php index 9a4f34e..67345db 100644 --- a/Classes/Controller/Frontend/CalendarController.php +++ b/Classes/Controller/Frontend/CalendarController.php @@ -27,9 +27,35 @@ 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; +use WerkraumMedia\Calendar\Domain\Model\Year; class CalendarController extends ActionController { + public function initializeYearAction() + { + if ($this->request->hasArgument('year') === false) { + $this->request->setArguments([ + 'year' => [ + 'year' => date('Y'), + ], + ]); + } + + $this->arguments->getArgument('year') + ->getPropertyMappingConfiguration() + ->allowAllProperties(); + } + + /** + * @Extbase\IgnoreValidation("year") + */ + public function yearAction(Year $year) + { + $this->view->assignMultiple([ + 'year' => $year, + ]); + } + public function initializeMonthAction() { if ($this->request->hasArgument('month') === false) { diff --git a/Classes/Domain/Model/ForeignDataFactory.php b/Classes/Domain/Model/ForeignDataFactory.php index 6eceab2..f47b4c4 100644 --- a/Classes/Domain/Model/ForeignDataFactory.php +++ b/Classes/Domain/Model/ForeignDataFactory.php @@ -24,7 +24,8 @@ namespace WerkraumMedia\Calendar\Domain\Model; interface ForeignDataFactory { /** - * + * Receives a specific day and may return arbirtrary data. + * This data is attached to the day and available through getter. */ public function getData(Day $day); } diff --git a/Classes/Domain/Model/Month.php b/Classes/Domain/Model/Month.php index 1180081..1bc5102 100644 --- a/Classes/Domain/Model/Month.php +++ b/Classes/Domain/Model/Month.php @@ -41,6 +41,11 @@ class Month */ private $weeks = []; + /** + * @var Day[] + */ + private $days = []; + public function __construct( int $month, int $year @@ -82,6 +87,23 @@ class Month return $this->weeks; } + public function getDays(): array + { + if ($this->days !== []) { + return $this->days; + } + + $currentDay = $this->getDateTimeInstance()->modify('first day of this month'); + $endOfWeek = $this->getDateTimeInstance()->modify('last day of this month'); + + while ($currentDay <= $endOfWeek) { + $this->days[] = new Day(\DateTime::createFromImmutable($currentDay)); + $currentDay = $currentDay->modify('+1 day'); + } + + return $this->days; + } + public function getPreviousMonth(): Month { $previousMonth = $this->month - 1; diff --git a/Classes/Domain/Model/Year.php b/Classes/Domain/Model/Year.php new file mode 100644 index 0000000..88f005f --- /dev/null +++ b/Classes/Domain/Model/Year.php @@ -0,0 +1,109 @@ + + * + * 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 Year +{ + /** + * @var int + */ + private $year; + + /** + * @var Month[] + */ + private $months = []; + + public function __construct( + int $year + ) { + $this->year = $year; + } + + public function isActive(): bool + { + foreach ($this->getMonths() as $month) { + if ($month->isActive()) { + return true; + } + } + + return false; + } + + public function getMonths(): array + { + if ($this->months !== []) { + return $this->months; + } + + $lastMonth = new \DateTimeImmutable($this->year . '-12-31'); + $currentMonth = new \DateTimeImmutable($this->year . '-01-01'); + + while ($currentMonth <= $lastMonth) { + $this->months[] = new Month( + (int) $currentMonth->format('n'), + $this->year + ); + + $currentMonth = $currentMonth->modify('+1 month'); + } + + return $this->months; + } + + public function getDays(): array + { + $days = []; + + foreach ($this->getMonths() as $month) { + $days = array_merge($days, $month->getDays()); + } + + return $days; + } + + public function getPreviousYear(): Year + { + return new self($this->year - 1); + } + + public function getNextYear(): Year + { + return new self($this->year + 1); + } + + public function getAsUrlArgument(): array + { + return [ + 'year' => $this->year, + ]; + } + + public function getDateTimeInstance(): \DateTimeImmutable + { + return new \DateTimeImmutable($this->year . '-01-01'); + } +} diff --git a/Tests/Unit/Controller/Frontend/CalendarControllerTest.php b/Tests/Unit/Controller/Frontend/CalendarControllerTest.php index 9080b8f..353d63e 100644 --- a/Tests/Unit/Controller/Frontend/CalendarControllerTest.php +++ b/Tests/Unit/Controller/Frontend/CalendarControllerTest.php @@ -34,6 +34,7 @@ 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\Domain\Model\Year; use WerkraumMedia\Calendar\Tests\ForcePropertyTrait; /** @@ -45,6 +46,68 @@ class CalendarControllerTest extends TestCase use ProphecyTrait; use ForcePropertyTrait; + /** + * @test + */ + public function setsCurrentYearAsDefaultArgument(): void + { + $subject = new CalendarController(); + + $arguments = $this->allowsMappingOfAllPropertiesForArgument('year')['arguments']; + + $request = $this->prophesize(Request::class); + $request->hasArgument('year')->willReturn(false); + $request->setArguments([ + 'year' => [ + 'year' => date('Y'), + ], + ])->shouldBeCalled(); + + $this->forceProperty($subject, 'request', $request->reveal()); + $this->forceProperty($subject, 'arguments', $arguments->reveal()); + + $subject->initializeYearAction(); + $request->checkProphecyMethodsPredictions(); + } + + /** + * @test + */ + public function allowsYearToBeMapped(): void + { + $subject = new CalendarController(); + + $arguments = $this->allowsMappingOfAllPropertiesForArgument('year')['arguments']; + + $request = $this->prophesize(Request::class); + $request->hasArgument('year')->willReturn(true); + + $this->forceProperty($subject, 'request', $request->reveal()); + $this->forceProperty($subject, 'arguments', $arguments->reveal()); + + $subject->initializeYearAction(); + $arguments->checkProphecyMethodsPredictions(); + } + + /** + * @test + */ + public function addsYearToView(): void + { + $subject = new CalendarController(); + + $year = $this->prophesize(Year::class); + $view = $this->prophesize(ViewInterface::class); + $view->assignMultiple([ + 'year' => $year->reveal(), + ])->shouldBeCalled(); + + $this->forceProperty($subject, 'view', $view->reveal()); + + $subject->yearAction($year->reveal()); + $view->checkProphecyMethodsPredictions(); + } + /** * @test */ diff --git a/Tests/Unit/Domain/Model/MonthTest.php b/Tests/Unit/Domain/Model/MonthTest.php index c385303..02a45f7 100644 --- a/Tests/Unit/Domain/Model/MonthTest.php +++ b/Tests/Unit/Domain/Model/MonthTest.php @@ -126,6 +126,44 @@ class MonthTest extends TestCase self::assertSame($subject->getWeeks(), $subject->getWeeks()); } + /** + * @test + */ + public function returnsAllDaysOfTheFebruaryMonth2021(): void + { + $subject = new Month(02, 2021); + + $result = $subject->getDays(); + + self::assertCount(28, $result); + self::assertSame('2021-02-01', $result[0]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2021-02-28', $result[27]->getDateTimeInstance()->format('Y-m-d')); + } + + /** + * @test + */ + public function returnsAllDaysOfTheJuneMonth2021(): void + { + $subject = new Month(06, 2021); + + $result = $subject->getDays(); + + self::assertCount(30, $result); + self::assertSame('2021-06-01', $result[0]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2021-06-30', $result[29]->getDateTimeInstance()->format('Y-m-d')); + } + + /** + * @test + */ + public function returnsSameDaysOnSecondCall(): void + { + $subject = new Month(06, 2021); + + self::assertSame($subject->getDays(), $subject->getDays()); + } + /** * @test */ diff --git a/Tests/Unit/Domain/Model/YearTest.php b/Tests/Unit/Domain/Model/YearTest.php new file mode 100644 index 0000000..97eee36 --- /dev/null +++ b/Tests/Unit/Domain/Model/YearTest.php @@ -0,0 +1,158 @@ + + * + * 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\Year; +use WerkraumMedia\Calendar\Tests\ForcePropertyTrait; + +/** + * @covers WerkraumMedia\Calendar\Domain\Model\Year + * @testdox A year + */ +class YearTest extends TestCase +{ + use ProphecyTrait; + use ForcePropertyTrait; + + /** + * @test + */ + public function canBeCreated(): void + { + $subject = new Year(2020); + + self::assertInstanceOf(Year::class, $subject); + } + + /** + * @test + */ + public function returnsPreviousYear(): void + { + $subject = new Year(2020); + + $result = $subject->getPreviousYear(); + + self::assertInstanceOf(Year::class, $result); + self::assertSame('2019', $result->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsNextYear(): void + { + $subject = new Year(2020); + + $result = $subject->getNextYear(); + + self::assertInstanceOf(Year::class, $result); + self::assertSame('2021', $result->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsAsUrlArguments(): void + { + $subject = new Year(2020); + + self::assertSame([ + 'year' => 2020, + ], $subject->getAsUrlArgument()); + } + + /** + * @test + */ + public function returnsMonthsForYear2020(): void + { + $subject = new Year(2020); + + $result = $subject->getMonths(); + + self::assertCount(12, $result); + + foreach ($result as $index => $month) { + self::assertInstanceOf(Month::class, $month); + $monthNumber = $index + 1; + self::assertSame((string) $monthNumber, $month->getDateTimeInstance()->format('n')); + } + } + + /** + * @test + */ + public function returnsSameMonthsOnSecondCall(): void + { + $subject = new Year(2020); + + self::assertSame($subject->getMonths(), $subject->getMonths()); + } + + /** + * @test + */ + public function returnsAllDaysFor2020(): void + { + $subject = new Year(2020); + + $result = $subject->getDays(); + + self::assertCount(366, $result); + self::assertSame('2020-01-01', $result[0]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-12-31', $result[365]->getDateTimeInstance()->format('Y-m-d')); + } + + /** + * @test + */ + public function returnsNotActiveIfAllMonthsAreInactive(): void + { + $subject = new Year(2020); + + $month = $this->prophesize(Month::class); + $month->isActive()->willReturn(false); + $months = [$month->reveal()]; + $this->forceProperty($subject, 'months', $months); + + self::assertFalse($subject->isActive()); + } + + /** + * @test + */ + public function returnsActiveIfASingleMonthIsActive(): void + { + $subject = new Year(2020); + + $month = $this->prophesize(Month::class); + $month->isActive()->willReturn(true); + $months = [$month->reveal()]; + $this->forceProperty($subject, 'months', $months); + + self::assertTrue($subject->isActive()); + } +}