Passed
Push — master ( fcb909...cb681d )
by Robbie
02:26
created

UpdatePackageInfoTask::run()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 6
nop 1
dl 0
loc 29
rs 8.439
c 0
b 0
f 0
1
<?php
2
3
namespace BringYourOwnIdeas\Maintenance\Tasks;
4
5
use BringYourOwnIdeas\Maintenance\Util\ComposerLoader;
6
use BringYourOwnIdeas\Maintenance\Util\ModuleHealthLoader;
7
use BringYourOwnIdeas\Maintenance\Util\SupportedAddonsLoader;
8
use RuntimeException;
9
use SilverStripe\Control\HTTPRequest;
10
use SilverStripe\ORM\Queries\SQLDelete;
11
use SilverStripe\ORM\DataObjectSchema;
12
use BringYourOwnIdeas\Maintenance\Model\Package;
13
use SilverStripe\Dev\BuildTask;
14
15
/**
16
 * Parses a composer lock file in order to cache information about the installation.
17
 */
18
class UpdatePackageInfoTask extends BuildTask
19
{
20
    /**
21
     * {@inheritDoc}
22
     * @var string
23
     */
24
    private static $segment = 'UpdatePackageInfoTask';
25
26
    /**
27
     * @var array Injector configuration
28
     * @config
29
     */
30
    private static $dependencies = [
31
        'ComposerLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\ComposerLoader',
32
        'SupportedAddonsLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\SupportedAddonsLoader',
33
        'ModuleHealthLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\ModuleHealthLoader',
34
    ];
35
36
    /**
37
     * The "types" of composer libraries that will be processed. Anything without these types will be ignored.
38
     *
39
     * @config
40
     * @var array
41
     */
42
    private static $allowed_types = [
43
        'silverstripe-module',
44
        'silverstripe-vendormodule',
45
    ];
46
47
    /**
48
     * @var ComposerLoader
49
     */
50
    protected $composerLoader;
51
52
    /**
53
     * @var SupportedAddonsLoader
54
     */
55
    protected $supportedAddonsLoader;
56
57
    /**
58
     * @var ModuleHealthLoader
59
     */
60
    protected $moduleHealthLoader;
61
62
    /**
63
     * Fetch the composer loader
64
     *
65
     * @return ComposerLoader
66
     */
67
    public function getComposerLoader()
68
    {
69
        return $this->composerLoader;
70
    }
71
72
    /**
73
     * set composer loader - provided for use with Injector {@see Injector}
74
     *
75
     * @param ComposerLoader $composerLoader
76
     *
77
     * @return UpdatePackageInfoTask $this
78
     */
79
    public function setComposerLoader($composerLoader)
80
    {
81
        $this->composerLoader = $composerLoader;
82
        return $this;
83
    }
84
85
    /**
86
     * @return SupportedAddonsLoader
87
     */
88
    public function getSupportedAddonsLoader()
89
    {
90
        return $this->supportedAddonsLoader;
91
    }
92
93
    /**
94
     * @param SupportedAddonsLoader $supportedAddonsLoader
95
     * @return $this
96
     */
97
    public function setSupportedAddonsLoader(SupportedAddonsLoader $supportedAddonsLoader)
98
    {
99
        $this->supportedAddonsLoader = $supportedAddonsLoader;
100
        return $this;
101
    }
102
103
    /**
104
     * @return ModuleHealthLoader
105
     */
106
    public function getModuleHealthLoader()
107
    {
108
        return $this->moduleHealthLoader;
109
    }
110
111
    /**
112
     * @param ModuleHealthLoader $moduleHealthLoader
113
     * @return $this
114
     */
115
    public function setModuleHealthLoader(ModuleHealthLoader $moduleHealthLoader)
116
    {
117
        $this->moduleHealthLoader = $moduleHealthLoader;
118
        return $this;
119
    }
120
121
    public function getTitle()
122
    {
123
        return _t(__CLASS__ . '.TITLE', 'Refresh installed package info');
124
    }
125
126
    public function getDescription()
127
    {
128
        return _t(
129
            __CLASS__ . '.DESCRIPTION',
130
            'Repopulates installation summary, listing installed modules'.
131
                ' and information associated with each.'
132
        );
133
    }
134
135
    /**
136
     * Update database cached information about this site.
137
     *
138
     * @param HTTPRequest $request unused, can be null (must match signature of parent function).
139
     */
140
    public function run($request)
141
    {
142
        $composerLock = $this->getComposerLoader()->getLock();
143
        $rawPackages = array_merge($composerLock->packages, (array) $composerLock->{'packages-dev'});
144
        $packages = $this->getPackageInfo($rawPackages);
145
146
        // Get "name" from $packages and put into an array
147
        $moduleNames = array_column($packages, 'Name');
148
149
        $supportedPackages = $this->getSupportedPackages();
150
        $moduleHealthInfo = $this->getHealthIndicator($moduleNames);
151
152
        // Extensions to the process that add data may rely on external services.
153
        // There may be a communication issue between the site and the external service,
154
        // so if there are 'none' we should assume this is untrue and _not_ proceed
155
        // to remove everything. Stale information is better than no information.
156
        if ($packages) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $packages 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...
157
            // There is no onBeforeDelete for Package
158
            $table = DataObjectSchema::create()->tableName(Package::class);
159
            SQLDelete::create("\"$table\"")->execute();
160
            foreach ($packages as $package) {
161
                $packageName = $package['Name'];
162
                if (is_array($supportedPackages)) {
163
                    $package['Supported'] = in_array($packageName, $supportedPackages);
164
                }
165
                if (is_array($moduleHealthInfo) && isset($moduleHealthInfo[$packageName])) {
166
                    $package['Rating'] = $moduleHealthInfo[$packageName];
167
                }
168
                Package::create()->update($package)->write();
169
            }
170
        }
171
    }
172
173
    /**
174
     * Fetch information about the installed packages.
175
     *
176
     * @param array $packageList list of packages as objects, formatted as one finds in a composer.lock
177
     *
178
     * @return array indexed array of package information, represented as associative arrays.
179
     */
180
    public function getPackageInfo($packageList)
181
    {
182
        $formatInfo = function ($package) {
183
            // Convert object to array, with Capitalised keys
184
            $package = get_object_vars($package);
185
            return array_combine(
186
                array_map('ucfirst', array_keys($package)),
187
                $package
188
            );
189
        };
190
191
        $packageList = array_map($formatInfo, $packageList);
192
        $this->extend('updatePackageInfo', $packageList);
193
        return $packageList;
194
    }
195
196
    /**
197
     * Return an array of supported modules as fetched from addons.silverstripe.org. Outputs a message and returns null
198
     * if an error occurs
199
     *
200
     * @return null|array
201
     */
202
    public function getSupportedPackages()
203
    {
204
        try {
205
            return $this->getSupportedAddonsLoader()->getAddonNames() ?: [];
206
        } catch (RuntimeException $exception) {
207
            echo $exception->getMessage() . PHP_EOL;
208
        }
209
210
        return null;
211
    }
212
213
    /**
214
     * Return an array of module health information as fetched from addons.silverstripe.org. Outputs a message and
215
     * returns null if an error occurs
216
     *
217
     * @param string[] $moduleNames
218
     * @return null|array
219
     */
220
    public function getHealthIndicator(array $moduleNames)
221
    {
222
        try {
223
            return $this->getModuleHealthLoader()->setModuleNames($moduleNames)->getModuleHealthInfo() ?: [];
224
        } catch (RuntimeException $exception) {
225
            echo $exception->getMessage() . PHP_EOL;
226
        }
227
228
        return null;
229
    }
230
}
231