diff --git a/database.sql b/database.sql index d7772920d8..9f4cee0528 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2020.06-dev (Red Hot Poker) --- DB_UPDATE_VERSION 1338 +-- DB_UPDATE_VERSION 1340 -- ------------------------------------------ @@ -1175,6 +1175,31 @@ CREATE TABLE IF NOT EXISTS `term` ( INDEX `guid` (`guid`(64)) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='item taxonomy (categories, tags, etc.) table'; +-- +-- TABLE tag +-- +CREATE TABLE IF NOT EXISTS `tag` ( + `id` int unsigned NOT NULL auto_increment COMMENT '', + `name` varchar(96) NOT NULL DEFAULT '' COMMENT '', + `url` varbinary(255) NOT NULL DEFAULT '' COMMENT '', + PRIMARY KEY(`id`), + UNIQUE INDEX `type_name_url` (`name`,`url`), + INDEX `url` (`url`) +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='tags and mentions'; + +-- +-- TABLE post-tag +-- +CREATE TABLE IF NOT EXISTS `post-tag` ( + `uri-id` int unsigned NOT NULL COMMENT 'Id of the item-uri table entry that contains the item uri', + `type` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', + `tid` int unsigned NOT NULL DEFAULT 0 COMMENT '', + `cid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Contact id of the mentioned public contact', + PRIMARY KEY(`uri-id`,`type`,`tid`,`cid`), + INDEX `uri-id` (`tid`), + INDEX `cid` (`tid`) +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='post relation to tags'; + -- -- TABLE thread -- @@ -1361,4 +1386,22 @@ CREATE TABLE IF NOT EXISTS `storage` ( PRIMARY KEY(`id`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Data stored by Database storage backend'; +-- +-- VIEW tag-view +-- +DROP VIEW IF EXISTS `tag-view`; +CREATE VIEW `tag-view` AS SELECT + `post-tag`.`uri-id` AS `uri-id`, + `item-uri`.`uri` AS `uri`, + `item-uri`.`guid` AS `guid`, + `post-tag`.`type` AS `type`, + `post-tag`.`tid` AS `tid`, + `post-tag`.`cid` AS `cid`, + CASE `cid` WHEN 0 THEN `tag`.`name` ELSE `contact`.`name` END AS `name`, + CASE `cid` WHEN 0 THEN `tag`.`url` ELSE `contact`.`url` END AS `url` + FROM `post-tag` + INNER JOIN `item-uri` ON `item-uri`.id = `post-tag`.`uri-id` + LEFT JOIN `tag` ON `post-tag`.`tid` = `tag`.`id` + LEFT JOIN `contact` ON `post-tag`.`cid` = `contact`.`id`; + diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php index 6fe4d614d8..372e3c496f 100644 --- a/src/Database/DBStructure.php +++ b/src/Database/DBStructure.php @@ -112,6 +112,8 @@ class DBStructure echo "\n"; } + + DBView::printStructure($basePath); } /** @@ -594,6 +596,8 @@ class DBStructure } } + DBView::create($verbose, $action); + if ($action && !$install) { DI::config()->set('system', 'maintenance', 0); DI::config()->set('system', 'maintenance_reason', ''); diff --git a/src/Database/DBView.php b/src/Database/DBView.php new file mode 100644 index 0000000000..f23ab152ee --- /dev/null +++ b/src/Database/DBView.php @@ -0,0 +1,138 @@ +. + * + */ + +namespace Friendica\Database; + +use Exception; +use Friendica\Core\Hook; +use Friendica\Core\Logger; +use Friendica\DI; +use Friendica\Util\DateTimeFormat; +use phpDocumentor\Reflection\Types\Boolean; + +require_once __DIR__ . '/../../include/dba.php'; + +class DBView +{ + /** + * view definition loaded from config/dbview.config.php + * + * @var array + */ + private static $definition = []; + + /** + * Loads the database structure definition from the config/dbview.config.php file. + * 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) + { + $definition = self::definition(); + + foreach ($definition as $name => $structure) { + self::createview($name, $structure, $verbose, $action); + } + } + + public static function printStructure($basePath) + { + $database = self::definition($basePath, false); + + foreach ($database AS $name => $structure) { + 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 = []; + foreach ($structure["fields"] AS $fieldname => $origin) { + $sql_rows[] = $origin . " AS `" . DBA::escape($fieldname) . "`"; + } + + $sql = sprintf("DROP VIEW IF EXISTS `%s`", DBA::escape($name)); + + if ($verbose) { + echo $sql . ";\n"; + } + + if ($action) { + 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; + } +} diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index 4eabe2d37b..50055f62ae 100755 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -51,7 +51,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1339); + define('DB_UPDATE_VERSION', 1340); } return [ diff --git a/static/dbview.config.php b/static/dbview.config.php new file mode 100755 index 0000000000..6bc327697a --- /dev/null +++ b/static/dbview.config.php @@ -0,0 +1,56 @@ +. + * + * Main view structure configuration file. + * + * Here are described all the view Friendica needs to work. + * + * Syntax (braces indicate optionale values): + * "" => [ + * "fields" => [ + * "" => "`table`.`field`", + * "" => "`other-table`.`field`", + * "" => "SQL expression", + * ... + * ], + * "query" => "FROM `table` INNER JOIN `other-table` ..." + * ], + * ], + * + * If you need to make any change, make sure to increment the DB_UPDATE_VERSION constant value in dbstructure.config.php. + * + */ + +return [ + "tag-view" => [ + "fields" => ["uri-id" => "`post-tag`.`uri-id`", + "uri" => "`item-uri`.`uri`", + "guid" => "`item-uri`.`guid`", + "type" => "`post-tag`.`type`", + "tid" => "`post-tag`.`tid`", + "cid" => "`post-tag`.`cid`", + "name" => "CASE `cid` WHEN 0 THEN `tag`.`name` ELSE `contact`.`name` END", + "url" => "CASE `cid` WHEN 0 THEN `tag`.`url` ELSE `contact`.`url` END"], + "query" => "FROM `post-tag` + INNER JOIN `item-uri` ON `item-uri`.id = `post-tag`.`uri-id` + LEFT JOIN `tag` ON `post-tag`.`tid` = `tag`.`id` + LEFT JOIN `contact` ON `post-tag`.`cid` = `contact`.`id`" + ] +]; +