Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
42.86% covered (danger)
42.86%
30 / 70
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
SqliteFile
42.86% covered (danger)
42.86%
30 / 70
0.00% covered (danger)
0.00%
0 / 5
78.45
0.00% covered (danger)
0.00%
0 / 1
 validateState
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
 getOrSetOnServerPath
8.00% covered (danger)
8.00%
2 / 25
0.00% covered (danger)
0.00%
0 / 1
72.07
 createRandom
88.24% covered (warning)
88.24%
15 / 17
0.00% covered (danger)
0.00%
0 / 1
3.01
 executeQuery
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
6
 fetchAll
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
2.00
1<?php
2
3namespace Apie\Core\FileStorage;
4
5use Apie\Core\Attributes\FakeMethod;
6use Apie\Core\Exceptions\InvalidTypeException;
7
8#[FakeMethod('createRandom')]
9class SqliteFile extends StoredFile
10{
11    protected function validateState(): void
12    {
13        $serverMime = $this->getServerMimeType();
14        if (!in_array($serverMime, ['application/vnd.sqlite3', 'application/x-empty', 'application/octet-stream'])) {
15            throw new InvalidTypeException($serverMime, 'Sqlite3 database');
16        }
17    }
18
19    public function getOrSetOnServerPath(): string
20    {
21        if ($this->serverPath !== null) {
22            return $this->serverPath;
23        }
24        $tempFile = tempnam(sys_get_temp_dir(), 'sqlite');
25        if ($tempFile === false) {
26            throw new \RuntimeException('Unable to create a temporary SQLite file');
27        }
28
29        $source = null;
30        $target = null;
31        try {
32            $source = $this->getStream()->detach();
33            if (!is_resource($source)) {
34                throw new \RuntimeException('Unable to open the SQLite file stream');
35            }
36            $target = fopen($tempFile, 'wb');
37            if ($target === false) {
38                throw new \RuntimeException('Unable to open the temporary SQLite file');
39            }
40            if (stream_copy_to_stream($source, $target) === false) {
41                throw new \RuntimeException('Unable to copy the SQLite file to a temporary file');
42            }
43
44            $this->serverPath = $tempFile;
45            $this->removeOnDestruct = true;
46            return $this->serverPath;
47        } catch (\Throwable $exception) {
48            @unlink($tempFile);
49            throw $exception;
50        } finally {
51            if (is_resource($source)) {
52                fclose($source);
53            }
54            if (is_resource($target)) {
55                fclose($target);
56            }
57        }
58    }
59
60    public static function createRandom(): static
61    {
62        $tempFile = tempnam(sys_get_temp_dir(), 'sqlite');
63        if ($tempFile === false) {
64            throw new \RuntimeException('Unable to create a temporary SQLite file');
65        }
66        $result = null;
67        try {
68            $conn = new \PDO(
69                'sqlite:' . $tempFile,
70                options: [
71                    \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
72                ]
73            );
74            $conn->exec('PRAGMA user_version = 0');
75            unset($conn);
76            $result = static::createFromLocalFile($tempFile, removeOnDestruct: true);
77            $result->indexing = [];
78        } finally {
79            // $tempFile ownership is not moved to the created file class.
80            if ($result === null) {
81                @unlink($tempFile);
82            }
83        }
84        
85        return $result;
86    }
87
88    /**
89     * @param array<array-key, string|null|int|float> $params
90     */
91    public function executeQuery(string $query, array $params = []): bool
92    {
93        $serverPath = $this->getOrSetOnServerPath();
94        $conn = new \PDO(
95            'sqlite:' . $serverPath,
96            options: [
97            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
98        ]
99        );
100        $statement = $conn->prepare($query);
101        if ($statement === false) {
102            return false;
103        }
104        $result = $statement->execute($params);
105        unset($conn, $statement);
106
107        return $result;
108    }
109    /**
110     * @param array<array-key, string|null|int|float> $params
111     * @return list<array<string, mixed>>
112     */
113    public function fetchAll(string $query, array $params = []): array
114    {
115        $serverPath = $this->getOrSetOnServerPath();
116        $conn = new \PDO(
117            'sqlite:' . $serverPath,
118            options: [
119                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
120            ]
121        );
122
123        $statement = $conn->prepare($query);
124        if ($statement === false) {
125            return [];
126        }
127
128        $statement->execute($params);
129
130        return $statement->fetchAll(\PDO::FETCH_ASSOC);
131    }
132
133
134}