1<?php
2
3namespace App\Repository;
4
5/**
6 * Repository for retrieving data from the bugdb_patchtracker database table.
7 */
8class PatchRepository
9{
10    /**
11     * Database handler.
12     * @var \PDO
13     */
14    private $dbh;
15
16    /**
17     * Parent directory where patches are uploaded.
18     * @var string
19     */
20    private $uploadsDir;
21
22    /**
23     * Class constructor.
24     */
25    public function __construct(\PDO $dbh, string $uploadsDir)
26    {
27        $this->dbh = $dbh;
28        $this->uploadsDir = $uploadsDir;
29    }
30
31    /**
32     * Retrieve a list of all patches and their revisions by given bug id.
33     */
34    public function findAllByBugId(int $bugId): array
35    {
36        $sql = 'SELECT patch, revision, developer
37                FROM bugdb_patchtracker
38                WHERE bugdb_id = ?
39                ORDER BY revision DESC
40        ';
41
42        $statement = $this->dbh->prepare($sql);
43        $statement->execute([$bugId]);
44
45        return $statement->fetchAll();
46    }
47
48    /**
49     * Retrieve the developer by patch.
50     */
51    public function findDeveloper(int $bugId, string $patch, int $revision): string
52    {
53        $sql = 'SELECT developer
54                FROM bugdb_patchtracker
55                WHERE bugdb_id = ? AND patch = ? AND revision = ?
56        ';
57
58        $arguments = [$bugId, $patch, $revision];
59
60        $statement = $this->dbh->prepare($sql);
61        $statement->execute($arguments);
62
63        return $statement->fetch(\PDO::FETCH_NUM)[0];
64    }
65
66    /**
67     * Retrieve a list of all patches and their revisions.
68     */
69    public function findRevisions(int $bugId, string $patch): array
70    {
71        $sql = 'SELECT revision
72                FROM bugdb_patchtracker
73                WHERE bugdb_id = ? AND patch = ?
74                ORDER BY revision DESC
75        ';
76
77        $statement = $this->dbh->prepare($sql);
78        $statement->execute([$bugId, $patch]);
79
80        return $statement->fetchAll();
81    }
82
83    /**
84     * Retrieve the actual contents of the patch.
85     */
86    public function getPatchContents(int $bugId, string $name, int $revision): string
87    {
88        $sql = 'SELECT bugdb_id
89                FROM bugdb_patchtracker
90                WHERE bugdb_id = ? AND patch = ? AND revision = ?
91        ';
92
93        $statement = $this->dbh->prepare($sql);
94        $statement->execute([$bugId, $name, $revision]);
95
96        if ($statement->fetch(\PDO::FETCH_NUM)[0]) {
97            $contents = @file_get_contents($this->getPatchPath($bugId, $name, $revision));
98
99            if (!$contents) {
100                throw new \Exception('Cannot retrieve patch revision "'.$revision.'" for patch "'.$name.'"');
101            }
102
103            return $contents;
104        }
105
106        throw new \Exception('No such patch revision "'.$revision.'", or no such patch "'.$name.'"');
107    }
108
109    /**
110     * Get absolute patch file name.
111     */
112    private function getPatchPath(int $bugId, string $name, int $revision): string
113    {
114        return $this->uploadsDir.'/p'.$bugId.'/'.$name.'/'.'p'.$revision.'.patch.txt';
115    }
116}
117