Passed
Push — phpstan ( c4fbd2...07dbe1 )
by Sam
08:10
created

VersionProvider   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 35
dl 0
loc 87
rs 10
c 0
b 0
f 0
wmc 16

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getModules() 0 4 2
A getModuleVersionFromComposer() 0 12 6
A getVersion() 0 12 3
A getComposerLock() 0 28 5
1
<?php
2
3
namespace SilverStripe\Core\Manifest;
4
5
use SilverStripe\Core\Config\Config;
6
use Psr\SimpleCache\CacheInterface;
7
use SilverStripe\Core\Convert;
8
use SilverStripe\Core\Injector\Injector;
9
10
/**
11
 * The version provider will look up configured modules and examine the composer.lock file
12
 * to find the current version installed for each. This is used for the logo title in the CMS
13
 * via {@link LeftAndMain::CMSVersion()}
14
 *
15
 * Example configuration:
16
 *
17
 * <code>
18
 * SilverStripe\Core\Manifest\VersionProvider:
19
 *   modules:
20
 *     # package/name: Package Title
21
 *     silverstripe/framework: Framework
22
 *     silverstripe/cms: CMS
23
 * </code>
24
 */
25
class VersionProvider
26
{
27
    /**
28
     * Gets a comma delimited string of package titles and versions
29
     *
30
     * @return string
31
     */
32
    public function getVersion()
33
    {
34
        $modules = $this->getModules();
35
        $lockModules = $this->getModuleVersionFromComposer(array_keys($modules));
36
        $output = [];
37
        foreach ($modules as $module => $title) {
38
            $version = isset($lockModules[$module])
39
                ? $lockModules[$module]
40
                : _t(__CLASS__ . '.VERSIONUNKNOWN', 'Unknown');
41
            $output[] = $title . ': ' . $version;
42
        }
43
        return implode(', ', $output);
44
    }
45
46
    /**
47
     * Gets the configured core modules to use for the SilverStripe application version. Filtering
48
     * is used to ensure that modules can turn the result off for other modules, e.g. CMS can disable Framework.
49
     *
50
     * @return array
51
     */
52
    public function getModules()
53
    {
54
        $modules = Config::inst()->get(self::class, 'modules');
55
        return $modules ? array_filter($modules) : [];
56
    }
57
58
    /**
59
     * Tries to obtain version number from composer.lock if it exists
60
     *
61
     * @param  array $modules
62
     * @return array
63
     */
64
    public function getModuleVersionFromComposer($modules = [])
65
    {
66
        $versions = [];
67
        $lockData = $this->getComposerLock();
68
        if ($lockData && !empty($lockData['packages'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lockData of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
69
            foreach ($lockData['packages'] as $package) {
70
                if (in_array($package['name'], $modules) && isset($package['version'])) {
71
                    $versions[$package['name']] = $package['version'];
72
                }
73
            }
74
        }
75
        return $versions;
76
    }
77
78
    /**
79
     * Load composer.lock's contents and return it
80
     *
81
     * @param  bool $cache
82
     * @return array
83
     */
84
    protected function getComposerLock($cache = true)
85
    {
86
        $composerLockPath = BASE_PATH . '/composer.lock';
87
        if (!file_exists($composerLockPath)) {
88
            return [];
89
        }
90
91
        $jsonData = file_get_contents($composerLockPath);
92
93
        //  TODO: The benefit of this cache isn't clear
94
        if ($cache) {
95
            $cache = Injector::inst()->get(CacheInterface::class . '.VersionProvider_composerlock');
96
            $cacheKey = md5($jsonData);
97
98
            if ($versions = $cache->get($cacheKey)) {
99
                $lockData = json_decode($versions, true);
0 ignored issues
show
Unused Code introduced by
The assignment to $lockData is dead and can be removed.
Loading history...
100
            }
101
102
            $lockData = json_decode($jsonData, true);
103
104
            $cache->set($cacheKey, $jsonData);
105
        } elseif ($jsonData) {
106
            $lockData = json_decode($jsonData, true);
107
        } else {
108
            $lockData = [];
109
        }
110
111
        return $lockData;
112
    }
113
}
114