Add content element "skills"

Allow editors to add new content element "skills".
The element contains an input for a comma separated list of skill IDs.
A preview in backend is shown.
Frontend rendering is provided.
This commit is contained in:
Daniel Siepmann 2020-09-21 16:36:01 +02:00
parent 7dd9311d13
commit da3aed135c
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
27 changed files with 716 additions and 0 deletions

3
.gitignore vendored Normal file
View file

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

View file

@ -0,0 +1,55 @@
<?php
namespace SkillDisplay\Typo3Extension\Backend;
/*
* 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 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);
}
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace SkillDisplay\Typo3Extension\Frontend\DataProcessing;
/*
* 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 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;
}
}

View file

@ -0,0 +1,70 @@
<?php
namespace SkillDisplay\Typo3Extension;
/*
* 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 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'];
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace SkillDisplay\Typo3Extension\ViewHelpers\Verification;
/*
* 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 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']
);
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace SkillDisplay\Typo3Extension\ViewHelpers\Verification;
/*
* 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 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']
);
}
}

View file

@ -0,0 +1 @@
@import 'EXT:skilldisplay/Configuration/PageTSconfig/Mod/Wizards/*.tsconfig'

View file

@ -0,0 +1,6 @@
mod {
wizards.newContentElement.wizardItems.skilldisplay {
header = LLL:EXT:skilldisplay/Resources/Private/Language/locallang_be.xlf:newContentElement.skilldisplay.header
show = *
}
}

View file

@ -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
}

View file

@ -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

View file

@ -0,0 +1,39 @@
<?php
(function (string $extensionKey, string $tableName) {
$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang_be.xlf:' . $tableName . '.';
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['SiteConfiguration']['site'], [
'columns' => [
'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');

View file

@ -0,0 +1,9 @@
<?php
(function (string $extensionKey, string $tableName) {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile(
$extensionKey,
'Configuration/TypoScript/',
'SkillDisplay'
);
})('skilldisplay', 'sys_template');

View file

@ -0,0 +1,27 @@
<?php
(function (string $extensionKey, string $tableName) {
$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang_tca.xlf:' . $tableName . '.';
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA'][$tableName], [
'columns' => [
'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');

View file

@ -0,0 +1,46 @@
<?php
(function (string $extensionKey, string $tableName, string $contentType) {
$languagePath = 'LLL:EXT:' . $extensionKey . '/Resources/Private/Language/locallang_tca.xlf:' . $tableName . '.';
\TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA'][$tableName], [
'ctrl' => [
'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');

View file

@ -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
}
}
}

View file

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
<file source-language="en" datatype="plaintext">
<header/>
<body>
<trans-unit id="newContentElement.skilldisplay.header">
<source>SkillDisplay</source>
</trans-unit>
<trans-unit id="newContentElement.skilldisplay.skills.description">
<source>Renders one or multiple skills.</source>
</trans-unit>
<trans-unit id="site.div.skilldisplay">
<source>SkillDisplay</source>
</trans-unit>
<trans-unit id="site.skilldisplay_user_secret">
<source>User secret</source>
</trans-unit>
<trans-unit id="site.skilldisplay_api_key">
<source>API Key</source>
</trans-unit>
<trans-unit id="site.skilldisplay_verifier_id">
<source>Verifier ID</source>
</trans-unit>
</body>
</file>
</xliff>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.0" xmlns:t3="http://typo3.org/schemas/xliff">
<file source-language="en" datatype="plaintext">
<header/>
<body>
<trans-unit id="tt_content.skilldisplay_skills">
<source>SkillDisplay: Skills</source>
</trans-unit>
<trans-unit id="tt_content.skilldisplay_skills.description">
<source>Comma separated list of UIDs.</source>
</trans-unit>
<trans-unit id="tt_content.CType.itemGroups.skilldisplay">
<source>SkillDisplay</source>
</trans-unit>
</body>
</file>
</xliff>

View file

@ -0,0 +1,19 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
xmlns:sd="http://typo3.org/ns/SkillDisplay/Typo3Extension/ViewHelpers"
data-namespace-typo3-fluid="true">
<a href="{be:uri.editRecord(
uid: uid,
table: 'tt_content'
)}">
<ol>
<f:for each="{skills}" as="skill">
<li>
<strong>{skill.title}</strong><br>
{sd:verification.url(skill: skill.id)}
</li>
</f:for>
</ol>
</a>
</html>

View file

@ -0,0 +1,13 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:sd="http://typo3.org/ns/SkillDisplay/Typo3Extension/ViewHelpers"
data-namespace-typo3-fluid="true">
<f:for each="{skills}" as="skill">
<div class="card">
<div class="card-body">
<h5 class="card-title">{skill.title}</h5>
<p class="card-text">{skill.description -> f:format.html()}</p>
<sd:verification.button skill="{skill.id}"/>
</div>
</div>
</f:for>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

62
composer.json Normal file
View file

@ -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"
}
}
}

21
ext_emconf.php Normal file
View file

@ -0,0 +1,21 @@
<?php
$EM_CONF[$_EXTKEY] = [
'title' => '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' => [],
],
];

26
ext_localconf.php Normal file
View file

@ -0,0 +1,26 @@
<?php
(function (string $extKey) {
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPageTSConfig(
"@import 'EXT:" . $extKey . "/Configuration/PageTSconfig/*.tsconfig'"
);
$icons = [
'skill',
];
$iconRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
\TYPO3\CMS\Core\Imaging\IconRegistry::class
);
foreach ($icons as $icon) {
$iconRegistry->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');

3
ext_tables.sql Normal file
View file

@ -0,0 +1,3 @@
CREATE TABLE tt_content (
skilldisplay_skills TEXT,
);

19
phpcs.xml.dist Normal file
View file

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<ruleset name="project">
<description>This project coding standard</description>
<file>Classes/</file>
<file>Tests/</file>
<!-- Set default settings -->
<arg value="sp"/>
<arg name="colors"/>
<arg name="encoding" value="utf-8" />
<arg name="extensions" value="php" />
<!-- Base rules -->
<rule ref="PSR12" />
<rule ref="Generic.Files.LineLength.TooLong">
<exclude-pattern>/Tests/*</exclude-pattern>
</rule>
</ruleset>

23
phpstan.neon Normal file
View file

@ -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