Update to current state and PHP 8.1

This commit is contained in:
Florian Brinker 2022-05-25 12:10:23 +02:00
parent cece9d0d02
commit ec94f51be0
18 changed files with 836 additions and 360 deletions

8
.gitignore vendored
View File

@ -1,4 +1,8 @@
/build/
/coverage/
/tmp/ /tmp/
/vendor/ /vendor/
*.phar
cs-check.json /*.cache
/*.phar
/cs-check.json

24
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,24 @@
# Contributing
## Code Analysis
To check the code quality, run
```php
composer check
```
To fix any style issues, run
```php
composer fix
```
## Tests
To run the test suite, execute
```php
composer test
```
## Build
[Box](https://github.com/box-project/box) is used to create the phar archive. Run the following command to create the phar:
```sh
./box.phar compile
```

View File

@ -7,7 +7,7 @@ use Laminas\ServiceManager\ServiceManager;
use Symfony\Component\Console\Application; use Symfony\Component\Console\Application;
use Symfony\Component\Console\Input\ArgvInput; use Symfony\Component\Console\Input\ArgvInput;
$serviceManager = new ServiceManager(require("config/serviceManager.php")); $serviceManager = new ServiceManager(require(__DIR__."/../config/serviceManager.php"));
$application = new Application(); $application = new Application();
$command = $serviceManager->get(CheckCommand::class); $command = $serviceManager->get(CheckCommand::class);

View File

@ -1,5 +1,8 @@
{ {
"base-path": null, "base-path": null,
"output": "build/extension-check.phar", "output": "build/extension-check.phar",
"chmod": "0700" "chmod": "0700",
"files": [
"config/serviceManager.php"
]
} }

View File

@ -46,12 +46,18 @@
}, },
"scripts": { "scripts": {
"check": [ "check": [
"./vendor/bin/phpcbf",
"./vendor/bin/phpcs", "./vendor/bin/phpcs",
"./vendor/bin/phpstan analyse" "./vendor/bin/phpstan analyse"
], ],
"test" : [ "fix": [
"./vendor/bin/phpunit tests" "./vendor/bin/phpcbf",
"./vendor/bin/phpcs"
],
"test": [
"./vendor/bin/phpunit --no-coverage"
],
"coverage": [
"XDEBUG_MODE=coverage ./vendor/bin/phpunit"
] ]
}, },
"scripts-descriptions": { "scripts-descriptions": {

870
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,8 @@ ENV COMPOSER_ALLOW_SUPERUSER 1
RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/xdebug.ini \ RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.log_level = 0" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.log=/tmp/xdebug.log" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.log=/tmp/xdebug.log" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.discover_client_host=1" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.client_port=9000" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.client_port=9000" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/xdebug.ini && echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/xdebug.ini

View File

@ -8,8 +8,8 @@ ENV COMPOSER_ALLOW_SUPERUSER 1
RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/xdebug.ini \ RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.log_level = 0" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.log=/tmp/xdebug.log" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.log=/tmp/xdebug.log" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.discover_client_host=1" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.client_port=9000" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.client_port=9000" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/xdebug.ini && echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/xdebug.ini

View File

@ -8,8 +8,8 @@ ENV COMPOSER_ALLOW_SUPERUSER 1
RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/xdebug.ini \ RUN echo "xdebug.start_with_request=yes" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.log_level = 0" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.log=/tmp/xdebug.log" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.log=/tmp/xdebug.log" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.discover_client_host=1" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.client_port=9000" >> /usr/local/etc/php/conf.d/xdebug.ini \ && echo "xdebug.client_port=9000" >> /usr/local/etc/php/conf.d/xdebug.ini \
&& echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/xdebug.ini && echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/xdebug.ini

25
phpunit.xml Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
bootstrap="tests/bootstrap.php"
colors="true"
>
<testsuites>
<testsuite name="unit">
<directory>./tests/Unit</directory>
</testsuite>
</testsuites>
<php>
<ini name="date.timezone" value="UTC"/>
</php>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
<logging>
<log type="coverage-html" target="./coverage"/>
<log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/>
</logging>
</phpunit>

View File

@ -16,6 +16,7 @@ class ExtensionDetails
public function __construct() public function __construct()
{ {
$this->loadedExtensions = array_map('strtolower', get_loaded_extensions()); $this->loadedExtensions = array_map('strtolower', get_loaded_extensions());
natcasesort($this->loadedExtensions);
} }
/** /**
@ -23,13 +24,12 @@ class ExtensionDetails
*/ */
public function getLoadedExtensions(): array public function getLoadedExtensions(): array
{ {
natcasesort($this->loadedExtensions);
return $this->loadedExtensions; return $this->loadedExtensions;
} }
public function getLoadedExtensionsCount(): int public function getLoadedExtensionsCount(): int
{ {
return count($this->loadedExtensions); return count($this->getLoadedExtensions());
} }
/** /**
@ -44,44 +44,47 @@ class ExtensionDetails
return $this->extensionMap; return $this->extensionMap;
} }
public function getExtensionInfo(string $extensionInfo): ExtensionInfo
{
return new ExtensionInfo($extensionInfo);
}
/** /**
* @param string[] $excludedExtensions * @param string[] $excludedExtensions
*/ */
private function buildExtensionMaps(array $excludedExtensions): ExtensionMap private function buildExtensionMaps(array $excludedExtensions): ExtensionMap
{ {
$extensionClasses = $extensionFunctions = $extensionConstants = $extensionDependencies = $uncheckedExtensions = []; $extensionClasses = $extensionFunctions = $extensionConstants = $extensionDependencies = $uncheckedExtensions = [];
foreach ($this->loadedExtensions as $loadedExtension) {
$loadedExtensions = $this->getLoadedExtensions();
foreach ($loadedExtensions as $loadedExtension) {
if (in_array($loadedExtension, $excludedExtensions, true)) { if (in_array($loadedExtension, $excludedExtensions, true)) {
continue; continue;
} }
$extensionInfo = $this->getExtensionInfo($loadedExtension);
$extension = new ReflectionExtension($loadedExtension); $classes = $extensionInfo->getClasses();
$classes = $extension->getClasses();
if (!empty($classes)) { if (!empty($classes)) {
natcasesort($classes); $extensionClasses = array_merge($extensionClasses, array_map(function () use ($loadedExtension) {
foreach ($classes as $class) { return $loadedExtension;
$extensionClasses[$class->getName()] = $loadedExtension; }, array_flip($classes)));
}
} }
$functions = $extension->getFunctions(); $functions = $extensionInfo->getFunctions();
if (!empty($functions)) { if (!empty($functions)) {
natcasesort($functions); $extensionFunctions = array_merge($extensionFunctions, array_map(function () use ($loadedExtension) {
foreach ($functions as $function) { return $loadedExtension;
$extensionFunctions[$function->getName()] = $loadedExtension; }, array_flip($functions)));
}
} }
$constants = $extension->getConstants(); $constants = $extensionInfo->getConstants();
if (!empty($constants)) { if (!empty($constants)) {
natcasesort($constants); $extensionConstants = array_merge($extensionConstants, array_map(function () use ($loadedExtension) {
foreach ($constants as $constant => $_) { return $loadedExtension;
$extensionConstants[$constant] = $loadedExtension; }, array_flip($constants)));
}
} }
$dependencies = $extension->getDependencies(); /*$dependencies = $extensionInfo->getRequiredDependencies();
if (!empty($dependencies)) { if (!empty($dependencies)) {
natcasesort($dependencies); natcasesort($dependencies);
foreach ($dependencies as $dependency => $status) { foreach ($dependencies as $dependency => $status) {
@ -95,13 +98,10 @@ class ExtensionDetails
$extensionDependencies[$loadedExtension][strtolower($status)][] = $dependency; $extensionDependencies[$loadedExtension][strtolower($status)][] = $dependency;
} }
} }*/
// $extension->getINIEntries() if (empty($classes) && empty($functions) && empty($constants) && empty($dependencies)) {
// should we check the ini for configured extensions? $uncheckedExtensions[] = $loadedExtension;
if (empty($classes) && empty($functions)) {
$uncheckedExtensions[] = $extension->getName();
} }
} }

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Fbrinker\ExtensionCheck\Extension;
use ReflectionExtension;
class ExtensionInfo
{
/** @var ReflectionExtension */
private $extensionReflection;
public function __construct(string $extension)
{
$this->extensionReflection = new ReflectionExtension($extension);
}
public function getClasses(): array
{
$classes = $this->extensionReflection->getClassNames();
\natcasesort($classes);
return $classes;
}
public function getFunctions(): array
{
$functionReflections = $this->extensionReflection->getFunctions();
if (empty($functionReflections)) {
return [];
}
$functions = [];
foreach ($functionReflections as $functionReflection) {
$functions[] = $functionReflection->getName();
}
\natcasesort($functions);
return $functions;
}
public function getConstants(): array
{
$constants = $this->extensionReflection->getConstants();
if (empty($constants)) {
return [];
}
$constants = array_keys($constants);
\natcasesort($constants);
return $constants;
}
public function getRequiredDependencies(): array
{
$dependencies = $this->extensionReflection->getDependencies();
if (empty($dependencies)) {
return [];
}
$requiredDependencies = [];
foreach ($dependencies as $dependency => $status) {
if ($status !== 'required') {
continue;
}
$requiredDependencies[] = $dependency;
}
\natcasesort($requiredDependencies);
return $requiredDependencies;
}
}

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Fbrinker\ExtensionCheck\Extension; namespace Fbrinker\ExtensionCheck\Extension;
class ExtensionMap class ExtensionMap

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types=1);
namespace Fbrinker\ExtensionCheck\Output; namespace Fbrinker\ExtensionCheck\Output;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;

