Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ManagementDatabaseMaintenanceLogic
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 5
90
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTableInfo
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
2
 startup
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
2
 validateImpl
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 executeImpl
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\App\Models\Domain\Page\Management;
6
7use Throwable;
8use PeServer\App\Models\AppConfiguration;
9use PeServer\App\Models\AuditLog;
10use PeServer\App\Models\Domain\Page\PageLogicBase;
11use PeServer\Core\Code;
12use PeServer\Core\Collection\Arr;
13use PeServer\Core\Database\DatabaseTableResult;
14use PeServer\Core\Database\IDatabaseContext;
15use PeServer\Core\Mvc\LogicCallMode;
16use PeServer\Core\Mvc\LogicParameter;
17use PeServer\Core\Mvc\Validator;
18use PeServer\Core\Regex;
19use PeServer\Core\Text;
20
21class ManagementDatabaseMaintenanceLogic extends PageLogicBase
22{
23    public function __construct(LogicParameter $parameter)
24    {
25        parent::__construct($parameter);
26    }
27
28    /**
29     * テーブル情報取得。
30     *
31     * @param IDatabaseContext $context
32     * @param array<mixed> $row
33     * @return array{name:string,sql:string,table:array{columns:array<mixed>}}
34     */
35    private function getTableInfo(IDatabaseContext $context, array $row): array
36    {
37        $name = Code::toLiteralString($row['name']);
38        $columns = $context->query(
39            "PRAGMA table_info('$name')"
40        );
41
42        //@phpstan-ignore-next-line
43        return [
44            'name' => (string)$row['name'],
45            'sql' => (string)$row['sql'],
46            'columns' => $columns->rows,
47        ];
48    }
49
50    //[PageLogicBase]
51
52    protected function startup(LogicCallMode $callMode): void
53    {
54        $this->registerParameterKeys([
55            'database_maintenance_statement',
56            'executed',
57            'result',
58            'tables',
59        ], true);
60        $this->setValue('executed', false);
61        $this->setValue('result', null);
62
63        $database = $this->openDatabase();
64        $schemas = $database->query(
65            <<<SQL
66
67            select
68                *
69            from
70                sqlite_master
71            where
72                type = 'table'
73            order by
74                name
75
76            SQL
77        );
78
79        $tables = array_map(function ($i) use ($database) {
80            return $this->getTableInfo($database, $i);
81        }, $schemas->rows);
82        $this->setValue('tables', $tables);
83    }
84
85    protected function validateImpl(LogicCallMode $callMode): void
86    {
87        if ($callMode === LogicCallMode::Initialize) {
88            return;
89        }
90
91        $this->validation('database_maintenance_statement', function (string $key, string $value) {
92            $this->validator->isNotWhiteSpace($key, $value);
93        });
94    }
95
96    protected function executeImpl(LogicCallMode $callMode): void
97    {
98        if ($callMode === LogicCallMode::Initialize) {
99            return;
100        }
101
102        $statement = $this->getRequest('database_maintenance_statement');
103
104        $database = $this->openDatabase();
105        $result = null;
106        try {
107            $database->transaction(function (IDatabaseContext $context) use (&$result, $statement) {
108                /** @phpstan-var literal-string $statement これはええねん */
109
110                $regex = new Regex();
111                if ($regex->isMatch($statement, '/^\s*\bselect\b/')) { // select だけの判定はよくないけどしんどいのだ
112                    $result = $context->query($statement);
113                } else {
114                    $result = $context->execute($statement);
115                }
116                return true;
117            });
118        } catch (Throwable $ex) {
119            $result = $ex;
120        }
121
122        $this->writeAuditLogCurrentUser(AuditLog::ADMINISTRATOR_EXECUTE_SQL, [
123            'sql' => $statement,
124            'result' => Text::dump($result),
125        ]);
126
127        $this->setValue('executed', true);
128        $this->setValue('result', $result);
129    }
130}