/** * Apply database structure updates */ public function structure() { $PM = new PermissionModel(); $PM->define(array('Plugins.PostUrl.Allow' => 'Plugins.PostUrl.Allow')); $Structure = Gdn::structure(); $Structure->table('PostUrl')->column('DiscussionID', 'int(11)', false, 'unique')->column('PostUrlValue', 'int(11)')->column('DateInserted', 'datetime')->set(false, false); }
/** * * * @return bool */ public function updateCounts() { // This option could take a while so set the timeout. set_time_limit(60 * 5); // Define the necessary SQL. $Sqls = array(); if (!$this->importExists('Discussion', 'LastCommentID')) { $Sqls['Discussion.LastCommentID'] = $this->GetCountSQL('max', 'Discussion', 'Comment'); } if (!$this->importExists('Discussion', 'DateLastComment')) { $Sqls['Discussion.DateLastComment'] = "update :_Discussion d\n left join :_Comment c\n on d.LastCommentID = c.CommentID\n set d.DateLastComment = coalesce(c.DateInserted, d.DateInserted)"; } if (!$this->importExists('Discussion', 'LastCommentUserID')) { $Sqls['Discussion.LastCommentUseID'] = "update :_Discussion d\n join :_Comment c\n on d.LastCommentID = c.CommentID\n set d.LastCommentUserID = c.InsertUserID"; } if (!$this->importExists('Discussion', 'Body')) { // Update the body of the discussion if it isn't there. if (!$this->importExists('Discussion', 'FirstCommentID')) { $Sqls['Discussion.FirstCommentID'] = $this->GetCountSQL('min', 'Discussion', 'Comment', 'FirstCommentID', 'CommentID'); } $Sqls['Discussion.Body'] = "update :_Discussion d\n join :_Comment c\n on d.FirstCommentID = c.CommentID\n set d.Body = c.Body, d.Format = c.Format"; if ($this->importExists('Media') && Gdn::structure()->TableExists('Media')) { // Comment Media has to go onto the discussion. $Sqls['Media.Foreign'] = "update :_Media m\n join :_Discussion d\n on d.FirstCommentID = m.ForeignID and m.ForeignTable = 'comment'\n set m.ForeignID = d.DiscussionID, m.ForeignTable = 'discussion'"; } $Sqls['Comment.FirstComment.Delete'] = "delete c.*\n from :_Comment c\n inner join :_Discussion d\n on d.FirstCommentID = c.CommentID"; } if (!$this->importExists('Discussion', 'CountComments')) { $Sqls['Discussion.CountComments'] = $this->GetCountSQL('count', 'Discussion', 'Comment'); } if ($this->importExists('UserDiscussion') && !$this->importExists('UserDiscussion', 'CountComments') && $this->importExists('UserDiscussion', 'DateLastViewed')) { $Sqls['UserDiscussuion.CountComments'] = "update :_UserDiscussion ud\n set CountComments = (\n select count(c.CommentID)\n from :_Comment c\n where c.DiscussionID = ud.DiscussionID\n and c.DateInserted <= ud.DateLastViewed)"; } if ($this->importExists('Tag') && $this->importExists('TagDiscussion')) { $Sqls['Tag.CoundDiscussions'] = $this->GetCountSQL('count', 'Tag', 'TagDiscussion', 'CountDiscussions', 'TagID'); } if ($this->importExists('Poll') && Gdn::structure()->TableExists('Poll')) { $Sqls['PollOption.CountVotes'] = $this->GetCountSQL('count', 'PollOption', 'PollVote', 'CountVotes', 'PollOptionID'); $Sqls['Poll.CountOptions'] = $this->GetCountSQL('count', 'Poll', 'PollOption', 'CountOptions', 'PollID'); $Sqls['Poll.CountVotes'] = $this->GetCountSQL('sum', 'Poll', 'PollOption', 'CountVotes', 'CountVotes', 'PollID'); } if ($this->importExists('Activity', 'ActivityType')) { $Sqls['Activity.ActivityTypeID'] = "\n update :_Activity a\n join :_ActivityType t\n on a.ActivityType = t.Name\n set a.ActivityTypeID = t.ActivityTypeID"; } if ($this->importExists('Tag') && $this->importExists('TagDiscussion')) { $Sqls['Tag.CoundDiscussions'] = $this->GetCountSQL('count', 'Tag', 'TagDiscussion', 'CountDiscussions', 'TagID'); } $Sqls['Category.CountDiscussions'] = $this->GetCountSQL('count', 'Category', 'Discussion'); $Sqls['Category.CountComments'] = $this->GetCountSQL('sum', 'Category', 'Discussion', 'CountComments', 'CountComments'); if (!$this->importExists('Category', 'PermissionCategoryID')) { $Sqls['Category.PermissionCategoryID'] = "update :_Category set PermissionCategoryID = -1"; } if ($this->importExists('Conversation') && $this->importExists('ConversationMessage')) { $Sqls['Conversation.FirstMessageID'] = $this->GetCountSQL('min', 'Conversation', 'ConversationMessage', 'FirstMessageID', 'MessageID'); if (!$this->importExists('Conversation', 'CountMessages')) { $Sqls['Conversation.CountMessages'] = $this->GetCountSQL('count', 'Conversation', 'ConversationMessage', 'CountMessages', 'MessageID'); } if (!$this->importExists('Conversation', 'LastMessageID')) { $Sqls['Conversation.LastMessageID'] = $this->GetCountSQL('max', 'Conversation', 'ConversationMessage', 'LastMessageID', 'MessageID'); } if (!$this->importExists('Conversation', 'DateUpdated')) { $Sqls['Converstation.DateUpdated'] = "update :_Conversation c join :_ConversationMessage m on c.LastMessageID = m.MessageID set c.DateUpdated = m.DateInserted"; } if ($this->importExists('UserConversation')) { if (!$this->importExists('UserConversation', 'LastMessageID')) { if ($this->importExists('UserConversation', 'DateLastViewed')) { // Get the value from the DateLastViewed. $Sqls['UserConversation.LastMessageID'] = "update :_UserConversation uc\n set LastMessageID = (\n select max(MessageID)\n from :_ConversationMessage m\n where m.ConversationID = uc.ConversationID\n and m.DateInserted >= uc.DateLastViewed)"; } else { // Get the value from the conversation. // In this case just mark all of the messages read. $Sqls['UserConversation.LastMessageID'] = "update :_UserConversation uc\n join :_Conversation c\n on c.ConversationID = uc.ConversationID\n set uc.CountReadMessages = c.CountMessages,\n uc.LastMessageID = c.LastMessageID"; } } elseif (!$this->importExists('UserConversation', 'DateLastViewed')) { // We have the last message so grab the date from that. $Sqls['UserConversation.DateLastViewed'] = "update :_UserConversation uc\n join :_ConversationMessage m\n on m.ConversationID = uc.ConversationID\n and m.MessageID = uc.LastMessageID\n set uc.DateLastViewed = m.DateInserted"; } } } // User counts. if (!$this->importExists('User', 'DateFirstVisit')) { $Sqls['User.DateFirstVisit'] = 'update :_User set DateFirstVisit = DateInserted'; } if (!$this->importExists('User', 'CountDiscussions')) { $Sqls['User.CountDiscussions'] = $this->GetCountSQL('count', 'User', 'Discussion', 'CountDiscussions', 'DiscussionID', 'UserID', 'InsertUserID'); } if (!$this->importExists('User', 'CountComments')) { $Sqls['User.CountComments'] = $this->GetCountSQL('count', 'User', 'Comment', 'CountComments', 'CommentID', 'UserID', 'InsertUserID'); } if (!$this->importExists('User', 'CountBookmarks')) { $Sqls['User.CountBookmarks'] = "update :_User u\n set CountBookmarks = (\n select count(ud.DiscussionID)\n from :_UserDiscussion ud\n where ud.Bookmarked = 1\n and ud.UserID = u.UserID\n )"; } // if (!$this->importExists('User', 'CountUnreadConversations')) { // $Sqls['User.CountUnreadConversations'] = // 'update :_User u // set u.CountUnreadConversations = ( // select count(c.ConversationID) // from :_Conversation c // inner join :_UserConversation uc // on c.ConversationID = uc.ConversationID // where uc.UserID = u.UserID // and uc.CountReadMessages < c.CountMessages // )'; // } // The updates start here. $CurrentSubstep = val('CurrentSubstep', $this->Data, 0); // $Sqls2 = array(); // $i = 1; // foreach ($Sqls as $Name => $Sql) { // $Sqls2[] = "/* $i. $Name */\n" // .str_replace(':_', $this->Database->DatabasePrefix, $Sql) // .";\n"; // $i++; // } // throw new Exception(implode("\n", $Sqls2)); // Execute the SQL. $Keys = array_keys($Sqls); for ($i = $CurrentSubstep; $i < count($Keys); $i++) { $this->Data['CurrentStepMessage'] = sprintf(t('%s of %s'), $CurrentSubstep + 1, count($Keys)); $Sql = $Sqls[$Keys[$i]]; $this->query($Sql); if ($this->Timer->ElapsedTime() > $this->MaxStepTime) { $this->Data['CurrentSubstep'] = $i + 1; return false; } } if (isset($this->Data['CurrentSubstep'])) { unset($this->Data['CurrentSubstep']); } $this->Data['CurrentStepMessage'] = ''; // Update the url codes of categories. if (!$this->importExists('Category', 'UrlCode')) { $Categories = CategoryModel::categories(); $TakenCodes = array(); foreach ($Categories as $Category) { $UrlCode = urldecode(Gdn_Format::url($Category['Name'])); if (strlen($UrlCode) > 50) { $UrlCode = 'c' . $Category['CategoryID']; } elseif (is_numeric($UrlCode)) { $UrlCode = 'c' . $UrlCode; } if (in_array($UrlCode, $TakenCodes)) { $ParentCategory = CategoryModel::categories($Category['ParentCategoryID']); if ($ParentCategory && $ParentCategory['CategoryID'] != -1) { $UrlCode = Gdn_Format::url($ParentCategory['Name']) . '-' . $UrlCode; } if (in_array($UrlCode, $TakenCodes)) { $UrlCode = $Category['CategoryID']; } } $TakenCodes[] = $UrlCode; Gdn::sql()->put('Category', array('UrlCode' => $UrlCode), array('CategoryID' => $Category['CategoryID'])); } } // Rebuild the category tree. $CategoryModel = new CategoryModel(); $CategoryModel->RebuildTree(); $this->SetCategoryPermissionIDs(); return true; }
/** * Database update. * * @throws Exception */ public function structure() { Gdn::structure()->table('Media')->primaryKey('MediaID')->column('Name', 'varchar(255)')->column('Type', 'varchar(128)')->column('Size', 'int(11)')->column('ImageWidth', 'usmallint', null)->column('ImageHeight', 'usmallint', null)->column('StorageMethod', 'varchar(24)', 'local')->column('Path', 'varchar(255)')->column('ThumbWidth', 'usmallint', null)->column('ThumbHeight', 'usmallint', null)->column('ThumbPath', 'varchar(255)', null)->column('InsertUserID', 'int(11)')->column('DateInserted', 'datetime')->column('ForeignID', 'int(11)', true)->column('ForeignTable', 'varchar(24)', true)->set(); Gdn::structure()->table('Category')->column('AllowFileUploads', 'tinyint(1)', '1')->set(); }
/** * Plugin structure method. * * Add 'Resolved' columns to the Discussion table. * * @return void */ public function structure() { Gdn::structure()->table('Discussion')->column('Resolved', 'int', '0')->column('DateResolved', 'datetime', true)->column('ResolvedUserID', 'int', true)->set(); }
/** * Run the structure for all addons. * * The structure runs the addons in priority order so that higher priority addons override lower priority ones. * * @param bool $captureOnly Run the structure or just capture the SQL changes. * @throws Exception Throws an exception if in debug mode and something goes wrong. */ public function runStructure($captureOnly = false) { $addons = array_reverse(Gdn::addonManager()->getEnabled()); // These variables are required for included structure files. $Database = Gdn::database(); $SQL = $this->SQL; $SQL->CaptureModifications = $captureOnly; $Structure = Gdn::structure(); $Structure->CaptureOnly = $captureOnly; /* @var Addon $addon */ foreach ($addons as $addon) { // Look for a structure file. if ($structure = $addon->getSpecial('structure')) { Logger::event('addon_structure', Logger::INFO, "Executing structure for {addonKey}.", ['addonKey' => $addon->getKey(), 'structureType' => 'file']); try { include $addon->path($structure); } catch (\Exception $ex) { if (debug()) { throw $ex; } } } // Look for a structure method on the plugin. if ($addon->getPluginClass()) { $plugin = Gdn::pluginManager()->getPluginInstance($addon->getPluginClass(), Gdn_PluginManager::ACCESS_CLASSNAME); if (is_object($plugin) && method_exists($plugin, 'structure')) { Logger::event('addon_structure', Logger::INFO, "Executing structure for {addonKey}.", ['addonKey' => $addon->getKey(), 'structureType' => 'method']); try { call_user_func([$plugin, 'structure']); } catch (\Exception $ex) { if (debug()) { throw $ex; } } } } // Register permissions. $permissions = $addon->getInfoValue('registerPermissions'); if (!empty($permissions)) { Logger::event('addon_permissions', Logger::INFO, "Defining permissions for {addonKey}.", ['addonKey' => $addon->getKey(), 'permissions' => $permissions]); Gdn::permissionModel()->define($permissions); } } $this->fireEvent('AfterStructure'); if ($captureOnly && property_exists($Structure->Database, 'CapturedSql')) { return $Structure->Database->CapturedSql; } return []; }
/** * Import a table from a CSV using SQL insert statements. * * @param string $Tablename The name of the table to import to. * @param string $Path The path to the CSV. * @param bool $skipHeader Whether the CSV contains a header row. * @param int $chunk The number of records to chunk the imports to. * @return bool */ public function loadTableInsert($Tablename, $Path, $skipHeader = true, $chunk = 100) { // Get the column count of the table. $St = Gdn::structure(); $St->get(self::TABLE_PREFIX . $Tablename); $ColumnCount = count($St->Columns()); $St->reset(); ini_set('auto_detect_line_endings', true); $fp = fopen($Path, 'rb'); // Figure out the current position. $fPosition = val('CurrentLoadPosition', $this->Data, 0); if ($fPosition == 0 && $skipHeader) { // Skip the header row. $Row = self::FGetCSV2($fp); } if ($fPosition == 0) { $Px = Gdn::database()->DatabasePrefix . self::TABLE_PREFIX; Gdn::database()->query("truncate table {$Px}{$Tablename}"); } else { fseek($fp, $fPosition); } $PDO = Gdn::database()->connection(); $PxTablename = Gdn::database()->DatabasePrefix . self::TABLE_PREFIX . $Tablename; $Inserts = ''; $Count = 0; while ($Row = self::FGetCSV2($fp)) { ++$Count; $Row = array_map('trim', $Row); // Quote the values in the row. $Row = array_map(array($PDO, 'quote'), $Row); // Add any extra columns to the row. while (count($Row) < $ColumnCount) { $Row[] = 'null'; } // Add the insert values to the sql. if (strlen($Inserts) > 0) { $Inserts .= ','; } $Inserts .= '(' . implode(',', $Row) . ')'; if ($Count >= $chunk) { // Insert in chunks. $Sql = "insert {$PxTablename} values {$Inserts}"; $this->Database->query($Sql); $Count = 0; $Inserts = ''; // Check for a timeout. if ($this->Timer->ElapsedTime() > $this->MaxStepTime) { // The step's taken too long. Save the file position. $Pos = ftell($fp); $this->Data['CurrentLoadPosition'] = $Pos; $Filesize = filesize($Path); if ($Filesize > 0) { $PercentComplete = $Pos / filesize($Path); $this->Data['CurrentStepMessage'] = $Tablename . ' (' . round($PercentComplete * 100.0) . '%)'; } fclose($fp); return 0; } } } fclose($fp); if (strlen($Inserts) > 0) { $Sql = "insert {$PxTablename} values {$Inserts}"; $this->query($Sql); } return $Count; }
/** * Runs on utility/update. * * @throws Exception */ public function structure() { // Pocket class isn't autoloaded on Enable. require_once 'library/class.pocket.php'; $St = Gdn::structure(); $St->table('Pocket')->primaryKey('PocketID')->column('Name', 'varchar(255)')->column('Page', 'varchar(50)', null)->column('Location', 'varchar(50)')->column('Sort', 'smallint')->column('Repeat', 'varchar(25)')->column('Body', 'text')->column('Format', 'varchar(20)')->column('Condition', 'varchar(500)', null)->column('Disabled', 'smallint', '0')->column('Attributes', 'text', null)->column('MobileOnly', 'tinyint', '0')->column('MobileNever', 'tinyint', '0')->column('EmbeddedNever', 'tinyint', '0')->column('ShowInDashboard', 'tinyint', '0')->column('Type', array(Pocket::TYPE_DEFAULT, Pocket::TYPE_AD), Pocket::TYPE_DEFAULT)->set(); $PermissionModel = Gdn::permissionModel(); $PermissionModel->define(array('Garden.NoAds.Allow' => 0)); }
/** * Run on utility/update. * * @throws Exception */ public function structure() { Gdn::structure()->table('Discussion')->column('DateRevived', 'datetime', true)->set(); }
if (!defined('APPLICATION')) { exit; } /** * * * @copyright 2009-2016 Vanilla Forums Inc. * @license http://www.opensource.org/licenses/gpl-2.0.php GNU GPL v2 * @package Addons * @since 2.0 */ $Drop = false; $Explicit = false; $SQL = Gdn::sql(); $Construct = Gdn::structure(); $Px = $Construct->databasePrefix(); $Construct->table('AddonType')->primaryKey('AddonTypeID')->column('Label', 'varchar(50)')->column('Visible', 'tinyint(1)', '1')->set($Explicit, $Drop); $SQL->replace('AddonType', array('Label' => 'Plugin', 'Visible' => '1'), array('AddonTypeID' => 1), true); $SQL->replace('AddonType', array('Label' => 'Theme', 'Visible' => '1'), array('AddonTypeID' => 2), true); $SQL->replace('AddonType', array('Label' => 'Style', 'Visible' => '0'), array('AddonTypeID' => 3), true); $SQL->replace('AddonType', array('Label' => 'Locale', 'Visible' => '1'), array('AddonTypeID' => 4), true); $SQL->replace('AddonType', array('Label' => 'Application', 'Visible' => '1'), array('AddonTypeID' => 5), true); $SQL->replace('AddonType', array('Label' => 'Core', 'Visible' => '1'), array('AddonTypeID' => 10), true); $Construct->table('Addon'); $Description2Exists = $Construct->columnExists('Description2'); $Construct->primaryKey('AddonID')->column('CurrentAddonVersionID', 'int', true, 'key')->column('AddonKey', 'varchar(50)', null, 'index')->column('AddonTypeID', 'int', false, 'key')->column('InsertUserID', 'int', false, 'key')->column('UpdateUserID', 'int', true)->column('Name', 'varchar(100)')->column('Icon', 'varchar(200)', true)->column('Description', 'text', true)->column('Description2', 'text', null)->column('Requirements', 'text', true)->column('CountComments', 'int', '0')->column('CountDownloads', 'int', '0')->column('Visible', 'tinyint(1)', '1')->column('Vanilla2', 'tinyint(1)', '1')->column('DateInserted', 'datetime')->column('DateUpdated', 'datetime', true)->column('Checked', 'tinyint(1)', '0')->column('Official', 'tinyint(1)', '0')->column('License', 'varchar(100)')->column('GitHub', 'varchar(100)', null)->column('EnName', 'varchar(100)', null)->column('PercentComplete', 'tinyint', null)->set($Explicit, $Drop); if (!$Description2Exists) { $Construct->query("update {$Px}Addon set Description2 = Description where Checked = 0"); } $Construct->table('AddonVersion')->primaryKey('AddonVersionID')->column('AddonID', 'int', false, 'key')->column('File', 'varchar(200)', true)->column('Version', 'varchar(20)')->column('TestedWith', 'text', null)->column('FileSize', 'int', null)->column('MD5', 'varchar(32)')->column('Notes', 'text', null)->column('Format', 'varchar(10)', 'Html')->column('InsertUserID', 'int', false, 'key')->column('DateInserted', 'datetime')->column('DateReviewed', 'datetime', true)->column('Checked', 'tinyint(1)', '0')->column('Deleted', 'tinyint(1)', '0')->set($Explicit, $Drop);
/** * Run the database structure or /utility/structure. * * Note: Keep this method protected! * * @param string $appName Unique app name or 'all' (default). * @param bool $captureOnly Whether to list changes rather than execute (0 or 1). * @throws Exception */ protected function runStructure($appName = 'all', $captureOnly = true) { // This permission is run again to be sure someone doesn't accidentally call this method incorrectly. $this->permission('Garden.Settings.Manage'); $Files = array(); $appName = $appName == '' ? 'all' : $appName; if ($appName == 'all') { // Load all application structure files. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->enabledApplications(); $AppNames = array_column($Apps, 'Folder'); foreach ($AppNames as $appName) { $Files[] = combinePaths(array(PATH_APPLICATIONS, $appName, 'settings', 'structure.php'), DS); } $appName = 'all'; } else { // Load that specific application structure file. $Files[] = combinePaths(array(PATH_APPLICATIONS, $appName, 'settings', 'structure.php'), DS); } $Drop = false; $Explicit = false; $captureOnly = !($captureOnly == '0'); $Structure = Gdn::structure(); $Structure->CaptureOnly = $captureOnly; $SQL = Gdn::sql(); $SQL->CaptureModifications = $captureOnly; $this->setData('CaptureOnly', $Structure->CaptureOnly); $this->setData('Drop', $Drop); $this->setData('Explicit', $Explicit); $this->setData('ApplicationName', $appName); $this->setData('Status', ''); $FoundStructureFile = false; foreach ($Files as $File) { if (file_exists($File)) { $FoundStructureFile = true; try { include $File; } catch (Exception $Ex) { $this->Form->addError($Ex); } } } // Run the structure of all of the plugins. $Plugins = Gdn::pluginManager()->enabledPlugins(); foreach ($Plugins as $PluginKey => $Plugin) { $PluginInstance = Gdn::pluginManager()->getPluginInstance($PluginKey, Gdn_PluginManager::ACCESS_PLUGINNAME); if (method_exists($PluginInstance, 'Structure')) { $PluginInstance->structure(); } } if (property_exists($Structure->Database, 'CapturedSql')) { $this->setData('CapturedSql', (array) $Structure->Database->CapturedSql); } else { $this->setData('CapturedSql', array()); } if ($this->Form->errorCount() == 0 && !$captureOnly && $FoundStructureFile) { $this->setData('Status', 'The structure was successfully executed.'); } }
/** * Update database structure based on current definitions in each app's structure.php file. * * @since 2.0.? * @access public * @param string $AppName Unique app name or 'all' (default). * @param int $CaptureOnly Whether to list changes rather than execture (0 or 1). * @param int $Drop Whether to drop first (0 or 1). * @param int $Explicit Whether to force to only columns currently listed (0 or 1). */ public function structure($AppName = 'all', $CaptureOnly = '1', $Drop = '0', $Explicit = '0') { $this->permission('Garden.Settings.Manage'); $Files = array(); $AppName = $AppName == '' ? 'all' : $AppName; if ($AppName == 'all') { // Load all application structure files. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->enabledApplications(); $AppNames = array_column($Apps, 'Folder'); foreach ($AppNames as $AppName) { $Files[] = combinePaths(array(PATH_APPLICATIONS, $AppName, 'settings', 'structure.php'), DS); } $AppName = 'all'; } else { // Load that specific application structure file. $Files[] = combinePaths(array(PATH_APPLICATIONS, $AppName, 'settings', 'structure.php'), DS); } $Validation = new Gdn_Validation(); $Database = Gdn::database(); $Drop = $Drop == '0' ? false : true; $Explicit = $Explicit == '0' ? false : true; $CaptureOnly = !($CaptureOnly == '0'); $Structure = Gdn::structure(); $Structure->CaptureOnly = $CaptureOnly; $SQL = Gdn::sql(); $SQL->CaptureModifications = $CaptureOnly; $this->setData('CaptureOnly', $Structure->CaptureOnly); $this->setData('Drop', $Drop); $this->setData('Explicit', $Explicit); $this->setData('ApplicationName', $AppName); $this->setData('Status', ''); $FoundStructureFile = false; foreach ($Files as $File) { if (file_exists($File)) { $FoundStructureFile = true; try { include $File; } catch (Exception $Ex) { $this->Form->addError($Ex); } } } // Run the structure of all of the plugins. $Plugins = Gdn::pluginManager()->enabledPlugins(); foreach ($Plugins as $PluginKey => $Plugin) { $PluginInstance = Gdn::pluginManager()->getPluginInstance($PluginKey, Gdn_PluginManager::ACCESS_PLUGINNAME); if (method_exists($PluginInstance, 'Structure')) { $PluginInstance->structure(); } } if (property_exists($Structure->Database, 'CapturedSql')) { $this->setData('CapturedSql', (array) $Structure->Database->CapturedSql); } else { $this->setData('CapturedSql', array()); } if ($this->Form->errorCount() == 0 && !$CaptureOnly && $FoundStructureFile) { $this->setData('Status', 'The structure was successfully executed.'); } $this->addSideMenu('dashboard/settings/configure'); $this->addCssFile('admin.css'); $this->setData('Title', t('Database Structure Upgrades')); $this->render(); }
/** * Database structure: on update */ public function structure() { Gdn::structure()->table('User')->column('Troll', 'int', '0')->column('Fingerprint', 'varchar(50)', null, 'index')->set(); }
} // Define 'Answer' badges if (Gdn::addonManager()->isEnabled('badges', \Vanilla\Addon::TYPE_ADDON) && c('Plugins.QnA.Badges', true)) { $this->Badges = true; } if ($this->Badges && class_exists('BadgeModel')) { $BadgeModel = new BadgeModel(); // Answer Counts $BadgeModel->define(array('Name' => 'First Answer', 'Slug' => 'answer', 'Type' => 'UserCount', 'Body' => 'Answering questions is a great way to show your support for a community!', 'Photo' => 'http://badges.vni.la/100/answer.png', 'Points' => 2, 'Attributes' => array('Column' => 'CountAcceptedAnswers'), 'Threshold' => 1, 'Class' => 'Answerer', 'Level' => 1, 'CanDelete' => 0)); $BadgeModel->define(array('Name' => '5 Answers', 'Slug' => 'answer-5', 'Type' => 'UserCount', 'Body' => 'Your willingness to share knowledge has definitely been noticed.', 'Photo' => 'http://badges.vni.la/100/answer-2.png', 'Points' => 3, 'Attributes' => array('Column' => 'CountAcceptedAnswers'), 'Threshold' => 5, 'Class' => 'Answerer', 'Level' => 2, 'CanDelete' => 0)); $BadgeModel->define(array('Name' => '25 Answers', 'Slug' => 'answer-25', 'Type' => 'UserCount', 'Body' => 'Looks like you’re starting to make a name for yourself as someone who knows the score!', 'Photo' => 'http://badges.vni.la/100/answer-3.png', 'Points' => 5, 'Attributes' => array('Column' => 'CountAcceptedAnswers'), 'Threshold' => 25, 'Class' => 'Answerer', 'Level' => 3, 'CanDelete' => 0)); $BadgeModel->define(array('Name' => '50 Answers', 'Slug' => 'answer-50', 'Type' => 'UserCount', 'Body' => 'Why use Google when we could just ask you?', 'Photo' => 'http://badges.vni.la/100/answer-4.png', 'Points' => 10, 'Attributes' => array('Column' => 'CountAcceptedAnswers'), 'Threshold' => 50, 'Class' => 'Answerer', 'Level' => 4, 'CanDelete' => 0)); $BadgeModel->define(array('Name' => '100 Answers', 'Slug' => 'answer-100', 'Type' => 'UserCount', 'Body' => 'Admit it, you read Wikipedia in your spare time.', 'Photo' => 'http://badges.vni.la/100/answer-5.png', 'Points' => 15, 'Attributes' => array('Column' => 'CountAcceptedAnswers'), 'Threshold' => 100, 'Class' => 'Answerer', 'Level' => 5, 'CanDelete' => 0)); $BadgeModel->define(array('Name' => '250 Answers', 'Slug' => 'answer-250', 'Type' => 'UserCount', 'Body' => 'Is there *anything* you don’t know?', 'Photo' => 'http://badges.vni.la/100/answer-6.png', 'Points' => 20, 'Attributes' => array('Column' => 'CountAcceptedAnswers'), 'Threshold' => 250, 'Class' => 'Answerer', 'Level' => 6, 'CanDelete' => 0)); } // Define 'Accept' reaction if (Gdn::addonManager()->isEnabled('Reactions', \Vanilla\Addon::TYPE_ADDON) && c('Plugins.QnA.Reactions', true)) { $this->Reactions = true; } if ($this->Reactions && class_exists('ReactionModel')) { $Rm = new ReactionModel(); if (Gdn::structure()->table('ReactionType')->columnExists('Hidden')) { $points = 3; if (c('QnA.Points.Enabled', false)) { $points = c('QnA.Points.AcceptedAnswer', 1); } // AcceptAnswer $Rm->defineReactionType(['UrlCode' => 'AcceptAnswer', 'Name' => 'Accept Answer', 'Sort' => 0, 'Class' => 'Positive', 'IncrementColumn' => 'Score', 'IncrementValue' => 5, 'Points' => $points, 'Permission' => 'Garden.Curation.Manage', 'Hidden' => 1, 'Description' => "When someone correctly answers a question, they are rewarded with this reaction."]); } Gdn::structure()->reset(); }
<?php if (!defined('APPLICATION')) { exit; } Gdn::structure()->table('Newsletter')->primaryKey('NewsletterID')->column('Email', 'varchar(200)', null)->column('Subscribe', 'tinyint(1)', '0')->column('DateInserted', 'datetime')->set(); Gdn::structure()->table('User')->column('Newsletter', 'tinyint(1)', '0')->column('DateContributorAgreement', 'datetime', true)->set();
public function structure() { $Structure = Gdn::structure(); $Structure->table('Discussion')->column('DiscussionEventDate', 'date', true, 'index')->set(); $Structure->table('Discussion')->column('DiscussionEventGuests', 'varchar(65535)', true, 'index')->set(); }
<?php if (!defined('APPLICATION')) { exit; } Gdn::structure()->table('Sprint')->primaryKey('SprintID')->column('DateStarted', 'datetime', true)->column('DateEnded', 'datetime', true)->set(); Gdn::structure()->table('SprintIssue')->primaryKey('SprintIssueID')->column('Name', 'varchar(100)', false)->column('InsertUserID', 'int', false)->column('CloseUserID', 'int', true)->column('DateInserted', 'datetime', false)->column('DateClosed', 'datetime', true)->set(); Gdn::structure()->table('SprintPR')->primaryKey('SprintPRID')->column('Name', 'varchar(100)', false)->column('Branch', 'varchar(100)', false)->column('InsertUserID', 'int', false)->column('UpdateUserID', 'int', true)->column('CloseUserID', 'int', true)->column('MergeUserID', 'int', true)->column('DateInserted', 'datetime', false)->column('DateUpdated', 'datetime', true)->column('DateMerged', 'datetime', true)->column('DateClosed', 'datetime', true)->set();
/** * * * @param null $AddonCode * @param bool $Explicit * @param bool $Drop * @throws Exception */ public function runStructure($AddonCode = null, $Explicit = false, $Drop = false) { // Get the structure files for all of the enabled applications. $ApplicationManager = new Gdn_ApplicationManager(); $Apps = $ApplicationManager->EnabledApplications(); $AppNames = consolidateArrayValuesByKey($Apps, 'Folder'); $Paths = array(); foreach ($Apps as $Key => $AppInfo) { $Path = PATH_APPLICATIONS . "/{$AppInfo['Folder']}/settings/structure.php"; if (file_exists($Path)) { $Paths[] = $Path; } Gdn::ApplicationManager()->RegisterPermissions($Key, $this->Validation); } // Execute the structures. $Database = Gdn::database(); $SQL = Gdn::sql(); $Structure = Gdn::structure(); foreach ($Paths as $Path) { include $Path; } // Execute the structures for all of the plugins. $PluginManager = Gdn::pluginManager(); $Registered = $PluginManager->RegisteredPlugins(); foreach ($Registered as $ClassName => $Enabled) { if (!$Enabled) { continue; } try { $Plugin = $PluginManager->GetPluginInstance($ClassName, Gdn_PluginManager::ACCESS_CLASSNAME); if (method_exists($Plugin, 'Structure')) { trace("{$ClassName}->Structure()"); $Plugin->Structure(); } } catch (Exception $Ex) { // Do nothing, plugin wouldn't load/structure. if (Debug()) { throw $Ex; } } } $this->fireEvent('AfterStructure'); }
/** * Database changes needed for this plugin. */ public function structure() { $Structure = Gdn::structure(); $Structure->table('Flag')->column('DiscussionID', 'int(11)', true)->column('InsertUserID', 'int(11)', false, 'key')->column('InsertName', 'varchar(64)')->column('AuthorID', 'int(11)')->column('AuthorName', 'varchar(64)')->column('ForeignURL', 'varchar(255)', false, 'key')->column('ForeignID', 'int(11)')->column('ForeignType', 'varchar(32)')->column('Comment', 'text')->column('DateInserted', 'datetime')->set(false, false); // Turn off disabled Flagging plugin (deprecated) if (c('Plugins.Flagging.Enabled', null) === false) { removeFromConfig('EnabledPlugins.Flagging'); } }
/** * * * @throws Exception */ public function structure() { // Set to false by default, so change in config if uploads allowed. touchConfig('Garden.AllowFileUploads', true); $Structure = Gdn::structure(); $Structure->table('Category')->column('AllowFileUploads', 'tinyint(1)', '1')->set(); }
/** * Run the database structure or /utility/structure. * * Note: Keep this method private! * * @param bool $captureOnly Whether to list changes rather than execute. * @throws Exception Throws an exception if there was an error in the structure process. */ private function runStructure($captureOnly = true) { // This permission is run again to be sure someone doesn't accidentally call this method incorrectly. $this->permission('Garden.Settings.Manage'); $updateModel = new UpdateModel(); $capturedSql = $updateModel->runStructure($captureOnly); $this->setData('CapturedSql', $capturedSql); $issues = Gdn::structure()->getIssues(); if ($this->Form->errorCount() == 0 && !$captureOnly) { if (empty($issues)) { $this->setData('Status', 'The structure was successfully executed.'); } else { $this->setData('Status', 'The structure completed with issues.'); } } $this->setData('Issues', $issues); }