1<?php
2
3/*
4 * This file is part of the Fxp Composer Asset Plugin package.
5 *
6 * (c) François Pluchino <francois.pluchino@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Fxp\Composer\AssetPlugin\Repository;
13
14use Composer\DependencyResolver\Pool;
15use Composer\IO\IOInterface;
16use Composer\Repository\RepositoryInterface;
17use Composer\Repository\RepositoryManager;
18use Fxp\Composer\AssetPlugin\Config\Config;
19
20/**
21 * The asset repository manager.
22 *
23 * @author François Pluchino <francois.pluchino@gmail.com>
24 */
25class AssetRepositoryManager
26{
27    /**
28     * @var IOInterface
29     */
30    protected $io;
31
32    /**
33     * @var RepositoryManager
34     */
35    protected $rm;
36
37    /**
38     * @var Config
39     */
40    protected $config;
41
42    /**
43     * @var VcsPackageFilter
44     */
45    protected $packageFilter;
46
47    /**
48     * @var null|Pool
49     */
50    protected $pool;
51
52    /**
53     * @var ResolutionManager
54     */
55    protected $resolutionManager;
56
57    /**
58     * @var RepositoryInterface[]
59     */
60    protected $repositories = array();
61
62    /**
63     * @var array
64     */
65    protected $poolRepositories = array();
66
67    /**
68     * Constructor.
69     *
70     * @param IOInterface       $io            The IO
71     * @param RepositoryManager $rm            The repository manager
72     * @param Config            $config        The asset config
73     * @param VcsPackageFilter  $packageFilter The package filter
74     */
75    public function __construct(IOInterface $io, RepositoryManager $rm, Config $config, VcsPackageFilter $packageFilter)
76    {
77        $this->io = $io;
78        $this->rm = $rm;
79        $this->config = $config;
80        $this->packageFilter = $packageFilter;
81    }
82
83    /**
84     * Get the repository manager.
85     *
86     * @return RepositoryManager
87     */
88    public function getRepositoryManager()
89    {
90        return $this->rm;
91    }
92
93    /**
94     * Get the asset config.
95     *
96     * @return Config
97     */
98    public function getConfig()
99    {
100        return $this->config;
101    }
102
103    /**
104     * Set the pool.
105     *
106     * @param Pool $pool The pool
107     *
108     * @return self
109     */
110    public function setPool(Pool $pool)
111    {
112        $this->pool = $pool;
113
114        foreach ($this->poolRepositories as $repo) {
115            $pool->addRepository($repo);
116        }
117
118        $this->poolRepositories = array();
119
120        return $this;
121    }
122
123    /**
124     * Set the dependency resolution manager.
125     *
126     * @param ResolutionManager $resolutionManager The dependency resolution manager
127     */
128    public function setResolutionManager(ResolutionManager $resolutionManager)
129    {
130        $this->resolutionManager = $resolutionManager;
131    }
132
133    /**
134     * Solve the dependency resolutions.
135     *
136     * @param array $data
137     *
138     * @return array
139     */
140    public function solveResolutions(array $data)
141    {
142        return null !== $this->resolutionManager
143            ? $this->resolutionManager->solveResolutions($data)
144            : $data;
145    }
146
147    /**
148     * Adds asset vcs repositories.
149     *
150     * @param array $repositories The repositories
151     *
152     * @throws \UnexpectedValueException When config of repository is not an array
153     * @throws \UnexpectedValueException When the config of repository has not a type defined
154     * @throws \UnexpectedValueException When the config of repository has an invalid type
155     */
156    public function addRepositories(array $repositories)
157    {
158        foreach ($repositories as $index => $repo) {
159            $this->validateRepositories($index, $repo);
160
161            if ('package' === $repo['type']) {
162                $name = $repo['package']['name'];
163            } else {
164                $name = \is_int($index) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
165                $name = isset($repo['name']) ? $repo['name'] : $name;
166                $repo['asset-repository-manager'] = $this;
167                $repo['vcs-package-filter'] = $this->packageFilter;
168            }
169
170            $repoInstance = Util::addRepository($this->io, $this->rm, $this->repositories, $name, $repo, $this->pool);
171
172            if (null === $this->pool && $repoInstance instanceof RepositoryInterface) {
173                $this->poolRepositories[] = $repoInstance;
174            }
175        }
176    }
177
178    /**
179     * Validates the config of repositories.
180     *
181     * @param int|string  $index The index
182     * @param array|mixed $repo  The config repo
183     *
184     * @throws \UnexpectedValueException
185     */
186    protected function validateRepositories($index, $repo)
187    {
188        if (!\is_array($repo)) {
189            throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') should be an array, '.\gettype($repo).' given');
190        }
191        if (!isset($repo['type'])) {
192            throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined');
193        }
194
195        $this->validatePackageRepositories($index, $repo);
196        $this->validateVcsRepositories($index, $repo);
197    }
198
199    /**
200     * Validates the config of package repositories.
201     *
202     * @param int|string  $index The index
203     * @param array|mixed $repo  The config repo
204     *
205     * @throws \UnexpectedValueException
206     */
207    protected function validatePackageRepositories($index, $repo)
208    {
209        if ('package' !== $repo['type']) {
210            return;
211        }
212
213        if (!isset($repo['package'])) {
214            throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a package definition"');
215        }
216
217        foreach (array('name', 'type', 'version', 'dist') as $key) {
218            if (!isset($repo['package'][$key])) {
219                throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have the "'.$key.'" key  in the package definition"');
220            }
221        }
222    }
223
224    /**
225     * Validates the config of vcs repositories.
226     *
227     * @param int|string  $index The index
228     * @param array|mixed $repo  The config repo
229     *
230     * @throws \UnexpectedValueException
231     */
232    protected function validateVcsRepositories($index, $repo)
233    {
234        if ('package' === $repo['type']) {
235            return;
236        }
237
238        if (false === strpos($repo['type'], '-')) {
239            throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined in this way: "%asset-type%-%type%"');
240        }
241        if (!isset($repo['url'])) {
242            throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a url defined');
243        }
244    }
245}
246