<?php
/**
* @brief Databases Model
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage Content
* @since 31 March 2014
*/
namespace IPS\cms;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
/**
* @brief Databases Model
*/
class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons = array();
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'database_';
/**
* @brief [ActiveRecord] ID Database Table
*/
public static $databaseTable = 'cms_databases';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array( 'database_key', 'database_page_id' );
/**
* @brief [ActiveRecord] Multiton Map
*/
protected static $multitonMap = array();
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnOrder = 'id';
/**
* @brief [Node] Sortable?
*/
public static $nodeSortable = FALSE;
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = '';
/**
* @brief Have fetched all?
*/
protected static $gotAll = FALSE;
/**
* @brief The map of permission columns
*/
public static $permissionMap = array(
'view' => 'view',
'read' => 2,
'add' => 3,
'edit' => 4,
'reply' => 5,
'review' => 7,
'rate' => 6
);
/**
* @brief [Node] App for permission index
*/
public static $permApp = 'cms';
/**
* @brief [Node] Type for permission index
*/
public static $permType = 'databases';
/**
* @brief [Node] Prefix string that is automatically prepended to permission matrix language strings
*/
public static $permissionLangPrefix = 'perm_content_';
/**
* @brief [Node] Show forms modally?
*/
public static $modalForms = FALSE;
/**
* [Brief] Bump on edit only
*/
const BUMP_ON_EDIT = 1;
/**
* [Brief] Bump on comment only
*/
const BUMP_ON_COMMENT = 2;
/**
* [Brief] Bump on edit only
*/
const CATEGORY_VIEW_CATEGORIES = 0;
/**
* [Brief] Bump on comment only
*/
const CATEGORY_VIEW_FEATURED = 1;
/**
* [Brief] Database template groups
*/
public static $templateGroups = array(
'categories' => 'category_index',
'featured' => 'category_articles',
'listing' => 'listing',
'display' => 'display',
'form' => 'form'
);
/**
* @brief Bitwise values for database_options field
*/
public static $bitOptions = array(
'options' => array(
'options' => array(
'comments' => 1, // Enable comments?
'reviews' => 2, // Enable reviews?
'comments_mod' => 4, // Enable comment moderation?
'reviews_mod' => 8, // Enable reviews moderation?
'indefinite_own_edit' => 16, // Enable authors to indefinitely edit their own articles
)
)
);
/**
* @brief Page title
*/
protected static $pageTitle = NULL;
/**
* Return all databases
*
* @return array
*/
public static function databases()
{
if ( ! static::$gotAll )
{
/* Avoid using SHOW TABLES LIKE / checkForTable() */
try
{
foreach( static::getDatabaseDataFromStore() as $db )
{
$id = $db[ static::$databasePrefix . static::$databaseColumnId ];
static::$multitons[ $id ] = static::constructFromData( $db );
}
}
catch( \Exception $e ) { }
static::$gotAll = true;
}
return static::$multitons;
}
/**
* Returns database data from the store
*
* @return array
*/
public static function getDatabaseDataFromStore()
{
if ( ! isset( \IPS\Data\Store::i()->cms_databases ) )
{
\IPS\Data\Store::i()->cms_databases = iterator_to_array(
\IPS\Db::i()->select(
static::$databaseTable . '.*, core_permission_index.perm_id, core_permission_index.perm_view, core_permission_index.perm_2, core_permission_index.perm_3, core_permission_index.perm_4, core_permission_index.perm_5, core_permission_index.perm_6, core_permission_index.perm_7',
static::$databaseTable
)->join(
'core_permission_index',
array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id=" . static::$databaseTable . "." . static::$databasePrefix . static::$databaseColumnId, static::$permApp, static::$permType )
)
->setKeyField('database_id')
);
}
return \IPS\Data\Store::i()->cms_databases;
}
/**
* Can we promote stuff to Pages?
*
* @return boolean
*/
public static function canPromote()
{
return TRUE;
}
/**
* Construct ActiveRecord from database row
*
* @param array $data Row from database table
* @param bool $updateMultitonStoreIfExists Replace current object in multiton store if it already exists there?
* @return static
*/
public static function constructFromData( $data, $updateMultitonStoreIfExists = TRUE )
{
$obj = parent::constructFromData( $data, $updateMultitonStoreIfExists );
$obj->preLoadWords();
return $obj;
}
/**
* Return data for the ACP Menu
*
* @return array
*/
public static function acpMenu()
{
$menu = array();
foreach(
\IPS\Db::i()->select( '*, core_sys_lang_words.word_custom as database_name', 'cms_databases', NULL, 'core_sys_lang_words.word_custom' )->join(
'core_sys_lang_words', "core_sys_lang_words.word_key=CONCAT( 'content_db_', cms_databases.database_id ) AND core_sys_lang_words.lang_id=" . \IPS\Member::loggedIn()->language()->id
)
as $row )
{
$menu[] = array(
'id' => $row['database_id'],
'title' => $row['database_name'],
'use_categories' => $row['database_use_categories']
);
}
return $menu;
}
/**
* Checks and fixes existing DB
*
* @param int $id Database ID
* @return int $fixes Number of fixes made (0 if none)
*
* @throws \OutOfRangeException
*/
public static function checkandFixDatabaseSchema( $id )
{
$fixes = 0;
$json = json_decode( @file_get_contents( \IPS\ROOT_PATH . "/applications/cms/data/databaseschema.json" ), true );
$table = $json['cms_custom_database_1'];
$tableName = 'cms_custom_database_' . $id;
if ( ! \IPS\Db::i()->checkForTable( $tableName ) )
{
throw new \OutOfRangeException;
}
$schema = \IPS\Db::i()->getTableDefinition( $tableName );
$changes = array();
/* Colums */
foreach( $table['columns'] as $key => $data )
{
if ( ! isset( $schema['columns'][ $key ] ) )
{
$changes[] = "ADD COLUMN " . \IPS\Db::i()->compileColumnDefinition( $data );
$fixes++;
}
}
/* Indexes */
foreach( $table['indexes'] as $key => $data )
{
/* No index */
if ( ! isset( $schema['indexes'][ $key ] ) )
{
$changes[] = \IPS\Db::i()->buildIndex( $tableName, $data );
$fixes++;
}
else if ( implode( '.', $data['columns'] ) != implode( '.', $schema['indexes'][ $key ]['columns'] ) )
{
/* Check columns */
if( $key == 'PRIMARY KEY' )
{
$changes[] = "DROP PRIMARY KEY";
}
else
{
$changes[] = "DROP " . \IPS\Db::i()->escape_string( $key );
}
$changes[] = \IPS\Db::i()->buildIndex( $tableName, $data );
$fixes++;
}
}
/* We collect all the changes so we can run one database query instead of, potentially, dozens */
if( count( $changes ) )
{
\IPS\Db::i()->query( "ALTER TABLE " . \IPS\Db::i()->prefix . $tableName . " " . implode( ', ', $changes ) );
}
return $fixes;
}
/**
* Create a new database
*
* @param \IPS\cms\Databases $database ID of database to create
* @return void
*/
public static function createDatabase( $database )
{
$json = json_decode( @file_get_contents( \IPS\ROOT_PATH . "/applications/cms/data/databaseschema.json" ), true );
$table = $json['cms_custom_database_1'];
$table['name'] = 'cms_custom_database_' . $database->id;
foreach( $table['columns'] as $name => $data )
{
if ( mb_substr( $name, 0, 6 ) === 'field_' )
{
unset( $table['columns'][ $name ] );
}
}
foreach( $table['indexes'] as $name => $data )
{
if ( mb_substr( $name, 0, 6 ) === 'field_' )
{
unset( $table['indexes'][ $name ] );
}
}
try
{
if ( ! \IPS\Db::i()->checkForTable( $table['name'] ) )
{
\IPS\Db::i()->createTable( $table );
}
}
catch( \IPS\Db\Exception $ex )
{
throw new \LogicException( $ex );
}
/* Populate default custom fields */
$fieldsClass = 'IPS\cms\Fields' . $database->id;
$fieldTitle = array();
$fieldContent = array();
$catTitle = array();
$catDesc = array();
foreach( \IPS\Lang::languages() as $id => $lang )
{
/* Try to get the actual database noun if it has been created */
try
{
$title = $lang->get( 'content_db_lang_pu_' . $database->id );
}
catch( \Exception $e )
{
$title = $lang->get('content_database_noun_pu');
}
$fieldTitle[ $id ] = $lang->get('content_fields_is_title');
$fieldContent[ $id ] = $lang->get('content_fields_is_content');
$catTitle[ $id ] = $title;
$catDesc[ $id ] = '';
}
/* Title */
$titleField = new $fieldsClass;
$titleField->saveForm( $titleField->formatFormValues( array(
'field_title' => $fieldTitle,
'field_type' => 'Text',
'field_key' => 'titlefield_' . $database->id,
'field_required' => 1,
'field_user_editable' => 1,
'field_display_listing' => 1,
'field_display_display' => 1,
'field_is_searchable' => 1,
'field_max_length' => 255
) ) );
$database->field_title = $titleField->id;
$perms = $titleField->permissions();
\IPS\Db::i()->update( 'core_permission_index', array(
'perm_view' => '*',
'perm_2' => '*',
'perm_3' => '*'
), array( 'perm_id=?', $perms['perm_id']) );
/* Content */
$contentField = new $fieldsClass;
$contentField->saveForm( $contentField->formatFormValues( array(
'field_title' => $fieldContent,
'field_type' => 'Editor',
'field_key' => 'contentfield_' . $database->id,
'field_required' => 1,
'field_user_editable' => 1,
'field_truncate' => 100,
'field_topic_format' => '{value}',
'field_display_listing' => 1,
'field_display_display' => 1,
'field_is_searchable' => 1
) ) );
$database->field_content = $contentField->id;
$perms = $contentField->permissions();
\IPS\Db::i()->update( 'core_permission_index', array(
'perm_view' => '*',
'perm_2' => '*',
'perm_3' => '*'
), array( 'perm_id=?', $perms['perm_id']) );
/* Create a category */
$category = new \IPS\cms\Categories;
$category->database_id = $database->id;
$category->saveForm( $category->formatFormValues( array(
'category_name' => $catTitle,
'category_description' => $catDesc,
'category_parent_id' => 0,
'category_has_perms' => 0,
'category_show_records' => 1
) ) );
$perms = $category->permissions();
\IPS\Db::i()->update( 'core_permission_index', array(
'perm_view' => '*',
'perm_2' => '*',
'perm_3' => '*'
), array( 'perm_id=?', $perms['perm_id']) );
$database->options['comments'] = 1;
$database->save();
}
/**
* @brief Language strings pre-loaded
*/
protected $langLoaded = FALSE;
/**
* Get database id
*
* @return string
*/
public function get__id()
{
return $this->id;
}
/**
* Get comment bump
*
* @return int
*/
public function get__comment_bump()
{
if ( $this->comment_bump === 0 )
{
return static::BUMP_ON_EDIT;
}
else if ( $this->comment_bump === 1 )
{
return static::BUMP_ON_COMMENT;
}
else if ( $this->comment_bump === 2 )
{
return static::BUMP_ON_EDIT + static::BUMP_ON_COMMENT;
}
}
/**
* Get database name
*
* @return string
*/
public function get__title()
{
return \IPS\Member::loggedIn()->language()->addToStack('content_db_' . $this->id);
}
/**
* Get database description
*
* @return string
*/
public function get__description()
{
return \IPS\Member::loggedIn()->language()->addToStack('content_db_' . $this->id . '_desc');
}
/**
* Get default category
*
* @return string
*/
public function get__default_category()
{
$categoryClass = '\IPS\cms\Categories' . $this->id;
if ( $this->default_category )
{
try
{
$categoryClass::load( $this->default_category );
return $this->default_category;
}
catch( \OutOfRangeException $e )
{
$this->default_category = NULL;
}
}
if ( ! $this->default_category )
{
$roots = $categoryClass::roots( NULL );
if ( ! count( $roots ) )
{
/* Create a category */
$category = new \IPS\cms\Categories;
$category->database_id = $this->id;
$catTitle = array();
$catDesc = array();
foreach( \IPS\Lang::languages() as $id => $lang )
{
$catTitle[ $id ] = $lang->get('content_database_noun_pu');
$catDesc[ $id ] = '';
}
$category->saveForm( $category->formatFormValues( array(
'category_name' => $catTitle,
'category_description' => $catDesc,
'category_parent_id' => 0,
'category_has_perms' => 0,
'category_show_records' => 1
) ) );
$perms = $category->permissions();
\IPS\Db::i()->update( 'core_permission_index', array(
'perm_view' => '*',
'perm_2' => '*',
'perm_3' => '*'
), array( 'perm_id=?', $perms['perm_id']) );
$roots = $categoryClass::roots( NULL );
}
$category = array_shift( $roots );
$this->default_category = $category->id;
$this->save();
/* Update records */
\IPS\Db::i()->update( 'cms_custom_database_' . $this->id, array( 'category_id' => $category->id ), array( 'category_id=0' ) );
}
return $this->default_category;
}
/**
* Get fixed field data
*
* @return array
*/
public function get_fixed_field_perms()
{
if ( ! is_array( $this->_data['fixed_field_perms'] ) )
{
$this->_data['fixed_field_perms'] = json_decode( $this->_data['fixed_field_perms'], true );
}
if ( is_array( $this->_data['fixed_field_perms'] ) )
{
return $this->_data['fixed_field_perms'];
}
return array();
}
/**
* Set the "fixed field" field
*
* @param string|array $value
* @return void
*/
public function set_fixed_field_perms( $value )
{
$this->_data['fixed_field_perms'] = ( is_array( $value ) ? json_encode( $value ) : $value );
}
/**
* Get fixed field settings
*
* @return array
*/
public function get_fixed_field_settings()
{
if ( ! is_array( $this->_data['fixed_field_settings'] ) )
{
$this->_data['fixed_field_settings'] = json_decode( $this->_data['fixed_field_settings'], true );
}
if ( is_array( $this->_data['fixed_field_settings'] ) )
{
return $this->_data['fixed_field_settings'];
}
return array();
}
/**
* Set the "fixed field" settings field
*
* @param string|array $value
* @return void
*/
public function set_fixed_field_settings( $value )
{
$this->_data['fixed_field_settings'] = ( is_array( $value ) ? json_encode( $value ) : $value );
}
/**
* Get feature settings, settings
*
* @return array
*/
public function get_featured_settings()
{
if ( ! is_array( $this->_data['featured_settings'] ) )
{
$this->_data['featured_settings'] = json_decode( $this->_data['featured_settings'], true );
}
if ( is_array( $this->_data['featured_settings'] ) )
{
return $this->_data['featured_settings'];
}
return array();
}
/**
* Set the "featured settings" field
*
* @param string|array $value
* @return void
*/
public function set_featured_settings( $value )
{
$this->_data['featured_settings'] = ( is_array( $value ) ? json_encode( $value ) : $value );
}
/**
* Get the title of the page when using a database
*
* @return string
*/
public function pageTitle()
{
if ( static::$pageTitle === NULL )
{
if ( $this->use_as_page_title )
{
static::$pageTitle = $this->_title;
}
else
{
try
{
static::$pageTitle = \IPS\cms\Pages\Page::load( $this->page_id )->getHtmlTitle();
}
catch( \Exception $e ) { }
}
}
return static::$pageTitle;
}
/**
* Check permissions
*
* @param mixed $permission A key which has a value in static::$permissionMap['view'] matching a column ID in core_permission_index
* @param \IPS\Member|\IPS\Member\Group|NULL $member The member or group to check (NULL for currently logged in member)
* @return bool
* @throws \OutOfBoundsException If $permission does not exist in static::$permissionMap
*/
public function can( $permission, $member=NULL )
{
/* If we're looking from the front, make sure the database page also passes */
if ( $permission === 'view' and \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation === 'front' and $this->page_id )
{
try
{
return parent::can( 'view', $member ) AND \IPS\cms\Pages\Page::load( $this->page_id )->can( 'view', $member );
}
catch( \OutOfRangeException $ex )
{
return parent::can( 'view', $member );
}
}
return parent::can( $permission, $member );
}
/**
* Sets up and preloads some words
*
* @return void
*/
public function preLoadWords()
{
/* Skip this during installation / uninstallation as the words won't be loaded */
if ( !\IPS\Dispatcher::hasInstance() or \IPS\Dispatcher::i()->controllerLocation === 'setup' OR ( \IPS\Dispatcher::i()->controllerLocation === 'admin' AND \IPS\Dispatcher::i()->module->key === 'applications' ) )
{
$this->langLoaded = TRUE;
return;
}
if ( ! $this->langLoaded )
{
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' )
{
/* Moderator tools */
\IPS\Member::loggedIn()->language()->words['modperms__core_Content_cms_Records' . $this->id ] = $this->_title;
\IPS\Member::loggedIn()->language()->words['cms' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack('categories');
/* Editor Areas */
\IPS\Member::loggedIn()->language()->words['editor__cms_Records' . $this->id ] = $this->_title;
foreach( array( 'pin', 'unpin', 'feature', 'unfeature', 'edit', 'hide', 'unhide', 'view_hidden', 'future_publish', 'view_future', 'move', 'lock', 'unlock', 'reply_to_locked', 'delete', 'feature_comments', 'unfeature_comments', 'add_item_message', 'edit_item_message', 'delete_item_message' ) as $lang )
{
\IPS\Member::loggedIn()->language()->words['can_' . $lang . '_content_db_lang_sl_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'can_' . $lang . '_record', FALSE, array( 'sprintf' => array( $this->recordWord( 1 ) ) ) );
\IPS\Member::loggedIn()->language()->words['can_' . $lang . '_content_db_lang_su_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'can_' . $lang . '_record', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
if ( in_array( $lang, array( 'edit', 'hide', 'unhide', 'view_hidden', 'delete' ) ) )
{
\IPS\Member::loggedIn()->language()->words['can_' . $lang . '_content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'can_' . $lang . '_rcomment', FALSE, array( 'sprintf' => array( $this->recordWord( 1 ) ) ) );
\IPS\Member::loggedIn()->language()->words['can_' . $lang . '_content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'can_' . $lang . '_rreview', FALSE, array( 'sprintf' => array( $this->recordWord( 1 ) ) ) );
}
}
}
$this->langLoaded = true;
}
}
/**
* "Records" / "Record" word
*
* @param int $number Number
* @param bool $upper ucfirst string
* @return string
*/
public function recordWord( $number = 2, $upper = FALSE )
{
if ( \IPS\Application::appIsEnabled('cms') )
{
return \IPS\Member::loggedIn()->language()->recordWord( $number, $upper, $this->id );
}
else
{
/* If the Pages app is disabled, just load a generic phrase */
$key = "content_database_noun_" . ( $number > 1 ? "p" : "s" ) . ( $upper ? "u" : "l" );
return \IPS\Member::loggedIn()->language()->addToStack( $key );
}
}
/**
* [ActiveRecord] Save Record
*
* @return void
*/
public function save()
{
/* If we are enabling search, we will need to index that content */
$rebuildSearchIndex = ( !$this->_new AND isset( $this->changed['search'] ) AND $this->changed['search'] );
$removeSearchIndex = ( !$this->_new AND isset( $this->changed['search'] ) AND !$this->changed['search'] );
parent::save();
/* Clear cache */
unset( \IPS\Data\Store::i()->cms_databases );
/* If this database isn't searchable, make sure its content is not in the search index */
if( $removeSearchIndex )
{
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $this->id );
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Comment' . $this->id );
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Review' . $this->id );
/* If there are any bg tasks to rebuild index, clear them */
foreach( \IPS\Db::i()->select( '*', 'core_queue', array( '`key`=?', 'RebuildSearchIndex' ) ) as $queue )
{
$details = json_decode( $queue['data'], true );
if( isset( $details['class'] ) AND $details['class'] == 'IPS\cms\Records' . $this->id )
{
\IPS\Db::i()->delete( 'core_queue', array( 'id=?', $queue['id'] ) );
}
}
}
elseif( $rebuildSearchIndex )
{
\IPS\Task::queue( 'core', 'RebuildSearchIndex', array( 'class' => 'IPS\cms\Records' . $this->id ), 5, TRUE );
}
}
/**
* [ActiveRecord] Delete Record
*
* @return void
*/
public function delete()
{
$fieldsClass = '\IPS\cms\Fields' . $this->id;
$class = '\IPS\cms\Categories' . $this->id;
foreach( $class::roots( NULL ) as $id => $cat )
{
$cat->delete();
}
foreach( $fieldsClass::roots( NULL ) as $id => $field )
{
$field->delete( TRUE );
}
/* Delete comments */
\IPS\Db::i()->delete( 'cms_database_comments', array( 'comment_database_id=?', $this->id ) );
/* Delete from view counter */
\IPS\Db::i()->delete( 'core_view_updates', array( 'classname=? ', 'IPS\cms\Records' . $this->id ) );
/* Delete records */
\IPS\Db::i()->dropTable( 'cms_custom_database_' . $this->id, TRUE );
/* Delete revisions */
\IPS\Db::i()->delete( 'cms_database_revisions', array( 'revision_database_id=?', $this->id ) );
/* Remove any reciprocal linking */
\IPS\Db::i()->delete( 'cms_database_fields_reciprocal_map', array( 'map_foreign_database_id=? or map_origin_database_id=?', $this->id, $this->id ) );
/* Delete notifications */
$memberIds = array();
foreach( \IPS\Db::i()->select( 'member', 'core_notifications', array( 'item_class=? ', 'IPS\cms\Records' . $this->id ) ) as $member )
{
$memberIds[ $member ] = $member;
}
\IPS\Db::i()->delete( 'core_notifications', array( 'item_class=? ', 'IPS\cms\Records' . $this->id ) );
\IPS\Db::i()->delete( 'core_follow', array( 'follow_app=? AND follow_area=?', 'cms', 'records' . $this->id ) );
/* Remove promoted content */
\IPS\Db::i()->delete( 'core_social_promote', array( 'promote_class=?', 'IPS\cms\Records' . $this->id ) );
/* remove deletion log */
\IPS\Db::i()->delete( 'core_deletion_log', array( 'dellog_content_class=?', 'IPS\cms\Records' . $this->id ) );
/* remove metadata */
\IPS\Db::i()->delete( 'core_content_meta', array( "meta_class=? ", 'IPS\cms\Records' . $this->id ) );
foreach( $memberIds as $member )
{
\IPS\Member::load( $member )->recountNotifications();
}
/* Remove from search */
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $this->id );
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Comment' . $this->id );
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records\Review' . $this->id );
/* Delete custom languages */
\IPS\Lang::deleteCustom( 'cms', "content_db_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "content_db_" . $this->id . '_desc');
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_sl_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_pl_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_su_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_pu_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_ia_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "content_db_lang_sl_" . $this->id . '_pl' );
\IPS\Lang::deleteCustom( 'cms', "__indefart_content_db_lang_sl_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "__defart_content_db_lang_sl_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "cms_create_menu_records_" . $this->id );
\IPS\Lang::deleteCustom( 'cms', "cms_records" . $this->id . '_pl' );
\IPS\Lang::deleteCustom( 'cms', "module__cms_records" . $this->id );
/* Unclaim attachments */
\IPS\File::unclaimAttachments( 'cms_Records', NULL, NULL, $this->id );
\IPS\File::unclaimAttachments( 'cms_Records' . $this->id );
/* Remove widgets */
$this->removeWidgets();
/* Delete the database record */
parent::delete();
/* Best remove the stored data */
unset( \IPS\Data\Store::i()->database_reciprocal_links, \IPS\Data\Store::i()->cms_databases );
}
/**
* Remove any database widgets
*
* @return void
*/
public function removeWidgets()
{
$databaseWidgets = array( 'Database', 'LatestArticles' );
foreach ( \IPS\Db::i()->select( '*', 'cms_page_widget_areas' ) as $item )
{
$pageBlocks = json_decode( $item['area_widgets'], TRUE );
$resaveBlock = NULL;
foreach( $pageBlocks as $id => $pageBlock )
{
if( $pageBlock['app'] == 'cms' AND in_array( $pageBlock['key'], $databaseWidgets ) AND ! empty( $pageBlock['configuration']['database'] ) )
{
if ( $pageBlock['configuration']['database'] == $this->id )
{
$resaveBlock = $pageBlocks;
unset( $resaveBlock[ $id ] );
}
}
}
if ( $resaveBlock !== NULL )
{
\IPS\Db::i()->update( 'cms_page_widget_areas', array( 'area_widgets' => json_encode( $resaveBlock ) ), array( 'area_page_id=? and area_area=?', $this->id, $item['area_area'] ) );
}
}
}
/**
* Set the permission index permissions
*
* @param array $insert Permission data to insert
* @param \IPS\Helpers\Form\Matrix $matrix \IPS\Helpers\Form\Matrix
* @return void
*/
public function setPermissions( $insert, \IPS\Helpers\Form\Matrix $matrix )
{
parent::setPermissions( $insert, $matrix );
/* Clear cache */
unset( \IPS\Data\Store::i()->cms_databases );
/* Clone these permissions to all categories that do not have permissions */
$class = '\IPS\cms\Categories' . $this->id;
foreach( $class::roots( NULL ) as $category )
{
$this->setPermssionsRecursively( $category );
}
}
/**
* Recursively set permissions
*
* @param \IPS\cms\Categrories $category Category object
* @return void
*/
protected function setPermssionsRecursively( $category )
{
if ( ! $category->has_perms )
{
$category->cloneDatabasePermissions();
}
foreach( $category->children() as $child )
{
$this->setPermssionsRecursively( $child );
}
}
/**
* @brief Number of categories
*/
protected $_numberOfCategories = NULL;
/**
* Get the number of categories in this database
*
* @return int
*/
public function numberOfCategories()
{
if ( $this->_numberOfCategories === NULL )
{
$this->_numberOfCategories = \IPS\Db::i()->select( 'count(*)', 'cms_database_categories', array( 'category_database_id=?', $this->_id ) )->first();
}
return $this->_numberOfCategories;
}
/**
* Determines if any fields from other databases are linking to items in this database via the Relational field
*
* @param int $databaseId The ID of the database
* @return boolean
*/
public static function hasReciprocalLinking( $databaseId )
{
if ( isset( \IPS\Data\Store::i()->database_reciprocal_links ) )
{
$values = \IPS\Data\Store::i()->database_reciprocal_links;
}
else
{
$values = array();
foreach( static::databases() as $database )
{
$fieldsClass = 'IPS\cms\Fields' . $database->_id;
foreach( $fieldsClass::data() as $field )
{
if ( $field->type === 'Item' )
{
$extra = $field->extra;
if ( ! empty( $extra['database'] ) )
{
$values[ $database->_id ][] = $extra;
}
}
}
\IPS\Data\Store::i()->database_reciprocal_links = $values;
}
}
if ( is_array( $values ) )
{
foreach( $values as $id => $fields )
{
foreach( $fields as $fieldid => $data )
{
if ( $data['database'] == $databaseId and $data['crosslink'] )
{
return TRUE;
}
}
}
}
return FALSE;
}
/**
* Rebuild the reciprocal linking maps across all databases
*
* @return void
*/
public static function rebuildReciprocalLinkMaps()
{
/* Ensure the SPL are loaded from /cms/Application.php as this may be called by a task or upgrade module */
\IPS\Application::load('cms');
\IPS\Db::i()->delete( 'cms_database_fields_reciprocal_map' );
foreach( static::databases() as $database )
{
$fieldsClass = 'IPS\cms\Fields' . $database->_id;
foreach( $fieldsClass::data() as $field )
{
if ( $field->type === 'Item' )
{
\IPS\Task::queue( 'cms', 'RebuildReciprocalMaps', array( 'database' => $database->_id, 'field' => $field->id ), 2, array( 'field' ) );
}
}
}
}
}