Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.91% covered (success)
90.91%
30 / 33
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ComposerPackagesLoader
90.62% covered (success)
90.62%
29 / 32
50.00% covered (danger)
50.00%
1 / 2
13.14
0.00% covered (danger)
0.00%
0 / 1
 load
88.46% covered (warning)
88.46%
23 / 26
0.00% covered (danger)
0.00%
0 / 1
9.12
 matchPackageFilter
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\About\Application\Service;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11/**
12 * Composer Installed Packages Loader.
13 *
14 * Reads and parses installed.json metadata.
15 *
16 * @package App\Modules\About\Application\Service
17 */
18final class ComposerPackagesLoader
19{
20    /**
21     * Parses installed.json and returns Composer packages.
22     *
23     * @param string|null $installedJsonPath Optional explicit path.
24     * @return array<int, array<string, mixed>> List of parsed packages.
25     */
26    public static function load(?string $installedJsonPath = null): array
27    {
28        $path = $installedJsonPath ?? dirname(__DIR__, 5) . '/vendor/composer/installed.json';
29        if (!file_exists($path)) {
30            $path = dirname(__DIR__, 4) . '/vendor/composer/installed.json';
31        }
32
33        if (!file_exists($path)) {
34            return [];
35        }
36
37        $content = file_get_contents($path);
38        if ($content === false) {
39            return [];
40        }
41
42        /** @var array{packages?: array<int, array<string, mixed>>} $data */
43        $data        = json_decode($content, true) ?? [];
44        $rawPackages = $data['packages'] ?? (is_array($data) ? $data : []);
45
46        $packages = [];
47        $id       = 1;
48
49        foreach ($rawPackages as $pkg) {
50            if (!is_array($pkg) || empty($pkg['name'])) {
51                continue;
52            }
53
54            $licenses = (array) ($pkg['license'] ?? ['Proprietary']);
55            $licenseStr = implode(', ', $licenses);
56
57            $packages[] = [
58                'id'          => (string) $id++,
59                'name'        => (string) $pkg['name'],
60                'version'     => (string) ($pkg['version_normalized'] ?? ($pkg['version'] ?? 'dev')),
61                'license'     => $licenseStr !== '' ? $licenseStr : 'Proprietary',
62                'description' => (string) ($pkg['description'] ?? ''),
63                'type'        => (string) ($pkg['type'] ?? 'library'),
64                'homepage'    => (string) ($pkg['homepage'] ?? ($pkg['source']['url'] ?? '')),
65            ];
66        }
67
68        return $packages;
69    }
70
71    /**
72     * Evaluates package matching against column criteria.
73     */
74    public static function matchPackageFilter(array $pkg, string $col, string $val): bool
75    {
76        $fieldVal = (string) ($pkg[$col] ?? '');
77        if ($col === 'id') {
78            return $fieldVal === $val;
79        }
80        if ($col === 'license') {
81            return strcasecmp($fieldVal, $val) === 0 || stripos($fieldVal, $val) !== false;
82        }
83
84        return stripos($fieldVal, $val) !== false;
85    }
86}