1<?php
2declare(strict_types=1);
3
4namespace PhpList\Core\Composer;
5
6use Composer\Composer;
7use Composer\Package\PackageInterface;
8
9/**
10 * Repository for Composer packages.
11 *
12 * @author Oliver Klee <oliver@phplist.com>
13 */
14class PackageRepository
15{
16    /**
17     * @var string
18     */
19    const PHPLIST_MODULE_TYPE = 'phplist-module';
20
21    /**
22     * @var Composer
23     */
24    private $composer = null;
25
26    /**
27     * @param Composer $composer
28     *
29     * @return void
30     */
31    public function injectComposer(Composer $composer)
32    {
33        $this->composer = $composer;
34    }
35
36    /**
37     * Finds all installed packages (including the root package).
38     *
39     * @return PackageInterface[]
40     */
41    public function findAll(): array
42    {
43        $rootPackage = $this->composer->getPackage();
44        $dependencies = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages();
45
46        $packagesWithDuplicates = array_merge([$rootPackage], $dependencies);
47
48        return $this->removeDuplicates($packagesWithDuplicates);
49    }
50
51    /**
52     * @param PackageInterface[] $packages
53     *
54     * @return PackageInterface[]
55     */
56    private function removeDuplicates(array $packages): array
57    {
58        /** @var bool[] $registeredPackages */
59        $registeredPackages = [];
60
61        $result = array_filter(
62            $packages,
63            function (PackageInterface $package) use (&$registeredPackages) {
64                $packageName = $package->getName();
65                if (isset($registeredPackages[$packageName])) {
66                    return false;
67                }
68
69                $registeredPackages[$packageName] = true;
70                return true;
71            }
72        );
73
74        return $result;
75    }
76
77    /**
78     * Finds all the installed packages (including the root package) that are phpList modules (as per their type).
79     *
80     * @return PackageInterface[]
81     */
82    public function findModules(): array
83    {
84        return array_filter(
85            $this->findAll(),
86            function (PackageInterface $package) {
87                return $package->getType() === static::PHPLIST_MODULE_TYPE;
88            }
89        );
90    }
91}
92