diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..46c68e4 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -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 diff --git a/.gitignore b/.gitignore index 752676a..8b32ebe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.Build/ /vendor/ +/composer.lock diff --git a/Classes/Controller/Frontend/CalendarController.php b/Classes/Controller/Frontend/CalendarController.php new file mode 100644 index 0000000..9a4f34e --- /dev/null +++ b/Classes/Controller/Frontend/CalendarController.php @@ -0,0 +1,115 @@ + + * + * 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, + ]); + } +} diff --git a/Classes/Domain/Model/Day.php b/Classes/Domain/Model/Day.php new file mode 100644 index 0000000..598c9f5 --- /dev/null +++ b/Classes/Domain/Model/Day.php @@ -0,0 +1,89 @@ + + * + * 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); + } +} diff --git a/Classes/Domain/Model/ForeignDataFactory.php b/Classes/Domain/Model/ForeignDataFactory.php new file mode 100644 index 0000000..6eceab2 --- /dev/null +++ b/Classes/Domain/Model/ForeignDataFactory.php @@ -0,0 +1,30 @@ + + * + * 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); +} diff --git a/Classes/Domain/Model/IsDayActive.php b/Classes/Domain/Model/IsDayActive.php new file mode 100644 index 0000000..8ef63ce --- /dev/null +++ b/Classes/Domain/Model/IsDayActive.php @@ -0,0 +1,27 @@ + + * + * 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; +} diff --git a/Classes/Domain/Model/Month.php b/Classes/Domain/Model/Month.php new file mode 100644 index 0000000..1180081 --- /dev/null +++ b/Classes/Domain/Model/Month.php @@ -0,0 +1,129 @@ + + * + * 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'); + } +} diff --git a/Classes/Domain/Model/NullDataFactory.php b/Classes/Domain/Model/NullDataFactory.php new file mode 100644 index 0000000..0b55153 --- /dev/null +++ b/Classes/Domain/Model/NullDataFactory.php @@ -0,0 +1,30 @@ + + * + * 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; + } +} diff --git a/Classes/Domain/Model/Week.php b/Classes/Domain/Model/Week.php new file mode 100644 index 0000000..f02ab53 --- /dev/null +++ b/Classes/Domain/Model/Week.php @@ -0,0 +1,118 @@ + + * + * 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; + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 0000000..ea2f924 --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,8 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + WerkraumMedia\Calendar\: + resource: '../Classes/*' diff --git a/Resources/Private/Templates/Frontend/Calendar/Day.html b/Resources/Private/Templates/Frontend/Calendar/Day.html new file mode 100644 index 0000000..687c6e5 --- /dev/null +++ b/Resources/Private/Templates/Frontend/Calendar/Day.html @@ -0,0 +1,8 @@ + + +

{day.dateTimeInstance -> f:format.date(format: 'd.m.Y')}

+ + TODO: Show periods + Maybe remove and instead link to filtered list + diff --git a/Resources/Private/Templates/Frontend/Calendar/Month.html b/Resources/Private/Templates/Frontend/Calendar/Month.html new file mode 100644 index 0000000..9016deb --- /dev/null +++ b/Resources/Private/Templates/Frontend/Calendar/Month.html @@ -0,0 +1,42 @@ + + +

{month.dateTimeInstance -> f:format.date(format: '%B %Y')}

+ + + Prev Month + + + Next Month + + + + + + + + + + + + + + + + + + + + + +
KWMoDiMiDoFrSaSo
+ + {week.dateTimeInstance -> f:format.date(format: '%V')} + + + + {day.dateTimeInstance -> f:format.date(format: 'd')} + +
+ + diff --git a/Resources/Private/Templates/Frontend/Calendar/Week.html b/Resources/Private/Templates/Frontend/Calendar/Week.html new file mode 100644 index 0000000..e3357e0 --- /dev/null +++ b/Resources/Private/Templates/Frontend/Calendar/Week.html @@ -0,0 +1,33 @@ + + +

{week.dateTimeInstance -> f:format.date(format: '%V %Y')}

+ + + Prev Week + + + Next Week + + + + + + + + + + + + + + + + + +
MoDiMiDoFrSaSo
+ + {day.dateTimeInstance -> f:format.date(format: 'd')} + +
+ diff --git a/Tests/ForcePropertyTrait.php b/Tests/ForcePropertyTrait.php new file mode 100644 index 0000000..1af013f --- /dev/null +++ b/Tests/ForcePropertyTrait.php @@ -0,0 +1,33 @@ + + * + * 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); + } +} diff --git a/Tests/Unit/Controller/Frontend/CalendarControllerTest.php b/Tests/Unit/Controller/Frontend/CalendarControllerTest.php new file mode 100644 index 0000000..9080b8f --- /dev/null +++ b/Tests/Unit/Controller/Frontend/CalendarControllerTest.php @@ -0,0 +1,275 @@ + + * + * 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, + ]; + } +} diff --git a/Tests/Unit/Domain/Model/DayTest.php b/Tests/Unit/Domain/Model/DayTest.php new file mode 100644 index 0000000..961932b --- /dev/null +++ b/Tests/Unit/Domain/Model/DayTest.php @@ -0,0 +1,144 @@ + + * + * 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()); + } +} diff --git a/Tests/Unit/Domain/Model/MonthTest.php b/Tests/Unit/Domain/Model/MonthTest.php new file mode 100644 index 0000000..c385303 --- /dev/null +++ b/Tests/Unit/Domain/Model/MonthTest.php @@ -0,0 +1,183 @@ + + * + * 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()); + } +} diff --git a/Tests/Unit/Domain/Model/NullDataFactoryTest.php b/Tests/Unit/Domain/Model/NullDataFactoryTest.php new file mode 100644 index 0000000..7e4ea07 --- /dev/null +++ b/Tests/Unit/Domain/Model/NullDataFactoryTest.php @@ -0,0 +1,45 @@ + + * + * 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 = $this->prophesize(Day::class); + self::assertNull($subject->getData($day->reveal())); + } +} diff --git a/Tests/Unit/Domain/Model/WeekTest.php b/Tests/Unit/Domain/Model/WeekTest.php new file mode 100644 index 0000000..be5a8cf --- /dev/null +++ b/Tests/Unit/Domain/Model/WeekTest.php @@ -0,0 +1,235 @@ + + * + * 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\Day; +use WerkraumMedia\Calendar\Domain\Model\Week; +use WerkraumMedia\Calendar\Tests\ForcePropertyTrait; + +/** + * @covers WerkraumMedia\Calendar\Domain\Model\Week + * @testdox A week + */ +class WeekTest extends TestCase +{ + use ProphecyTrait; + use ForcePropertyTrait; + + /** + * @test + */ + public function canBeCreated(): void + { + $subject = new Week(1, 2020); + + self::assertInstanceOf(Week::class, $subject); + } + + /** + * @test + */ + public function returnsSevenDays(): void + { + $subject = new Week(1, 2020); + + self::assertCount(7, $subject->getDays()); + } + + /** + * @test + */ + public function returnsSameDaysOnSecondCall(): void + { + $subject = new Week(1, 2020); + + self::assertSame($subject->getDays(), $subject->getDays()); + } + + /** + * @test + */ + public function returnsDaysForWeek1(): void + { + $subject = new Week(1, 2020); + $days = $subject->getDays(); + + self::assertSame('2019-12-30', $days[0]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2019-12-31', $days[1]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-01-01', $days[2]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-01-02', $days[3]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-01-03', $days[4]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-01-04', $days[5]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-01-05', $days[6]->getDateTimeInstance()->format('Y-m-d')); + } + + /** + * @test + */ + public function returnsDaysForWeek53(): void + { + $subject = new Week(53, 2020); + $days = $subject->getDays(); + + self::assertSame('2020-12-28', $days[0]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-12-29', $days[1]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-12-30', $days[2]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2020-12-31', $days[3]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2021-01-01', $days[4]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2021-01-02', $days[5]->getDateTimeInstance()->format('Y-m-d')); + self::assertSame('2021-01-03', $days[6]->getDateTimeInstance()->format('Y-m-d')); + } + + /** + * @test + */ + public function returnsPreviousWeekForSameYear(): void + { + $subject = new Week(2, 2020); + + self::assertSame('01', $subject->getPreviousWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2020', $subject->getPreviousWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsPreviousWeekForYearSwitchFrom2019To2018(): void + { + $subject = new Week(1, 2019); + + self::assertSame('52', $subject->getPreviousWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2018', $subject->getPreviousWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsPreviousWeekForYearSwitchFrom2018To2017(): void + { + $subject = new Week(1, 2018); + + self::assertSame('52', $subject->getPreviousWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2017', $subject->getPreviousWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsPreviousWeekForPreviousYear(): void + { + $subject = new Week(1, 2021); + + self::assertSame('53', $subject->getPreviousWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2020', $subject->getPreviousWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsNextWeekForSameYear(): void + { + $subject = new Week(1, 2020); + + self::assertSame('02', $subject->getNextWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2020', $subject->getNextWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsNextWeekForNextYear(): void + { + $subject = new Week(53, 2020); + + self::assertSame('01', $subject->getNextWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2021', $subject->getNextWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function returnsNextWeekForNextYearFrom2018To2019(): void + { + $subject = new Week(52, 2018); + + self::assertSame('01', $subject->getNextWeek()->getDateTimeInstance()->format('W')); + self::assertSame('2019', $subject->getNextWeek()->getDateTimeInstance()->format('Y')); + } + + /** + * @test + */ + public function providesDateTimeInstance(): void + { + $subject = new Week(52, 2018); + + self::assertSame('52', $subject->getDateTimeInstance()->format('W')); + self::assertSame('2018-12-27 Thursday', $subject->getDateTimeInstance()->format('Y-m-d l')); + } + + /** + * @test + */ + public function providesItselfAsUrlArgument(): void + { + $subject = new Week(52, 2018); + + self::assertSame([ + 'week' => 52, + 'year' => 2018, + ], $subject->getAsUrlArgument()); + } + + /** + * @test + */ + public function returnsNotActiveIfAllDaysAreInactive(): void + { + $subject = new Week(02, 2018); + + $day = $this->prophesize(Day::class); + $day->isActive()->willReturn(false); + $days = [$day->reveal()]; + $this->forceProperty($subject, 'days', $days); + + self::assertFalse($subject->isActive()); + } + + /** + * @test + */ + public function returnsActiveIfASingleDayActive(): void + { + $subject = new Week(02, 2018); + + $day = $this->prophesize(Day::class); + $day->isActive()->willReturn(true); + $day2 = $this->prophesize(Day::class); + $day2->isActive()->willReturn(false); + $days = [$day->reveal(), $day2->reveal()]; + $this->forceProperty($subject, 'days', $days); + + self::assertTrue($subject->isActive()); + } +} diff --git a/composer.json b/composer.json index 6f5d9ae..584e6e4 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "sort-packages": true }, "require": { + "php": "^7.3.0 || ^7.4.0", "typo3/cms-core": "^10.4", "typo3/cms-extbase": "^10.4" }, @@ -28,8 +29,10 @@ }, "require-dev": { "jangregor/phpstan-prophecy": "^0.6.2", + "maglnet/composer-require-checker": "^2.1", "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.4" + "phpunit/phpunit": "^9.4", + "squizlabs/php_codesniffer": "^3.5" }, "extra": { "typo3/cms": { diff --git a/ext_emconf.php b/ext_emconf.php new file mode 100644 index 0000000..166046b --- /dev/null +++ b/ext_emconf.php @@ -0,0 +1,21 @@ + 'Calendar', + 'description' => 'API for extensions to create calendar', + 'category' => 'misc', + 'author' => 'Daniel Siepmann', + 'author_email' => 'coding@daniel-siepmann.de', + 'author_company' => 'Codappix GmbH', + 'state' => 'alpha', + 'uploadfolder' => 0, + 'clearCacheOnLoad' => 0, + 'version' => '1.0.0', + 'constraints' => [ + 'depends' => [ + 'typo3' => '*', + ], + 'conflicts' => [], + 'suggests' => [], + ], +]; diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..68b095a --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,19 @@ + + + This project coding standard + + Classes/ + Tests/ + + + + + + + + + + + /Tests/* + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..7b93a5c --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + Tests/Unit/ + + + + + + Classes + + +