Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ includes:
- phar://phpstan.phar/conf/bleedingEdge.neon

parameters:
level: 8
level: 9
paths:
- src
3 changes: 2 additions & 1 deletion src/Block/Inspector.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ public function getJsUrl(): string
*/
public function getTheme(): string
{
return (string) $this->scopeConfig->getValue('mageforge/inspector/theme') ?: 'dark';
$value = $this->scopeConfig->getValue('mageforge/inspector/theme');
return is_string($value) && $value !== '' ? $value : 'dark';
}

/**
Expand Down
25 changes: 10 additions & 15 deletions src/Console/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

use Laravel\Prompts\SelectPrompt;
use Magento\Framework\Console\Cli;
use OpenForgeProject\MageForge\Service\ThemeSuggester;
use OpenForgeProject\MageForge\Model\ThemeList;
use OpenForgeProject\MageForge\Service\ThemeSuggester;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
Expand Down Expand Up @@ -183,7 +183,7 @@ protected function handleInvalidThemeWithSuggestions(
return null;
}

return $selection;
return is_string($selection) ? $selection : null;
} catch (\Exception $e) {
$this->resetPromptEnvironment();
$this->io->error('Selection failed: ' . $e->getMessage());
Expand Down Expand Up @@ -487,10 +487,8 @@ private function removeSecureEnvironmentValue(string $name): void
* @param ThemeList $themeList
* @return array<string>
*/
protected function resolveVendorThemes(
array $themeCodes,
ThemeList $themeList
): array {
protected function resolveVendorThemes(array $themeCodes, ThemeList $themeList): array
{
$resolved = [];
$availableThemes = null;

Expand All @@ -502,10 +500,7 @@ protected function resolveVendorThemes(
if ($isExplicitWildcard || $isVendorOnly) {
// Lazy-load themes only when needed
if ($availableThemes === null) {
$availableThemes = array_map(
fn($theme) => $theme->getCode(),
$themeList->getAllThemes()
);
$availableThemes = array_map(fn($theme) => $theme->getCode(), $themeList->getAllThemes());
}

if ($isExplicitWildcard) {
Expand All @@ -514,10 +509,10 @@ protected function resolveVendorThemes(
$prefix = $code . '/'; // e.g. "Vendor" -> "Vendor/"
}

$matched = array_filter(
$availableThemes,
fn(string $availableCode) => \str_starts_with($availableCode, $prefix)
);
$matched = array_filter($availableThemes, fn(string $availableCode) => \str_starts_with(
$availableCode,
$prefix,
));

if (empty($matched)) {
$this->io->warning(sprintf("No themes found for vendor/prefix '%s'", $prefix));
Expand All @@ -532,7 +527,7 @@ protected function resolveVendorThemes(
"Resolved vendor '%s' to %d theme(s): %s",
$code,
count($matched),
implode(', ', $matched)
implode(', ', $matched),
));

foreach ($matched as $match) {
Expand Down
3 changes: 2 additions & 1 deletion src/Console/Command/Dev/InspectorCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ protected function configure(): void
*/
protected function executeCommand(InputInterface $input, OutputInterface $output): int
{
$action = strtolower((string) $input->getArgument(self::ARGUMENT_ACTION));
$arg = $input->getArgument(self::ARGUMENT_ACTION);
$action = strtolower(is_string($arg) ? $arg : '');

// Validate action
if (!in_array($action, ['enable', 'disable', 'status'], true)) {
Expand Down
20 changes: 12 additions & 8 deletions src/Console/Command/Hyva/CompatibilityCheckCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
*
* Scans modules for RequireJS, Knockout.js, jQuery, and UI Components usage
* that would be incompatible with Hyvä themes.
*
* @phpstan-import-type CheckResults from \OpenForgeProject\MageForge\Service\Hyva\CompatibilityChecker
* @phpstan-import-type CheckSummary from \OpenForgeProject\MageForge\Service\Hyva\CompatibilityChecker
* @phpstan-import-type ModuleEntry from \OpenForgeProject\MageForge\Service\Hyva\CompatibilityChecker
*/
class CompatibilityCheckCommand extends AbstractCommand
{
Expand Down Expand Up @@ -146,7 +150,7 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
// Detailed view confirmation
$detailedPrompt = new ConfirmPrompt(label: 'Show detailed file-level issues?', default: false);

$detailed = $detailedPrompt->prompt();
$detailed = (bool) $detailedPrompt->prompt();

// Map selected options to flags
$showAll = $displayMode === self::DISPLAY_MODE_SHOW_ALL;
Expand Down Expand Up @@ -193,10 +197,10 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
*/
private function runDirectMode(InputInterface $input, OutputInterface $output): int
{
$showAll = $input->getOption(self::OPTION_SHOW_ALL);
$thirdPartyOnly = $input->getOption(self::OPTION_THIRD_PARTY_ONLY);
$includeVendor = $input->getOption(self::OPTION_INCLUDE_VENDOR);
$detailed = $input->getOption(self::OPTION_DETAILED);
$showAll = (bool) $input->getOption(self::OPTION_SHOW_ALL);
$thirdPartyOnly = (bool) $input->getOption(self::OPTION_THIRD_PARTY_ONLY);
$includeVendor = (bool) $input->getOption(self::OPTION_INCLUDE_VENDOR);
$detailed = (bool) $input->getOption(self::OPTION_DETAILED);

$this->io->title('Hyvä Theme Compatibility Check');

Expand Down Expand Up @@ -271,7 +275,7 @@ private function runScan(
* Display compatibility check results
*
* @param array $results
* @phpstan-param array<string, mixed> $results
* @phpstan-param CheckResults $results
* @param bool $showAll
*/
private function displayResults(array $results, bool $showAll): void
Expand All @@ -292,7 +296,7 @@ private function displayResults(array $results, bool $showAll): void
* Display detailed file-level issues
*
* @param array $results
* @phpstan-param array<string, mixed> $results
* @phpstan-param CheckResults $results
*/
private function displayDetailedIssues(array $results): void
{
Expand Down Expand Up @@ -333,7 +337,7 @@ private function displayDetailedIssues(array $results): void
* Display summary statistics
*
* @param array $results
* @phpstan-param array<string, mixed> $results
* @phpstan-param array{summary: CheckSummary} $results
*/
private function displaySummary(array $results): void
{
Expand Down
63 changes: 45 additions & 18 deletions src/Console/Command/System/CheckCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,13 @@ private function getLatestLtsNodeVersion(): string
return 'Unknown';
}

/** @var array<int, array<string, mixed>> $nodes */
foreach ($nodes as $node) {
if (isset($node['lts']) && $node['lts'] !== false) {
if (isset($node['lts'])
&& $node['lts'] !== false
&& isset($node['version'])
&& is_string($node['version'])
) {
return trim($node['version'], 'v');
}
}
Expand Down Expand Up @@ -407,12 +412,15 @@ private function getSearchEngineFromMagentoConfig(): ?string
private function checkSearchEngineViaDeploymentConfig($objectManager): ?string
{
try {
/** @var \Magento\Framework\App\DeploymentConfig $deploymentConfig */
$deploymentConfig = $objectManager->get(\Magento\Framework\App\DeploymentConfig::class);
$engineConfig = $deploymentConfig->get('system/search/engine');

if (!empty($engineConfig)) {
$host = $deploymentConfig->get('system/search/engine_host') ?: 'localhost';
$port = $deploymentConfig->get('system/search/engine_port') ?: '9200';
if (!empty($engineConfig) && is_string($engineConfig)) {
$hostRaw = $deploymentConfig->get('system/search/engine_host');
$portRaw = $deploymentConfig->get('system/search/engine_port');
$host = is_string($hostRaw) ? $hostRaw : 'localhost';
$port = is_string($portRaw) ? $portRaw : '9200';

$url = "http://{$host}:{$port}";
if ($this->testElasticsearchConnection($url)) {
Expand All @@ -439,12 +447,11 @@ private function checkSearchEngineViaDeploymentConfig($objectManager): ?string
private function checkSearchEngineViaEngineResolver($objectManager): ?string
{
try {
/** @var \Magento\Framework\Search\EngineResolverInterface $engineResolver */
$engineResolver = $objectManager->get(\Magento\Framework\Search\EngineResolverInterface::class);
if ($engineResolver) {
$currentEngine = $engineResolver->getCurrentSearchEngine();
if (!empty($currentEngine)) {
return ucfirst($currentEngine) . ' (Magento config)';
}
$currentEngine = $engineResolver->getCurrentSearchEngine();
if (!empty($currentEngine)) {
return ucfirst($currentEngine) . ' (Magento config)';
}
} catch (\Exception $e) {
if ($this->io->isVerbose()) {
Expand Down Expand Up @@ -541,12 +548,16 @@ private function getSearchEngineHosts(): array
*/
private function formatSearchEngineVersion(array $info): string
{
if (isset($info['version']['distribution']) && $info['version']['distribution'] === 'opensearch') {
return 'OpenSearch ' . $info['version']['number'];
$version = $info['version'] ?? null;
if (!is_array($version)) {
return 'Search Engine Available';
}
if (isset($version['distribution']) && $version['distribution'] === 'opensearch') {
return 'OpenSearch ' . (is_string($version['number']) ? $version['number'] : '');
}

if (isset($info['version']['number'])) {
return 'Elasticsearch ' . $info['version']['number'];
if (isset($version['number'])) {
return 'Elasticsearch ' . (is_string($version['number']) ? $version['number'] : '');
}

return 'Search Engine Available';
Expand Down Expand Up @@ -597,6 +608,7 @@ private function tryMagentoHttpClient(string $url): ?array
if ($status === 200 && !empty($response)) {
$data = json_decode($response, true);
if (is_array($data)) {
/** @var array<string, mixed> $data */
return $data;
}
}
Expand Down Expand Up @@ -661,10 +673,24 @@ private function getDiskSpace(): string
$totalSpace = disk_total_space('.');
$freeSpace = disk_free_space('.');

$totalGB = round((($totalSpace / 1024) / 1024) / 1024, 2);
$freeGB = round((($freeSpace / 1024) / 1024) / 1024, 2);
if ($totalSpace === false || $freeSpace === false) {
return 'Unknown';
}

if ($totalSpace <= 0) {
$totalGB = 0.0;
$usedGB = 0.0;
$usedPercent = 0.0;

return "$usedGB GB / $totalGB GB ($usedPercent%)";
}

$totalGB = round($totalSpace / 1024 / 1024 / 1024, 2);
$freeGB = round($freeSpace / 1024 / 1024 / 1024, 2);
$usedGB = round($totalGB - $freeGB, 2);
$usedPercent = round(($usedGB / $totalGB) * 100, 2);
$usedPercent = $totalGB > 0.0
? round(($usedGB / $totalGB) * 100, 2)
: 0.0;

return "$usedGB GB / $totalGB GB ($usedPercent%)";
}
Expand Down Expand Up @@ -734,9 +760,10 @@ private function getMagentoEnvironmentValue(string $name): ?string
private function getValueFromDeploymentConfig($objectManager, string $name): ?string
{
try {
/** @var \Magento\Framework\App\DeploymentConfig $deploymentConfig */
$deploymentConfig = $objectManager->get(\Magento\Framework\App\DeploymentConfig::class);
$envValue = $deploymentConfig->get('system/default/environment/' . $name);
if ($envValue !== null) {
if ($envValue !== null && is_scalar($envValue)) {
return (string) $envValue;
}
} catch (\Exception $e) {
Expand All @@ -760,7 +787,7 @@ private function getValueFromEnvironmentService($objectManager, string $name): ?
try {
$environmentService = $objectManager->get(\Magento\Framework\App\EnvironmentInterface::class);
$method = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name))));
if (method_exists($environmentService, $method)) {
if (is_object($environmentService) && method_exists($environmentService, $method)) {
$value = $environmentService->$method();
if ($value !== null) {
return (string) $value;
Expand Down
Empty file.
9 changes: 7 additions & 2 deletions src/Console/Command/System/VersionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ private function getModuleVersion(): string
try {
$composerJson = $this->fileDriver->fileGetContents(__DIR__ . '/../../../../composer.json');
$composerData = json_decode($composerJson, true);
return $composerData['version'] ?? self::UNKNOWN_VERSION;
if (is_array($composerData) && isset($composerData['version']) && is_string($composerData['version'])) {
return $composerData['version'];
}
return self::UNKNOWN_VERSION;
} catch (\Exception $e) {
return self::UNKNOWN_VERSION;
}
Expand All @@ -96,7 +99,9 @@ private function getLatestVersion(): string

if ($response->getStatusCode() === 200) {
$data = json_decode($response->getBody()->getContents(), true);
return $data['tag_name'] ?? self::UNKNOWN_VERSION;
if (is_array($data) && isset($data['tag_name']) && is_string($data['tag_name'])) {
return $data['tag_name'];
}
}
} catch (\Exception $e) {
if ($this->io->isVerbose()) {
Expand Down
8 changes: 5 additions & 3 deletions src/Console/Command/Theme/BuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ protected function configure(): void
*/
protected function executeCommand(InputInterface $input, OutputInterface $output): int
{
/** @var array<string> $themeCodes */
$themeCodes = $input->getArgument('themeCodes');

// Allow wildcards using the AbstractCommand helper
Expand Down Expand Up @@ -97,7 +98,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output
label: 'Select themes to build',
options: fn(string $value) => empty($value)
? $options
: array_values(array_filter($options, fn($option) => stripos((string)$option, $value) !== false)),
: array_values(array_filter($options, fn($option) => stripos((string) $option, $value) !== false)),
placeholder: 'Type to search theme...',
hint: 'Type to search, arrow keys to navigate, Space to toggle, Enter to confirm',
required: false,
Expand All @@ -106,6 +107,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output
try {
$themeCodes = $themeCodesPrompt->prompt();
\Laravel\Prompts\Prompt::terminal()->restoreTty();
/** @var array<string> $themeCodes */

// Reset environment
$this->resetPromptEnvironment();
Expand Down Expand Up @@ -355,14 +357,14 @@ private function displayBuildSummary(SymfonyStyle $io, array $successList, float
$io->success(sprintf(
'🚀 Successfully built %d theme(s). Build process completed in %.2f seconds.',
$successCount,
$duration
$duration,
));
$io->writeln('Summary:');
$io->newLine();
} else {
$io->warning(sprintf(
'Build process completed in %.2f seconds, but no themes were built successfully.',
$duration
$duration,
));
return;
}
Expand Down
Loading
Loading