Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 18
CRAP
0.00% covered (danger)
0.00%
0 / 1
manager
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 18
812
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 install
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 pre_install
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 post_install
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 update
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 pre_update
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 post_update
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 remove
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 pre_remove
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 post_remove
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 is_managed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_managed_packages
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 get_all_managed_packages
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 get_available_packages
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 reset_cache
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 start_managing
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 check_requirements
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 normalize_version
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 *
4 * This file is part of the phpBB Forum Software package.
5 *
6 * @copyright (c) phpBB Limited <https://www.phpbb.com>
7 * @license GNU General Public License, version 2 (GPL-2.0)
8 *
9 * For full copyright and license information, please see
10 * the docs/CREDITS.txt file.
11 *
12 */
13
14namespace phpbb\composer;
15
16use Composer\IO\IOInterface;
17use phpbb\cache\driver\driver_interface;
18use phpbb\composer\exception\runtime_exception;
19
20/**
21 * Class to manage packages through composer.
22 */
23class manager implements manager_interface
24{
25    /**
26     * @var installer Composer packages installer
27     */
28    protected $installer;
29
30    /**
31     * @var driver_interface Cache instance
32     */
33    protected $cache;
34
35    /**
36     * @var string Type of packages (phpbb-packages per example)
37     */
38    protected $package_type;
39
40    /**
41     * @var string Prefix used for the exception's language string
42     */
43    protected $exception_prefix;
44
45    /**
46     * @var array|null Caches the managed packages list (for the current type)
47     */
48    private $managed_packages;
49
50    /**
51     * @var array|null Caches the managed packages list (for all phpBB types)
52     */
53    private $all_managed_packages;
54
55    /**
56     * @var array|null Caches the available packages list
57     */
58    private $available_packages;
59
60    /**
61     * @param installer            $installer            Installer object
62     * @param driver_interface    $cache                Cache object
63     * @param string            $package_type        Composer type of managed packages
64     * @param string            $exception_prefix    Exception prefix to use
65     */
66    public function __construct(installer $installer, driver_interface $cache, $package_type, $exception_prefix)
67    {
68        $this->installer = $installer;
69        $this->cache = $cache;
70        $this->package_type = $package_type;
71        $this->exception_prefix = $exception_prefix;
72    }
73
74    /**
75     * {@inheritdoc}
76     */
77    public function install(array $packages, IOInterface $io = null)
78    {
79        $packages = $this->normalize_version($packages);
80
81        $already_managed = array_intersect(array_keys($this->get_managed_packages()), array_keys($packages));
82        if (count($already_managed) !== 0)
83        {
84            throw new runtime_exception($this->exception_prefix, 'ALREADY_INSTALLED', [implode('|', $already_managed)]);
85        }
86
87        $this->pre_install($packages, $io);
88
89        $managed_packages = array_merge($this->get_all_managed_packages(), $packages);
90        ksort($managed_packages);
91
92        $this->installer->install($managed_packages, [], $io);
93
94        $this->post_install($packages, $io);
95
96        $this->managed_packages = null;
97    }
98
99    /**
100     * Hook called before installing the packages
101     *
102     * @param array $packages Packages to update.
103     *                        Each entry may be a name or an array associating a version constraint to a name
104     * @param IOInterface|null $io IO object used for the output
105     */
106    protected function pre_install(array $packages, IOInterface $io = null)
107    {
108    }
109
110    /**
111     * Hook called after installing the packages
112     *
113     * @param array $packages Packages to update.
114     *                        Each entry may be a name or an array associating a version constraint to a name
115     * @param IOInterface|null $io IO object used for the output
116     */
117    protected function post_install(array $packages, IOInterface $io = null)
118    {
119    }
120
121    /**
122     * {@inheritdoc}
123     */
124    public function update(array $packages, IOInterface $io = null)
125    {
126        $packages = $this->normalize_version($packages);
127
128        $not_managed = array_diff_key($packages, $this->get_managed_packages());
129        if (count($not_managed) !== 0)
130        {
131            throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]);
132        }
133
134        $this->pre_update($packages, $io);
135
136        $managed_packages = array_merge($this->get_all_managed_packages(), $packages);
137        ksort($managed_packages);
138
139        $this->installer->install($managed_packages, array_keys($packages), $io);
140
141        $this->post_update($packages, $io);
142    }
143
144    /**
145     * Hook called before updating the packages
146     *
147     * @param array $packages Packages to update.
148     *                        Each entry may be a name or an array associating a version constraint to a name
149     * @param IOInterface|null $io IO object used for the output
150     */
151    protected function pre_update(array $packages, IOInterface $io = null)
152    {
153    }
154
155    /**
156     * Hook called after updating the packages
157     *
158     * @param array $packages Packages to update.
159     *                        Each entry may be a name or an array associating a version constraint to a name
160     * @param IOInterface|null $io IO object used for the output
161     */
162    protected function post_update(array $packages, IOInterface $io = null)
163    {
164    }
165
166    /**
167     * {@inheritdoc}
168     */
169    public function remove(array $packages, IOInterface $io = null)
170    {
171        $packages = $this->normalize_version($packages);
172
173        $not_managed = array_diff_key($packages, $this->get_managed_packages());
174        if (count($not_managed) !== 0)
175        {
176            throw new runtime_exception($this->exception_prefix, 'NOT_MANAGED', [implode('|', array_keys($not_managed))]);
177        }
178
179        $this->pre_remove($packages, $io);
180
181        $managed_packages = array_diff_key($this->get_all_managed_packages(), $packages);
182        ksort($managed_packages);
183
184        $this->installer->install($managed_packages, array_keys($packages), $io);
185
186        $this->post_remove($packages, $io);
187
188        $this->managed_packages = null;
189    }
190
191    /**
192     * Hook called before removing the packages
193     *
194     * @param array $packages Packages to update.
195     *                        Each entry may be a name or an array associating a version constraint to a name
196     * @param IOInterface|null $io IO object used for the output
197     */
198    protected function pre_remove(array $packages, IOInterface $io = null)
199    {
200    }
201
202    /**
203     * Hook called after removing the packages
204     *
205     * @param array $packages Packages to update.
206     *                        Each entry may be a name or an array associating a version constraint to a name
207     * @param IOInterface|null $io IO object used for the output
208     */
209    protected function post_remove(array $packages, IOInterface $io = null)
210    {
211    }
212
213    /**
214     * {@inheritdoc}
215     */
216    public function is_managed($package)
217    {
218        return array_key_exists($package, $this->get_managed_packages());
219    }
220
221    /**
222     * {@inheritdoc}
223     */
224    public function get_managed_packages()
225    {
226        if ($this->managed_packages === null)
227        {
228            $this->managed_packages = $this->installer->get_installed_packages($this->package_type);
229        }
230
231        return $this->managed_packages;
232    }
233
234    /**
235     * {@inheritdoc}
236     */
237    public function get_all_managed_packages()
238    {
239        if ($this->all_managed_packages === null)
240        {
241            $this->all_managed_packages = $this->installer->get_installed_packages(explode(',', installer::PHPBB_TYPES));
242        }
243
244        return $this->all_managed_packages;
245    }
246
247    /**
248     * {@inheritdoc}
249     */
250    public function get_available_packages()
251    {
252        if ($this->available_packages === null)
253        {
254            $this->available_packages = $this->cache->get('_composer_' . $this->package_type . '_available');
255
256            if (!$this->available_packages)
257            {
258                $this->available_packages = $this->installer->get_available_packages($this->package_type);
259                $this->cache->put('_composer_' . $this->package_type . '_available', $this->available_packages, 24*60*60);
260            }
261        }
262
263        return $this->available_packages;
264    }
265
266    /**
267     * {@inheritdoc}
268     */
269    public function reset_cache()
270    {
271        $this->cache->destroy('_composer_' . $this->package_type . '_available');
272
273        $this->available_packages = null;
274        $this->managed_packages = null;
275        $this->all_managed_packages = null;
276    }
277
278    /**
279     * {@inheritdoc}
280     */
281    public function start_managing($package, $io)
282    {
283        throw new \phpbb\exception\runtime_exception('COMPOSER_UNSUPPORTED_OPERATION', (array) $this->package_type);
284    }
285
286    /**
287     * {@inheritdoc}
288     */
289    public function check_requirements()
290    {
291        return $this->installer->check_requirements();
292    }
293
294    /**
295     * Normalize a packages/version array. Every entry can have 3 different forms:
296     *  - $package => $version
297     *  - $indice => $package:$version
298     *  - $indice => $package
299     * They are converted to he form:
300     *  - $package => $version ($version is set to '*' for the third form)
301     *
302     * @param array $packages
303     *
304     * @return array
305     */
306    protected function normalize_version(array $packages)
307    {
308        $normalized_packages = [];
309
310        foreach ($packages as $package => $version)
311        {
312            if (is_numeric($package))
313            {
314                if (strpos($version, ':') !== false)
315                {
316                    $parts = explode(':', $version);
317                    $normalized_packages[$parts[0]] = $parts[1];
318                }
319                else
320                {
321                    $normalized_packages[$version] = '*';
322                }
323            }
324            else
325            {
326                $normalized_packages[$package] = $version;
327            }
328        }
329
330        return $normalized_packages;
331    }
332}