mirror of
https://github.com/werkraum-media/watchlist.git
synced 2024-11-21 21:36:10 +01:00
[TASK] Kickstart extension with basic features (#1)
This commit is contained in:
parent
15120714de
commit
916b2723d5
33 changed files with 1546 additions and 3 deletions
150
.github/workflows/ci.yaml
vendored
Normal file
150
.github/workflows/ci.yaml
vendored
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
- pull_request
|
||||||
|
jobs:
|
||||||
|
check-composer:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install Composer
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: 8.1
|
||||||
|
coverage: none
|
||||||
|
tools: composer:v2
|
||||||
|
env:
|
||||||
|
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Validate composer.json
|
||||||
|
run: composer validate
|
||||||
|
|
||||||
|
php-linting:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
php-version:
|
||||||
|
- 7.4
|
||||||
|
- 8.0
|
||||||
|
- 8.1
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: PHP lint
|
||||||
|
run: "find *.php Classes Configuration Tests -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l"
|
||||||
|
|
||||||
|
xml-linting:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [check-composer]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "8.1"
|
||||||
|
coverage: none
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Install xmllint
|
||||||
|
run: sudo apt-get install libxml2-utils
|
||||||
|
|
||||||
|
- 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: Fetch schema for xliff
|
||||||
|
run: wget https://docs.oasis-open.org/xliff/v1.2/os/xliff-core-1.2-strict.xsd --output-document=xliff-core-1.2-strict.xsd
|
||||||
|
|
||||||
|
- name: TYPO3 language files
|
||||||
|
run: xmllint --schema xliff-core-1.2-strict.xsd --noout $(find Resources -name '*.xlf')
|
||||||
|
|
||||||
|
coding-guideline:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- php-linting
|
||||||
|
- xml-linting
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "8.1"
|
||||||
|
coverage: none
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: composer install --prefer-dist --no-progress --no-suggest
|
||||||
|
|
||||||
|
- name: Coding Guideline
|
||||||
|
run: ./vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||||
|
|
||||||
|
code-quality:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- php-linting
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php-version: '7.4'
|
||||||
|
- php-version: '8.0'
|
||||||
|
- php-version: '8.1'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "${{ matrix.php-version }}"
|
||||||
|
coverage: none
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Install dependencies with expected TYPO3 version
|
||||||
|
run: composer require --no-interaction --prefer-dist --no-progress
|
||||||
|
|
||||||
|
- name: Code Quality (by PHPStan)
|
||||||
|
run: ./vendor/bin/phpstan analyse
|
||||||
|
|
||||||
|
tests-mysql:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs:
|
||||||
|
- php-linting
|
||||||
|
- xml-linting
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- php-version: '7.4'
|
||||||
|
- php-version: '8.0'
|
||||||
|
- php-version: '8.1'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: "${{ matrix.php-version }}"
|
||||||
|
coverage: none
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Setup MySQL
|
||||||
|
uses: mirromutth/mysql-action@v1.1
|
||||||
|
with:
|
||||||
|
mysql version: '8'
|
||||||
|
mysql database: 'typo3'
|
||||||
|
mysql root password: 'root'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: composer require --no-interaction --prefer-dist --no-progress
|
||||||
|
|
||||||
|
- name: PHPUnit Tests
|
||||||
|
run: |-
|
||||||
|
export typo3DatabaseDriver="pdo_mysql"
|
||||||
|
export typo3DatabaseName="typo3"
|
||||||
|
export typo3DatabaseHost="127.0.0.1"
|
||||||
|
export typo3DatabaseUsername="root"
|
||||||
|
export typo3DatabasePassword="root"
|
||||||
|
./vendor/bin/phpunit --testdox
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
/composer.lock
|
||||||
|
/.php-cs-fixer.cache
|
||||||
|
/vendor/
|
||||||
|
/public/
|
||||||
|
/var/
|
62
.php-cs-fixer.dist.php
Normal file
62
.php-cs-fixer.dist.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
$finder = (new PhpCsFixer\Finder())
|
||||||
|
->ignoreVCSIgnored(true)
|
||||||
|
->in(realpath(__DIR__));
|
||||||
|
|
||||||
|
return (new \PhpCsFixer\Config())
|
||||||
|
->setRiskyAllowed(true)
|
||||||
|
->setRules([
|
||||||
|
'@DoctrineAnnotation' => true,
|
||||||
|
'@PSR2' => true,
|
||||||
|
'array_syntax' => ['syntax' => 'short'],
|
||||||
|
'blank_line_after_opening_tag' => true,
|
||||||
|
'braces' => ['allow_single_line_closure' => true],
|
||||||
|
'cast_spaces' => ['space' => 'none'],
|
||||||
|
'compact_nullable_typehint' => true,
|
||||||
|
'concat_space' => ['spacing' => 'one'],
|
||||||
|
'declare_equal_normalize' => ['space' => 'none'],
|
||||||
|
'dir_constant' => true,
|
||||||
|
'function_to_constant' => ['functions' => ['get_called_class', 'get_class', 'get_class_this', 'php_sapi_name', 'phpversion', 'pi']],
|
||||||
|
'function_typehint_space' => true,
|
||||||
|
'lowercase_cast' => true,
|
||||||
|
'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
|
||||||
|
'modernize_strpos' => true,
|
||||||
|
'modernize_types_casting' => true,
|
||||||
|
'native_function_casing' => true,
|
||||||
|
'new_with_braces' => true,
|
||||||
|
'no_alias_functions' => true,
|
||||||
|
'no_blank_lines_after_phpdoc' => true,
|
||||||
|
'no_empty_phpdoc' => true,
|
||||||
|
'no_empty_statement' => true,
|
||||||
|
'no_extra_blank_lines' => true,
|
||||||
|
'no_leading_import_slash' => true,
|
||||||
|
'no_leading_namespace_whitespace' => true,
|
||||||
|
'no_null_property_initialization' => true,
|
||||||
|
'no_short_bool_cast' => true,
|
||||||
|
'no_singleline_whitespace_before_semicolons' => true,
|
||||||
|
'no_superfluous_elseif' => true,
|
||||||
|
'no_trailing_comma_in_singleline_array' => true,
|
||||||
|
'no_unneeded_control_parentheses' => true,
|
||||||
|
'no_unused_imports' => true,
|
||||||
|
'no_useless_else' => true,
|
||||||
|
'no_whitespace_in_blank_line' => true,
|
||||||
|
'ordered_imports' => true,
|
||||||
|
'php_unit_construct' => ['assertions' => ['assertEquals', 'assertSame', 'assertNotEquals', 'assertNotSame']],
|
||||||
|
'php_unit_mock_short_will_return' => true,
|
||||||
|
'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
|
||||||
|
'phpdoc_no_access' => true,
|
||||||
|
'phpdoc_no_empty_return' => true,
|
||||||
|
'phpdoc_no_package' => true,
|
||||||
|
'phpdoc_scalar' => true,
|
||||||
|
'phpdoc_trim' => true,
|
||||||
|
'phpdoc_types' => true,
|
||||||
|
'phpdoc_types_order' => ['null_adjustment' => 'always_last', 'sort_algorithm' => 'none'],
|
||||||
|
'return_type_declaration' => ['space_before' => 'none'],
|
||||||
|
'single_quote' => true,
|
||||||
|
'single_line_comment_style' => ['comment_types' => ['hash']],
|
||||||
|
'single_trait_insert_per_statement' => true,
|
||||||
|
'trailing_comma_in_multiline' => ['elements' => ['arrays']],
|
||||||
|
'whitespace_after_comma_in_array' => true,
|
||||||
|
'yoda_style' => ['equal' => false, 'identical' => false, 'less_and_greater' => false],
|
||||||
|
])
|
||||||
|
->setFinder($finder);
|
84
Classes/Controller/WatchlistController.php
Normal file
84
Classes/Controller/WatchlistController.php
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Controller;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use TYPO3\CMS\Core\Http\PropagateResponseException;
|
||||||
|
use TYPO3\CMS\Core\Http\RedirectResponse;
|
||||||
|
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Watchlist;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Repository\WatchlistRepository;
|
||||||
|
|
||||||
|
class WatchlistController extends ActionController
|
||||||
|
{
|
||||||
|
private WatchlistRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
WatchlistRepository $repository
|
||||||
|
) {
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function initializeAction(): void
|
||||||
|
{
|
||||||
|
if ($this->request->hasArgument('watchlist') === false) {
|
||||||
|
$this->request->setArgument('watchlist', 'default');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexAction(
|
||||||
|
Watchlist $watchlist
|
||||||
|
): ResponseInterface {
|
||||||
|
$this->view->assignMultiple([
|
||||||
|
'watchlist' => $watchlist,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $this->htmlResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addAction(
|
||||||
|
Watchlist $watchlist,
|
||||||
|
Item $item,
|
||||||
|
string $redirectUri = ''
|
||||||
|
): void {
|
||||||
|
$watchlist->addItem($item);
|
||||||
|
|
||||||
|
$this->repository->update($watchlist);
|
||||||
|
|
||||||
|
throw new PropagateResponseException(new RedirectResponse($redirectUri, 303), 1664189968);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeAction(
|
||||||
|
Watchlist $watchlist,
|
||||||
|
Item $item,
|
||||||
|
string $redirectUri
|
||||||
|
): void {
|
||||||
|
$watchlist->removeItem($item);
|
||||||
|
|
||||||
|
$this->repository->update($watchlist);
|
||||||
|
|
||||||
|
throw new PropagateResponseException(new RedirectResponse($redirectUri, 303), 1664189969);
|
||||||
|
}
|
||||||
|
}
|
45
Classes/Domain/ItemHandlerInterface.php
Normal file
45
Classes/Domain/ItemHandlerInterface.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain;
|
||||||
|
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines interface of concrete handler implementations per item type.
|
||||||
|
*
|
||||||
|
* Each item has a type, and each type has an handler.
|
||||||
|
* The handler needs to take care of creating the item instances.
|
||||||
|
*/
|
||||||
|
interface ItemHandlerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns an item instance based on its identifier.
|
||||||
|
*/
|
||||||
|
public function return(string $identifier): ?Item;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type the handler can handle, e.g. "pages" or "tt_address".
|
||||||
|
*/
|
||||||
|
public function handlesType(): string;
|
||||||
|
}
|
55
Classes/Domain/ItemHandlerRegistry.php
Normal file
55
Classes/Domain/ItemHandlerRegistry.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain;
|
||||||
|
|
||||||
|
class ItemHandlerRegistry
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ItemHandlerInterface[]
|
||||||
|
*/
|
||||||
|
private array $itemHandler = [];
|
||||||
|
|
||||||
|
public function exists(string $type): bool
|
||||||
|
{
|
||||||
|
return isset($this->itemHandler[$type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(string $type): ItemHandlerInterface
|
||||||
|
{
|
||||||
|
return $this->itemHandler[$type];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(ItemHandlerInterface $itemHandler): void
|
||||||
|
{
|
||||||
|
$this->itemHandler[$itemHandler->handlesType()] = $itemHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getSupportedTypes(): array
|
||||||
|
{
|
||||||
|
return array_keys($this->itemHandler);
|
||||||
|
}
|
||||||
|
}
|
65
Classes/Domain/Items/Page/ItemHandler.php
Normal file
65
Classes/Domain/Items/Page/ItemHandler.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain\Items\Page;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\ItemHandlerInterface;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
|
||||||
|
class ItemHandler implements ItemHandlerInterface
|
||||||
|
{
|
||||||
|
private ConnectionPool $connectionPool;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ConnectionPool $connectionPool
|
||||||
|
) {
|
||||||
|
$this->connectionPool = $connectionPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function return(string $identifier): ?Item
|
||||||
|
{
|
||||||
|
$pageUid = (int)$identifier;
|
||||||
|
$pageRecord = $this->getPageRecord($pageUid);
|
||||||
|
|
||||||
|
return new Page(
|
||||||
|
$pageUid,
|
||||||
|
(string)$pageRecord['title']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handlesType(): string
|
||||||
|
{
|
||||||
|
return 'page';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPageRecord(int $uid): array
|
||||||
|
{
|
||||||
|
$qb = $this->connectionPool->getQueryBuilderForTable('pages');
|
||||||
|
$qb->select('title');
|
||||||
|
$qb->from('pages');
|
||||||
|
$qb->where($qb->expr()->eq('uid', $qb->createNamedParameter($uid)));
|
||||||
|
$qb->setMaxResults(1);
|
||||||
|
return $qb->execute()->fetchAssociative() ?: [];
|
||||||
|
}
|
||||||
|
}
|
51
Classes/Domain/Items/Page/Page.php
Normal file
51
Classes/Domain/Items/Page/Page.php
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain\Items\Page;
|
||||||
|
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
|
||||||
|
class Page implements Item
|
||||||
|
{
|
||||||
|
private int $pageUid;
|
||||||
|
|
||||||
|
private string $title;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
int $pageUid,
|
||||||
|
string $title
|
||||||
|
) {
|
||||||
|
$this->pageUid = $pageUid;
|
||||||
|
$this->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUniqueIdentifier(): string
|
||||||
|
{
|
||||||
|
return 'page-' . $this->pageUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTitle(): string
|
||||||
|
{
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
}
|
32
Classes/Domain/Model/Item.php
Normal file
32
Classes/Domain/Model/Item.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain\Model;
|
||||||
|
|
||||||
|
interface Item
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Needs to uniquely identify the thing throughout the system.
|
||||||
|
*/
|
||||||
|
public function getUniqueIdentifier(): string;
|
||||||
|
}
|
60
Classes/Domain/Model/Watchlist.php
Normal file
60
Classes/Domain/Model/Watchlist.php
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain\Model;
|
||||||
|
|
||||||
|
class Watchlist
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Item[]
|
||||||
|
*/
|
||||||
|
private array $items = [];
|
||||||
|
|
||||||
|
public function getIdentifier(): string
|
||||||
|
{
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Item[]
|
||||||
|
*/
|
||||||
|
public function getItems(): array
|
||||||
|
{
|
||||||
|
return array_values($this->items);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addItem(Item $item): void
|
||||||
|
{
|
||||||
|
$this->items[$item->getUniqueIdentifier()] = $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeItem(Item $item): void
|
||||||
|
{
|
||||||
|
unset($this->items[$item->getUniqueIdentifier()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEmpty(): bool
|
||||||
|
{
|
||||||
|
return $this->items === [];
|
||||||
|
}
|
||||||
|
}
|
56
Classes/Domain/Repository/ItemRepository.php
Normal file
56
Classes/Domain/Repository/ItemRepository.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain\Repository;
|
||||||
|
|
||||||
|
use WerkraumMedia\Watchlist\Domain\ItemHandlerRegistry;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
|
||||||
|
class ItemRepository
|
||||||
|
{
|
||||||
|
private ItemHandlerRegistry $registry;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ItemHandlerRegistry $registry
|
||||||
|
) {
|
||||||
|
$this->registry = $registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getByUniqueIdentifier(string $uniqueIdentifier): ?Item
|
||||||
|
{
|
||||||
|
[$type, $identifier] = explode('-', $uniqueIdentifier, 2);
|
||||||
|
|
||||||
|
if ($this->registry->exists($type)) {
|
||||||
|
return $this->registry->get($type)->return($identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \Exception(
|
||||||
|
sprintf(
|
||||||
|
'No item handler for type "%s", only supported: %s.',
|
||||||
|
$type,
|
||||||
|
implode(', ', $this->registry->getSupportedTypes()),
|
||||||
|
),
|
||||||
|
1664186139
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
57
Classes/Domain/Repository/WatchlistRepository.php
Normal file
57
Classes/Domain/Repository/WatchlistRepository.php
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Domain\Repository;
|
||||||
|
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Watchlist;
|
||||||
|
use WerkraumMedia\Watchlist\Session\SessionServiceInterface;
|
||||||
|
|
||||||
|
class WatchlistRepository
|
||||||
|
{
|
||||||
|
private SessionServiceInterface $sessionService;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
SessionServiceInterface $sessionService
|
||||||
|
) {
|
||||||
|
$this->sessionService = $sessionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getByIdentifier(string $identifier): ?Watchlist
|
||||||
|
{
|
||||||
|
$watchlist = $this->sessionService->getWatchlist($identifier);
|
||||||
|
if ($watchlist instanceof Watchlist) {
|
||||||
|
return $watchlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($identifier === 'default') {
|
||||||
|
return new Watchlist();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Watchlist $watchlist): void
|
||||||
|
{
|
||||||
|
$this->sessionService->update($watchlist);
|
||||||
|
}
|
||||||
|
}
|
59
Classes/Extbase/TypeConverter/ItemTypeConverter.php
Normal file
59
Classes/Extbase/TypeConverter/ItemTypeConverter.php
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Extbase\TypeConverter;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
|
||||||
|
use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Repository\ItemRepository;
|
||||||
|
|
||||||
|
class ItemTypeConverter extends AbstractTypeConverter
|
||||||
|
{
|
||||||
|
protected $sourceTypes = ['string'];
|
||||||
|
|
||||||
|
protected $targetType = Item::class;
|
||||||
|
|
||||||
|
protected $priority = 10;
|
||||||
|
|
||||||
|
private ItemRepository $itemRepository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
ItemRepository $itemRepository
|
||||||
|
) {
|
||||||
|
$this->itemRepository = $itemRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertFrom(
|
||||||
|
$source,
|
||||||
|
string $targetType,
|
||||||
|
array $convertedChildProperties = [],
|
||||||
|
PropertyMappingConfigurationInterface $configuration = null
|
||||||
|
): ?Item {
|
||||||
|
if (is_string($source) === false) {
|
||||||
|
throw new \InvalidArgumentException('Source was not of expected type string.', 1664197305);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->itemRepository->getByUniqueIdentifier($source);
|
||||||
|
}
|
||||||
|
}
|
58
Classes/Extbase/TypeConverter/WatchlistTypeConverter.php
Normal file
58
Classes/Extbase/TypeConverter/WatchlistTypeConverter.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Extbase\TypeConverter;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface;
|
||||||
|
use TYPO3\CMS\Extbase\Property\TypeConverter\AbstractTypeConverter;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Watchlist;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Repository\WatchlistRepository;
|
||||||
|
|
||||||
|
class WatchlistTypeConverter extends AbstractTypeConverter
|
||||||
|
{
|
||||||
|
protected $sourceTypes = ['string'];
|
||||||
|
|
||||||
|
protected $targetType = Watchlist::class;
|
||||||
|
|
||||||
|
protected $priority = 10;
|
||||||
|
|
||||||
|
private WatchlistRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
WatchlistRepository $repository
|
||||||
|
) {
|
||||||
|
$this->repository = $repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertFrom(
|
||||||
|
$source,
|
||||||
|
string $targetType,
|
||||||
|
array $convertedChildProperties = [],
|
||||||
|
PropertyMappingConfigurationInterface $configuration = null
|
||||||
|
): ?Watchlist {
|
||||||
|
if (is_string($source) === false) {
|
||||||
|
throw new \InvalidArgumentException('Source was not of expected type string.', 1664197358);
|
||||||
|
}
|
||||||
|
return $this->repository->getByIdentifier($source);
|
||||||
|
}
|
||||||
|
}
|
33
Classes/Session/SessionServiceInterface.php
Normal file
33
Classes/Session/SessionServiceInterface.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Session;
|
||||||
|
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Watchlist;
|
||||||
|
|
||||||
|
interface SessionServiceInterface
|
||||||
|
{
|
||||||
|
public function getWatchlist(string $identifier): ?Watchlist;
|
||||||
|
|
||||||
|
public function update(Watchlist $watchlist): void;
|
||||||
|
}
|
73
Classes/Session/Typo3FrontendSessionService.php
Normal file
73
Classes/Session/Typo3FrontendSessionService.php
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Session;
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Property\PropertyMapper;
|
||||||
|
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Item;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Watchlist;
|
||||||
|
|
||||||
|
class Typo3FrontendSessionService implements SessionServiceInterface
|
||||||
|
{
|
||||||
|
private PropertyMapper $propertyMapper;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
PropertyMapper $propertyMapper
|
||||||
|
) {
|
||||||
|
$this->propertyMapper = $propertyMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWatchlist(string $identifier): ?Watchlist
|
||||||
|
{
|
||||||
|
$items = $this->getTsfe()->fe_user->getSessionData('watchlist-' . $identifier) ?: [];
|
||||||
|
if ($items === [] || is_array($items) === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$watchlist = new Watchlist();
|
||||||
|
|
||||||
|
array_map(function (string $item) use ($watchlist) {
|
||||||
|
$mappedItem = $this->propertyMapper->convert($item, Item::class);
|
||||||
|
if (!$mappedItem instanceof Item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$watchlist->addItem($mappedItem);
|
||||||
|
}, $items);
|
||||||
|
|
||||||
|
return $watchlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Watchlist $watchlist): void
|
||||||
|
{
|
||||||
|
$this->getTsfe()->fe_user->setAndSaveSessionData(
|
||||||
|
'watchlist-' . $watchlist->getIdentifier(),
|
||||||
|
array_map(fn (Item $item) => $item->getUniqueIdentifier(), $watchlist->getItems())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private function getTsfe(): TypoScriptFrontendController
|
||||||
|
{
|
||||||
|
return $GLOBALS['TSFE'];
|
||||||
|
}
|
||||||
|
}
|
49
Configuration/Services.php
Normal file
49
Configuration/Services.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\ItemHandlerRegistry;
|
||||||
|
|
||||||
|
return function (ContainerConfigurator $container, ContainerBuilder $containerBuilder) {
|
||||||
|
$containerBuilder->addCompilerPass(new class() implements CompilerPassInterface {
|
||||||
|
public function process(ContainerBuilder $container): void
|
||||||
|
{
|
||||||
|
$registry = $container->getDefinition(ItemHandlerRegistry::class)
|
||||||
|
->setShared(true);
|
||||||
|
|
||||||
|
foreach (array_keys($container->findTaggedServiceIds('watchlist.itemHandler')) as $id) {
|
||||||
|
$definition = $container->getDefinition($id);
|
||||||
|
|
||||||
|
if (!$definition->isAutoconfigured() || $definition->isAbstract()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$registry->addMethodCall('add', [$definition]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
13
Configuration/Services.yaml
Normal file
13
Configuration/Services.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
public: false
|
||||||
|
|
||||||
|
WerkraumMedia\Watchlist\:
|
||||||
|
resource: '../Classes/*'
|
||||||
|
exclude:
|
||||||
|
- '../Classes/Domain/Model/*'
|
||||||
|
|
||||||
|
WerkraumMedia\Watchlist\Domain\Items\Page\ItemHandler:
|
||||||
|
tags: ['watchlist.itemHandler']
|
14
Configuration/TCA/Overrides/tt_content.php
Normal file
14
Configuration/TCA/Overrides/tt_content.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
|
||||||
|
|
||||||
|
defined('TYPO3') || die();
|
||||||
|
|
||||||
|
ExtensionUtility::registerPlugin(
|
||||||
|
'Watchlist',
|
||||||
|
'Watchlist',
|
||||||
|
'LLL:EXT:watchlist/Resources/Private/Language/locallang.xlf:plugin.watchlist',
|
||||||
|
'EXT:watchlist/Resources/Public/Icons/Extension.svg'
|
||||||
|
);
|
||||||
|
|
||||||
|
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist']['watchlist_watchlist'] = 'recursive,select_key,pages';
|
|
@ -1,3 +0,0 @@
|
||||||
# watchlist
|
|
||||||
|
|
||||||
TYPO3 watchlist extension
|
|
53
README.rst
Normal file
53
README.rst
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
=========================
|
||||||
|
TYPO3 Extension Watchlist
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Adds the feature of a watchlist to the frontend of TYPO3 CMS.
|
||||||
|
|
||||||
|
Users are able to add "items" to the watchlist.
|
||||||
|
They are also able to remove things from watchlist and show the current watchlist.
|
||||||
|
|
||||||
|
Items can be anything. The extension uses interfaces and developers are able to
|
||||||
|
connect whatever they want to be a thing that can be added to the watchlist.
|
||||||
|
|
||||||
|
Feature set
|
||||||
|
===========
|
||||||
|
|
||||||
|
The extension provides an controller with actions to add and remove items from watchlist.
|
||||||
|
|
||||||
|
There is also an action to show the current watchlist.
|
||||||
|
|
||||||
|
The extension ships with support for items of type ``pages``,
|
||||||
|
but this is more a demonstration an used for testing.
|
||||||
|
Projects are way too different and should provide their own items, see "Custom Items".
|
||||||
|
|
||||||
|
Custom Items
|
||||||
|
============
|
||||||
|
|
||||||
|
A developer needs to implement an ``ItemHandler`` and an class representing the ``Item``.
|
||||||
|
|
||||||
|
``ItemHandler``
|
||||||
|
---------------
|
||||||
|
|
||||||
|
The class needs to implement the ``WerkraumMedia\Watchlist\Domain\ItemHandlerInterface``.
|
||||||
|
The purpose is to convert an identifier of that item to an actual instance of that item.
|
||||||
|
The Handler needs to be registered via Symfony Tags, e.g. via ``Services.yaml``:
|
||||||
|
|
||||||
|
.. code:: yam;
|
||||||
|
|
||||||
|
services:
|
||||||
|
_defaults:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
public: false
|
||||||
|
|
||||||
|
WerkraumMedia\Watchlist\:
|
||||||
|
resource: '../Classes/*'
|
||||||
|
|
||||||
|
WerkraumMedia\Watchlist\Domain\Items\Page\ItemHandler:
|
||||||
|
tags: ['watchlist.itemHandler']
|
||||||
|
|
||||||
|
``Item``
|
||||||
|
--------
|
||||||
|
|
||||||
|
The class needs to implement the ``WerkraumMedia\Watchlist\Domain\Model\Item``.
|
14
Resources/Private/Language/locallang.xlf
Normal file
14
Resources/Private/Language/locallang.xlf
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<file source-language="en" datatype="plaintext" original="messages" date="2022-09-26T10:43:30Z" product-name="Watchlist">
|
||||||
|
<header/>
|
||||||
|
<body>
|
||||||
|
<trans-unit id="headline.index" xml:space="preserve">
|
||||||
|
<source>Watchlist</source>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="text.watchlist.isEmpty" xml:space="preserve">
|
||||||
|
<source>Watchlist is empty</source>
|
||||||
|
</trans-unit>
|
||||||
|
</body>
|
||||||
|
</file>
|
||||||
|
</xliff>
|
18
Resources/Private/Templates/Watchlist/Index.html
Normal file
18
Resources/Private/Templates/Watchlist/Index.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
|
||||||
|
data-namespace-typo3-fluid="true">
|
||||||
|
|
||||||
|
<h2>{f:translate(id: 'headline.index', extensionName: 'Watchlist')}</h2>
|
||||||
|
|
||||||
|
<f:if condition="{watchlist.empty}">
|
||||||
|
<f:then>
|
||||||
|
<p>{f:translate(id: 'text.watchlist.isEmpty', extensionName: 'Watchlist')}
|
||||||
|
</f:then>
|
||||||
|
<f:else>
|
||||||
|
<ol>
|
||||||
|
<f:for each="{watchlist.items}" as="item">
|
||||||
|
<li>{item.title}</li>
|
||||||
|
</f:for>
|
||||||
|
</ol>
|
||||||
|
</f:else>
|
||||||
|
</f:if>
|
||||||
|
</html>
|
144
Tests/Functional/Frontend/BasicsTest.php
Normal file
144
Tests/Functional/Frontend/BasicsTest.php
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Tests\Functional\Frontend;
|
||||||
|
|
||||||
|
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
|
||||||
|
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalResponse;
|
||||||
|
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \WerkraumMedia\Watchlist\Frontend\Basics
|
||||||
|
*/
|
||||||
|
class BasicsTest extends FunctionalTestCase
|
||||||
|
{
|
||||||
|
protected $coreExtensionsToLoad = [
|
||||||
|
'fluid_styled_content',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $testExtensionsToLoad = [
|
||||||
|
'typo3conf/ext/watchlist',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $pathsToProvideInTestInstance = [
|
||||||
|
'typo3conf/ext/watchlist/Tests/Functional/Frontend/Fixtures/Sites/' => 'typo3conf/sites/',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->setUpBackendUserFromFixture(1);
|
||||||
|
|
||||||
|
$this->importCSVDataSet(__DIR__ . '/Fixtures/BasicDatabase.csv');
|
||||||
|
$this->setUpFrontendRootPage(1, [
|
||||||
|
'EXT:watchlist/Tests/Functional/Frontend/Fixtures/FrontendRendering.typoscript',
|
||||||
|
'EXT:fluid_styled_content/Configuration/TypoScript/setup.typoscript',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function watchlistIsRenderedAsEmptyByDefault(): void
|
||||||
|
{
|
||||||
|
$request = new InternalRequest();
|
||||||
|
$request = $request->withPageId(1);
|
||||||
|
$result = $this->executeFrontendRequest($request);
|
||||||
|
|
||||||
|
self::assertSame(200, $result->getStatusCode());
|
||||||
|
self::assertStringContainsString('Watchlist is empty', $result->getBody()->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function canStorePagesOnWatchlistAccrossPageCalls(): void
|
||||||
|
{
|
||||||
|
$request = new InternalRequest();
|
||||||
|
$request = $request->withPageId(1);
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[redirectUri]', $request->getUri()->__toString());
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[action]', 'add');
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[item]', 'page-1');
|
||||||
|
$result = $this->executeFrontendRequest($request);
|
||||||
|
|
||||||
|
self::assertIsRedirect('http://localhost/?id=1', $result);
|
||||||
|
self::assertHasCookie('fe_typo_user', $result);
|
||||||
|
|
||||||
|
$request = new InternalRequest();
|
||||||
|
$request = $request->withPageId(1);
|
||||||
|
$request = $request->withHeader('Cookie', self::getCookies($result));
|
||||||
|
$result = $this->executeFrontendRequest($request);
|
||||||
|
|
||||||
|
self::assertStringContainsString('Page Title', $result->getBody()->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function canRemoveStoredEntryFromWatchlist(): void
|
||||||
|
{
|
||||||
|
$request = new InternalRequest();
|
||||||
|
$request = $request->withPageId(1);
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[redirectUri]', $request->getUri()->__toString());
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[action]', 'add');
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[item]', 'page-1');
|
||||||
|
$result = $this->executeFrontendRequest($request);
|
||||||
|
|
||||||
|
$cookies = self::getCookies($result);
|
||||||
|
|
||||||
|
$request = new InternalRequest();
|
||||||
|
$request = $request->withHeader('Cookie', $cookies);
|
||||||
|
$request = $request->withPageId(1);
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[redirectUri]', $request->getUri()->__toString());
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[action]', 'remove');
|
||||||
|
$request = $request->withQueryParameter('tx_watchlist_watchlist[item]', 'page-1');
|
||||||
|
$result = $this->executeFrontendRequest($request);
|
||||||
|
|
||||||
|
self::assertIsRedirect('http://localhost/?id=1', $result);
|
||||||
|
|
||||||
|
$request = new InternalRequest();
|
||||||
|
$request = $request->withHeader('Cookie', $cookies);
|
||||||
|
$request = $request->withPageId(1);
|
||||||
|
$result = $this->executeFrontendRequest($request);
|
||||||
|
|
||||||
|
self::assertSame(200, $result->getStatusCode());
|
||||||
|
self::assertStringContainsString('Watchlist is empty', $result->getBody()->__toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function assertIsRedirect(string $redirectLocation, InternalResponse $result): void
|
||||||
|
{
|
||||||
|
self::assertSame(303, $result->getStatusCode());
|
||||||
|
self::assertSame($redirectLocation, $result->getHeader('location')[0] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function assertHasCookie(string $cookieName, InternalResponse $result): void
|
||||||
|
{
|
||||||
|
self::assertStringContainsString($cookieName . '=', self::getCookies($result));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getCookies(InternalResponse $result): string
|
||||||
|
{
|
||||||
|
return explode(' ', $result->getHeader('Set-Cookie')[0] ?? '', 2)[0] ?? '';
|
||||||
|
}
|
||||||
|
}
|
3
Tests/Functional/Frontend/Fixtures/BasicDatabase.csv
Normal file
3
Tests/Functional/Frontend/Fixtures/BasicDatabase.csv
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pages
|
||||||
|
,uid,pid,slug,title
|
||||||
|
,1,0,/,Page Title
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
page = PAGE
|
||||||
|
page.10 =< tt_content.watchlist_watchlist.20
|
32
Tests/Functional/Frontend/Fixtures/Sites/default/config.yaml
Normal file
32
Tests/Functional/Frontend/Fixtures/Sites/default/config.yaml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
base: /
|
||||||
|
languages:
|
||||||
|
-
|
||||||
|
title: Deutsch
|
||||||
|
enabled: true
|
||||||
|
base: /
|
||||||
|
typo3Language: de
|
||||||
|
locale: de_DE.UTF-8
|
||||||
|
iso-639-1: de
|
||||||
|
navigationTitle: Deutsch
|
||||||
|
hreflang: de-DE
|
||||||
|
direction: ''
|
||||||
|
flag: de
|
||||||
|
websiteTitle: ''
|
||||||
|
languageId: 0
|
||||||
|
-
|
||||||
|
title: English
|
||||||
|
enabled: true
|
||||||
|
base: /en
|
||||||
|
typo3Language: default
|
||||||
|
locale: en_GB.UTF-8
|
||||||
|
iso-639-1: en
|
||||||
|
websiteTitle: ''
|
||||||
|
navigationTitle: English
|
||||||
|
hreflang: en-GB
|
||||||
|
direction: ''
|
||||||
|
flag: gb
|
||||||
|
languageId: 1
|
||||||
|
fallbackType: strict
|
||||||
|
fallbacks: '0'
|
||||||
|
rootPageId: 1
|
||||||
|
websiteTitle: 'Example Website'
|
87
Tests/Unit/Domain/Model/WatchlistTest.php
Normal file
87
Tests/Unit/Domain/Model/WatchlistTest.php
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WerkraumMedia\Watchlist\Tests\Unit\Domain\Model;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Items\Page\Page;
|
||||||
|
use WerkraumMedia\Watchlist\Domain\Model\Watchlist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \WerkraumMedia\Watchlist\Domain\Model\Watchlist
|
||||||
|
* @testdox The Watchlist
|
||||||
|
*/
|
||||||
|
class WatchlistTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function canBeCreated(): void
|
||||||
|
{
|
||||||
|
$subject = new Watchlist();
|
||||||
|
|
||||||
|
self::assertInstanceOf(
|
||||||
|
Watchlist::class,
|
||||||
|
$subject
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function doesNotHaveItemsByDefault(): void
|
||||||
|
{
|
||||||
|
$subject = new Watchlist();
|
||||||
|
|
||||||
|
self::assertCount(0, $subject->getItems());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function canAddAItem(): void
|
||||||
|
{
|
||||||
|
$subject = new Watchlist();
|
||||||
|
|
||||||
|
$thing = new Page(1, 'test');
|
||||||
|
$subject->addItem($thing);
|
||||||
|
|
||||||
|
self::assertCount(1, $subject->getItems());
|
||||||
|
self::assertSame($thing, $subject->getItems()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function canRemoveAItem(): void
|
||||||
|
{
|
||||||
|
$subject = new Watchlist();
|
||||||
|
|
||||||
|
$thing = new Page(1, 'test');
|
||||||
|
$subject->addItem($thing);
|
||||||
|
|
||||||
|
$subject->removeItem($thing);
|
||||||
|
|
||||||
|
self::assertCount(0, $subject->getItems());
|
||||||
|
}
|
||||||
|
}
|
80
composer.json
Normal file
80
composer.json
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
{
|
||||||
|
"name": "werkraummedia/watchlist",
|
||||||
|
"description": "Add a watchlist to frontend of TYPO3",
|
||||||
|
"type": "typo3-cms-extension",
|
||||||
|
"license": "GPL-2.0-or-later",
|
||||||
|
"homepage": "https://github.com/werkraum-media/watchlist",
|
||||||
|
"support": {
|
||||||
|
"docs": "https://docs.typo3.org/p/werkraummedia/watchlist/master/en-us/",
|
||||||
|
"email": "coding@daniel-siepmann.de",
|
||||||
|
"issues": "https://github.com/werkraum-media/watchlist/issues",
|
||||||
|
"source": "https://github.com/werkraum-media/watchlist"
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Daniel Siepmann",
|
||||||
|
"email": "coding@daniel-siepmann.de",
|
||||||
|
"homepage": "https://daniel-siepmann.de/",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"WerkraumMedia\\Watchlist\\": "Classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"WerkraumMedia\\Watchlist\\Tests\\": "Tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~7.4.0 || ~8.0.0 || ~8.1.0",
|
||||||
|
"typo3/cms-backend": "^11.5",
|
||||||
|
"typo3/cms-core": "^11.5",
|
||||||
|
"typo3/cms-extbase": "^11.5",
|
||||||
|
"typo3/cms-frontend": "^11.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"cweagans/composer-patches": "^1.7",
|
||||||
|
"friendsofphp/php-cs-fixer": "^3.11",
|
||||||
|
"phpstan/extension-installer": "^1.1",
|
||||||
|
"phpstan/phpstan": "1.1.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0",
|
||||||
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"saschaegerer/phpstan-typo3": "^1.1",
|
||||||
|
"typo3/cms-fluid-styled-content": "^11.5",
|
||||||
|
"typo3/cms-tstemplate": "^11.5",
|
||||||
|
"typo3/testing-framework": "^6.6"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"sort-packages": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"typo3/cms-composer-installers": true,
|
||||||
|
"typo3/class-alias-loader": true,
|
||||||
|
"ocramius/package-versions": true,
|
||||||
|
"phpstan/extension-installer": true,
|
||||||
|
"cweagans/composer-patches": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"typo3/cms": {
|
||||||
|
"cms-package-dir": "{$vendor-dir}/typo3/cms",
|
||||||
|
"extension-key": "watchlist",
|
||||||
|
"web-dir": "public"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"post-autoload-dump": [
|
||||||
|
"@php -r 'is_dir($extFolder=__DIR__.\"/public/typo3conf/ext/\") || mkdir($extFolder, 0777, true);'",
|
||||||
|
"@php -r 'file_exists($extFolder=__DIR__.\"/public/typo3conf/ext/watchlist\") || symlink(__DIR__,$extFolder);'"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"patches": {
|
||||||
|
"typo3/testing-framework": {
|
||||||
|
"Support cookies in request": "patches/testing-framework-cookies.patch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
ext_localconf.php
Normal file
25
ext_localconf.php
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
|
||||||
|
use WerkraumMedia\Watchlist\Controller\WatchlistController;
|
||||||
|
use WerkraumMedia\Watchlist\Extbase\TypeConverter\ItemTypeConverter;
|
||||||
|
use WerkraumMedia\Watchlist\Extbase\TypeConverter\WatchlistTypeConverter;
|
||||||
|
|
||||||
|
defined('TYPO3') || die('Access denied.');
|
||||||
|
|
||||||
|
(static function (): void {
|
||||||
|
ExtensionUtility::configurePlugin(
|
||||||
|
'Watchlist',
|
||||||
|
'Watchlist',
|
||||||
|
[
|
||||||
|
WatchlistController::class => 'index, add, remove',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
WatchlistController::class => 'index',
|
||||||
|
],
|
||||||
|
ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
ExtensionUtility::registerTypeConverter(WatchlistTypeConverter::class);
|
||||||
|
ExtensionUtility::registerTypeConverter(ItemTypeConverter::class);
|
||||||
|
})();
|
17
patches/testing-framework-cookies.patch
Normal file
17
patches/testing-framework-cookies.patch
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
diff --git a/Classes/Core/Functional/Framework/Frontend/RequestBootstrap.php b/Classes/Core/Functional/Framework/Frontend/RequestBootstrap.php
|
||||||
|
index f8b2a40..4f4020d 100644
|
||||||
|
--- a/Classes/Core/Functional/Framework/Frontend/RequestBootstrap.php
|
||||||
|
+++ b/Classes/Core/Functional/Framework/Frontend/RequestBootstrap.php
|
||||||
|
@@ -106,6 +106,12 @@ class RequestBootstrap
|
||||||
|
}
|
||||||
|
// Populating $_COOKIE
|
||||||
|
$_COOKIE = [];
|
||||||
|
+ if ($this->request->hasHeader('Cookie')) {
|
||||||
|
+ foreach ($this->request->getHeader('Cookie') as $cookie) {
|
||||||
|
+ [$cookieName, $cookieValue] = explode('=', $cookie, 2);
|
||||||
|
+ $_COOKIE[$cookieName] = rtrim($cookieValue, ';');
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
|
||||||
|
// Setting up the server environment
|
||||||
|
$_SERVER = [];
|
12
phpstan.neon
Normal file
12
phpstan.neon
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
parameters:
|
||||||
|
level: max
|
||||||
|
paths:
|
||||||
|
- Classes
|
||||||
|
- Configuration
|
||||||
|
- Tests
|
||||||
|
checkMissingIterableValueType: false
|
||||||
|
reportUnmatchedIgnoredErrors: true
|
||||||
|
checkGenericClassInNonGenericObjectType: false
|
||||||
|
ignoreErrors:
|
||||||
|
- "#^Cannot call method fetchAssociative\\(\\) on Doctrine\\\\DBAL\\\\Result\\|int\\.$#"
|
||||||
|
- "#^Right side of \\|\\| is always false\\.$#"
|
38
phpunit.xml.dist
Normal file
38
phpunit.xml.dist
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
|
||||||
|
backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
beStrictAboutCoversAnnotation="true"
|
||||||
|
bootstrap="vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTestsBootstrap.php"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
forceCoversAnnotation="true"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnError="false"
|
||||||
|
stopOnFailure="false"
|
||||||
|
stopOnIncomplete="false"
|
||||||
|
stopOnSkipped="false"
|
||||||
|
verbose="false"
|
||||||
|
>
|
||||||
|
|
||||||
|
<coverage processUncoveredFiles="true">
|
||||||
|
<include>
|
||||||
|
<directory suffix=".php">Classes</directory>
|
||||||
|
</include>
|
||||||
|
</coverage>
|
||||||
|
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="unit">
|
||||||
|
<directory>Tests/Unit/</directory>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="functional">
|
||||||
|
<directory>Tests/Functional/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<php>
|
||||||
|
<env name="typo3DatabaseDriver" value="pdo_sqlite"/>
|
||||||
|
</php>
|
||||||
|
</phpunit>
|
Loading…
Reference in a new issue