diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51313d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.Build/ +/composer.lock +/vendor/ diff --git a/Classes/Backend/Preview.php b/Classes/Backend/Preview.php new file mode 100644 index 0000000..135af10 --- /dev/null +++ b/Classes/Backend/Preview.php @@ -0,0 +1,55 @@ + + * + * 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 SkillDisplay\PHPToolKit\Api\Skill; +use TYPO3\CMS\Backend\View\PageLayoutView; +use TYPO3\CMS\Backend\View\PageLayoutViewDrawItemHookInterface; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +class Preview implements PageLayoutViewDrawItemHookInterface +{ + /** + * @var Skill + */ + protected $skillApi; + + public function __construct( + Skill $skillApi + ) { + $this->skillApi = $skillApi; + } + + public function preProcess( + PageLayoutView &$parentObject, + &$drawItem, + &$headerContent, + &$itemContent, + array &$row + ) { + $row['skills'] = []; + $skills = GeneralUtility::intExplode(',', $row['skilldisplay_skills'], true); + foreach ($skills as $skillId) { + $row['skills'][] = $this->skillApi->getById($skillId); + } + } +} diff --git a/Classes/Frontend/DataProcessing/Skills.php b/Classes/Frontend/DataProcessing/Skills.php new file mode 100644 index 0000000..4235c95 --- /dev/null +++ b/Classes/Frontend/DataProcessing/Skills.php @@ -0,0 +1,63 @@ + + * + * 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 SkillDisplay\PHPToolKit\Api\Skill; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface; + +class Skills implements DataProcessorInterface +{ + /** + * @var Skill + */ + protected $skillApi; + + public function __construct( + Skill $skillApi + ) { + $this->skillApi = $skillApi; + } + + public function process( + ContentObjectRenderer $cObj, + array $contentObjectConfiguration, + array $processorConfiguration, + array $processedData + ) { + $as = $cObj->stdWrapValue('as', $processorConfiguration, 'skills'); + $skillIds = GeneralUtility::intExplode( + ',', + $cObj->stdWrapValue('skills', $processorConfiguration, ''), + true + ); + $skills = []; + + foreach ($skillIds as $skillId) { + $skills[] = $this->skillApi->getById($skillId); + } + + $processedData[$as] = $skills; + return $processedData; + } +} diff --git a/Classes/SettingsFactory.php b/Classes/SettingsFactory.php new file mode 100644 index 0000000..ab87e4b --- /dev/null +++ b/Classes/SettingsFactory.php @@ -0,0 +1,70 @@ + + * + * 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 SkillDisplay\PHPToolKit\Configuration\Settings; +use TYPO3\CMS\Core\Context\Context; +use TYPO3\CMS\Core\Http\ServerRequest; +use TYPO3\CMS\Core\Site\SiteFinder; + +class SettingsFactory +{ + /** + * @var SiteFinder + */ + private $siteFinder; + + /** + * @var Context + */ + private $context; + + + public function __construct( + SiteFinder $siteFinder, + Context $context + ) { + $this->siteFinder = $siteFinder; + $this->context = $context; + } + + public function createFromCurrentSiteConfiguration(): Settings + { + $site = $this->getRequest()->getAttribute('site'); + if ($site === null) { + throw new \Exception('Could not determine current site.', 1599721652); + } + + $config = $site->getConfiguration(); + + return new Settings( + $config['skilldisplay_api_key'] ?? '', + ((int)$config['skilldisplay_verifier_id']) ?? 0, + $config['skilldisplay_user_secret'] ?? '' + ); + } + + private function getRequest(): ServerRequest + { + return $GLOBALS['TYPO3_REQUEST']; + } +} diff --git a/Classes/ViewHelpers/Verification/ButtonViewHelper.php b/Classes/ViewHelpers/Verification/ButtonViewHelper.php new file mode 100644 index 0000000..352397a --- /dev/null +++ b/Classes/ViewHelpers/Verification/ButtonViewHelper.php @@ -0,0 +1,54 @@ + + * + * 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 SkillDisplay\PHPToolKit\Verification\Link; +use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; +use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; +use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +class ButtonViewHelper extends AbstractViewHelper +{ + use CompileWithRenderStatic; + + protected $escapeOutput = false; + + public function initializeArguments() + { + $this->registerArgument('skill', 'integer', 'ID of the skill.', true); + $this->registerArgument('type', 'string', 'Type of verification', false, 'self'); + } + + public static function renderStatic( + array $arguments, + \Closure $renderChildrenClosure, + RenderingContextInterface $renderingContext + ) { + /** @var Link $link */ + $link = GeneralUtility::makeInstance(Link::class); + return $link->getVerificationButton( + $arguments['type'], + $arguments['skill'] + ); + } +} diff --git a/Classes/ViewHelpers/Verification/UrlViewHelper.php b/Classes/ViewHelpers/Verification/UrlViewHelper.php new file mode 100644 index 0000000..5ad21f3 --- /dev/null +++ b/Classes/ViewHelpers/Verification/UrlViewHelper.php @@ -0,0 +1,54 @@ + + * + * 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 SkillDisplay\PHPToolKit\Verification\Link; +use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface; +use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper; +use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; +use TYPO3\CMS\Core\Utility\GeneralUtility; + +class UrlViewHelper extends AbstractViewHelper +{ + use CompileWithRenderStatic; + + protected $escapeOutput = false; + + public function initializeArguments() + { + $this->registerArgument('skill', 'integer', 'ID of the skill.', true); + $this->registerArgument('type', 'string', 'Type of verification', false, 'self'); + } + + public static function renderStatic( + array $arguments, + \Closure $renderChildrenClosure, + RenderingContextInterface $renderingContext + ) { + /** @var Link $link */ + $link = GeneralUtility::makeInstance(Link::class); + return $link->getVerificationLink( + $arguments['type'], + $arguments['skill'] + ); + } +} diff --git a/Configuration/PageTSconfig/Index.tsconfig b/Configuration/PageTSconfig/Index.tsconfig new file mode 100644 index 0000000..3877dc0 --- /dev/null +++ b/Configuration/PageTSconfig/Index.tsconfig @@ -0,0 +1 @@ +@import 'EXT:skilldisplay/Configuration/PageTSconfig/Mod/Wizards/*.tsconfig' diff --git a/Configuration/PageTSconfig/Mod/Wizards/Index.tsconfig b/Configuration/PageTSconfig/Mod/Wizards/Index.tsconfig new file mode 100644 index 0000000..be1c85a --- /dev/null +++ b/Configuration/PageTSconfig/Mod/Wizards/Index.tsconfig @@ -0,0 +1,6 @@ +mod { + wizards.newContentElement.wizardItems.skilldisplay { + header = LLL:EXT:skilldisplay/Resources/Private/Language/locallang_be.xlf:newContentElement.skilldisplay.header + show = * + } +} diff --git a/Configuration/PageTSconfig/Mod/Wizards/Skills.tsconfig b/Configuration/PageTSconfig/Mod/Wizards/Skills.tsconfig new file mode 100644 index 0000000..60f2414 --- /dev/null +++ b/Configuration/PageTSconfig/Mod/Wizards/Skills.tsconfig @@ -0,0 +1,15 @@ +mod { + wizards.newContentElement.wizardItems.skilldisplay { + elements { + skilldisplay_skills { + iconIdentifier = skilldisplay-skill + title = LLL:EXT:skilldisplay/Resources/Private/Language/locallang_tca.xlf:tt_content.skilldisplay_skills + description = LLL:EXT:skilldisplay/Resources/Private/Language/locallang_be.xlf:newContentElement.skilldisplay.skills.description + tt_content_defValues { + CType = skilldisplay_skills + } + } + } + } + web_layout.tt_content.preview.skilldisplay_skills = EXT:skilldisplay/Resources/Private/Templates/Backend/ContentElements/Skills.html +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml new file mode 100644 index 0000000..0809d6f --- /dev/null +++ b/Configuration/Services.yaml @@ -0,0 +1,33 @@ +services: + _defaults: + autowire: true + autoconfigure: true + public: false + + SkillDisplay\Typo3Extension\: + resource: '../Classes/*' + + SkillDisplay\Typo3Extension\Frontend\DataProcessing\: + resource: '../Classes/Frontend/DataProcessing/*' + public: true + + skilldisplay.settings: + class: 'SkillDisplay\PHPToolKit\Configuration\Settings' + factory: + - '@SkillDisplay\Typo3Extension\SettingsFactory' + - 'createFromCurrentSiteConfiguration' + + SkillDisplay\PHPToolKit\Configuration\Settings: + alias: '@skilldisplay.settings' + + SkillDisplay\PHPToolKit\Api\Skill: + arguments: + $settings: '@skilldisplay.settings' + + SkillDisplay\PHPToolKit\Verification\Link: + public: true + arguments: + $settings: '@skilldisplay.settings' + + SkillDisplay\Typo3Extension\Backend\Preview: + public: true diff --git a/Configuration/SiteConfiguration/Overrides/sites.php b/Configuration/SiteConfiguration/Overrides/sites.php new file mode 100644 index 0000000..bebd83c --- /dev/null +++ b/Configuration/SiteConfiguration/Overrides/sites.php @@ -0,0 +1,39 @@ + [ + 'skilldisplay_user_secret' => [ + 'label' => $languagePath . 'skilldisplay_user_secret', + 'config' => [ + 'type' => 'input', + ], + ], + 'skilldisplay_api_key' => [ + 'label' => $languagePath . 'skilldisplay_api_key', + 'config' => [ + 'type' => 'input', + ], + ], + 'skilldisplay_verifier_id' => [ + 'label' => $languagePath . 'skilldisplay_verifier_id', + 'config' => [ + 'type' => 'input', + ], + ], + ], + 'types' => [ + '0' => [ + 'showitem' => $GLOBALS['SiteConfiguration']['site']['types']['0']['showitem'] + . ', ' . implode(',', [ + '--div--;' . $languagePath . 'div.skilldisplay', + 'skilldisplay_user_secret', + 'skilldisplay_api_key', + 'skilldisplay_verifier_id', + ]), + ], + ], + ]); +})('skilldisplay', 'site'); diff --git a/Configuration/TCA/Overrides/sys_template.php b/Configuration/TCA/Overrides/sys_template.php new file mode 100644 index 0000000..624a6bb --- /dev/null +++ b/Configuration/TCA/Overrides/sys_template.php @@ -0,0 +1,9 @@ + [ + 'CType' => [ + 'config' => [ + 'itemGroups' => [ + 'skilldisplay' => $languagePath . 'CType.itemGroups.skilldisplay', + ], + ], + ], + 'skilldisplay_skills' => [ + 'exclude' => 1, + 'label' => $languagePath . 'skilldisplay_skills', + 'description' => $languagePath . 'skilldisplay_skills.description', + 'config' => [ + 'type' => 'input', + 'eval' => 'required', + 'size' => 10, + ], + ], + ], + ]); +})('skilldisplay', 'tt_content'); diff --git a/Configuration/TCA/Overrides/tt_content_skills.php b/Configuration/TCA/Overrides/tt_content_skills.php new file mode 100644 index 0000000..a5e677f --- /dev/null +++ b/Configuration/TCA/Overrides/tt_content_skills.php @@ -0,0 +1,46 @@ + [ + 'typeicon_classes' => [ + $contentType => 'skilldisplay-skill', + ], + ], + 'types' => [ + $contentType => [ + 'showitem' => implode(',', [ + '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general', + '--palette--;;general', + 'skilldisplay_skills', + '--div--;LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance', + '--palette--;;frames', + '--palette--;;appearanceLinks', + '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language', + '--palette--;;language', + '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access', + '--palette--;;hidden', + '--palette--;;access', + '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:categories', + 'categories', + '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:notes', + 'rowDescription', + '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:extended', + ]), + ], + ], + ]); + + \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTcaSelectItem( + $tableName, + 'CType', + [ + $languagePath . $contentType, + $contentType, + 'skilldisplay-skill', + 'skilldisplay' + ] + ); +})('skilldisplay', 'tt_content', 'skilldisplay_skills'); diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript new file mode 100644 index 0000000..c7ec84d --- /dev/null +++ b/Configuration/TypoScript/setup.typoscript @@ -0,0 +1,11 @@ +tt_content.skilldisplay_skills = < lib.contentElement +tt_content.skilldisplay_skills { + templateName = SkillDisplaySkills + + dataProcessing { + 10 = SkillDisplay\Typo3Extension\Frontend\DataProcessing\Skills + 10 { + skills.field = skilldisplay_skills + } + } +} diff --git a/Resources/Private/Language/locallang_be.xlf b/Resources/Private/Language/locallang_be.xlf new file mode 100644 index 0000000..1673611 --- /dev/null +++ b/Resources/Private/Language/locallang_be.xlf @@ -0,0 +1,27 @@ + + + +
+ + + SkillDisplay + + + Renders one or multiple skills. + + + + SkillDisplay + + + User secret + + + API Key + + + Verifier ID + + + + diff --git a/Resources/Private/Language/locallang_tca.xlf b/Resources/Private/Language/locallang_tca.xlf new file mode 100644 index 0000000..5db767b --- /dev/null +++ b/Resources/Private/Language/locallang_tca.xlf @@ -0,0 +1,17 @@ + + + +
+ + + SkillDisplay: Skills + + + Comma separated list of UIDs. + + + SkillDisplay + + + + diff --git a/Resources/Private/Templates/Backend/ContentElements/Skills.html b/Resources/Private/Templates/Backend/ContentElements/Skills.html new file mode 100644 index 0000000..eb64f88 --- /dev/null +++ b/Resources/Private/Templates/Backend/ContentElements/Skills.html @@ -0,0 +1,19 @@ + + + +
    + +
  1. + {skill.title}
    + {sd:verification.url(skill: skill.id)} +
  2. +
    +
