1<?php
2
3namespace App\Repository;
4
5/**
6 * Repository class for retrieving data from the bugdb_pseudo_packages database
7 * table.
8 */
9class PackageRepository
10{
11    /**
12     * Database handler.
13     * @var \PDO
14     */
15    private $dbh;
16
17    /**
18     * Project types.
19     */
20    public const PROJECTS = [
21        'PHP'  => 'php',
22        'PECL' => 'pecl',
23    ];
24
25    /**
26     * Class constructor.
27     */
28    public function __construct(\PDO $dbh)
29    {
30        $this->dbh = $dbh;
31    }
32
33    /**
34     * Find all packages by project type.
35     */
36    public function findAll(string $project = ''): array
37    {
38        $sql = 'SELECT * FROM bugdb_pseudo_packages';
39        $arguments = [];
40
41        $project = strtolower($project);
42        if (in_array($project, self::PROJECTS)) {
43            $sql .= " WHERE project IN ('', ?)";
44            $arguments[] = $project;
45        }
46
47        $sql .= ' ORDER BY parent, disabled, id';
48
49        $statement = $this->dbh->prepare($sql);
50        $statement->execute($arguments);
51        $data = $statement->fetchAll();
52
53        return $this->getNested($data);
54    }
55
56    /**
57     * Find all enabled packages by project type.
58     */
59    public function findEnabled(string $project = ''): array
60    {
61        $sql = 'SELECT * FROM bugdb_pseudo_packages WHERE disabled = 0';
62        $arguments = [];
63
64        $project = strtolower($project);
65        if (in_array($project, self::PROJECTS)) {
66            $sql .= " AND project IN ('', ?)";
67            $arguments[] = $project;
68        }
69
70        $sql .= ' ORDER BY parent, id';
71
72        $statement = $this->dbh->prepare($sql);
73        $statement->execute($arguments);
74
75        $data = $statement->fetchAll();
76
77        return $this->getNested($data);
78    }
79
80    /**
81     * Convert flat array to nested structure.
82     */
83    private function getNested(array $data): array
84    {
85        $packages = [];
86        $nodes = [];
87        $tree = [];
88
89        foreach ($data as &$node) {
90            $node['children'] = [];
91            $id = $node['id'];
92            $parentId = $node['parent'];
93            $nodes[$id] =& $node;
94
95            if (array_key_exists($parentId, $nodes)) {
96                $nodes[$parentId]['children'][] =& $node;
97            } else {
98                $tree[] =& $node;
99            }
100        }
101
102        foreach ($tree as $data) {
103            if (isset($data['children'])) {
104                $packages[$data['name']] = [$data['long_name'], $data['disabled'], []];
105                $children = &$packages[$data['name']][2];
106                $longNames = [];
107
108                foreach ($data['children'] as $k => $v) {
109                    $longNames[$k] = strtolower($v['long_name']);
110                }
111
112                array_multisort($longNames, SORT_ASC, SORT_STRING, $data['children']);
113
114                foreach ($data['children'] as $child) {
115                    $packages[$child['name']] = ["{$child['long_name']}", $child['disabled'], null];
116                    $children[] = $child['name'];
117                }
118            } elseif (!isset($packages[$data['name']])) {
119                $packages[$data['name']] = [$data['long_name'], $data['disabled'], null];
120            }
121        }
122
123        return $packages;
124    }
125
126    /**
127     * Find all package mailing lists.
128     */
129    public function findLists(): array
130    {
131        $sql = "SELECT name, list_email
132                FROM bugdb_pseudo_packages
133                WHERE project = 'php' AND LENGTH(list_email) > 0
134                ORDER BY list_email
135        ";
136
137        $statement = $this->dbh->query($sql);
138
139        return $statement->fetchAll();
140    }
141}
142