]> git.mxchange.org Git - friendica.git/blob - src/Database/View.php
18db875ea8ebf182ca460993213c4138616d6221
[friendica.git] / src / Database / View.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  */
21
22 namespace Friendica\Database;
23
24 use Exception;
25 use Friendica\Core\Hook;
26 use Friendica\DI;
27
28 class View
29 {
30         /**
31          * view definition loaded from static/dbview.config.php
32          *
33          * @var array
34          */
35         private static $definition = [];
36
37         /**
38          * Loads the database structure definition from the static/dbview.config.php file.
39          * On first pass, defines DB_UPDATE_VERSION constant.
40          *
41          * @see static/dbview.config.php
42          * @param string  $basePath              The base path of this application
43          * @param boolean $with_addons_structure Whether to tack on addons additional tables
44          * @return array
45          * @throws Exception
46          */
47         public static function definition(string $basePath = '', bool $with_addons_structure = true): array
48         {
49                 if (!self::$definition) {
50                         if (empty($basePath)) {
51                                 $basePath = DI::app()->getBasePath();
52                         }
53
54                         $filename = $basePath . '/static/dbview.config.php';
55
56                         if (!is_readable($filename)) {
57                                 throw new Exception('Missing database view config file static/dbview.config.php');
58                         }
59
60                         $definition = require $filename;
61
62                         if (!$definition) {
63                                 throw new Exception('Corrupted database view config file static/dbview.config.php');
64                         }
65
66                         self::$definition = $definition;
67                 } else {
68                         $definition = self::$definition;
69                 }
70
71                 if ($with_addons_structure) {
72                         Hook::callAll('dbview_definition', $definition);
73                 }
74
75                 return $definition;
76         }
77
78         /**
79          * Creates a view
80          *
81          * @param bool $verbose Whether to show SQL statements
82          * @param bool $action Whether to execute SQL statements
83          * @return void
84          */
85         public static function create(bool $verbose, bool $action)
86         {
87                 // Delete previously used views that aren't used anymore
88                 foreach(['post-view', 'post-thread-view'] as $view) {
89                         if (self::isView($view)) {
90                                 $sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($view));
91                                 if (!empty($sql) && $verbose) {
92                                         echo $sql . ";\n";
93                                 }
94                 
95                                 if (!empty($sql) && $action) {
96                                         DBA::e($sql);
97                                 }
98                         }
99                 }
100
101                 $definition = self::definition();
102
103                 foreach ($definition as $name => $structure) {
104                         self::createView($name, $structure, $verbose, $action);
105                 }
106         }
107
108         /**
109          * Prints view structure
110          *
111          * @param string $basePath Base path
112          * @return void
113          */
114         public static function printStructure(string $basePath)
115         {
116                 $database = self::definition($basePath, false);
117
118                 foreach ($database as $name => $structure) {
119                         echo "--\n";
120                         echo "-- VIEW $name\n";
121                         echo "--\n";
122                         self::createView($name, $structure, true, false);
123
124                         echo "\n";
125                 }
126         }
127
128         /**
129          * Creates view
130          *
131          * @param string $name Name of view
132          * @param array $structure Structure of view
133          * @param bool $verbose Whether to show SQL statements
134          * @param bool $action Whether to execute SQL statements
135          * @return bool Whether execution went fine
136          */
137         private static function createView(string $name, array $structure, bool $verbose, bool $action): bool
138         {
139                 $r = true;
140
141                 $sql_rows = [];
142                 foreach ($structure['fields'] as $fieldname => $origin) {
143                         if (is_string($origin)) {
144                                 $sql_rows[] = $origin . " AS `" . DBA::escape($fieldname) . "`";
145                         } elseif (is_array($origin) && (sizeof($origin) == 2)) {
146                                 $sql_rows[] = "`" . DBA::escape($origin[0]) . "`.`" . DBA::escape($origin[1]) . "` AS `" . DBA::escape($fieldname) . "`";
147                         }
148                 }
149
150                 if (self::isView($name)) {
151                         $sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name));
152                 } elseif (self::isTable($name)) {
153                         $sql = sprintf("DROP TABLE IF EXISTS `%s`", DBA::escape($name));
154                 }
155
156                 if (!empty($sql) && $verbose) {
157                         echo $sql . ";\n";
158                 }
159
160                 if (!empty($sql) && $action) {
161                         DBA::e($sql);
162                 }
163
164                 $sql = sprintf("CREATE VIEW `%s` AS SELECT \n\t", DBA::escape($name)) .
165                         implode(",\n\t", $sql_rows) . "\n\t" . $structure['query'];
166         
167                 if ($verbose) {
168                         echo $sql . ";\n";
169                 }
170
171                 if ($action) {
172                         $r = DBA::e($sql);
173                 }
174
175                 return $r;
176         }
177
178         /**
179          * Check if the given table/view is a view
180          *
181          * @param string $view
182          * @return boolean "true" if it's a view
183          */
184         private static function isView(string $view): bool
185         {
186                 $status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['TABLE_TYPE'],
187                         ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $view]);
188
189                 if (empty($status['TABLE_TYPE'])) {
190                         return false;
191                 }
192
193                 return $status['TABLE_TYPE'] == 'VIEW';
194         }
195
196         /**
197          * Check if the given table/view is a table
198          *
199          * @param string $table
200          * @return boolean "true" if it's a table
201          */
202         private static function isTable(string $table): bool
203         {
204                 $status = DBA::selectFirst('INFORMATION_SCHEMA.TABLES', ['TABLE_TYPE'],
205                         ['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $table]);
206
207                 if (empty($status['TABLE_TYPE'])) {
208                         return false;
209                 }
210
211                 return $status['TABLE_TYPE'] == 'BASE TABLE';
212         }
213 }