ComposerJson::isReplacing()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/**
4
 * This file is part of tenside/core.
5
 *
6
 * (c) Christian Schiffler <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * This project is provided in good faith and hope to be usable by anyone.
12
 *
13
 * @package    tenside/core
14
 * @author     Christian Schiffler <[email protected]>
15
 * @copyright  2015 Christian Schiffler <[email protected]>
16
 * @license    https://github.com/tenside/core/blob/master/LICENSE MIT
17
 * @link       https://github.com/tenside/core
18
 * @filesource
19
 */
20
21
namespace Tenside\Core\Composer;
22
23
use Composer\Package\PackageInterface;
24
use Tenside\Core\Util\JsonFile;
25
26
/**
27
 * This class abstracts the composer.json file manipulation.
28
 *
29
 * @SuppressWarnings(PHPMD.TooManyPublicMethods)
30
 */
31
class ComposerJson extends JsonFile
32
{
33
    /**
34
     * Add a requirement to composer.json.
35
     *
36
     * @param string $name       The package name.
37
     *
38
     * @param string $constraint The version constraint.
39
     *
40
     * @return ComposerJson
41
     */
42
    public function requirePackage($name, $constraint)
43
    {
44
        return $this->setLink('require', $name, $constraint);
45
    }
46
47
    /**
48
     * Add a requirement to composer.json for dev.
49
     *
50
     * @param string $name       The package name.
51
     *
52
     * @param string $constraint The version constraint.
53
     *
54
     * @return ComposerJson
55
     */
56
    public function requirePackageDev($name, $constraint)
57
    {
58
        return $this->setLink('require-dev', $name, $constraint);
59
    }
60
61
    /**
62
     * Add a replacement to composer.json.
63
     *
64
     * @param string $name       The package name.
65
     *
66
     * @param string $constraint The version constraint.
67
     *
68
     * @return ComposerJson
69
     */
70
    public function replacePackage($name, $constraint)
71
    {
72
        return $this->setLink('replace', $name, $constraint);
73
    }
74
75
    /**
76
     * Add a replacement to composer.json.
77
     *
78
     * @param string $name       The package name.
79
     *
80
     * @param string $constraint The version constraint.
81
     *
82
     * @return ComposerJson
83
     */
84
    public function providePackage($name, $constraint)
85
    {
86
        return $this->setLink('provide', $name, $constraint);
87
    }
88
89
    /**
90
     * Get a requirement from composer.json.
91
     *
92
     * @param string $name The package name.
93
     *
94
     * @return string|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
95
     */
96
    public function getRequire($name)
97
    {
98
        return $this->getLink('require', $name);
99
    }
100
101
    /**
102
     * Get a requirement from composer.json for dev.
103
     *
104
     * @param string $name The package name.
105
     *
106
     * @return string|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
107
     */
108
    public function getRequireDev($name)
109
    {
110
        return $this->getLink('require-dev', $name);
111
    }
112
113
    /**
114
     * Get a requirement from composer.json.
115
     *
116
     * @param string $name The package name.
117
     *
118
     * @return string|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
119
     */
120
    public function getReplace($name)
121
    {
122
        return $this->getLink('replace', $name);
123
    }
124
125
    /**
126
     * Get a requirement from composer.json.
127
     *
128
     * @param string $name The package name.
129
     *
130
     * @return string|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
131
     */
132
    public function getProvide($name)
133
    {
134
        return $this->getLink('provide', $name);
135
    }
136
137
    /**
138
     * Check if a require entry has been defined.
139
     *
140
     * @param string $name The package name.
141
     *
142
     * @return bool
143
     */
144
    public function isRequiring($name)
145
    {
146
        return $this->hasLink('require', $name);
147
    }
148
149
    /**
150
     * Check if a require-dev entry has been defined.
151
     *
152
     * @param string $name The package name.
153
     *
154
     * @return bool
155
     */
156
    public function isRequiringDev($name)
157
    {
158
        return $this->hasLink('require-dev', $name);
159
    }
160
161
    /**
162
     * Check if a replacement entry has been defined.
163
     *
164
     * @param string $name The package name.
165
     *
166
     * @return bool
167
     */
168
    public function isReplacing($name)
169
    {
170
        return $this->hasLink('replace', $name);
171
    }
172
173
    /**
174
     * Check if a provide entry has been defined.
175
     *
176
     * @param string $name The package name.
177
     *
178
     * @return bool
179
     */
180
    public function isProviding($name)
181
    {
182
        return $this->hasLink('provide', $name);
183
    }
184
185
    /**
186
     * Set a link on a dependency to a constraint.
187
     *
188
     * @param string $type       The link type (require, require-dev, provide, replace).
189
     *
190
     * @param string $name       The package name.
191
     *
192
     * @param string $constraint The version constraint.
193
     *
194
     * @return ComposerJson
195
     */
196
    private function setLink($type, $name, $constraint)
197
    {
198
        $this->set($type . '/' . $this->escape($name), $constraint);
199
200
        return $this;
201
    }
202
203
    /**
204
     * Check if a link has been defined.
205
     *
206
     * @param string $type The link type (require, require-dev, provide, replace).
207
     *
208
     * @param string $name The package name.
209
     *
210
     * @return bool
211
     */
212
    private function hasLink($type, $name)
213
    {
214
        return $this->has($type . '/' . $this->escape($name));
215
    }
216
217
    /**
218
     * Check if a link has been defined.
219
     *
220
     * @param string $type The link type (require, require-dev, provide, replace).
221
     *
222
     * @param string $name The package name.
223
     *
224
     * @return string|null
0 ignored issues
show
Documentation introduced by
Should the return type not be array|string|integer|null? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
225
     */
226
    private function getLink($type, $name)
227
    {
228
        return $this->get($type . '/' . $this->escape($name));
229
    }
230
231
    /**
232
     * Check if a package is locked.
233
     *
234
     * @param string $packageName The name of the package to test.
235
     *
236
     * @return bool
237
     */
238
    public function isLocked($packageName)
239
    {
240
        return $this->has('extra/tenside/version-locks/' . $this->escape($packageName));
241
    }
242
243
    /**
244
     * Unlock a locked package version.
245
     *
246
     * @param PackageInterface $package The repository holding the packages to convert.
247
     *
248
     * @return ComposerJson
249
     */
250
    public function lockPackage(PackageInterface $package)
251
    {
252
        $name = $package->getPrettyName();
253
        $lock = 'extra/tenside/version-locks/' . $this->escape($name);
254
255
        // Nothing to do?
256
        if ($this->has($lock)) {
257
            return $this;
258
        }
259
260
        if ($this->isRequiring($name)) {
261
            $this->set($lock, $this->getRequire($name));
262
        } else {
263
            $this->set($lock, false);
264
        }
265
266
        $this->requirePackage(
267
            $package->getPrettyName(),
268
            PackageConverter::convertPackageVersion($package, true)
269
        );
270
271
        return $this;
272
    }
273
274
    /**
275
     * Unlock a locked package version.
276
     *
277
     * @param PackageInterface $package The repository holding the packages to convert.
278
     *
279
     * @return ComposerJson
280
     */
281
    public function unlockPackage(PackageInterface $package)
282
    {
283
        $name = $package->getPrettyName();
284
        $lock = 'extra/tenside/version-locks/' . $this->escape($name);
285
286
        // Nothing to do?
287
        if (!$this->has($lock)) {
288
            return $this;
289
        }
290
291
        if (false === ($constraint = $this->get($lock))) {
292
            $this->remove($lock);
293
            $this->requirePackage($name, null);
294
            $this->cleanEmptyArraysInPath('extra/tenside');
295
296
            return $this;
297
        }
298
299
        $this->requirePackage($name, $constraint);
300
        $this->remove($lock);
301
        $this->cleanEmptyArraysInPath('extra/tenside');
302
303
        return $this;
304
    }
305
306
    /**
307
     * Set the locking state for the passed package.
308
     *
309
     * @param PackageInterface $package The package to lock.
310
     *
311
     * @param bool             $state   The desired state.
312
     *
313
     * @return ComposerJson
314
     */
315
    public function setLock(PackageInterface $package, $state)
316
    {
317
        if ((bool) $state) {
318
            return $this->lockPackage($package);
319
        }
320
321
        return $this->unlockPackage($package);
322
    }
323
324
    /**
325
     * Cleanup the array section at the given path by removing empty sub arrays.
326
     *
327
     * @param string $path The base path to remove empty elements from.
328
     *
329
     * @return void
330
     */
331
    private function cleanEmptyArraysInPath($path)
332
    {
333
        $subs = $this->getEntries($path);
334
        if (!empty($subs)) {
335
            foreach ($subs as $subPath) {
336
                $this->cleanEmptyArraysInPath($subPath);
337
            }
338
        }
339
340
        if ([] === $this->get($path)) {
341
            $this->remove($path);
342
        }
343
    }
344
}
345