+
+ diff --git a/Resources/Private/Templates/ContentElements/SkillDisplaySkills.html b/Resources/Private/Templates/ContentElements/SkillDisplaySkills.html new file mode 100644 index 0000000..4b59455 --- /dev/null +++ b/Resources/Private/Templates/ContentElements/SkillDisplaySkills.html @@ -0,0 +1,13 @@ + + +
+
+
{skill.title}
+

{skill.description -> f:format.html()}

+ +
+
+
+ diff --git a/Resources/Public/Icons/Extension.png b/Resources/Public/Icons/Extension.png new file mode 100644 index 0000000..3fc45ff Binary files /dev/null and b/Resources/Public/Icons/Extension.png differ diff --git a/Resources/Public/Icons/skill.png b/Resources/Public/Icons/skill.png new file mode 100644 index 0000000..c97729e Binary files /dev/null and b/Resources/Public/Icons/skill.png differ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..98532d7 --- /dev/null +++ b/composer.json @@ -0,0 +1,62 @@ +{ + "name": "skilldisplay/typo3-skilldisplay", + "description": "SkillDisplay integration for TYPO3", + "type": "typo3-cms-extension", + "license": "GPL-2.0-or-later", + "homepage": "https://daniel-siepmann.de/projects/typo3-extension-skilldisplay.html", + "support": { + "email": "coding@daniel-siepmann.de", + "source": "https://github.com/DanielSiepmann/SkillDisplay/", + "issues": "https://github.com/DanielSiepmann/SkillDisplay/issues" + }, + "authors": [ + { + "name": "Daniel Siepmann", + "email": "coding@daniel-siepmann.de" + } + ], + "autoload": { + "psr-4": { + "SkillDisplay\\Typo3Extension\\": "Classes/" + } + }, + "autoload-dev": { + "psr-4": { + "SkillDisplay\\Typo3Extension\\Tests\\": "Tests/" + } + }, + "require": { + "php": "^7.3.0", + "typo3/cms-core": "^10.4", + "skilldisplay/phptoolkit": "^1.0", + "typo3/cms-backend": "^10.4", + "typo3/cms-frontend": "^10.4" + }, + "require-dev": { + "squizlabs/php_codesniffer": "^3.5", + "phpstan/phpstan": "^0.12.18", + "phpstan/extension-installer": "^1.0", + "maglnet/composer-require-checker": "^2.1", + "phpspec/prophecy-phpunit": "^2.0", + "saschaegerer/phpstan-typo3": "^0.13.1", + "sensiolabs/security-checker": "^6.0" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "scripts": { + "post-autoload-dump": [ + "mkdir -p .Build/web/typo3conf/ext/", + "[ -L .Build/web/typo3conf/ext/skilldisplay ] || ln -snvf ../../../../. .Build/web/typo3conf/ext/skilldisplay" + ] + }, + "extra": { + "typo3/cms": { + "cms-package-dir": "{$vendor-dir}/typo3/cms", + "extension-key": "skilldisplay", + "web-dir": ".Build/web" + }, + "branch-alias": { + "dev-main": "1.0.x-dev" + } + } +} diff --git a/ext_emconf.php b/ext_emconf.php new file mode 100644 index 0000000..041bb16 --- /dev/null +++ b/ext_emconf.php @@ -0,0 +1,21 @@ + 'SkillDisplay', + 'description' => 'Integrates SkillDisplay', + 'category' => 'fe', + 'state' => 'alpha', + 'uploadfolder' => 0, + 'createDirs' => '', + 'clearCacheOnLoad' => 0, + 'author' => 'Daniel Siepmann', + 'author_email' => 'coding@daniel-siepmann.de', + 'author_company' => '', + 'version' => '0.1.0', + 'constraints' => [ + 'depends' => [ + 'core' => '', + ], + 'conflicts' => [], + 'suggests' => [], + ], +]; diff --git a/ext_localconf.php b/ext_localconf.php new file mode 100644 index 0000000..442a883 --- /dev/null +++ b/ext_localconf.php @@ -0,0 +1,26 @@ +registerIcon( + 'skilldisplay-' . $icon, + \TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider::class, + [ + 'source' => 'EXT:' . $extKey . '/Resources/Public/Icons/' . $icon . '.png', + ] + ); + } + + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['tt_content_drawItem'][$extKey] = + \SkillDisplay\Typo3Extension\Backend\Preview::class; +})('skilldisplay'); diff --git a/ext_tables.sql b/ext_tables.sql new file mode 100644 index 0000000..42244d0 --- /dev/null +++ b/ext_tables.sql @@ -0,0 +1,3 @@ +CREATE TABLE tt_content ( + skilldisplay_skills TEXT, +); 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/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..22b9fa5 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,23 @@ +parameters: + level: max + paths: + - Classes + - Tests + checkMissingIterableValueType: false + reportUnmatchedIgnoredErrors: true + ignoreErrors: + - '#Cannot call method fetch\(\) on Doctrine\\DBAL\\Driver\\Statement\|int\.#' + - '#Cannot call method fetchAll\(\) on Doctrine\\DBAL\\Driver\\Statement\|int\.#' + - '#Cannot call method fetchColumn\(\) on Doctrine\\DBAL\\Driver\\Statement\|int\.#' + - + message: '#\$timestamp of function date expects int, int\|false given\.#' + path: Classes/Dashboard/Provider/PageviewsPerDay.php + count: 1 + - + message: '#Parameter \#1 \$start of method DanielSiepmann\\Tracking\\Dashboard\\Provider\\PageviewsPerDay::getPageviewsInPeriod\(\) expects int, int\|false given\.#' + path: Classes/Dashboard/Provider/PageviewsPerDay.php + count: 1 + - + message: '#Parameter \#2 \$end of method DanielSiepmann\\Tracking\\Dashboard\\Provider\\PageviewsPerDay::getPageviewsInPeriod\(\) expects int, int\|false given\.#' + path: Classes/Dashboard/Provider/PageviewsPerDay.php + count: 1