From 456c86b49273c6b1d76f5dcd5559a1e34c6e87ae Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Thu, 25 Nov 2021 14:40:00 +0100 Subject: [PATCH] Update PHPStan PHPStan was released with first stable public version 1.x. The version is updated together with extensions. The new version finds new issues which are solved right away to not break CI. --- .../Dashboard/Provider/NewestPageviews.php | 4 ++ .../Provider/PageviewsPerOperatingSystem.php | 4 ++ .../Dashboard/Provider/PageviewsPerPage.php | 8 +++ Classes/Dashboard/Provider/Recordviews.php | 21 ++++--- Classes/Domain/Model/RecordRule.php | 17 +----- Classes/Domain/Pageview/Factory.php | 26 +++++++-- Classes/Domain/Recordview/Factory.php | 37 +++++++++++-- Classes/Domain/Repository/Pageview.php | 12 +++- .../Dashboard/Provider/RecordviewsTest.php | 55 +++---------------- Tests/Functional/Typo3FeaturesTest.php | 28 +++++++--- Tests/Unit/Domain/Model/RecordRuleTest.php | 4 -- Tests/Unit/Domain/Recordview/FactoryTest.php | 14 ++--- composer.json | 8 +-- 13 files changed, 134 insertions(+), 104 deletions(-) diff --git a/Classes/Dashboard/Provider/NewestPageviews.php b/Classes/Dashboard/Provider/NewestPageviews.php index 30d3821..9c8ad5f 100644 --- a/Classes/Dashboard/Provider/NewestPageviews.php +++ b/Classes/Dashboard/Provider/NewestPageviews.php @@ -97,6 +97,10 @@ class NewestPageviews implements ListDataProviderInterface $items = $this->queryBuilder->execute()->fetchAll(); foreach ($items as $item) { + if (is_array($item) === false) { + continue; + } + $preparedItems[] = sprintf( '%s - %s', $item['url'], diff --git a/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php b/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php index 9c6c6d6..91bb5f6 100644 --- a/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php +++ b/Classes/Dashboard/Provider/PageviewsPerOperatingSystem.php @@ -114,6 +114,10 @@ class PageviewsPerOperatingSystem implements ChartDataProviderInterface ->fetchAll(); foreach ($result as $row) { + if (is_array($row) === false) { + continue; + } + $labels[] = mb_strimwidth($row['operating_system'], 0, 50, '…'); $data[] = $row['total']; } diff --git a/Classes/Dashboard/Provider/PageviewsPerPage.php b/Classes/Dashboard/Provider/PageviewsPerPage.php index aa8377d..9ac47bc 100644 --- a/Classes/Dashboard/Provider/PageviewsPerPage.php +++ b/Classes/Dashboard/Provider/PageviewsPerPage.php @@ -140,6 +140,10 @@ class PageviewsPerPage implements ChartDataProviderInterface ->fetchAll(); foreach ($result as $row) { + if (is_array($row) === false) { + continue; + } + $labels[] = $this->getRecordTitle($row['pid']); $data[] = $row['total']; } @@ -157,6 +161,10 @@ class PageviewsPerPage implements ChartDataProviderInterface $record = $this->pageRepository->getRecordOverlay('pages', $record, $this->languageLimitation[0]); } + if (is_array($record) === false) { + return 'Unkown'; + } + return strip_tags(BackendUtility::getRecordTitle('pages', $record, true)); } } diff --git a/Classes/Dashboard/Provider/Recordviews.php b/Classes/Dashboard/Provider/Recordviews.php index 92af663..9aed165 100644 --- a/Classes/Dashboard/Provider/Recordviews.php +++ b/Classes/Dashboard/Provider/Recordviews.php @@ -26,7 +26,6 @@ use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Statement; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\Connection; -use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\QueryBuilder; use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction; use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction; @@ -37,11 +36,6 @@ use TYPO3\CMS\Dashboard\Widgets\ChartDataProviderInterface; class Recordviews implements ChartDataProviderInterface { - /** - * @var ConnectionPool - */ - private $connectionPool; - /** * @var PageRepository */ @@ -83,7 +77,6 @@ class Recordviews implements ChartDataProviderInterface private $recordTypeLimitation; public function __construct( - ConnectionPool $connectionPool, PageRepository $pageRepository, QueryBuilder $queryBuilder, int $days = 31, @@ -93,7 +86,6 @@ class Recordviews implements ChartDataProviderInterface array $recordTableLimitation = [], array $recordTypeLimitation = [] ) { - $this->connectionPool = $connectionPool; $this->pageRepository = $pageRepository; $this->queryBuilder = $queryBuilder; $this->days = $days; @@ -131,8 +123,11 @@ class Recordviews implements ChartDataProviderInterface ); if ( - $this->recordTypeLimitation !== [] - && in_array($record['type'], $this->recordTypeLimitation) === false + $record === null + || ( + $this->recordTypeLimitation !== [] + && in_array($record['type'], $this->recordTypeLimitation) === false + ) ) { continue; } @@ -208,7 +203,7 @@ class Recordviews implements ChartDataProviderInterface private function getRecord( int $uid, string $table - ): array { + ): ?array { $recordTypeField = $GLOBALS['TCA'][$table]['ctrl']['type'] ?? ''; $record = BackendUtility::getRecord($table, $uid); @@ -216,6 +211,10 @@ class Recordviews implements ChartDataProviderInterface $record = $this->pageRepository->getRecordOverlay($table, $record, $this->languageLimitation[0]); } + if (is_array($record) === false) { + return null; + } + return [ 'title' => strip_tags(BackendUtility::getRecordTitle($table, $record, true)), 'type' => $record[$recordTypeField] ?? '', diff --git a/Classes/Domain/Model/RecordRule.php b/Classes/Domain/Model/RecordRule.php index ee05b77..32ebf69 100644 --- a/Classes/Domain/Model/RecordRule.php +++ b/Classes/Domain/Model/RecordRule.php @@ -23,11 +23,6 @@ namespace DanielSiepmann\Tracking\Domain\Model; class RecordRule { - /** - * @var string - */ - private $identifier; - /** * @var string */ @@ -44,12 +39,10 @@ class RecordRule private $tableName; public function __construct( - string $identifier, string $matches, string $recordUid, string $tableName ) { - $this->identifier = $identifier; $this->matches = $matches; $this->recordUid = $recordUid; $this->tableName = $tableName; @@ -58,7 +51,6 @@ class RecordRule public static function fromArray(array $config): self { return new RecordRule( - $config['identifier'], $config['matches'], $config['recordUid'], $config['tableName'] @@ -68,13 +60,8 @@ class RecordRule public static function multipleFromArray(array $configs): array { $rules = []; - foreach ($configs as $identifier => $config) { - $rules[] = static::fromArray(array_merge( - [ - 'identifier' => $identifier, - ], - $config - )); + foreach ($configs as $config) { + $rules[] = static::fromArray($config); } return $rules; } diff --git a/Classes/Domain/Pageview/Factory.php b/Classes/Domain/Pageview/Factory.php index 10726eb..b8687ce 100644 --- a/Classes/Domain/Pageview/Factory.php +++ b/Classes/Domain/Pageview/Factory.php @@ -24,6 +24,7 @@ namespace DanielSiepmann\Tracking\Domain\Pageview; use DanielSiepmann\Tracking\Domain\Model\Pageview; use Psr\Http\Message\ServerRequestInterface; use TYPO3\CMS\Core\Routing\PageArguments; +use TYPO3\CMS\Core\Site\Entity\SiteLanguage; use TYPO3\CMS\Core\Site\SiteFinder; class Factory @@ -41,10 +42,10 @@ class Factory public static function fromRequest(ServerRequestInterface $request): Pageview { return new Pageview( - static::getRouting($request)->getPageId(), - $request->getAttribute('language'), + self::getRouting($request)->getPageId(), + self::getLanguage($request), new \DateTimeImmutable(), - (int) static::getRouting($request)->getPageType(), + (int) self::getRouting($request)->getPageType(), (string) $request->getUri(), $request->getHeader('User-Agent')[0] ?? '' ); @@ -63,8 +64,25 @@ class Factory ); } + private static function getLanguage(ServerRequestInterface $request): SiteLanguage + { + $language = $request->getAttribute('language'); + + if (!$language instanceof SiteLanguage) { + throw new \UnexpectedValueException('Could not fetch SiteLanguage from request attributes.', 1637847002); + } + + return $language; + } + private static function getRouting(ServerRequestInterface $request): PageArguments { - return $request->getAttribute('routing'); + $routing = $request->getAttribute('routing'); + + if (!$routing instanceof PageArguments) { + throw new \UnexpectedValueException('Could not fetch PageArguments from request attributes.', 1637847002); + } + + return $routing; } } diff --git a/Classes/Domain/Recordview/Factory.php b/Classes/Domain/Recordview/Factory.php index 32c68eb..f4761b5 100644 --- a/Classes/Domain/Recordview/Factory.php +++ b/Classes/Domain/Recordview/Factory.php @@ -26,6 +26,7 @@ use DanielSiepmann\Tracking\Domain\Model\Recordview; use Psr\Http\Message\ServerRequestInterface; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use TYPO3\CMS\Core\Routing\PageArguments; +use TYPO3\CMS\Core\Site\Entity\SiteLanguage; class Factory { @@ -39,19 +40,47 @@ class Factory ['request' => $request] ); + if (is_numeric($recordUid) === false) { + throw new \UnexpectedValueException( + sprintf( + 'Could not determine record uid based on expression: "%1$s", got type "%2$s".', + $rule->getUidExpression(), + gettype($recordUid) + ), + 1637846881 + ); + } + return new Recordview( - static::getRouting($request)->getPageId(), - $request->getAttribute('language'), + self::getRouting($request)->getPageId(), + self::getLanguage($request), new \DateTimeImmutable(), (string) $request->getUri(), $request->getHeader('User-Agent')[0] ?? '', - $recordUid, + (int) $recordUid, $rule->getTableName() ); } + private static function getLanguage(ServerRequestInterface $request): SiteLanguage + { + $language = $request->getAttribute('language'); + + if (!$language instanceof SiteLanguage) { + throw new \UnexpectedValueException('Could not fetch SiteLanguage from request attributes.', 1637847002); + } + + return $language; + } + private static function getRouting(ServerRequestInterface $request): PageArguments { - return $request->getAttribute('routing'); + $routing = $request->getAttribute('routing'); + + if (!$routing instanceof PageArguments) { + throw new \UnexpectedValueException('Could not fetch PageArguments from request attributes.', 1637847002); + } + + return $routing; } } diff --git a/Classes/Domain/Repository/Pageview.php b/Classes/Domain/Repository/Pageview.php index 978fc61..f24df7b 100644 --- a/Classes/Domain/Repository/Pageview.php +++ b/Classes/Domain/Repository/Pageview.php @@ -47,11 +47,17 @@ class Pageview public function countAll(): int { - return $this->connection->createQueryBuilder() + $result = $this->connection->createQueryBuilder() ->count('uid') ->from('tx_tracking_pageview') ->execute() ->fetchColumn(); + + if (is_numeric($result)) { + return (int) $result; + } + + return 0; } public function findAll(): \Generator @@ -60,6 +66,10 @@ class Pageview $pageViews = $queryBuilder->select('*')->from('tx_tracking_pageview')->execute(); while ($pageView = $pageViews->fetch()) { + if (is_array($pageView) === false) { + continue; + } + yield $this->factory->fromDbRow($pageView); } } diff --git a/Tests/Functional/Dashboard/Provider/RecordviewsTest.php b/Tests/Functional/Dashboard/Provider/RecordviewsTest.php index b85777d..79d4dbe 100644 --- a/Tests/Functional/Dashboard/Provider/RecordviewsTest.php +++ b/Tests/Functional/Dashboard/Provider/RecordviewsTest.php @@ -22,7 +22,6 @@ namespace DanielSiepmann\Tracking\Tests\Functional\Dashboard\Provider; */ use DanielSiepmann\Tracking\Dashboard\Provider\Recordviews; -use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Domain\Repository\PageRepository; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase; @@ -52,13 +51,9 @@ class RecordviewsTest extends TestCase ]); } - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview') + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview') ); $result = $subject->getChartData(); @@ -105,13 +100,9 @@ class RecordviewsTest extends TestCase 'record_table_name' => 'sys_category', ]); - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 2 ); @@ -150,13 +141,9 @@ class RecordviewsTest extends TestCase 'record_table_name' => 'sys_category', ]); - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 2 ); @@ -184,13 +171,9 @@ class RecordviewsTest extends TestCase ]); } - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 31, 2 ); @@ -220,13 +203,9 @@ class RecordviewsTest extends TestCase ]); } - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 31, 6, [1, 2, 3, 4, 5] @@ -265,13 +244,9 @@ class RecordviewsTest extends TestCase 'record_table_name' => 'tt_content', ]); - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 31, 6, [], @@ -308,13 +283,9 @@ class RecordviewsTest extends TestCase ]); } - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 31, 6, [], @@ -360,13 +331,9 @@ class RecordviewsTest extends TestCase 'record_table_name' => 'sys_category', ]); - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 31, 6, [], @@ -412,13 +379,9 @@ class RecordviewsTest extends TestCase 'record_table_name' => 'sys_category', ]); - $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class); - /* @var ConnectionPool $connectionPool */ - $subject = new Recordviews( - $connectionPool, GeneralUtility::makeInstance(PageRepository::class), - $connectionPool->getQueryBuilderForTable('tx_tracking_recordview'), + $this->getConnectionPool()->getQueryBuilderForTable('tx_tracking_recordview'), 31, 6, [], diff --git a/Tests/Functional/Typo3FeaturesTest.php b/Tests/Functional/Typo3FeaturesTest.php index ab30ae9..95e5864 100644 --- a/Tests/Functional/Typo3FeaturesTest.php +++ b/Tests/Functional/Typo3FeaturesTest.php @@ -36,16 +36,32 @@ class Typo3FeaturesTest extends TestCase 'typo3conf/ext/tracking', ]; + public function setUp(): void + { + parent::setUp(); + + $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml'); + $this->setUpBackendUserFromFixture(1); + $languageServiceFactory = $this->getContainer()->get(LanguageServiceFactory::class); + if (!$languageServiceFactory instanceof LanguageServiceFactory) { + throw new \UnexpectedValueException('Did not retrieve LanguageServiceFactory.', 1637847250); + } + $GLOBALS['LANG'] = $languageServiceFactory->create('default'); + } + + public function tearDown(): void + { + unset($GLOBALS['LANG']); + + parent::tearDown(); + } + /** * @test * @testdox Copy pages. Tracking records will not be copied. */ public function copyContainingRecords(): void { - $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml'); - $this->setUpBackendUserFromFixture(1); - $GLOBALS['LANG'] = $this->getContainer()->get(LanguageServiceFactory::class)->create('default'); - $dataHandler = new DataHandler(); $dataHandler->start([], [ 'pages' => [ @@ -68,10 +84,6 @@ class Typo3FeaturesTest extends TestCase */ public function copyCustomTablesViaDataHandler(): void { - $this->importDataSet('EXT:tracking/Tests/Functional/Fixtures/Typo3FeaturesTest/PageWithRecords.xml'); - $this->setUpBackendUserFromFixture(1); - $GLOBALS['LANG'] = $this->getContainer()->get(LanguageServiceFactory::class)->create('default'); - $dataHandler = new DataHandler(); $dataHandler->copyWhichTables = 'pages,tx_tracking_pageview,tx_tracking_recordview'; $dataHandler->start([], [ diff --git a/Tests/Unit/Domain/Model/RecordRuleTest.php b/Tests/Unit/Domain/Model/RecordRuleTest.php index c3f01b9..e61a5e3 100644 --- a/Tests/Unit/Domain/Model/RecordRuleTest.php +++ b/Tests/Unit/Domain/Model/RecordRuleTest.php @@ -35,7 +35,6 @@ class RecordRuleTest extends TestCase public function canBeCreatedViaConstructor(): void { $subject = new RecordRule( - '', '', '', '' @@ -88,7 +87,6 @@ class RecordRuleTest extends TestCase public function returnsMatchExpression(): void { $subject = new RecordRule( - '', 'match expression', '', '' @@ -103,7 +101,6 @@ class RecordRuleTest extends TestCase public function returnsUidExpression(): void { $subject = new RecordRule( - '', '', 'match expression', '' @@ -118,7 +115,6 @@ class RecordRuleTest extends TestCase public function returnsTableName(): void { $subject = new RecordRule( - '', '', '', 'table_name' diff --git a/Tests/Unit/Domain/Recordview/FactoryTest.php b/Tests/Unit/Domain/Recordview/FactoryTest.php index 973ce63..50efccb 100644 --- a/Tests/Unit/Domain/Recordview/FactoryTest.php +++ b/Tests/Unit/Domain/Recordview/FactoryTest.php @@ -43,7 +43,7 @@ class FactoryTest extends TestCase public function returnsRecordviewFromRequest(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); @@ -70,7 +70,7 @@ class FactoryTest extends TestCase public function returnedRecordviewContainsUserAgent(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); @@ -97,7 +97,7 @@ class FactoryTest extends TestCase public function returnedRecordviewContainsUri(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); @@ -124,7 +124,7 @@ class FactoryTest extends TestCase public function returnedRecordviewContainsDateTime(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); @@ -151,7 +151,7 @@ class FactoryTest extends TestCase public function returnedRecordviewContainsLanguage(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); @@ -178,7 +178,7 @@ class FactoryTest extends TestCase public function returnedRecordviewContainsPageId(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); @@ -232,7 +232,7 @@ class FactoryTest extends TestCase public function returnedRecordviewContainsTableName(): void { $rule = $this->prophesize(RecordRule::class); - $rule->getUidExpression()->willReturn('request.getQueryParams()["category"] > 0'); + $rule->getUidExpression()->willReturn('request.getQueryParams()["category"]'); $rule->getTableName()->willReturn('sys_category'); $routing = $this->prophesize(PageArguments::class); diff --git a/composer.json b/composer.json index a0fa003..9910d27 100644 --- a/composer.json +++ b/composer.json @@ -40,12 +40,12 @@ }, "require-dev": { "phpunit/phpunit": "^9.0", - "phpstan/phpstan": "^0.12.18", - "phpstan/extension-installer": "^1.0", - "jangregor/phpstan-prophecy": "^0.8.1", + "phpstan/phpstan": "^1.2", + "phpstan/extension-installer": "^1.1", + "jangregor/phpstan-prophecy": "^1.0", "phpspec/prophecy-phpunit": "^2.0", "typo3/testing-framework": "^6.14", - "saschaegerer/phpstan-typo3": "^0.13.1", + "saschaegerer/phpstan-typo3": "^1.0", "symplify/easy-coding-standard": "^9.3", "cweagans/composer-patches": "^1.7" },