MoodlePackageRepository::resolveComponent()   B
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 33
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 33
ccs 0
cts 21
cp 0
rs 8.439
c 0
b 0
f 0
cc 5
eloc 22
nc 6
nop 2
crap 30
1
<?php
2
3
/**
4
 * Moodle component manager.
5
 *
6
 * @author Luke Carrier <[email protected]>
7
 * @copyright 2016 Luke Carrier
8
 * @license GPL-3.0+
9
 */
10
11
namespace ComponentManager\PackageRepository;
12
13
use ComponentManager\Component;
14
use ComponentManager\ComponentSource\GitComponentSource;
15
use ComponentManager\ComponentSource\ZipComponentSource;
16
use ComponentManager\ComponentSpecification;
17
use ComponentManager\ComponentVersion;
18
use ComponentManager\Exception\InvalidProjectException;
19
use DateTime;
20
use Psr\Log\LoggerInterface;
21
use stdClass;
22
use Symfony\Component\HttpFoundation\Request;
23
24
/**
25
 * Moodle.org/plugins package repository.
26
 */
27
class MoodlePackageRepository extends AbstractCachingPackageRepository
28
        implements CachingPackageRepository, PackageRepository {
29
    /**
30
     * Metadata cache filename.
31
     *
32
     * @var string
33
     */
34
    const METADATA_CACHE_FILENAME = 'components.json';
35
36
    /**
37
     * Plugin information endpoint URL.
38
     *
39
     * The service here returns information about the specified and latest
40
     * available releases of the specified plugins.
41
     *
42
     * @var string
43
     */
44
    const PLUGIN_INFO_URL = 'https://download.moodle.org/api/1.2/pluginfo.php';
45
46
    /**
47
     * Complete plugin list endpoint URL.
48
     *
49
     * Returns all metadata and versions of all plugins known to the plugin
50
     * repository.
51
     *
52
     * @var string
53
     */
54
    const PLUGIN_LIST_URL = 'https://download.moodle.org/api/1.3/pluglist.php';
55
56
    /**
57
     * Package cache.
58
     *
59
     * @var stdClass
60
     */
61
    protected $packageCache;
62
63
    /**
64
     * Get the component metadata cache filename.
65
     *
66
     * @return string
67
     */
68
    protected function getMetadataCacheFilename() {
69
        return $this->platform->joinPaths([
70
            $this->getMetadataCacheDirectory(),
71
            static::METADATA_CACHE_FILENAME,
72
        ]);
73
    }
74
75
    /**
76
     * @inheritdoc PackageRepository
77
     */
78
    public function getId() {
79
        return 'Moodle';
80
    }
81
82
    /**
83
     * @inheritdoc PackageRepository
84
     */
85
    public function getName() {
86
        return 'Moodle.org plugin repository';
87
    }
88
89
    /**
90
     * @inheritdoc PackageRepository
91
     */
92
    public function resolveComponent(ComponentSpecification $componentSpecification,
93
                                     LoggerInterface $logger) {
94
        $this->maybeLoadPackageCache();
95
96
        $componentName = $componentSpecification->getName();
97
        if (!property_exists($this->packageCache, $componentName)) {
98
            throw new InvalidProjectException(
99
                    "No component named \"{$componentName}\"",
0 ignored issues
show
Coding Style Best Practice introduced by
As per coding-style, please use concatenation or sprintf for the variable $componentName instead of interpolation.

It is generally a best practice as it is often more readable to use concatenation instead of interpolation for variables inside strings.

// Instead of
$x = "foo $bar $baz";

// Better use either
$x = "foo " . $bar . " " . $baz;
$x = sprintf("foo %s %s", $bar, $baz);
Loading history...
100
                    InvalidProjectException::CODE_MISSING_COMPONENT);
101
        }
102
        $package = $this->packageCache->{$componentName};
103
104
        $versions = [];
105
        foreach ($package->versions as $version) {
106
            $sources = [];
107
108
            if ($version->downloadurl) {
109
                $sources[] = new ZipComponentSource(
110
                        $version->downloadurl, $version->downloadmd5);
111
            }
112
113
            if ($version->vcssystem === 'git') {
114
                $sources[] = new GitComponentSource(
115
                        $version->vcsrepositoryurl, $version->vcstag);
116
            }
117
118
            $versions[] = new ComponentVersion(
119
                    $version->version, $version->release, $version->maturity,
120
                    $sources);
121
        }
122
123
        return new Component($package->component, $versions, $this);
124
    }
125
126
    /**
127
     * Load the package cache.
128
     *
129
     * @return void
130
     */
131
    protected function loadPackageCache() {
132
        $this->packageCache = json_decode(file_get_contents(
133
                $this->getMetadataCacheFilename()));
134
    }
135
136
    /**
137
     * Load the package cache (if not already loaded).
138
     *
139
     * @return void
140
     */
141
    protected function maybeLoadPackageCache() {
142
        if ($this->packageCache === null) {
143
            $this->loadPackageCache();
144
        }
145
    }
146
147
    /**
148
     * @inheritdoc CachingPackageRepository
149
     */
150 View Code Duplication
    public function metadataCacheLastRefreshed() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
151
        $filename = $this->getMetadataCacheFilename();
152
153
        if (!$this->filesystem->exists($filename)) {
154
            return null;
155
        }
156
157
        $time = new DateTime();
158
        $time->setTimestamp(filemtime($filename));
159
160
        return $time;
161
    }
162
163
    /**
164
     * @inheritdoc CachingPackageRepository
165
     */
166
    public function refreshMetadataCache(LoggerInterface $logger) {
167
        $logger->debug('Fetching metadata', [
168
            'url' => static::PLUGIN_LIST_URL,
169
        ]);
170
171
        $message = $this->httpClient->createRequest(
172
                Request::METHOD_GET, static::PLUGIN_LIST_URL);
173
        $response = $this->httpClient->sendRequest($message);
174
175
        $logger->debug('Indexing component data');
176
        $rawComponents = json_decode($response->getBody());
177
        $components    = new stdClass();
178
        foreach ($rawComponents->plugins as $component) {
179
            if ($component->component === null) {
180
                $logger->warning('Component has no component name; is it a patch or external tool?', [
181
                    'id'   => $component->id,
182
                    'name' => $component->name,
183
                ]);
184
                continue;
185
            }
186
            $components->{$component->component} = $component;
187
        }
188
189
        $file = $this->getMetadataCacheFilename();
190
        $logger->info('Storing metadata', [
191
            'filename' => $file,
192
        ]);
193
        $this->filesystem->dumpFile($file, json_encode($components));
194
    }
195
196
    /**
197
     * @inheritdoc PackageRepository
198
     */
199
    public function satisfiesVersion($versionSpecification, ComponentVersion $version) {
200
        return $versionSpecification == $version->getVersion()
201
                || $versionSpecification == $version->getRelease();
202
    }
203
}
204