View File

@ -9,7 +9,6 @@ use PhpParser\NodeVisitorAbstract;
class ClassCollector extends NodeVisitorAbstract implements CollectorInferface class ClassCollector extends NodeVisitorAbstract implements CollectorInferface
{ {
/** /**
* @var array<string,bool> $classes * @var array<string,bool> $classes
*/ */

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Fbrinker\ExtensionCheck\Tests\Unit\Command;
use Fbrinker\ExtensionCheck\Command\CheckCommand;
use Fbrinker\ExtensionCheck\Extension\ExtensionCheck;
use Fbrinker\ExtensionCheck\Output\SymfonyStyleFactory;
use Fbrinker\ExtensionCheck\Parser\FileParser;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
class CheckCommandTest extends TestCase
{
public function testExecuteEmpty(): void
{
$sut = $this->createEmptySut();
$commandTester = new CommandTester($sut);
$commandTester->execute([]);
$result = $commandTester->getDisplay();
$this->assertStringContainsStringIgnoringCase("Files: 0", $result);
$this->assertStringContainsStringIgnoringCase("0 Classes, 0 Functions, 0 Constants", $result);
$this->assertStringContainsStringIgnoringCase("Loaded Extensions: 0", $result);
$this->assertStringContainsStringIgnoringCase("0 Used, 0 Unused", $result);
}
public function testExecuteWithResults(): void
{
$sut = $this->createSutWithResult();
$commandTester = new CommandTester($sut);
$commandTester->execute([]);
$result = $commandTester->getDisplay();
$this->assertStringContainsStringIgnoringCase("Files: 3", $result);
$this->assertStringContainsStringIgnoringCase("3 Classes, 2 Functions, 1 Constants", $result);
$this->assertStringContainsStringIgnoringCase("Loaded Extensions: 2", $result);
$this->assertStringContainsStringIgnoringCase("1 Used, 1 Unused", $result);
$this->assertStringContainsStringIgnoringCase("Used [Usage: class]", $result);
}
private function createEmptySut(): CheckCommand
{
$symfonyStyleFactory = new SymfonyStyleFactory();
$fileParserMock = $this->createMock(FileParser::class);
$fileParserMock->method('parseFiles')->willReturn([
[],
[],
[],
]);
$extensionCheckMock = $this->createMock(ExtensionCheck::class);
$extensionCheckMock->method('checkUsages')->willReturn([]);
return new CheckCommand($symfonyStyleFactory, $fileParserMock, $extensionCheckMock);
}
private function createSutWithResult(): CheckCommand
{
$symfonyStyleFactory = new SymfonyStyleFactory();
$fileParserMock = $this->createMock(FileParser::class);
$fileParserMock->method('getFileCount')->willReturn(3);
$fileParserMock->method('parseFiles')->willReturn([
['A', 'B', 'C'],
['gotoA', 'gotoB'],
['CONST_C'],
]);
$extensionCheckMock = $this->createMock(ExtensionCheck::class);
$extensionCheckMock->method('getLoadedExtensionsCount')->willReturn(2);
$extensionCheckMock->method('checkUsages')->willReturn(['Used' => ['class' => true]]);
$extensionCheckMock->method('getUnused')->willReturn(['Unused']);
return new CheckCommand($symfonyStyleFactory, $fileParserMock, $extensionCheckMock);
}
}

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Fbrinker\ExtensionCheck\Tests\Unit;
use Laminas\ServiceManager\ServiceManager;
use PHPUnit\Framework\TestCase;
class ServiceManagerTest extends TestCase
{
public function testServiceManagerConfig(): void
{
$config = require(__DIR__ . '/../../config/serviceManager.php');
$sut = new ServiceManager($config);
foreach ($config['factories'] as $class => $factory) {
$instance = $sut->get($class);
$this->assertInstanceOf($class, $instance);
}
}
}

5
tests/bootstrap.php Normal file
View File

@ -0,0 +1,5 @@
<?php
declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';