Invision Power Services, Inc. * @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\modules\admin\databases; /* 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; } /** * databases */ class _databases extends \IPS\Node\Controller { /** * Node Class */ protected $nodeClass = '\IPS\cms\Databases'; /** * Execute * * @return void */ public function execute() { \IPS\Dispatcher::i()->checkAcpPermission( 'databases_manage' ); parent::execute(); } /** * Manage * * @return void */ protected function manage() { /* Create the table */ $table = new \IPS\Helpers\Table\Db( 'cms_databases', \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases' ) ); $table->langPrefix = 'content_'; /* Columns */ $table->joins = array( array( 'select' => 'w.word_custom as database_name', 'from' => array( 'core_sys_lang_words', 'w' ), 'where' => "w.word_key=CONCAT( 'content_db_', cms_databases.database_id ) AND w.lang_id=" . \IPS\Member::loggedIn()->language()->id ) ); $table->include = array( 'database_name', 'database_record_count', 'database_category_count' ); $table->widths = array( 'database_name' => '50' ); $table->mainColumn = 'database_name'; $table->quickSearch = 'word_custom'; $table->sortBy = $table->sortBy ?: 'word_custom'; $table->sortDirection = $table->sortDirection ?: 'asc'; /* Parsers */ $table->parsers = array( 'database_name' => function( $val, $row ) { $page = NULL; $database = NULL; try { $database = \IPS\cms\Databases::load( $row['database_id'] ); if ( $database->page_id > 0 ) { try { $page = \IPS\cms\Pages\Page::load( $database->page_id ); } catch ( \OutOfRangeException $ex ) { $database->page_id = 0; $database->save(); } } } catch ( \OutOfRangeException $ex ) { } return \IPS\Theme::i()->getTemplate( 'databases' )->manageDatabaseName( $database, $row, $page ); }, 'database_category_count' => function( $val, $row ) { try { $database = \IPS\cms\Databases::load( $row['database_id'] ); if ( ! $database->use_categories ) { return \IPS\Member::loggedIn()->language()->addToStack('cms_db_cats_disabled'); } } catch ( \OutOfRangeException $ex ) { } /* This sucks but adding a COUNT into a join breaks the query and sub selects not easy with DB driver */ return \IPS\Db::i()->select( 'COUNT(*)', 'cms_database_categories', array( 'category_database_id=?', $row['database_id'] ) )->first(); }, 'database_record_count' => function( $val, $row ) { return \IPS\Db::i()->select( 'SUM(category_records)', 'cms_database_categories', array( 'category_database_id=?', $row['database_id'] ) )->first(); } ); /* Buttons */ \IPS\Output::i()->sidebar['actions']['add'] = array( 'primary' => true, 'title' => 'add', 'icon' => 'plus', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=add' ), 'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_database_add') ) ); /*if ( \IPS\Application::appIsEnabled('forums') ) { \IPS\Output::i()->sidebar['actions']['promote'] = array( 'title' => 'cms_database_promote', 'icon' => 'comments', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=promote' ), 'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_database_promote') ) ); }*/ $table->rowButtons = function( $row ) { $return = array(); if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'databases', 'databases_edit' ) ) { $return['edit'] = array( 'title' => 'edit', 'icon' => 'pencil', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=form&id=' . $row['database_id'] ), ); } $return['records'] = array( 'title' => 'content_database_manage_records', 'icon' => 'file-text-o', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=records&database_id=' . $row['database_id'] ), ); $return['permissions'] = array( 'title' => 'content_database_manage_permissions', 'icon' => 'lock', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=permissions&id=' . $row['database_id'] ), ); if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'categories', 'categories_manage' ) and $row['database_use_categories'] ) { $return['categories'] = array( 'title' => 'content_database_manage_categories', 'icon' => 'folder-o', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=categories&database_id=' . $row['database_id'] ), ); } if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'fields', 'cms_fields_manage' ) ) { $return['fields'] = array( 'title' => 'content_database_manage_fields', 'icon' => 'tasks', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=fields&database_id=' . $row['database_id'] ), ); } if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'databases', 'databases_edit' ) ) { $return['download'] = array( 'title' => 'download', 'icon' => 'download', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=download&id=' . $row['database_id'] ), 'data' => array( 'controller' => 'cms.admin.databases.download', 'downloadURL' => \IPS\Http\Url::internal( "app=cms&module=databases&controller=databases&do=download&id=" . $row['database_id'] . '&go=true' ) ) ); } if ( \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'databases', 'databases_delete' ) ) { $return['delete'] = array( 'title' => 'delete', 'icon' => 'times-circle', 'link' => \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=delete&id=' . $row['database_id'] ), 'data' => array( 'delete' => '' ) ); } return $return; }; /* Javascript */ \IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_databases.js', 'cms', 'admin' ) ); /* Display */ \IPS\Output::i()->output = (string) $table; \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('menu__cms_databases_databases'); } /** * Add a theme dialog * * @return void */ public function add() { $form = new \IPS\Helpers\Form( 'form', 'next' ); $form->addTab( 'cms_database_add_new' ); $form->addMessage( \IPS\Member::loggedIn()->language()->addToStack('cms_add_db_normal') ); $form->addTab( 'cms_database_add_upload' ); $form->add( new \IPS\Helpers\Form\Upload( 'cms_database_import', NULL, FALSE, array( 'allowedFileTypes' => array( 'xml' ), 'temporary' => TRUE ), NULL, NULL, NULL, 'cms_database_import' ) ); if ( $values = $form->values() ) { if ( $values['cms_database_import'] ) { /* Move it to a temporary location */ $tempFile = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' ); move_uploaded_file( $values['cms_database_import'], $tempFile ); /* Initate a redirector */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=import' )->setQueryString( array( 'file' => $tempFile, 'key' => md5_file( $tempFile ) ) ) ); } else { \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=form' ) ); } } \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'global', 'core', 'admin' )->block( 'cms_database_add', $form, FALSE ); } /** * Import from upload * * @return void */ public function import() { if ( !file_exists( \IPS\Request::i()->file ) or md5_file( \IPS\Request::i()->file ) !== \IPS\Request::i()->key ) { \IPS\Output::i()->error( 'generic_error', '3T259/3', 403, '' ); } \IPS\Output::i()->output = new \IPS\Helpers\MultipleRedirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=import' )->setQueryString( array( 'file' => \IPS\Request::i()->file, 'key' => \IPS\Request::i()->key ) ), function( $data ) { /* Open XML file */ $xml = new \IPS\Xml\XMLReader; $xml->open( \IPS\Request::i()->file ); if ( ! @$xml->read() ) { @unlink( \IPS\Request::i()->file ); \IPS\Output::i()->error( 'xml_upload_invalid', '2C163/1', 403, '' ); } /* Is this the first batch? */ $database = null; $i = 0; if ( !is_array( $data ) ) { $database = new \IPS\cms\Databases; $database->key = uniqid(); $database->save(); /* Set default perms, these will be editable post DB import */ \IPS\Db::i()->replace( 'core_permission_index', array( 'app' => 'cms', 'perm_type' => $database::$permType, 'perm_type_id' => $database->id, 'perm_view' => '*', 'perm_2' => '*', #read 'perm_3' => \IPS\Settings::i()->admin_group, #add 'perm_4' => \IPS\Settings::i()->admin_group, #edit 'perm_5' => \IPS\Settings::i()->admin_group, #reply 'perm_6' => \IPS\Settings::i()->admin_group, #rate 'perm_7' => \IPS\Settings::i()->admin_group, #review ) ); $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 ); } $langs = array(); foreach( array( 'content_db_lang_sl', 'content_db_lang_pl', 'content_db_lang_su', 'content_db_lang_pu', 'content_db_lang_ia' ) as $lang ) { if ( $xml->getAttribute( $lang ) ) { $langs[ $lang ] = $xml->getAttribute( $lang ); \IPS\Lang::saveCustom( 'cms', $lang . "_" . $database->id, $xml->getAttribute( $lang ) ); if ( $lang === 'content_db_lang_pu' ) { \IPS\Lang::saveCustom( 'cms', $lang . "_" . $database->id . '_pl', $xml->getAttribute( $lang ) ); } } } /* Other data */ while ( $xml->read() ) { $name = NULL; $desc = NULL; if ( $xml->name == 'data' ) { /* Life is too short otherwise */ $node = new \SimpleXMLElement( $xml->readOuterXML() ); foreach( $node->attributes() as $k => $v ) { $database->$k = (string) $v; } /* Any kids of your own? */ foreach( $node->children() as $k => $v ) { if ( $k === 'name' ) { $name = $v; } else if ( $k === 'description' ) { $desc = $v; } else { $tryJson = json_decode( $v, TRUE ); $database->$k = ( $tryJson ) ? $tryJson : (string) $v; } } \IPS\Lang::saveCustom( 'cms', "content_db_" . $database->id, $name ); \IPS\Lang::saveCustom( 'cms', "content_db_" . $database->id . '_desc', $desc ); \IPS\Lang::saveCustom( 'cms', "digest_area_cms_records" . $database->id, $langs['content_db_lang_pu'] ); \IPS\Lang::saveCustom( 'cms', "digest_area_cms_categories" . $database->id, $langs['content_db_lang_pu'] ); $menu = array(); foreach( \IPS\Lang::languages() as $id => $lang ) { $menu[ $lang->_id ] = \sprintf( $lang->get('cms_create_menu_records_x'), $langs['content_db_lang_su'], $name ); } /* Notification, search/followed/new content langs */ \IPS\Lang::saveCustom( 'cms', "cms_create_menu_records_" . $database->id, $menu ); \IPS\Lang::saveCustom( 'cms', "cms_records" . $database->id . '_pl', $langs['content_db_lang_su'] ); \IPS\Lang::saveCustom( 'cms', "module__cms_records" . $database->id, $name ); break; } } $database->save(); /* set up some stores (and make sure they are clean from previous possibly broken imports */ \IPS\Data\Store::i()->db_import_cat_map = array(); \IPS\Data\Store::i()->db_import_cat_parent_map = array(); \IPS\Data\Store::i()->db_import_field_map = array(); \IPS\Data\Store::i()->db_import_db_id = $database->id; /* Start impoprting */ $data = array( 'next' => 'field', 'done' => 0 ); return array( $data, \IPS\Member::loggedIn()->language()->addToStack('processing') ); } $database = \IPS\cms\Databases::load( \IPS\Data\Store::i()->db_import_db_id ); $xml->read(); $next = NULL; $areas = array( 'field', 'category', 'template' ); if ( $data['next'] ) { while ( $xml->read() ) { if( ! in_array( $xml->name, $areas ) OR $xml->nodeType != \XMLReader::ELEMENT ) { continue; } $i++; if ( $data['done'] ) { if ( $i - 1 < $data['done'] ) { $xml->next(); continue; } } $doneSomething = false; if ( $xml->name == $data['next'] ) { $data['done']++; $areaName = $xml->name; $node = new \SimpleXMLElement( $xml->readOuterXML() ); /* Import */ switch ( $areaName ) { case 'field': $attrs = array(); $perms = array(); foreach( $node->attributes() as $k => $v ) { if ( mb_substr( $k, 0, 5 ) === 'perm_' or in_array( $k, array( 'app', 'owner_only', 'friend_only', 'authorized_users' ) ) ) { $perms[ $k ] = (string) $v; } else { $attrs[ $k ] = (string) $v; } } /* Any kids of your own? */ $displayJson = NULL; foreach( $node->children() as $k => $v ) { if ( $k == 'field_name' ) { $k = 'field_title'; } $tryJson = json_decode( $v, TRUE ); if ( $k === 'field_display_json' AND is_array( $tryJson ) ) { $displayJson = $tryJson; continue; } $attrs[ $k ] = ( $tryJson ) ? $tryJson : (string) $v; } $attrs['_skip_formatting'] = TRUE; $originalFieldId = $attrs['field_id']; unset( $attrs['field_id'] ); $fieldsClass = 'IPS\cms\Fields' . $database->id; $obj = new $fieldsClass; $values = $obj->formatFormValues( $attrs ); if ( isset( $attrs['field_extra'] ) ) { /* The export format is always correct */ $values['field_extra'] = $attrs['field_extra']; } $obj->saveForm( $values ); if ( $displayJson ) { $obj->display_json = $displayJson; $obj->save(); } if ( $originalFieldId == $database->field_title ) { $database->field_title = $obj->id; $database->save(); } else if ( $originalFieldId == $database->field_content ) { $database->field_content = $obj->id; $database->save(); } $map = \IPS\Data\Store::i()->db_import_field_map; $map[ $originalFieldId ] = $obj->id; \IPS\Data\Store::i()->db_import_field_map = $map; $existingPerms = $obj->permissions(); $newPerms = array_merge( $perms, array( 'perm_id' => $existingPerms['perm_id'], 'perm_type_id' => $obj->id ) ); /* Set default permissions if not defined in export */ if( !isset( $perms['perm_view'] ) ) { $newPerms['perm_view'] = '*'; } if( !isset( $perms['perm_2'] ) ) { $newPerms['perm_2'] = \IPS\Settings::i()->admin_group; } if( !isset( $perms['perm_3'] ) ) { $newPerms['perm_3'] = \IPS\Settings::i()->admin_group; } \IPS\Db::i()->update( 'core_permission_index', $newPerms, array( 'perm_id=?', $existingPerms['perm_id'] ) ); \IPS\Lang::saveCustom( 'cms', "content_field_" . $obj->id, $attrs['field_title'] ); if ( isset($attrs['field_description']) ) { \IPS\Lang::saveCustom( 'cms', "content_field_" . $obj->id . '_desc', $attrs['field_description'] ); } if ( isset($attrs['field_validator_error']) ) { \IPS\Lang::saveCustom( 'cms', "content_field_" . $obj->id . '_validation_error', $attrs['field_validator_error'] ); } $next = 'category'; $doneSomething = true; break; case 'category': $attrs = array(); $perms = array(); foreach( $node->attributes() as $k => $v ) { if ( mb_substr( $k, 0, 5 ) === 'perm_' or in_array( $k, array( 'app', 'owner_only', 'friend_only', 'authorized_users' ) ) ) { $perms[ $k ] = (string) $v; } else { $attrs[ $k ] = ( in_array( $k, array( 'category_parent_id' ) ) ) ? (int) $v : (string) $v; } } /* Any kids of your own? */ foreach( $node->children() as $k => $v ) { $tryJson = json_decode( $v, TRUE ); $attrs[ $k ] = ( $tryJson ) ? $tryJson : (string) $v; } $originalCategoryId = $attrs['category_id']; $originalParentId = $attrs['category_parent_id']; unset( $attrs['category_id'] ); $attrs['category_parent_id'] = 0; /* Create a category */ $category = new \IPS\cms\Categories; $category->database_id = $database->id; $category->saveForm( $category->formatFormValues( $attrs ) ); if ( $category->fields AND $category->fields !== '*' ) { if ( is_array( $category->fields ) ) { $field_map = \IPS\Data\Store::i()->db_import_field_map; $newMap = array(); foreach( $category->fields as $fid ) { if ( isset( $field_map[ $fid ] ) ) { $newMap[] = $field_map[ $fid ]; } } if ( count( $newMap ) ) { $category->fields = json_encode( $newMap ); $category->save(); } } } $cat_map = \IPS\Data\Store::i()->db_import_cat_map; $parent_map = \IPS\Data\Store::i()->db_import_cat_parent_map; $cat_map[ $originalCategoryId ] = $category->id; $parent_map[ $category->id ] = $originalParentId; \IPS\Data\Store::i()->db_import_cat_map = $cat_map; \IPS\Data\Store::i()->db_import_cat_parent_map = $parent_map; /* Perms */ $existingPerms = $category->permissions(); \IPS\Db::i()->update( 'core_permission_index', array_merge( $perms, array( 'perm_id' => $existingPerms['perm_id'], 'perm_type_id' => $category->id ) ), array( 'perm_id=?', $existingPerms['perm_id'] ) ); $next = 'template'; $doneSomething = true; break; case 'template': $templates = \IPS\cms\Theme::i()->getRawTemplates( 'cms', 'database', NULL, \IPS\cms\Theme::RETURN_ALL ); $attrs = array(); foreach( $node->attributes() as $k => $v ) { $attrs[ $k ] = (string) $v; } /* Any kids of your own? */ foreach( $node->children() as $k => $v ) { $tryJson = json_decode( $v, TRUE ); $attrs[ $k ] = ( $tryJson ) ? $tryJson : (string) $v; } $obj = new \IPS\cms\Templates; $obj->location = $attrs['template_location']; $obj->group = $attrs['template_group']; $obj->title = $attrs['template_title']; $obj->params = $attrs['template_params']; $obj->content = $attrs['template_content']; $obj->original_group = $attrs['template_original_group']; $obj->user_created = 1; $obj->user_edited = 1; $obj->desc = ''; if ( $attrs['template_group'] !== 'template_form' ) { $obj->group .= '_' . $database->id; foreach( array( 'template_listing', 'template_display', 'template_categories', 'template_form', 'template_featured' ) as $name ) { if ( $database->$name == $attrs['template_group'] ) { $database->$name = $obj->group; $database->save(); } } } else { $obj->title .= '_' . $database->_id; $database->template_form = $obj->title; $database->save(); } $obj->save(); $obj->key = 'database_' . \IPS\Http\Url\Friendly::seoTitle( $obj->group ) . '_' . \IPS\Http\Url\Friendly::seoTitle( $obj->title ) . '_' . $obj->id; $obj->save(); $doneSomething = true; $next = NULL; break; } if ( $i % 10 === 0 ) { return array( $data, \IPS\Member::loggedIn()->language()->addToStack('cms_db_import_progress', FALSE, array( 'sprintf' => array( \ucfirst( $data['next'] ) ) ) ) ); } $xml->next(); } else { /* Did we do anything? if not, skip to the next section */ if ( ! $doneSomething ) { switch ( $data['next'] ) { case 'field': $data['next'] = 'category'; break; case 'category': $data['next'] = 'template'; break; case 'template': $data['next'] = null; break; } if ( $data['next'] ) { return array( $data, \IPS\Member::loggedIn()->language()->addToStack('cms_db_import_progress', FALSE, array( 'sprintf' => array( \ucfirst( $data['next'] ) ) ) ) ); } } $xml->next(); } } /* Done */ $data['next'] = $next; return array( $data, \IPS\Member::loggedIn()->language()->addToStack('cms_db_import_progress', FALSE, array( 'sprintf' => array( \ucfirst( $data['next'] ) ) ) ) ); } else { return NULL; } }, function() { /* Remap categories */ if ( isset( \IPS\Data\Store::i()->db_import_cat_map ) and isset( \IPS\Data\Store::i()->db_import_cat_parent_map ) ) { foreach( \IPS\Data\Store::i()->db_import_cat_parent_map as $new => $oldParent ) { if ( $oldParent > 0 ) { if ( isset( \IPS\Data\Store::i()->db_import_cat_map[ $oldParent ] ) ) { $cat = \IPS\cms\Categories::load( $new ); $cat->parent_id = \IPS\Data\Store::i()->db_import_cat_map[ $oldParent ]; $cat->save(); } } } unset( \IPS\Data\Store::i()->db_import_cat_map ); unset( \IPS\Data\Store::i()->db_import_cat_parent_map ); unset( \IPS\Data\Store::i()->db_import_field_map ); } $databaseId = \IPS\Data\Store::i()->db_import_db_id; unset( \IPS\Data\Store::i()->db_import_db_id ); $database = \IPS\cms\Databases::load( $databaseId ); foreach( array( 'template_listing', 'template_display', 'template_categories', 'template_form', 'template_featured' ) as $name ) { \IPS\cms\Templates::fixTemplateTags( $database->$name ); } @unlink( \IPS\Request::i()->file ); /* Done */ \IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=cms&module=databases&controller=databases&do=permissions&id=' . $databaseId ) ); } ); } /** * Download * * @return void */ protected function download() { \IPS\Dispatcher::i()->checkAcpPermission( 'databases_edit' ); try { $database = \IPS\cms\Databases::load( \IPS\Request::i()->id ); } catch( \OutofRangeException $ex ) { \IPS\Output::i()->error( 'cms_database_not_exist', '3T259/4', 403, '' ); } if( empty( \IPS\Request::i()->go ) ) { \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'databases' )->downloadDialog( $database ); return; } else { /* We need to know the database schema to prevent non-standard columns from add-ons being added to the XML (which then causes the import to fail) */ $schema = json_decode( \file_get_contents( \IPS\ROOT_PATH . '/applications/cms/data/schema.json' ), TRUE ); /* Init */ $xml = new \XMLWriter; $xml->openMemory(); $xml->setIndent( TRUE ); $xml->startDocument( '1.0', 'UTF-8' ); /* Root tag */ $xml->startElement('database'); foreach( array( 'content_db_lang_sl', 'content_db_lang_pl', 'content_db_lang_su', 'content_db_lang_pu', 'content_db_lang_ia' ) as $lang ) { try { $xml->startAttribute( $lang ); $xml->text( \IPS\Member::loggedIn()->language()->get( $lang . '_' . $database->id ) ); $xml->endAttribute(); } catch( \UnderflowException $ex ) { } } /* Initiate the tag */ $xml->startElement('data'); $arrays = array(); foreach( array( 'use_categories', 'template_listing', 'template_display', 'template_categories', 'all_editable', 'revisions', 'field_title', 'field_content', 'field_sort', 'field_direction', 'field_perpage', 'comment_approve', 'record_approve', 'rss', 'comment_bump', 'forum_record', 'forum_comments', 'forum_delete', 'forum_forum', 'forum_prefix', 'forum_suffix', 'search', 'tags_enabled', 'tags_noprefixes', 'tags_predefined', 'fixed_field_perms', 'cat_index_type', 'template_form', 'template_featured', 'featured_settings', 'options' ) as $field ) { if ( is_array( $database->$field ) ) { $arrays[ $field ] = $database->$field; } else { $store = $database->$field; if ( $database->$field instanceof \IPS\Patterns\Bitwise ) { $bwfield = $database->$field; $store = intval( $bwfield->values['options'] ); } $xml->startAttribute( $field ); $xml->text( $store ); $xml->endAttribute(); } } if ( count( $arrays ) ) { foreach( $arrays as $field => $v ) { $xml->startElement( $field ); $xml->writeCData( json_encode( $v ) ); $xml->endElement(); } } $xml->startElement('name'); $xml->writeCData( $database->_title ); $xml->endElement(); $xml->startElement('description'); $xml->writeCData( $database->_description ); $xml->endElement(); $xml->endElement(); /* Custom fields */ $textFields = array( 'field_extra', 'field_default_value', 'field_name', 'field_description', 'field_display_json', 'field_validator_error' ); $removeFields = array( 'field_database_id' ); $fieldSchema = $schema['cms_database_fields']; foreach ( \IPS\Db::i()->select( 'f.*, w.word_custom as field_name, w2.word_custom as field_description, w3.word_custom as field_validator_error, p.*', array('cms_database_fields', 'f'), array( 'field_database_id=?', $database->id ) ) ->join( array( 'core_sys_lang_words', 'w' ), "w.word_key=CONCAT( 'content_field_', f.field_id ) and w.lang_id=" . \IPS\Lang::defaultLanguage() ) ->join( array( 'core_sys_lang_words', 'w2' ), "w2.word_key=CONCAT( 'content_field_', f.field_id, '_desc' ) and w2.lang_id=" . \IPS\Lang::defaultLanguage() ) ->join( array( 'core_sys_lang_words', 'w3' ), "w3.word_key=CONCAT( 'content_field_', f.field_id, '_validation_error' ) and w3.lang_id=" . \IPS\Lang::defaultLanguage() ) ->join( array( 'core_permission_index', 'p' ), "p.app='cms' and p.perm_type='fields' and p.perm_type_id=f.field_id" ) as $row ) { /* Initiate the tag */ $xml->startElement('field'); foreach( $row as $k => $v ) { if ( array_key_exists( $k, $fieldSchema['columns'] ) AND ! in_array( $k, $removeFields ) AND ! in_array( $k, $textFields ) ) { $xml->startAttribute( $k ); $xml->text( $v ); $xml->endAttribute(); } } /* Write (potential) HTML fields */ foreach( $textFields as $field ) { if ( isset( $row[ $field ] ) ) { $xml->startElement( $field ); if ( preg_match( '/<|>|&/', $row[ $field ] ) ) { $xml->writeCData( str_replace( ']]>', ']]]]>', $row[ $field ] ) ); } else { $xml->text( $row[ $field ] ); } $xml->endElement(); } } /* Close the tag */ $xml->endElement(); } /* Categories */ $textFields = array( 'category_name', 'category_description', 'category_meta_keywords', 'category_meta_description', 'category_page_title' ); $removeFields = array( 'category_database_id', 'category_last_record_id', 'category_last_record_date', 'category_last_record_member', 'category_last_record_name', 'category_last_record_seo_name', 'category_records', 'category_record_comments', 'category_record_comments_queued', 'category_rss_cache', 'category_rss_cached', 'category_rss_exclude', 'category_forum_override', 'category_forum_record', 'category_forum_comments', 'category_forum_delete', 'category_forum_suffix', 'category_forum_prefix', 'category_forum_forum', 'category_full_path', 'category_last_title', 'category_last_seo_title'); $categorySchema = $schema['cms_database_categories']; foreach ( \IPS\Db::i()->select( 'c.*, w.word_custom as category_name, w2.word_custom as category_description, p.*', array('cms_database_categories', 'c'), array( 'category_database_id=?', $database->id ) ) ->join( array( 'core_sys_lang_words', 'w' ), "w.word_key=CONCAT( 'content_cat_name_', c.category_id ) and w.lang_id=" . \IPS\Lang::defaultLanguage() ) ->join( array( 'core_sys_lang_words', 'w2' ), "w2.word_key=CONCAT( 'content_cat_name_', c.category_id, '_desc' ) and w2.lang_id=" . \IPS\Lang::defaultLanguage() ) ->join( array( 'core_permission_index', 'p' ), "p.app='cms' and p.perm_type='categories' and p.perm_type_id=c.category_id" ) as $row ) { /* Initiate the tag */ $xml->startElement('category'); foreach( $row as $k => $v ) { if ( array_key_exists( $k, $categorySchema['columns'] ) AND ! in_array( $k, $removeFields ) AND ! in_array( $k, $textFields ) ) { $xml->startAttribute( $k ); $xml->text( $v ); $xml->endAttribute(); } } /* Write (potential) HTML fields */ foreach( $textFields as $field ) { if ( isset( $row[ $field ] ) ) { $xml->startElement( $field ); if ( preg_match( '/<|>|&/', $row[ $field ] ) ) { $xml->writeCData( str_replace( ']]>', ']]]]>', $row[ $field ] ) ); } else { $xml->text( $row[ $field ] ); } $xml->endElement(); } } /* Close the tag */ $xml->endElement(); } /* Templates @todo see if blocks are used in template and export too */ $templates = \IPS\cms\Theme::i()->getRawTemplates( 'cms', 'database', NULL, \IPS\cms\Theme::RETURN_ALL ); $toSave = array(); foreach( array('template_listing', 'template_display', 'template_categories', 'template_featured') as $area ) { if ( isset( $templates['cms']['database'][ $database->$area ] ) and is_array( $templates['cms']['database'][ $database->$area ] ) ) { /* Only fetch edited/added templates, no point in fetching default theme templates */ foreach( $templates['cms']['database'][ $database->$area ] as $key => $item ) { if ( $item['template_user_created'] or $item['template_user_edited'] ) { $toSave[ $database->$area ][ $key ] = $item; } } } } /* Form template */ if ( isset( $templates['cms']['database']['form'][ $database->template_form ] ) ) { $item = $templates['cms']['database']['form'][ $database->template_form ]; if ( $item['template_user_created'] or $item['template_user_edited'] ) { $toSave['form'][ $database->template_form ] = $item; } } if ( count( $toSave ) ) { foreach( $toSave as $group => $items ) { foreach( $items as $key => $item ) { /* Initiate the