2020-04-23 08:19:44 +02:00
|
|
|
<?php
|
|
|
|
/**
|
2021-03-29 08:40:20 +02:00
|
|
|
* @copyright Copyright (C) 2010-2021, the Friendica project
|
2020-04-23 08:19:44 +02:00
|
|
|
*
|
|
|
|
* @license GNU AGPL version 3 or any later version
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Friendica\Database;
|
|
|
|
|
|
|
|
use Exception;
|
|
|
|
use Friendica\Core\Hook;
|
|
|
|
use Friendica\DI;
|
|
|
|
|
2020-04-24 10:48:34 +02:00
|
|
|
class View
|
2020-04-23 08:19:44 +02:00
|
|
|
{
|
|
|
|
/**
|
2020-04-26 18:20:17 +02:00
|
|
|
* view definition loaded from static/dbview.config.php
|
2020-04-23 08:19:44 +02:00
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
private static $definition = [];
|
|
|
|
|
|
|
|
/**
|
2020-04-25 20:36:58 +02:00
|
|
|
* Loads the database structure definition from the static/dbview.config.php file.
|
2020-04-23 08:19:44 +02:00
|
|
|
* On first pass, defines DB_UPDATE_VERSION constant.
|
|
|
|
*
|
|
|
|
* @see static/dbview.config.php
|
|
|
|
* @param boolean $with_addons_structure Whether to tack on addons additional tables
|
|
|
|
* @param string $basePath The base path of this application
|
|
|
|
* @return array
|
|
|
|
* @throws Exception
|
|
|
|
*/
|
|
|
|
public static function definition($basePath = '', $with_addons_structure = true)
|
|
|
|
{
|
|
|
|
if (!self::$definition) {
|
|
|
|
if (empty($basePath)) {
|
|
|
|
$basePath = DI::app()->getBasePath();
|
|
|
|
}
|
|
|
|
|
|
|
|
$filename = $basePath . '/static/dbview.config.php';
|
|
|
|
|
|
|
|
if (!is_readable($filename)) {
|
|
|
|
throw new Exception('Missing database view config file static/dbview.config.php');
|
|
|
|
}
|
|
|
|
|
|
|
|
$definition = require $filename;
|
|
|
|
|
|
|
|
if (!$definition) {
|
|
|
|
throw new Exception('Corrupted database view config file static/dbview.config.php');
|
|
|
|
}
|
|
|
|
|
|
|
|
self::$definition = $definition;
|
|
|
|
} else {
|
|
|
|
$definition = self::$definition;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($with_addons_structure) {
|
|
|
|
Hook::callAll('dbview_definition', $definition);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $definition;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function create(bool $verbose, bool $action)
|
|
|
|
{
|
2021-03-04 01:02:34 +01:00
|
|
|
// Delete previously used views that aren't used anymore
|
|
|
|
foreach(['post-view', 'post-thread-view'] as $view) {
|
|
|
|
if (self::isView($view)) {
|
|
|
|
$sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($view));
|
|
|
|
if (!empty($sql) && $verbose) {
|
|
|
|
echo $sql . ";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!empty($sql) && $action) {
|
|
|
|
DBA::e($sql);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-23 08:19:44 +02:00
|
|
|
$definition = self::definition();
|
|
|
|
|
|
|
|
foreach ($definition as $name => $structure) {
|
|
|
|
self::createview($name, $structure, $verbose, $action);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function printStructure($basePath)
|
|
|
|
{
|
|
|
|
$database = self::definition($basePath, false);
|
|
|
|
|
2021-10-03 12:34:41 +02:00
|
|
|
foreach ($database as $name => $structure) {
|
2020-04-23 08:19:44 +02:00
|
|
|
echo "--\n";
|
|
|
|
echo "-- VIEW $name\n";
|
|
|
|
echo "--\n";
|
|
|
|
self::createView($name, $structure, true, false);
|
|
|
|
|
|
|
|
echo "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static function createview($name, $structure, $verbose, $action)
|
|
|
|
{
|
|
|
|
$r = true;
|
|
|
|
|
|
|
|
$sql_rows = [];
|
2021-10-03 12:34:41 +02:00
|
|
|
foreach ($structure["fields"] as $fieldname => $origin) {
|
2020-04-23 09:02:18 +02:00
|
|
|
if (is_string($origin)) {
|
|
|
|
$sql_rows[] = $origin . " AS `" . DBA::escape($fieldname) . "`";
|
|
|
|
} elseif (is_array($origin) && (sizeof($origin) == 2)) {
|
|
|
|
$sql_rows[] = "`" . DBA::escape($origin[0]) . "`.`" . DBA::escape($origin[1]) . "` AS `" . DBA::escape($fieldname) . "`";
|
|
|
|
}
|
2020-04-23 08:19:44 +02:00
|
|
|
}
|
|
|
|
|
2020-11-29 20:06:43 +01:00
|
|
|
if (self::isView($name)) {
|
2020-12-02 09:50:45 +01:00
|
|
|
$sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name));
|
2020-11-29 20:06:43 +01:00
|
|
|
} elseif (self::isTable($name)) {
|
2020-12-02 09:50:45 +01:00
|
|
|
$sql = sprintf("DROP TABLE IF EXISTS `%s`", DBA::escape($name));
|
2020-11-29 20:06:43 +01:00
|
|
|
}
|
2020-04-23 08:19:44 +02:00
|
|
|
|
2020-12-26 19:51:36 +01:00
|
|
|
if (!empty($sql) && $verbose) {
|
2020-04-23 08:19:44 +02:00
|
|
|
echo $sql . ";\n";
|
|
|
|
}
|
|
|
|
|
2020-12-26 19:51:36 +01:00
|
|
|
if (!empty($sql) && $action) {
|
2020-04-23 08:19:44 +02:00
|
|
|
DBA::e($sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
$sql = sprintf("CREATE VIEW `%s` AS SELECT \n\t", DBA::escape($name)) .
|
|
|
|
implode(",\n\t", $sql_rows) . "\n\t" . $structure['query'];
|
|
|
|
|
|
|
|
if ($verbose) {
|
|
|
|
echo $sql . ";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($action) {
|
|
|
|
$r = DBA::e($sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $r;
|
|
|
|
}
|
2020-11-29 20:06:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the given table/view is a view
|
|
|
|
*
|
|
|
|
* @param string $view
|
|
|
|
* @return boolean "true" if it's a view
|
|
|
|
*/
|
|
|
|
private static function isView(string $view)
|
|
|
|
{
|
|
|
|
$status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_TYPE'],
|
|
|
|
['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $view]);
|
|
|
|
|
|
|
|
if (empty($status['TABLE_TYPE'])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $status['TABLE_TYPE'] == 'VIEW';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-12-20 15:01:46 +01:00
|
|
|
* Check if the given table/view is a table
|
2020-11-29 20:06:43 +01:00
|
|
|
*
|
|
|
|
* @param string $table
|
|
|
|
* @return boolean "true" if it's a table
|
|
|
|
*/
|
|
|
|
private static function isTable(string $table)
|
|
|
|
{
|
|
|
|
$status = DBA::selectFirst(['INFORMATION_SCHEMA' => 'TABLES'], ['TABLE_TYPE'],
|
|
|
|
['TABLE_SCHEMA' => DBA::databaseName(), 'TABLE_NAME' => $table]);
|
|
|
|
|
2020-11-29 21:59:24 +01:00
|
|
|
if (empty($status['TABLE_TYPE'])) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-11-29 20:06:43 +01:00
|
|
|
|
2020-11-29 21:59:24 +01:00
|
|
|
return $status['TABLE_TYPE'] == 'BASE TABLE';
|
2020-11-29 20:06:43 +01:00
|
|
|
}
|
2020-04-23 08:19:44 +02:00
|
|
|
}
|