Version 4.0.13.1
This commit is contained in:
1 parent
f9e857d255
commit
c6a86f0d9b
7517 files changed
+597400
-668041
No files matched your search
@@ -0,0 +1,939 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Block Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 19 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Blocks;
|
||||
|
||||
/* 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 Block Model
|
||||
*/
|
||||
class _Block extends \IPS\Node\Model implements \IPS\Node\Permissions
|
||||
{
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_blocks';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'block_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array('block_key');
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
public static $databaseColumnParent = null;
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node ID Database Column
|
||||
*/
|
||||
public static $parentNodeColumnId = 'category';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent Node Class
|
||||
*/
|
||||
public static $parentNodeClass = 'IPS\cms\Blocks\Container';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] Sortable?
|
||||
*/
|
||||
public static $nodeSortable = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] Title
|
||||
*/
|
||||
public static $nodeTitle = 'block';
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'content_block_name_';
|
||||
|
||||
/**
|
||||
* @brief [Node] Description suffix. If specified, will look for a language key with "{$titleLangPrefix}_{$id}_{$descriptionLangSuffix}" as the key
|
||||
*/
|
||||
public static $descriptionLangSuffix = '_desc';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
* @code
|
||||
array(
|
||||
'app' => 'core', // The application key which holds the restrictrions
|
||||
'module' => 'foo', // The module key which holds the restrictions
|
||||
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
|
||||
'add' => 'foo_add',
|
||||
'edit' => 'foo_edit',
|
||||
'permissions' => 'foo_perms',
|
||||
'delete' => 'foo_delete'
|
||||
),
|
||||
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
|
||||
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
|
||||
* @endcode
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'cms',
|
||||
'module' => 'pages',
|
||||
'prefix' => 'block_'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Node] App for permission index
|
||||
*/
|
||||
public static $permApp = 'cms';
|
||||
|
||||
/**
|
||||
* @brief [Node] Type for permission index
|
||||
*/
|
||||
public static $permType = 'blocks';
|
||||
|
||||
/**
|
||||
* @brief The map of permission columns
|
||||
*/
|
||||
public static $permissionMap = array(
|
||||
'view' => 'view'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief [Node] Prefix string that is automatically prepended to permission matrix language strings
|
||||
*/
|
||||
public static $permissionLangPrefix = 'perm_cms_block_';
|
||||
|
||||
/**
|
||||
* @brief Templates already loaded and evald via getTemplate()
|
||||
*/
|
||||
public static $calledTemplates = array();
|
||||
|
||||
/**
|
||||
* Parse a block for display
|
||||
* Wrapped in a static method so we can catch the OutOfRangeException and take action.
|
||||
*
|
||||
* @param string|int|\IPS\cms\Blocks\Block $block Block ID
|
||||
* @param string $orientation Orientation
|
||||
* @return string Ready to display HTML
|
||||
*/
|
||||
public static function display( $block, $orientation=NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( is_numeric( $block ) )
|
||||
{
|
||||
$block = static::load( $block );
|
||||
}
|
||||
else if ( ! $block instanceof \IPS\cms\Blocks\Block )
|
||||
{
|
||||
$block = static::load( $block, 'block_key' );
|
||||
}
|
||||
|
||||
if ( !$block->active )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We gots the perms to see this? */
|
||||
if ( !$block->can( 'view' ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( $block->type === 'custom' )
|
||||
{
|
||||
$functionName = 'content_blocks_' . $block->id;
|
||||
|
||||
if ( ! isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
$content = $block->content;
|
||||
|
||||
if( $block->getConfig('editor') == 'php' )
|
||||
{
|
||||
ob_start();
|
||||
eval( $content );
|
||||
$content = ob_get_clean();
|
||||
}
|
||||
|
||||
\IPS\Data\Store::i()->$functionName = \IPS\Theme::compileTemplate( $content, $functionName, null, true );
|
||||
}
|
||||
|
||||
\IPS\Theme::runProcessFunction( \IPS\Data\Store::i()->$functionName, $functionName );
|
||||
|
||||
if( $block->getConfig('editor') == 'php' )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$functionName );
|
||||
}
|
||||
|
||||
return call_user_func( 'IPS\\Theme\\'. $functionName );
|
||||
}
|
||||
else
|
||||
{
|
||||
$block->orientation = $orientation;
|
||||
|
||||
if ( $block->template OR $block->content )
|
||||
{
|
||||
$block->widget()->template( array( $block, 'getTemplate' ) );
|
||||
}
|
||||
|
||||
return $block->widget()->render();
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to overload standard widget templates
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getTemplate()
|
||||
{
|
||||
$args = func_get_args();
|
||||
$functionName = 'content_template_for_block_' . $this->id;
|
||||
|
||||
unset( \IPS\Data\Store::i()->$functionName );
|
||||
|
||||
/* Still here */
|
||||
if ( ! in_array( $functionName, array_keys( self::$calledTemplates ) ) )
|
||||
{
|
||||
if ( ! isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
if ( $this->content )
|
||||
{
|
||||
\IPS\Data\Store::i()->$functionName = \IPS\Theme::compileTemplate( $this->content, 'run', $this->template_params, true );
|
||||
|
||||
}
|
||||
else if ( $this->template )
|
||||
{
|
||||
try
|
||||
{
|
||||
$template = \IPS\cms\Templates::load( $this->template );
|
||||
return call_user_func_array( array( \IPS\cms\Theme::i()->getTemplate( $template->group, 'cms', $template->location ), $template->title ), $args );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
/* @todo what to do here? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Put them in a class */
|
||||
$template = <<<EOF
|
||||
class class_{$functionName}
|
||||
{
|
||||
|
||||
EOF;
|
||||
$template .= \IPS\Data\Store::i()->$functionName;
|
||||
|
||||
$template .= <<<EOF
|
||||
}
|
||||
EOF;
|
||||
|
||||
/* It lives! */
|
||||
\IPS\Theme::runProcessFunction( $template, $functionName );
|
||||
|
||||
$class = "\IPS\Theme\\class_{$functionName}";
|
||||
|
||||
/* Init */
|
||||
self::$calledTemplates[ $functionName ] = new $class();
|
||||
}
|
||||
|
||||
return call_user_func_array( array( self::$calledTemplates[ $functionName ], 'run' ), $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete compiled versions
|
||||
*
|
||||
* @param int|array $ids Integer ID or Array IDs to remove
|
||||
* @return void
|
||||
*/
|
||||
public static function deleteCompiled( $ids )
|
||||
{
|
||||
if ( is_numeric( $ids ) )
|
||||
{
|
||||
$ids = array( $ids );
|
||||
}
|
||||
|
||||
foreach( $ids as $id )
|
||||
{
|
||||
$functionName = 'content_blocks_' . $id;
|
||||
if ( isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$functionName );
|
||||
}
|
||||
|
||||
$functionName = 'content_template_for_block_' . $id;
|
||||
if ( isset( \IPS\Data\Store::i()->$functionName ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$functionName );
|
||||
}
|
||||
}
|
||||
|
||||
/* We can also use blocks in per-page CSS */
|
||||
\IPS\cms\Pages\Page::deleteCompiledIncludes();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Config json as array
|
||||
*/
|
||||
protected $_config = null;
|
||||
|
||||
/**
|
||||
* @brief Stores a \IPS\Widget object if this is a custom block with an embedded widget
|
||||
*/
|
||||
protected $widgetLoaded = NULL;
|
||||
|
||||
/**
|
||||
* @brief Orientation for an embedded widget
|
||||
*/
|
||||
protected $orientation = NULL;
|
||||
|
||||
/**
|
||||
* Get config as an array if no $key, or as whatever type corresponds to key
|
||||
*
|
||||
* @param string|null $key Config key to fetch
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig( $key = NULL)
|
||||
{
|
||||
if ( $this->_config === NULL )
|
||||
{
|
||||
$this->_config = json_decode( $this->config, TRUE );
|
||||
|
||||
if ( $this->_config === FALSE )
|
||||
{
|
||||
$this->_config = array();
|
||||
}
|
||||
}
|
||||
|
||||
if ( $key )
|
||||
{
|
||||
if ( isset( $this->_config[ $key ] ) )
|
||||
{
|
||||
return $this->_config[ $key ];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return $this->_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set config key and value
|
||||
*
|
||||
* @param string $key Config key
|
||||
* @param mixed $value Config value
|
||||
* @return mixed
|
||||
*/
|
||||
public function setConfig( $key, $value )
|
||||
{
|
||||
$this->_config[ $key ] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Return the custom badge for each row
|
||||
*
|
||||
* @return NULL|array Null for no badge, or an array of badge data (0 => CSS class type, 1 => language string, 2 => optional raw HTML to show instead of language string)
|
||||
*/
|
||||
protected function get__badge()
|
||||
{
|
||||
return array(
|
||||
0 => 'ipsBadge ipsBadge_intermediary ipsPos_right',
|
||||
1 => $this->type === 'custom' ? 'content_block_add_type_custom' : 'content_block_add_type_plugin',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get__description()
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( 'content_block_name_' . $this->_id . '_desc' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get configuration.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get__plugin_config()
|
||||
{
|
||||
return ( $this->plugin_config ? ( is_array( $this->plugin_config ) ? $this->plugin_config : json_decode( $this->plugin_config, TRUE ) ) : array() );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get buttons to display in tree
|
||||
* Example code explains return value
|
||||
* @endcode
|
||||
* @param string $url Base URL
|
||||
* @param bool $subnode Is this a subnode?
|
||||
* @return array
|
||||
*/
|
||||
public function getButtons( $url, $subnode=FALSE )
|
||||
{
|
||||
$buttons = parent::getButtons( $url, $subnode );
|
||||
|
||||
if ( isset( $buttons['add'] ) )
|
||||
{
|
||||
unset( $buttons['add']['data'] );
|
||||
}
|
||||
|
||||
if ( isset( $buttons['edit'] ) )
|
||||
{
|
||||
unset( $buttons['edit']['data'] );
|
||||
}
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
$block_type = ( isset( \IPS\Request::i()->block_type ) ) ? \IPS\Request::i()->block_type : ( $this->id ? $this->type : null );
|
||||
$block_editor = ( isset( \IPS\Request::i()->block_editor ) ) ? \IPS\Request::i()->block_editor : ( $this->id ? $this->getConfig('editor') : null );
|
||||
$block_plugin = ( isset( \IPS\Request::i()->block_plugin ) ) ? \IPS\Request::i()->block_plugin : ( $this->id ? $this->plugin : null );
|
||||
|
||||
/* Build form */
|
||||
$form->addtab( 'content_block_form_tab__details' );
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'block_name', NULL, TRUE, array(
|
||||
'app' => 'cms',
|
||||
'key' => ( $this->id ? "content_block_name_" . $this->id : NULL )
|
||||
) ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Translatable( 'block_description', NULL, FALSE, array(
|
||||
'app' => 'cms',
|
||||
'key' => ( $this->id ? "content_block_name_" . $this->id . '_desc' : NULL )
|
||||
) ) );
|
||||
|
||||
$nodeContainer = $this->id ? $this->category :
|
||||
( \IPS\Request::i()->parent ?: \IPS\cms\Blocks\Container::load( ( $block_type == 'custom' ? 'block_custom' : 'block_plugins' ), 'container_key' )->id );
|
||||
$form->add( new \IPS\Helpers\Form\Node( 'block_category', $nodeContainer, TRUE, array(
|
||||
'class' => '\IPS\cms\Blocks\Container',
|
||||
'subnodes' => false
|
||||
) ) );
|
||||
|
||||
$form->addHeader( 'cms_block_form_display' );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'block_key', $this->id ? $this->key : FALSE, FALSE, array(), function( $val )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( ! $val )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$block = \IPS\cms\Blocks\Block::load( $val, 'block_key');
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
/* Doesn't exist? Good! */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* It's taken... */
|
||||
if ( \IPS\Request::i()->id == $block->id )
|
||||
{
|
||||
/* But it's this one so that's ok */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* and if we're here, it's not... */
|
||||
throw new \InvalidArgumentException('cms_block_key_not_unique');
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* Slug is OK as load failed */
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
} ) );
|
||||
|
||||
/* Do we have config? */
|
||||
if ( $block_type === 'plugin' and $block_plugin )
|
||||
{
|
||||
if ( ! $this->id )
|
||||
{
|
||||
$this->type = 'plugin';
|
||||
$this->plugin = $block_plugin;
|
||||
|
||||
if ( isset( \IPS\Request::i()->block_plugin_app ) )
|
||||
{
|
||||
$this->plugin_app = \IPS\Request::i()->block_plugin_app;
|
||||
}
|
||||
elseif ( isset( \IPS\Request::i()->block_plugin_plugin ) )
|
||||
{
|
||||
$this->plugin_plugin = \IPS\Request::i()->block_plugin_plugin;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mb_substr( $block_plugin, 0, 8 ) === 'db_feed_' )
|
||||
{
|
||||
$databaseId = intval( mb_substr( $block_plugin, 8 ) );
|
||||
$this->plugin = 'RecordFeed';
|
||||
$this->plugin_config = array( 'cms_rf_database' => $databaseId );
|
||||
|
||||
/* JS needs this to produce the preview */
|
||||
$form->hiddenValues['cms_rf_database'] = $databaseId;
|
||||
}
|
||||
else if ( $this->id and $block_plugin === 'RecordFeed' )
|
||||
{
|
||||
$form->hiddenValues['cms_rf_database'] = $this->_plugin_config['cms_rf_database'];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$block_editor = 'html';
|
||||
|
||||
\IPS\Output::i()->output .= \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->message( \IPS\Member::loggedIn()->language()->addToStack( 'cms_block_feed_form_message', FALSE, array( 'sprintf' => $this->widget()->title() ) ), 'information', NULL, FALSE );
|
||||
}
|
||||
catch ( \OutOfRangeException $ex )
|
||||
{
|
||||
throw new \LogicException( 'cms_error_block_plugin_not_found' );
|
||||
}
|
||||
|
||||
if ( is_callable( array( $this->widget(), 'configuration' ) ) )
|
||||
{
|
||||
$form->addtab( 'content_block_form_tab__feed' );
|
||||
$this->widget()->configuration( $form );
|
||||
}
|
||||
}
|
||||
|
||||
$form->addtab( 'content_block_form_tab__content');
|
||||
|
||||
if ( $block_type === 'plugin' )
|
||||
{
|
||||
$form->addHtml( \IPS\Theme::i()->getTemplate( 'blocks', 'cms', 'admin' )->previewBlock() );
|
||||
|
||||
$templates = array( '_default_' => \IPS\Member::loggedIn()->language()->addToStack('content_block_template_use_default') );
|
||||
|
||||
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_BLOCK ) as $id => $obj )
|
||||
{
|
||||
if ( $obj->group == $this->widget()->key )
|
||||
{
|
||||
$templates[ $obj->key ] = $obj->title;
|
||||
}
|
||||
}
|
||||
|
||||
/* List of templates */
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'block_template_id', ( $this->id and $this->template ) ? $this->template : NULL, FALSE, array(
|
||||
'options' => $templates
|
||||
), NULL, NULL, \IPS\Theme::i()->getTemplate( 'blocks', 'cms', 'admin' )->previewTemplateLink( $block_plugin ), 'block_template_id' ) );
|
||||
|
||||
/* Use or copy to edit */
|
||||
$useHow = NULL;
|
||||
if ( $this->id )
|
||||
{
|
||||
if ( intval( $this->template ) or ( ! intval( $this->template ) and ! $this->content ) )
|
||||
{
|
||||
$useHow = 'use';
|
||||
}
|
||||
else
|
||||
{
|
||||
$useHow = 'copy';
|
||||
}
|
||||
}
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Select( 'block_template_use_how', $useHow, FALSE, array(
|
||||
'options' => array(
|
||||
'use' => 'block_template_use_how_use',
|
||||
'copy' => 'block_template_use_how_copy'
|
||||
),
|
||||
'toggles' => array(
|
||||
'copy' => array( 'block_content', 'block_save_as_template' )
|
||||
)
|
||||
), NULL, NULL, NULL, 'block_template_use_how' ) );
|
||||
}
|
||||
|
||||
if ( $block_editor === 'editor' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Editor( 'block_content', $this->content, FALSE, array(
|
||||
'app' => 'cms',
|
||||
'key' => 'BlockContent',
|
||||
'autoSaveKey' => 'block-content-' . ( $this->id ? $this->id : 'new' ) ), NULL, NULL, NULL, 'block_content_editor' ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Codemirror( 'block_content', $this->content, FALSE, array(), NULL, NULL, NULL, 'block_content' ) );
|
||||
}
|
||||
|
||||
if ( $block_type === 'plugin' and ! $this->id )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'block_save_as_template', FALSE, FALSE, array(
|
||||
'togglesOn' => array( 'block_save_as_template_name' )
|
||||
), NULL, NULL, NULL, 'block_save_as_template' ) );
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'block_save_as_template_name', NULL, FALSE, array(), NULL, NULL, NULL, 'block_save_as_template_name' ) );
|
||||
}
|
||||
|
||||
if ( $block_type === 'custom' )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\YesNo( 'block_cache', ( $this->id ) ? $this->cache : FALSE, FALSE, array(), NULL, NULL, NULL, 'block_cache' ) );
|
||||
}
|
||||
|
||||
$form->hiddenValues['block_type'] = $block_type;
|
||||
$form->hiddenValues['block_editor'] = $block_editor;
|
||||
$form->hiddenValues['block_plugin'] = $this->plugin;
|
||||
if ( $this->plugin_app )
|
||||
{
|
||||
$form->hiddenValues['block_plugin_app']= $this->plugin_app;
|
||||
}
|
||||
if ( $this->plugin_plugin )
|
||||
{
|
||||
$form->hiddenValues['block_plugin_plugin']= $this->plugin_plugin;
|
||||
}
|
||||
$form->hiddenValues['template_params'] = ( $this->id ) ? $this->template_params : '';
|
||||
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'templates/view.css', 'cms', 'admin' ) );
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'blocks/form.css', 'cms', 'admin' ) );
|
||||
|
||||
\IPS\Output::i()->globalControllers[] = 'cms.admin.blocks.form';
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'admin_blocks.js', 'cms' ) );
|
||||
\IPS\Output::i()->title = ( $this->id ) ? \IPS\Member::loggedIn()->language()->addToStack('content_block_block_editing', NULL, array( 'sprintf' => array( $this->_title ) ) ) : \IPS\Member::loggedIn()->language()->addToStack('content_block_block_add');
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Format form values from add/edit form for save
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
{
|
||||
if ( ! $this->id )
|
||||
{
|
||||
$this->active = 1;
|
||||
$this->save();
|
||||
|
||||
if ( \IPS\Request::i()->block_editor === 'editor' )
|
||||
{
|
||||
\IPS\File::claimAttachments( 'block-content/block-' . $this->id, $this->id );
|
||||
}
|
||||
}
|
||||
|
||||
$config = array();
|
||||
|
||||
if( isset( $values['block_name'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'cms', "content_block_name_" . $this->id, $values['block_name'] );
|
||||
}
|
||||
|
||||
if( isset( $values['block_description'] ) )
|
||||
{
|
||||
\IPS\Lang::saveCustom( 'cms', "content_block_name_" . $this->id . '_desc', $values['block_description'] );
|
||||
|
||||
unset ( $values['block_description'] );
|
||||
}
|
||||
|
||||
$this->type = \IPS\Request::i()->block_type;
|
||||
$values['type'] = $this->type;
|
||||
|
||||
if( isset( $values['block_key'] ) )
|
||||
{
|
||||
if ( ! $values['block_key'] )
|
||||
{
|
||||
if ( is_array( $values['block_name'] ) )
|
||||
{
|
||||
$values['block_key'] = \IPS\Http\Url::seoTitle( $values['block_name'][ key( $values['block_name'] ) ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$values['block_key'] = \IPS\Http\Url::seoTitle( $values['block_name'] );
|
||||
}
|
||||
|
||||
/* Now test it */
|
||||
try
|
||||
{
|
||||
$block = \IPS\cms\Blocks\Block::load( $this->key, 'block_key');
|
||||
|
||||
/* It's taken... */
|
||||
if ( $this->id != $block->id )
|
||||
{
|
||||
$values['block_key'] .= '_' . uniqid();
|
||||
}
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
/* Doesn't exist? Good! */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( \IPS\Request::i()->block_type === 'plugin' )
|
||||
{
|
||||
$values['plugin_app'] = \IPS\Request::i()->block_plugin_app;
|
||||
|
||||
/* configure widget related values */
|
||||
if ( is_callable( array( $this->widget(), 'preConfig' ) ) )
|
||||
{
|
||||
$values = $this->widget()->preConfig( $values );
|
||||
}
|
||||
|
||||
/* Store config */
|
||||
foreach( $values as $k => $v )
|
||||
{
|
||||
if ( ! in_array( $k, array( 'block_name', 'block_key', 'block_description', 'block_category', 'block_template_id', 'block_template_use_how', 'block_content', 'block_save_as_template', 'block_save_as_template_name' ) ) )
|
||||
{
|
||||
if ( is_array( $v ) )
|
||||
{
|
||||
$theValue = NULL;
|
||||
foreach( $v as $eachKey => $eachValue )
|
||||
{
|
||||
if ( !( $eachValue instanceof \IPS\Node\Model ) AND $eachValue instanceof \IPS\Patterns\ActiveRecord )
|
||||
{
|
||||
$column = $eachValue::$databaseColumnId;
|
||||
$theValue[] = $eachValue->$column;
|
||||
}
|
||||
elseif( $eachValue instanceof \IPS\Node\Model )
|
||||
{
|
||||
$theValue[ $eachKey ] = $eachValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
$theValue[] = $eachValue;
|
||||
}
|
||||
}
|
||||
$v = $theValue;
|
||||
}
|
||||
else if ( !( $v instanceof \IPS\Node\Model ) AND $v instanceof \IPS\Patterns\ActiveRecord )
|
||||
{
|
||||
$column = $v::$databaseColumnId;
|
||||
$v = $v->$column;
|
||||
}
|
||||
else if ( $v instanceof \IPS\Http\Url )
|
||||
{
|
||||
$v = (string) $v;
|
||||
}
|
||||
|
||||
$config[ $k ] = $v;
|
||||
|
||||
unset( $values[ $k ] );
|
||||
}
|
||||
}
|
||||
|
||||
$values['plugin'] = \IPS\Request::i()->block_plugin;
|
||||
$values['plugin_config'] = json_encode( $config );
|
||||
|
||||
/* Are we using the template as-is? */
|
||||
if ( $values['block_template_use_how'] === 'use' )
|
||||
{
|
||||
$values['content'] = null;
|
||||
|
||||
/* Not using default? */
|
||||
if ( $values['block_template_id'] != '_default_' )
|
||||
{
|
||||
$values['template'] = $values['block_template_id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$values['template'] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We're using a copy */
|
||||
if ( isset( $values['block_save_as_template'] ) AND $values['block_save_as_template'] )
|
||||
{
|
||||
if ( $values['block_template_id'] == '_default_' )
|
||||
{
|
||||
/* Find it from the normal template system */
|
||||
$plugin = $this->widget();
|
||||
|
||||
$location = $plugin->getTemplateLocation();
|
||||
|
||||
$templateBits = \IPS\Theme::master()->getRawTemplates( $location['app'], $location['location'], $location['group'], \IPS\Theme::RETURN_ALL );
|
||||
$templateBit = $templateBits[ $location['app'] ][ $location['location'] ][ $location['group'] ][ $location['name'] ];
|
||||
|
||||
$templateArray = array(
|
||||
'key' => 'template_' . $templateBit['template_name'] . '.' . uniqid(),
|
||||
'title' => str_replace( '-', '_', \IPS\Http\Url::seoTitle( $values['block_save_as_template_name'] ? $values['block_save_as_template_name'] : $templateBit['template_name'] . '_' . \IPS\Member::loggedIn()->language()->get('copy_noun') ) ),
|
||||
'desc' => null,
|
||||
'content' => $values['block_content'],
|
||||
'location' => 'block',
|
||||
'group' => \IPS\Request::i()->block_plugin,
|
||||
'container' => null,
|
||||
'rel_id' => 0,
|
||||
'user_created' => 1,
|
||||
'user_edited' => 0,
|
||||
'params' => $templateBit['template_data']
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$template = \IPS\cms\Templates::load( $values['block_template_id'] );
|
||||
|
||||
$templateArray = array(
|
||||
'key' => 'template_' . $template->name . '.' . uniqid(),
|
||||
'title' => str_replace( '-', '_', \IPS\Http\Url::seoTitle( $values['block_save_as_template_name'] ? $values['block_save_as_template_name'] : $template->name . '_' . \IPS\Member::loggedIn()->language()->get('copy_noun') ) ),
|
||||
'desc' => null,
|
||||
'content' => $values['block_content'],
|
||||
'location' => 'block',
|
||||
'group' => \IPS\Request::i()->block_plugin,
|
||||
'container' => null,
|
||||
'rel_id' => 0,
|
||||
'user_created' => 1,
|
||||
'user_edited' => 0,
|
||||
'params' => $template->params
|
||||
);
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
throw new \LogicException('cms_error_no_template_found');
|
||||
}
|
||||
}
|
||||
|
||||
/* Save */
|
||||
$newTemplate = \IPS\cms\Templates::add( $templateArray );
|
||||
|
||||
$values['content'] = null;
|
||||
$values['template'] = $newTemplate->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Just use it this once */
|
||||
$values['content'] = $values['block_content'];
|
||||
$values['template'] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( isset( $values['block_content'] ) )
|
||||
{
|
||||
$values['template'] = 0;
|
||||
}
|
||||
|
||||
if ( isset( $values['block_category'] ) AND ( ! empty( $values['block_category'] ) OR $values['block_category'] === 0 ) )
|
||||
{
|
||||
$values['block_category'] = ( $values['block_category'] === 0 ) ? 0 : $values['block_category'];
|
||||
|
||||
if( isset( $values['block_category'] ) AND $values['block_category'] instanceof \IPS\Node\Model )
|
||||
{
|
||||
$values['block_category'] = $values['block_category']->_id;
|
||||
}
|
||||
}
|
||||
|
||||
if( isset( \IPS\Request::i()->template_params ) )
|
||||
{
|
||||
$values['template_params'] = \IPS\Request::i()->template_params;
|
||||
}
|
||||
|
||||
/* Config */
|
||||
if( isset( \IPS\Request::i()->block_editor ) )
|
||||
{
|
||||
$this->setConfig( 'editor', \IPS\Request::i()->block_editor );
|
||||
}
|
||||
|
||||
foreach( array( 'block_name', 'block_description', 'block_save_as_template', 'block_template_id', 'block_template_use_how', 'block_save_as_template_name', 'block_editor', 'block_plugin_app', 'block_plugin' ) as $field )
|
||||
{
|
||||
if ( array_key_exists( $field, $values ) )
|
||||
{
|
||||
unset( $values[ $field ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
if ( $this->_config !== NULL )
|
||||
{
|
||||
$this->config = json_encode( $this->_config );
|
||||
}
|
||||
|
||||
if ( $this->id )
|
||||
{
|
||||
static::deleteCompiled( $this->id );
|
||||
\IPS\cms\Widget::deleteCachesForBlocks( $this->key );
|
||||
}
|
||||
|
||||
parent::save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the widget object associated with this custom block
|
||||
*
|
||||
* @return \IPS\Widget
|
||||
*/
|
||||
public function widget()
|
||||
{
|
||||
if ( $this->type === 'plugin' AND $this->plugin )
|
||||
{
|
||||
if ( mb_substr( $this->plugin, 0, 8 ) === 'db_feed_' )
|
||||
{
|
||||
$this->plugin = 'RecordFeed';
|
||||
}
|
||||
|
||||
if ( ! $this->widgetLoaded )
|
||||
{
|
||||
$this->widgetLoaded = \IPS\Widget::load( $this->plugin_app ? \IPS\Application::load( $this->plugin_app ) : \IPS\Plugin::load( $this->plugin_plugin ), $this->plugin, uniqid(), $this->_plugin_config, NULL, $this->orientation );
|
||||
}
|
||||
|
||||
return $this->widgetLoaded;
|
||||
}
|
||||
|
||||
throw new \OutOfRangeException;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Block Container Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 19 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Blocks;
|
||||
|
||||
/* 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 Block Container Model
|
||||
*/
|
||||
class _Container extends \IPS\Node\Model
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_containers';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'container_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array('container_key');
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
public static $databaseColumnParent = 'parent_id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Root Value
|
||||
* @note This normally doesn't need changing though some legacy areas use -1 to indicate a root node
|
||||
*/
|
||||
public static $databaseColumnParentRootValue = 0;
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'order';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = '';
|
||||
|
||||
/**
|
||||
* @brief [Node] Subnode class
|
||||
*/
|
||||
public static $subnodeClass = 'IPS\cms\Blocks\Block';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] Sortable?
|
||||
*/
|
||||
public static $nodeSortable = TRUE;
|
||||
|
||||
/**
|
||||
* [Node] Get Title
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get__title()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch All Root Nodes
|
||||
*
|
||||
* @param string|NULL $permissionCheck The permission key to check for or NULl to not check permissions
|
||||
* @param \IPS\Member|NULL $member The member to check permissions for or NULL for the currently logged in member
|
||||
* @param mixed $where Additional WHERE clause
|
||||
* @return array
|
||||
*/
|
||||
public static function roots( $permissionCheck='view', $member=NULL, $where=array() )
|
||||
{
|
||||
return parent::roots( $permissionCheck, $member, array( array('container_type=?', 'block' ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get buttons to display in tree
|
||||
* Example code explains return value
|
||||
* @endcode
|
||||
* @param string $url Base URL
|
||||
* @param bool $subnode Is this a subnode?
|
||||
* @return array
|
||||
*/
|
||||
public function getButtons( $url, $subnode=FALSE )
|
||||
{
|
||||
$buttons = parent::getButtons( $url, $subnode );
|
||||
$return = array();
|
||||
|
||||
if ( isset( $buttons['copy'] ) )
|
||||
{
|
||||
unset( $buttons['copy'] );
|
||||
}
|
||||
|
||||
if ( isset( $buttons['add'] ) )
|
||||
{
|
||||
$buttons['add']['icon'] = 'folder-open';
|
||||
$buttons['add']['title'] = 'content_block_cat_add';
|
||||
$buttons['add']['data'] = array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('content_block_cat_add') );
|
||||
$buttons['add']['link'] = $url->setQueryString( array( 'subnode' => 0, 'do' => 'form', 'parent' => $this->_id ) );
|
||||
|
||||
$buttons['add_block'] = array(
|
||||
'icon' => 'plus-circle',
|
||||
'title' => 'content_block_block_add',
|
||||
'link' => $url->setQueryString( array( 'subnode' => 1, 'do' => 'addBlockType', 'parent' => $this->_id ) )
|
||||
);
|
||||
}
|
||||
|
||||
/* Re-arrange */
|
||||
if ( isset( $buttons['edit'] ) )
|
||||
{
|
||||
$return['edit'] = $buttons['edit'];
|
||||
}
|
||||
|
||||
if ( isset( $buttons['add_block'] ) )
|
||||
{
|
||||
$return['add_block'] = $buttons['add_block'];
|
||||
}
|
||||
|
||||
if ( isset( $buttons['add'] ) )
|
||||
{
|
||||
$return['add'] = $buttons['add'];
|
||||
}
|
||||
|
||||
if ( isset( $buttons['delete'] ) )
|
||||
{
|
||||
$return['delete'] = $buttons['delete'];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to delete this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canDelete()
|
||||
{
|
||||
if ( $this->key == 'block_custom' OR $this->key == 'block_plugins' )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return parent::canDelete();
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
/* Build form */
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'container_name', $this->id ? $this->name : '', TRUE, array( 'maxLength' => 64 ) ) );
|
||||
|
||||
$class = get_called_class();
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Node( 'container_parent_id', $this->parent_id ? $this->parent_id : 0, FALSE, array(
|
||||
'class' => '\IPS\cms\Blocks\Container',
|
||||
'zeroVal' => 'node_no_parent',
|
||||
'permissionCheck' => function( $node ) use ( $class )
|
||||
{
|
||||
if( isset( $class::$subnodeClass ) AND $class::$subnodeClass AND $node instanceof $class::$subnodeClass )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return !isset( \IPS\Request::i()->id ) or ( $node->id != \IPS\Request::i()->id and !$node->isChildOf( $node::load( \IPS\Request::i()->id ) ) );
|
||||
}
|
||||
) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Format form values from add/edit form for save
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
{
|
||||
if ( isset( $values['container_parent_id'] ) AND ( ! empty( $values['container_parent_id'] ) OR $values['container_parent_id'] === 0 ) )
|
||||
{
|
||||
$values['container_parent_id'] = ( $values['container_parent_id'] === 0 ) ? 0 : $values['container_parent_id']->id;
|
||||
}
|
||||
|
||||
$values['type'] = 'block';
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search
|
||||
*
|
||||
* @param string $column Column to search
|
||||
* @param string $query Search query
|
||||
* @param string|null $order Column to order by
|
||||
* @param mixed $where Where clause
|
||||
* @return array
|
||||
*/
|
||||
public static function search( $column, $query, $order, $where=array() )
|
||||
{
|
||||
if ( $column === '_title' )
|
||||
{
|
||||
$column = 'container_name';
|
||||
}
|
||||
|
||||
$where = array( array( 'container_type=?', 'block' ) );
|
||||
|
||||
return parent::search( $column, $query, 'container_name ASC', $where );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Abstract class that Controllers should extend
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 16 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract class that Controllers should extend
|
||||
*/
|
||||
abstract class _Controller extends \IPS\Dispatcher\Controller
|
||||
{
|
||||
/**
|
||||
* @brief Base URL
|
||||
*/
|
||||
public $url;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \IPS\Http\Url|NULL $url The base URL for this controller or NULL to calculate automatically
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $url=NULL )
|
||||
{
|
||||
if ( $url === NULL )
|
||||
{
|
||||
$class = get_called_class();
|
||||
$exploded = explode( '\\', $class );
|
||||
$this->url = \IPS\Http\Url::internal( "app=cms&module=database", 'front' ); /* @todo fix URL */
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,886 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Databases Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 31 March 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
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 [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
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Return all databases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function databases()
|
||||
{
|
||||
if ( ! static::$gotAll )
|
||||
{
|
||||
if ( \IPS\Db::i()->checkForTable( static::$databaseTable ) )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', static::$databaseTable ) as $db )
|
||||
{
|
||||
$id = $db[ static::$databasePrefix . static::$databaseColumnId ];
|
||||
static::$multitons[ $id ] = static::constructFromData( $db );
|
||||
}
|
||||
}
|
||||
|
||||
static::$gotAll = true;
|
||||
}
|
||||
|
||||
return static::$multitons;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
$fieldTitle[ $id ] = $lang->get('content_fields_is_title');
|
||||
$fieldContent[ $id ] = $lang->get('content_fields_is_content');
|
||||
$catTitle[ $id ] = $lang->get('content_database_noun_pu');
|
||||
$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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 OR \IPS\Dispatcher::i()->module->key === 'applications' ) ) )
|
||||
{
|
||||
$this->langLoaded = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $this->langLoaded )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['__indefart_content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( '__indefart_content_record_comments_title' );
|
||||
\IPS\Member::loggedIn()->language()->words['__indefart_content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( '__indefart_content_record_reviews_title' );
|
||||
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comments_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_reviews_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comments_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_reviews_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
|
||||
|
||||
$fieldsClass = '\IPS\cms\Fields' . $this->id;
|
||||
$customFields = $fieldsClass::data( 'view', $this );
|
||||
|
||||
foreach ( $customFields AS $id => $field)
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['sort_field_' . $id] = $field->_title;
|
||||
}
|
||||
|
||||
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' )
|
||||
{
|
||||
/* Moderator tools */
|
||||
\IPS\Member::loggedIn()->language()->words['modperms__core_Content_cms_Records' . $this->id ] = $this->_title;
|
||||
|
||||
/* 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' ) 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 ) ) ) );
|
||||
|
||||
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 )
|
||||
{
|
||||
$case = $upper ? 'u' : 'l';
|
||||
return $number == 1 ? \IPS\Member::loggedIn()->language()->addToStack("content_db_lang_s{$case}_{$this->id}") : \IPS\Member::loggedIn()->language()->addToStack("content_db_lang_p{$case}_{$this->id}");
|
||||
}
|
||||
|
||||
/**
|
||||
* [ActiveRecord] Delete Record
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$fieldsClass = '\IPS\cms\Fields' . $this->id;
|
||||
|
||||
$class = '\IPS\cms\Categories' . $this->id;
|
||||
foreach( $class::roots( NULL, NULL, array(), $this->id ) 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 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 ) );
|
||||
|
||||
/* 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 ) );
|
||||
|
||||
foreach( $memberIds as $member )
|
||||
{
|
||||
\IPS\Member::load( $member )->recountNotifications();
|
||||
}
|
||||
|
||||
/* Remove from search */
|
||||
\IPS\Content\Search\Index::i()->removeClassFromSearchIndex( 'IPS\cms\Records' . $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', "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( 'content_Records_' . $this->id );
|
||||
|
||||
/* Remove widgets */
|
||||
$this->removeWidgets();
|
||||
|
||||
parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
|
||||
/* Clone these permissions to all categories that do not have permissions */
|
||||
$class = '\IPS\cms\Categories' . $this->id;
|
||||
foreach( $class::roots( NULL, NULL, array(), $this->id ) 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Database Dispatcher
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 16 April 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Database Dispatcher
|
||||
*/
|
||||
class _Dispatcher extends \IPS\Dispatcher
|
||||
{
|
||||
/**
|
||||
* @brief Singleton Instance (So we don't re-use the regular dispatcher)
|
||||
*/
|
||||
protected static $instance = NULL;
|
||||
|
||||
/**
|
||||
* @brief Controller location
|
||||
*/
|
||||
public $controllerLocation = 'front';
|
||||
|
||||
/**
|
||||
* @brief Database Id
|
||||
*/
|
||||
public $databaseId = NULL;
|
||||
|
||||
/**
|
||||
* @brief Category Id
|
||||
*/
|
||||
public $categoryId = NULL;
|
||||
|
||||
/**
|
||||
* @brief Record Id
|
||||
*/
|
||||
public $recordId = NULL;
|
||||
|
||||
/**
|
||||
* @brief Url
|
||||
*/
|
||||
public $url = NULL;
|
||||
|
||||
/**
|
||||
* @brief Module
|
||||
*/
|
||||
public $module = NULL;
|
||||
|
||||
/**
|
||||
* @brief Output to return
|
||||
*/
|
||||
public $output = NULL;
|
||||
|
||||
/**
|
||||
* Set Database ID
|
||||
*
|
||||
* @param mixed $databaseId Database key or ID
|
||||
* @return \IPS\Dispatcher
|
||||
*/
|
||||
public function setDatabase( $databaseId )
|
||||
{
|
||||
/* Other areas rely on $this->databaseId being numeric */
|
||||
if ( ! is_numeric( $databaseId ) )
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $databaseId, 'database_key' );
|
||||
$databaseId = $database->id;
|
||||
}
|
||||
|
||||
$this->databaseId = $databaseId;
|
||||
|
||||
$database = \IPS\cms\Databases::load( $databaseId );
|
||||
if ( ! $database->use_categories )
|
||||
{
|
||||
$this->categoryId = $database->_default_category;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Category ID
|
||||
*
|
||||
* @param mixed $categoryId Category ID
|
||||
* @return \IPS\Dispatcher
|
||||
*/
|
||||
public function setCategory( $categoryId )
|
||||
{
|
||||
$this->categoryId = $categoryId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ( ( \IPS\cms\Pages\Page::$currentPage AND ! ( \IPS\Application::load('cms')->default AND ! \IPS\cms\Pages\Page::$currentPage->folder_id AND \IPS\cms\Pages\Page::$currentPage->default ) ) )
|
||||
{
|
||||
\IPS\Output::i()->breadcrumb['module'] = array( \IPS\cms\Pages\Page::$currentPage->url(), \IPS\cms\Pages\Page::$currentPage->_title );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
/* Coming from a widget? */
|
||||
if ( isset( \IPS\Request::i()->pageID ) and isset( \IPS\Request::i()->blockID ) )
|
||||
{
|
||||
if ( \IPS\cms\Pages\Page::$currentPage === NULL )
|
||||
{
|
||||
/* make sure this is a valid widgetized page to stop tampering */
|
||||
try
|
||||
{
|
||||
foreach ( \IPS\Db::i()->select( '*', 'cms_page_widget_areas', array( 'area_page_id=?', \IPS\Request::i()->pageID ) ) as $item )
|
||||
{
|
||||
foreach( json_decode( $item['area_widgets'], TRUE ) as $block )
|
||||
{
|
||||
if ( $block['key'] === 'Database' and isset( $block['configuration']['database'] ) and intval( $block['configuration']['database'] ) === $this->databaseId )
|
||||
{
|
||||
\IPS\cms\Pages\Page::$currentPage = \IPS\cms\Pages\Page::load( \IPS\Request::i()->pageID );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
|
||||
/* Try again */
|
||||
if ( \IPS\cms\Pages\Page::$currentPage === NULL )
|
||||
{
|
||||
\IPS\Output::i()->error( 'page_doesnt_exist', '2T251/1', 404 );
|
||||
}
|
||||
|
||||
/* Unset do query param otherwise it confuses the controller->execute(); */
|
||||
\IPS\Request::i()->do = NULL;
|
||||
}
|
||||
|
||||
$url = 'app=cms&module=pages&controller=page&path=' . \IPS\cms\Pages\Page::$currentPage->full_path;
|
||||
|
||||
try
|
||||
{
|
||||
$database = \IPS\cms\Databases::load( $this->databaseId );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
\IPS\Output::i()->error( 'page_doesnt_exist', '2T251/2', 404 );
|
||||
}
|
||||
|
||||
$path = trim( preg_replace( '#' . \IPS\cms\Pages\Page::$currentPage->full_path . '#', '', \IPS\Request::i()->path, 1 ), '/' );
|
||||
|
||||
$this->databaseId = $database->id;
|
||||
|
||||
if ( ! $database->use_categories )
|
||||
{
|
||||
$this->categoryId = $database->default_category;
|
||||
}
|
||||
|
||||
/* Got a specific category ID? */
|
||||
if ( $this->categoryId !== NULL and ! $path and ( ( $database->use_categories and $database->cat_index_type !== 1 ) OR ( ! $database->use_categories and isset( \IPS\Request::i()->do ) ) ) )
|
||||
{
|
||||
$this->module = 'category';
|
||||
}
|
||||
else if ( isset( \IPS\Request::i()->c ) AND is_numeric( \IPS\Request::i()->c ) )
|
||||
{
|
||||
$this->categoryId = \IPS\Request::i()->c;
|
||||
$this->module = 'category';
|
||||
}
|
||||
else if ( empty( $path ) )
|
||||
{
|
||||
$this->module = 'index';
|
||||
}
|
||||
else
|
||||
{
|
||||
$url .= '/' . $path;
|
||||
$recordClass = '\IPS\cms\Records' . $database->id;
|
||||
|
||||
if ( $database->use_categories )
|
||||
{
|
||||
$catClass = '\IPS\cms\Categories' . $database->id;
|
||||
$category = $catClass::loadFromPath( $path, $database->id );
|
||||
|
||||
if ( $category === NULL )
|
||||
{
|
||||
/* Is this a record? */
|
||||
$bits = explode( '/', $path );
|
||||
$slug = array_pop( $bits );
|
||||
|
||||
try
|
||||
{
|
||||
$record = $recordClass::loadFromSlug( $slug );
|
||||
|
||||
\IPS\Output::i()->redirect( $record->url(), NULL, 301 );
|
||||
}
|
||||
catch ( \OutOfRangeException $ex )
|
||||
{
|
||||
/* Check slug history */
|
||||
try
|
||||
{
|
||||
$record = $recordClass::loadFromSlugHistory( $slug );
|
||||
|
||||
\IPS\Output::i()->redirect( $record->url(), NULL, 301 );
|
||||
}
|
||||
catch ( \OutOfRangeException $ex )
|
||||
{
|
||||
\IPS\Output::i()->error( 'page_doesnt_exist', '2T251/4', 404 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$whatsLeft = preg_replace( '#' . $category->full_path . '#', '', $path, 1 );
|
||||
|
||||
$this->categoryId = $category->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$whatsLeft = $path;
|
||||
}
|
||||
|
||||
if ( $whatsLeft )
|
||||
{
|
||||
/* Find the record */
|
||||
try
|
||||
{
|
||||
$record = $recordClass::loadFromSlug( $whatsLeft );
|
||||
|
||||
/* Make the Content controller all kinds of happy */
|
||||
\IPS\Request::i()->id = $this->recordId = $record->primary_id_field;
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
/* Check slug history */
|
||||
try
|
||||
{
|
||||
$record = $recordClass::loadFromSlugHistory( $whatsLeft );
|
||||
|
||||
\IPS\Output::i()->redirect( $record->url(), NULL, 301 );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
\IPS\Output::i()->error( 'page_doesnt_exist', '2T251/5', 404 );
|
||||
}
|
||||
}
|
||||
|
||||
$this->module = 'record';
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's a category listing */
|
||||
$this->module = 'category';
|
||||
}
|
||||
}
|
||||
|
||||
$this->url = \IPS\Http\Url::internal( $url, 'front', 'content_page_path' );
|
||||
$className = '\\IPS\\cms\\modules\\front\\database\\' . $this->module;
|
||||
|
||||
/* Init class */
|
||||
if( !class_exists( $className ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'page_doesnt_exist', '2T251/6', 404 );
|
||||
}
|
||||
$controller = new $className;
|
||||
if( !( $controller instanceof \IPS\Dispatcher\Controller ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'page_not_found', '3T251/7', 500, '' );
|
||||
}
|
||||
|
||||
\IPS\Dispatcher::i()->dispatcherController = $controller;
|
||||
|
||||
/* Add database key to body classes for easier database specific themeing */
|
||||
\IPS\Output::i()->bodyClasses[] = 'cCmsDatabase_' . $database->key;
|
||||
|
||||
/* Execute */
|
||||
$controller->execute();
|
||||
|
||||
return $this->finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Soundcloud input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Fields;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Soundcloud input class for Form Builder
|
||||
*/
|
||||
class _Soundcloud extends \IPS\Helpers\Form\Text
|
||||
{
|
||||
/**
|
||||
* @brief Default Options
|
||||
*/
|
||||
public $childDefaultOptions = array(
|
||||
'parameters' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Sets that the field is required if there is a minimum length and vice-versa
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->childDefaultOptions['placeholder'] = \IPS\Member::loggedIn()->language()->addToStack('field_placeholder_soundcloud');
|
||||
|
||||
/* Call parent constructor */
|
||||
call_user_func_array( 'parent::__construct', func_get_args() );
|
||||
|
||||
$this->formType = 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display value
|
||||
*
|
||||
* @param mixed $value Stored value from form
|
||||
* @param \IPS\cms\Field $customField Custom Field Object
|
||||
* @return string
|
||||
*/
|
||||
public static function displayValue( $value, $customField )
|
||||
{
|
||||
$params = $customField->extra;
|
||||
|
||||
if ( ! isset( $params['width'] ) )
|
||||
{
|
||||
$params['width'] = '100%';
|
||||
}
|
||||
|
||||
if ( ! isset( $params['height'] ) )
|
||||
{
|
||||
$params['height'] = 166;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'records', 'cms', 'global' )->soundcloud( urlencode( $value ), $params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \DomainException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
if ( $this->value )
|
||||
{
|
||||
/* Check the URL is valid */
|
||||
if ( !( $this->value instanceof \IPS\Http\Url ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_url_bad');
|
||||
}
|
||||
|
||||
/* Check its a valid Soundcloud URL */
|
||||
if ( ! mb_stristr( $this->value->data['host'], 'soundcloud.com' ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_url_bad');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
$val = parent::getValue();
|
||||
if ( $val and !mb_strpos( $val, '://' ) )
|
||||
{
|
||||
$val = "http://{$val}";
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Value
|
||||
*
|
||||
* @return \IPS\Http\Url|string
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
if ( $this->value and !( $this->value instanceof \IPS\Http\Url ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
return new \IPS\Http\Url( $this->value );
|
||||
}
|
||||
catch ( \InvalidArgumentException $e )
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Spotify input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Fields;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spotify input class for Form Builder
|
||||
*/
|
||||
class _Spotify extends \IPS\Helpers\Form\Text
|
||||
{
|
||||
/**
|
||||
* @brief Default Options
|
||||
*/
|
||||
public $childDefaultOptions = array(
|
||||
'parameters' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Sets that the field is required if there is a minimum length and vice-versa
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->childDefaultOptions['placeholder'] = \IPS\Member::loggedIn()->language()->addToStack('field_placeholder_spotify');
|
||||
|
||||
/* Call parent constructor */
|
||||
call_user_func_array( 'parent::__construct', func_get_args() );
|
||||
|
||||
$this->formType = 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display value
|
||||
*
|
||||
* @param mixed $value Stored value from form
|
||||
* @param \IPS\cms\Field $customField Custom Field Object
|
||||
* @return string
|
||||
*/
|
||||
public static function displayValue( $value, $customField )
|
||||
{
|
||||
$params = $customField->extra;
|
||||
|
||||
if ( ! isset( $params['width'] ) )
|
||||
{
|
||||
$params['width'] = 300;
|
||||
}
|
||||
|
||||
if ( ! isset( $params['height'] ) )
|
||||
{
|
||||
$params['height'] = 80;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'records', 'cms', 'global' )->spotify( $value, $params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \DomainException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
if ( $this->value )
|
||||
{
|
||||
/* Check the URL is valid */
|
||||
if ( !( $this->value instanceof \IPS\Http\Url ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_url_bad');
|
||||
}
|
||||
|
||||
/* Check its a valid Spotify URL */
|
||||
if ( ! mb_stristr( $this->value->data['host'], 'spotify.com' ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_url_bad');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
$val = parent::getValue();
|
||||
if ( $val and !mb_strpos( $val, '://' ) )
|
||||
{
|
||||
$val = "http://{$val}";
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Value
|
||||
*
|
||||
* @return \IPS\Http\Url|string
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
if ( $this->value and !( $this->value instanceof \IPS\Http\Url ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
return new \IPS\Http\Url( $this->value );
|
||||
}
|
||||
catch ( \InvalidArgumentException $e )
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Youtube input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Fields;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Youtube input class for Form Builder
|
||||
*/
|
||||
class _Youtube extends \IPS\Helpers\Form\Text
|
||||
{
|
||||
/**
|
||||
* @brief Default Options
|
||||
*/
|
||||
public $childDefaultOptions = array(
|
||||
'parameters' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Sets that the field is required if there is a minimum length and vice-versa
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->childDefaultOptions['placeholder'] = \IPS\Member::loggedIn()->language()->addToStack('field_placeholder_youtube');
|
||||
|
||||
/* Call parent constructor */
|
||||
call_user_func_array( 'parent::__construct', func_get_args() );
|
||||
|
||||
$this->formType = 'text';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display value
|
||||
*
|
||||
* @param mixed $value Stored value from form
|
||||
* @param \IPS\cms\Field $customField Custom Field Object
|
||||
* @return string
|
||||
*/
|
||||
public static function displayValue( $value, $customField )
|
||||
{
|
||||
$url = new \IPS\Http\Url( $value );
|
||||
|
||||
if ( isset( $url->queryString['v'] ) )
|
||||
{
|
||||
$url = 'https://www.youtube.com/embed/' . $url->queryString['v'];
|
||||
}
|
||||
else if ( $url->data['host'] === 'youtu.be' and ! mb_strpos( $url->data['path'], 'embed' ) )
|
||||
{
|
||||
$url = 'https://www.youtube.com/embed/' . trim( $url->data['path'], '/' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$url = $value;
|
||||
}
|
||||
|
||||
$params = $customField->extra;
|
||||
|
||||
if ( ! isset( $params['width'] ) )
|
||||
{
|
||||
$params['width'] = 640;
|
||||
}
|
||||
|
||||
if ( ! isset( $params['height'] ) )
|
||||
{
|
||||
$params['height'] = 390;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'records', 'cms', 'global' )->youtube( $url, $params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \DomainException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
if ( $this->value )
|
||||
{
|
||||
/* Check the URL is valid */
|
||||
if ( !( $this->value instanceof \IPS\Http\Url ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_url_bad');
|
||||
}
|
||||
|
||||
/* Check its a valid Youtube URL */
|
||||
if ( ! mb_stristr( $this->value->data['host'], 'youtube.' ) and ! mb_stristr( $this->value->data['host'], 'youtu.be' ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_url_bad');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
$val = parent::getValue();
|
||||
if ( $val and !mb_strpos( $val, '://' ) )
|
||||
{
|
||||
$val = "http://{$val}";
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Value
|
||||
*
|
||||
* @return \IPS\Http\Url|string
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
if ( $this->value and !( $this->value instanceof \IPS\Http\Url ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
return new \IPS\Http\Url( $this->value );
|
||||
}
|
||||
catch ( \InvalidArgumentException $e )
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,378 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Folder Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 15 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Pages;
|
||||
|
||||
/* 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 Folder Model
|
||||
*/
|
||||
class _Folder extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* Munge different record types
|
||||
*
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function munge()
|
||||
{
|
||||
$rows = array();
|
||||
$args = func_get_args();
|
||||
|
||||
foreach( $args as $arg )
|
||||
{
|
||||
foreach( $arg as $id => $obj )
|
||||
{
|
||||
$rows[ $obj->getSortableName() . '_' . $obj::$databaseTable . '_' . $obj->id ] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
ksort( $rows );
|
||||
|
||||
return $rows;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_folders';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'folder_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array('folder_name', 'folder_path');
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
public static $databaseColumnParent = 'parent_id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Root Value
|
||||
* @note This normally doesn't need changing though some legacy areas use -1 to indicate a root node
|
||||
*/
|
||||
public static $databaseColumnParentRootValue = 0;
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'path';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'folder';
|
||||
|
||||
/**
|
||||
* @brief [Node] Subnode class
|
||||
*/
|
||||
public static $subnodeClass = 'IPS\cms\Pages\Page';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
protected static $restrictions = array(
|
||||
'app' => 'cms',
|
||||
'module' => 'pages',
|
||||
'all' => 'page_manage',
|
||||
'prefix' => 'page_'
|
||||
);
|
||||
|
||||
/**
|
||||
* [Node] Get Title
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get__title()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sortable name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSortableName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get buttons to display in tree
|
||||
* Example code explains return value
|
||||
* @endcode
|
||||
* @param string $url Base URL
|
||||
* @param bool $subnode Is this a subnode?
|
||||
* @return array
|
||||
*/
|
||||
public function getButtons( $url, $subnode=FALSE )
|
||||
{
|
||||
$buttons = parent::getButtons( $url, $subnode );
|
||||
$return = array();
|
||||
|
||||
if ( isset( $buttons['copy'] ) )
|
||||
{
|
||||
unset( $buttons['copy'] );
|
||||
}
|
||||
|
||||
if ( isset( $buttons['add'] ) )
|
||||
{
|
||||
$buttons['add']['icon'] = 'folder-open';
|
||||
$buttons['add']['title'] = 'content_add_folder';
|
||||
$buttons['add']['data'] = array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('content_add_folder') );
|
||||
$buttons['add']['link'] = $url->setQueryString( array( 'subnode' => 0, 'do' => 'form', 'parent' => $this->_id ) );
|
||||
|
||||
$buttons['add_page'] = array(
|
||||
'icon' => 'plus-circle',
|
||||
'title' => 'content_add_page',
|
||||
'link' => $url->setQueryString( array( 'subnode' => 1, 'do' => 'add', 'parent' => $this->_id ) ),
|
||||
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('content_add_page') )
|
||||
);
|
||||
}
|
||||
|
||||
/* Re-arrange */
|
||||
if ( isset( $buttons['edit'] ) )
|
||||
{
|
||||
$return['edit'] = $buttons['edit'];
|
||||
}
|
||||
|
||||
if ( isset( $buttons['add_page'] ) )
|
||||
{
|
||||
$return['add_page'] = $buttons['add_page'];
|
||||
}
|
||||
|
||||
if ( isset( $buttons['add'] ) )
|
||||
{
|
||||
$return['add'] = $buttons['add'];
|
||||
}
|
||||
|
||||
if ( isset( $buttons['delete'] ) )
|
||||
{
|
||||
$return['delete'] = $buttons['delete'];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
/* Build form */
|
||||
$form->add( new \IPS\Helpers\Form\Text( 'folder_name', $this->id ? $this->name : '', TRUE, array( 'maxLength' => 64 ), function( $val )
|
||||
{
|
||||
try
|
||||
{
|
||||
$test = \IPS\cms\Pages\Folder::load( \IPS\Http\Url::seoTitle( $val ), 'folder_name' );
|
||||
|
||||
if ( ! empty( \IPS\Request::i()->id ) and $test->id != \IPS\Request::i()->id )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_folder_name_in_use');
|
||||
}
|
||||
}
|
||||
catch ( \OutOfRangeException $e )
|
||||
{
|
||||
/* If we hit here, we don't have an existing folder by that name so check for a collision */
|
||||
if ( \IPS\Request::i()->folder_parent_id == 0 AND \IPS\cms\Pages\Page::isFurlCollision( \IPS\Http\Url::seoTitle( $val ) ) )
|
||||
{
|
||||
throw new \InvalidArgumentException('content_folder_name_furl_collision');
|
||||
}
|
||||
}
|
||||
} ) );
|
||||
|
||||
$class = get_called_class();
|
||||
|
||||
$form->add( new \IPS\Helpers\Form\Node( 'folder_parent_id', $this->parent_id ? $this->parent_id : 0, FALSE, array(
|
||||
'class' => '\IPS\cms\Pages\Folder',
|
||||
'zeroVal' => 'node_no_parent',
|
||||
'permissionCheck' => function( $node ) use ( $class )
|
||||
{
|
||||
if( isset( $class::$subnodeClass ) AND $class::$subnodeClass AND $node instanceof $class::$subnodeClass )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return !isset( \IPS\Request::i()->id ) or ( $node->id != \IPS\Request::i()->id and !$node->isChildOf( $node::load( \IPS\Request::i()->id ) ) );
|
||||
}
|
||||
) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Format form values from add/edit form for save
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
{
|
||||
$isNew = $this->_new;
|
||||
|
||||
if ( !$this->id )
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
$this->origParentId = $this->parent_id;
|
||||
$this->origName = $this->name;
|
||||
|
||||
if ( isset( $values['folder_parent_id'] ) AND ( ! empty( $values['folder_parent_id'] ) OR $values['folder_parent_id'] === 0 ) )
|
||||
{
|
||||
$values['parent_id'] = ( $values['folder_parent_id'] === 0 ) ? 0 : $values['folder_parent_id']->id;
|
||||
unset( $values['folder_parent_id'] );
|
||||
}
|
||||
|
||||
if( isset( $values['folder_name'] ) )
|
||||
{
|
||||
$values['name'] = \IPS\Http\Url::seoTitle( $values['folder_name'] );
|
||||
unset( $values['folder_name'] );
|
||||
}
|
||||
|
||||
if ( ! $isNew and ( $this->parent_id !== $values['parent_id'] or $this->name !== $values['name'] ) )
|
||||
{
|
||||
$this->storeUrl();
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Original parent ID
|
||||
*/
|
||||
protected $origParentId;
|
||||
|
||||
/**
|
||||
* @brief Original Name
|
||||
*/
|
||||
protected $origName;
|
||||
|
||||
/**
|
||||
* [Node] Perform actions after saving the form
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return void
|
||||
*/
|
||||
public function postSaveForm( $values )
|
||||
{
|
||||
if ( $this->origParentId !== $values['parent_id'] OR $this->origName !== $values['name'] )
|
||||
{
|
||||
$this->resetPath( true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the URL so when its changed, the old can 301 to the new location
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function storeUrl()
|
||||
{
|
||||
\IPS\Db::i()->insert( 'cms_url_store', array(
|
||||
'store_path' => $this->path,
|
||||
'store_current_id' => $this->_id,
|
||||
'store_type' => 'folder'
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a folder
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->last_modified = time();
|
||||
|
||||
parent::save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the stored path
|
||||
*
|
||||
* @param boolean $recursivelyCheck Recursively reset up and down the tree
|
||||
* @return void
|
||||
*/
|
||||
public function resetPath( $recursivelyCheck=true )
|
||||
{
|
||||
$path = array();
|
||||
|
||||
foreach( $this->parents() as $obj )
|
||||
{
|
||||
$path[] = $obj->name;
|
||||
}
|
||||
|
||||
$this->path = ( count( $path ) ) ? implode( '/', $path ) . '/' . $this->name : $this->name;
|
||||
|
||||
/* Save path update */
|
||||
parent::save();
|
||||
|
||||
/* Update pages */
|
||||
\IPS\cms\Pages\Page::resetPath( $this->id );
|
||||
|
||||
if ( $recursivelyCheck === true )
|
||||
{
|
||||
/* Fix children */
|
||||
foreach( $this->children( NULL, NULL, FALSE ) as $child )
|
||||
{
|
||||
$child->resetPath( false );
|
||||
$child->_recursivelyResetChildPaths();
|
||||
}
|
||||
|
||||
/* Fix parents */
|
||||
foreach( $this->parents() as $parent )
|
||||
{
|
||||
$parent->resetPath( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurse through the node tree to reset kids
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _recursivelyResetChildPaths()
|
||||
{
|
||||
foreach( $this->children( NULL, NULL, FALSE ) as $child )
|
||||
{
|
||||
$child->resetPath( false );
|
||||
$child->_recursivelyResetChildPaths();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Menu Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 15 Sept 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Pages;
|
||||
|
||||
/* 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 Menu Model
|
||||
*/
|
||||
class _Menu extends \IPS\Node\Model
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_page_menu';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'menu_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array();
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Database Column
|
||||
*/
|
||||
public static $databaseColumnParent = 'parent_id';
|
||||
|
||||
/**
|
||||
* @brief [Node] Parent ID Root Value
|
||||
* @note This normally doesn't need changing though some legacy areas use -1 to indicate a root node
|
||||
*/
|
||||
public static $databaseColumnParentRootValue = 0;
|
||||
|
||||
/**
|
||||
* @brief [Node] Order Database Column
|
||||
*/
|
||||
public static $databaseColumnOrder = 'position';
|
||||
|
||||
/**
|
||||
* @brief [Node] Node Title
|
||||
*/
|
||||
public static $nodeTitle = 'cms_menu';
|
||||
|
||||
/**
|
||||
* @brief [Node] Show forms modally?
|
||||
*/
|
||||
public static $modalForms = TRUE;
|
||||
|
||||
/**
|
||||
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
|
||||
*/
|
||||
public static $titleLangPrefix = 'cms_menu_title_';
|
||||
|
||||
/**
|
||||
* @brief [Node] ACP Restrictions
|
||||
* @code
|
||||
array(
|
||||
'app' => 'core', // The application key which holds the restrictrions
|
||||
'module' => 'foo', // The module key which holds the restrictions
|
||||
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
|
||||
'add' => 'foo_add',
|
||||
'edit' => 'foo_edit',
|
||||
'permissions' => 'foo_perms',
|
||||
'delete' => 'foo_delete'
|
||||
),
|
||||
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
|
||||
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
|
||||
* @endcode
|
||||
*/
|
||||
protected static $restrictions = array(
|
||||
'app' => 'cms',
|
||||
'module' => 'pages',
|
||||
'all' => 'page_manage',
|
||||
'prefix' => 'page_'
|
||||
);
|
||||
|
||||
/**
|
||||
* Form elements
|
||||
*
|
||||
* @param \IPS\cms\Pages\Menu|null $node Menu item
|
||||
* @return array
|
||||
*/
|
||||
public static function formElements( $node=NULL, $forceType=NULL )
|
||||
{
|
||||
$form = array();
|
||||
|
||||
if ( $forceType === NULL )
|
||||
{
|
||||
$form['menu_type'] = new \IPS\Helpers\Form\Select( 'menu_type', ( $node !== NULL ? $node->type : 'page' ), TRUE, array(
|
||||
'options' => array(
|
||||
'page' => 'cms_menu_form_type_page',
|
||||
'url' => 'cms_menu_form_type_url',
|
||||
'folder' => 'cms_menu_form_type_folder',
|
||||
#'separator' => 'cms_menu_form_type_separator'
|
||||
),
|
||||
'toggles' => array(
|
||||
'page' => array( 'menu_content_page', 'menu_title_page', 'menu_permission_from_page'),
|
||||
'url' => array( 'menu_content_url', 'menu_title_url', 'menu_permission' ),
|
||||
'folder' => array( 'menu_title_folder', 'menu_permission')
|
||||
)
|
||||
) );
|
||||
}
|
||||
|
||||
/* Page fields */
|
||||
if ( $forceType !== 'page' )
|
||||
{
|
||||
$pages = array();
|
||||
foreach( \IPS\cms\Pages\Page::roots() as $id => $page )
|
||||
{
|
||||
$pages[ $id ] = $page->_title . ' (' . $page->full_path . ')';
|
||||
}
|
||||
|
||||
$form['menu_content_page'] = new \IPS\Helpers\Form\Select( 'menu_content_page', $node !== NULL ? ( $node->type === 'page' ? $node->content : NULL ) : 0, FALSE, array(
|
||||
'options' => $pages
|
||||
), NULL, NULL, NULL, 'menu_content_page' );
|
||||
}
|
||||
|
||||
$form['menu_title_page'] = new \IPS\Helpers\Form\Translatable( 'menu_title_page', NULL, FALSE, array( 'app' => 'cms', 'key' => ( ( ! empty( $node ) and $node->type === 'page' ) ? "cms_menu_title_" . $node->id : NULL ), 'maxLength' => 64 ), NULL, NULL, NULL, 'menu_title_page' );
|
||||
|
||||
/* URL Fields */
|
||||
if ( $forceType === NULL or $forceType === 'url' )
|
||||
{
|
||||
$form['menu_content_url'] = new \IPS\Helpers\Form\Text( 'menu_content_url', $node !== NULL ? ( $node->type === 'url' ? $node->content : NULL ) : '', FALSE, array(), NULL, NULL, NULL, 'menu_content_url' );
|
||||
|
||||
$form['menu_title_url'] = new \IPS\Helpers\Form\Translatable( 'menu_title_url', NULL, FALSE, array( 'app' => 'cms', 'key' => ( ( ! empty( $node ) and $node->type === 'url' ) ? "cms_menu_title_" . $node->id : NULL ), 'maxLength' => 64 ), NULL, NULL, NULL, 'menu_title_url' );
|
||||
}
|
||||
|
||||
/* Folder fields */
|
||||
if ( $forceType === NULL or $forceType === 'folder' )
|
||||
{
|
||||
$form['menu_title_folder'] = new \IPS\Helpers\Form\Translatable( 'menu_title_folder', NULL, FALSE, array( 'app' => 'cms', 'key' => ( ( ! empty( $node ) and $node->type === 'folder' ) ? "cms_menu_title_" . $node->id : NULL ), 'maxLength' => 64 ), NULL, NULL, NULL, 'menu_title_folder' );
|
||||
}
|
||||
|
||||
/* Shared fields */
|
||||
$form['menu_parent_id'] = new \IPS\Helpers\Form\Node( 'menu_parent_id', $node !== NULL ? intval( $node->parent_id ) : 0, FALSE, array(
|
||||
'class' => '\IPS\cms\Pages\Menu',
|
||||
'zeroVal' => 'node_no_parent',
|
||||
'permissionCheck' => function( $node )
|
||||
{
|
||||
return $node->type === 'folder';
|
||||
}
|
||||
), NULL, NULL, NULL, 'menu_parent_id' );
|
||||
|
||||
$form['menu_permission_from_page'] = new \IPS\Helpers\Form\Radio( 'menu_permission_type', $node !== NULL ? ( $node->permission === 'page' ? 'page' : 'manual' ) : ( $forceType === 'page' ? 'page' : 'manual' ), FALSE, array(
|
||||
'options' => array(
|
||||
'page' => 'cms_menu_form_perm_page',
|
||||
'manual' => 'cms_menu_form_perm_manual'
|
||||
),
|
||||
'toggles' => array(
|
||||
'manual' => array( 'menu_permission' )
|
||||
)
|
||||
), NULL, NULL, NULL, 'menu_permission_from_page' );
|
||||
|
||||
$form['menu_permission'] = new \IPS\Helpers\Form\Select( 'menu_permission', ( $node !== NULL ) ? ( ( $node->permission === '*' ) ? '*' : explode( ',', $node->permission ) ) : NULL, FALSE, array(
|
||||
'options' => array_combine( array_keys( \IPS\Member\Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups() ) ),
|
||||
'multiple' => true,
|
||||
'unlimited' => '*',
|
||||
'unlimitedLang' => 'cms_menu_perm_any'
|
||||
), NULL, NULL, NULL, 'menu_permission' );
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear caches
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clearCaches()
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->cms_menu );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Set Title
|
||||
*
|
||||
* @param string $title Title
|
||||
* @return string|null
|
||||
*/
|
||||
protected function set__title( $title )
|
||||
{
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get Title
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get__title()
|
||||
{
|
||||
if ( ! $this->title AND $this->type === 'page' )
|
||||
{
|
||||
try
|
||||
{
|
||||
$this->title = \IPS\cms\Pages\Page::load( $this->content )->_title;
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
$this->title = '';
|
||||
}
|
||||
}
|
||||
else if ( ! $this->title )
|
||||
{
|
||||
/* This is stored in a separate \Data\Store cache, so we can't return the hash */
|
||||
$this->title = \IPS\Member::loggedIn()->language()->get( 'cms_menu_title_' . $this->id );
|
||||
}
|
||||
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get URL
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function get__url()
|
||||
{
|
||||
if ( $this->type === 'page' )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\cms\Pages\Page::load( $this->content )->url();
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Return the custom badge for each row
|
||||
*
|
||||
* @return NULL|array Null for no badge, or an array of badge data (0 => CSS class type, 1 => language string, 2 => optional raw HTML to show instead of language string)
|
||||
*/
|
||||
protected function get__badge()
|
||||
{
|
||||
if ( ! $this->permission )
|
||||
{
|
||||
return array( 'ipsBadge ipsBadge_negative', 'cms_menu_no_item_perm' );
|
||||
}
|
||||
|
||||
return ( $this->type === 'folder' ) ? NULL : array( 'ipsBadge ipsBadge_intermediary ipsPos_right', 'cms_menu_form_type_' . $this->type );
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Get buttons to display in tree
|
||||
* Example code explains return value
|
||||
*
|
||||
* @code
|
||||
array(
|
||||
array(
|
||||
'icon' => 'plus-circle', // Name of FontAwesome icon to use
|
||||
'title' => 'foo', // Language key to use for button's title parameter
|
||||
'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to
|
||||
'class' => 'modalLink' // CSS Class to use on link (Optional)
|
||||
),
|
||||
... // Additional buttons
|
||||
);
|
||||
* @endcode
|
||||
* @param string $url Base URL
|
||||
* @param bool $subnode Is this a subnode?
|
||||
* @return array
|
||||
*/
|
||||
public function getButtons( $url, $subnode=FALSE )
|
||||
{
|
||||
$buttons = parent::getButtons( $url, $subnode );
|
||||
|
||||
if ( isset( $buttons['copy'] ) and $this->type === 'folder' )
|
||||
{
|
||||
unset( $buttons['copy'] );
|
||||
}
|
||||
|
||||
return $buttons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sortable name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSortableName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Add/Edit Form
|
||||
*
|
||||
* @param \IPS\Helpers\Form $form The form
|
||||
* @return void
|
||||
*/
|
||||
public function form( &$form )
|
||||
{
|
||||
/* Build form */
|
||||
foreach( static::formElements( $this ) as $element )
|
||||
{
|
||||
$form->add( $element );
|
||||
}
|
||||
|
||||
if ( $this->id )
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_menu_edit', FALSE, array( 'sprintf' => array( $this->_title ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_menu_adding');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Format form values from add/edit form for save
|
||||
*
|
||||
* @param array $values Values from the form
|
||||
* @return array
|
||||
*/
|
||||
public function formatFormValues( $values )
|
||||
{
|
||||
if ( ! $this->id )
|
||||
{
|
||||
$this->parent_id = 0;
|
||||
$this->save();
|
||||
}
|
||||
|
||||
if( isset( $values['menu_type'] ) )
|
||||
{
|
||||
$title = '';
|
||||
$content = NULL;
|
||||
|
||||
switch ( $values['menu_type'] )
|
||||
{
|
||||
case 'page':
|
||||
$title = $values['menu_title_page'];
|
||||
$content = $values['menu_content_page'];
|
||||
break;
|
||||
case 'url':
|
||||
$title = $values['menu_title_url'];
|
||||
$content = $values['menu_content_url'];
|
||||
break;
|
||||
case 'folder':
|
||||
$title = $values['menu_title_folder'];
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need to store something in menu_title field in the database as we can leave this blank to get the current page title. We can't examine an addToStack to see if any data was returned */
|
||||
$values['title'] = current( $title );
|
||||
$values['content'] = $content;
|
||||
|
||||
\IPS\Lang::saveCustom( 'cms', "cms_menu_title_" . $this->id, $title );
|
||||
|
||||
unset( $values['menu_title_folder'], $values['menu_title_url'], $values['menu_title_page'], $values['menu_content_page'], $values['menu_content_url'] );
|
||||
}
|
||||
|
||||
if( isset( $values['menu_permission'] ) )
|
||||
{
|
||||
$values['menu_permission'] = ( is_array( $values['menu_permission'] ) ) ? implode( ',', $values['menu_permission'] ) : $values['menu_permission'];
|
||||
}
|
||||
|
||||
if ( isset( $values['menu_type'] ) AND $values['menu_type'] === 'page' and $values['menu_permission_type'] === 'page' )
|
||||
{
|
||||
$values['menu_permission'] = 'page';
|
||||
}
|
||||
|
||||
if ( isset( $values['menu_parent_id'] ) AND ( ! empty( $values['menu_parent_id'] ) OR $values['menu_parent_id'] === 0 ) )
|
||||
{
|
||||
$values['menu_parent_id'] = ( $values['menu_parent_id'] === 0 ) ? 0 : $values['menu_parent_id']->id;
|
||||
}
|
||||
|
||||
if( isset( $values['menu_permission_type'] ) )
|
||||
{
|
||||
unset( $values['menu_permission_type'] );
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Node] Does the currently logged in user have permission to add a child node to this node?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdd()
|
||||
{
|
||||
if ( parent::canAdd() )
|
||||
{
|
||||
return $this->type === 'folder';
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
static::clearCaches();
|
||||
parent::save();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Whitespace-only changes.
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Post Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Board
|
||||
* @since 8 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Records;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post Model
|
||||
*/
|
||||
class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter, \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Reputation, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = NULL;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_database_comments';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'comment_';
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'cms';
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'content_comment';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'item' => 'record_id',
|
||||
'author' => 'user',
|
||||
'author_name' => 'author',
|
||||
'content' => 'post',
|
||||
'date' => 'date',
|
||||
'ip_address' => 'ip_address',
|
||||
'edit_time' => 'edit_date',
|
||||
'edit_show' => 'edit_show',
|
||||
'edit_member_name' => 'edit_member_name',
|
||||
'edit_member_id' => 'edit_member_id',
|
||||
'edit_reason' => 'edit_reason',
|
||||
'approved' => 'approved',
|
||||
# 'first' => 'new_topic'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'comment';
|
||||
|
||||
/**
|
||||
* @brief Reputation Type
|
||||
*/
|
||||
public static $reputationType = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Comment Template
|
||||
*/
|
||||
public static $commentTemplate = array( array( 'display', 'cms', 'database' ), 'commentContainer' );
|
||||
|
||||
/**
|
||||
* @brief Database ID
|
||||
*/
|
||||
public static $customDatabaseId = NULL;
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
*/
|
||||
public static $hideLogKey = 'ccs-records';
|
||||
|
||||
/**
|
||||
* Return custom where for SQL delete
|
||||
*
|
||||
* @param int $id Content item to delete from
|
||||
* @return array
|
||||
*/
|
||||
public static function deleteWhereSql( $id )
|
||||
{
|
||||
return array( array( static::$databasePrefix . static::$databaseColumnMap['item'] . '=?', $id ), array( static::$databasePrefix . 'database_id=?', static::$customDatabaseId ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Do stuff after creating (abstracted as comments and reviews need to do different things)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function postCreate()
|
||||
{
|
||||
$this->database_id = static::$customDatabaseId;
|
||||
$this->save();
|
||||
|
||||
$item = $this->item();
|
||||
if ( $item->hidden() OR ( \IPS\cms\Databases::load( static::$customDatabaseId )->_comment_bump & \IPS\cms\Databases::BUMP_ON_COMMENT ) )
|
||||
{
|
||||
parent::postCreate();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No bump, so don't update the record's last_action stuff */
|
||||
if ( isset( $item::$databaseColumnMap['num_comments'] ) )
|
||||
{
|
||||
$item->resyncCommentCounts();
|
||||
}
|
||||
|
||||
if ( $item->containerWrapper() AND $item->container()->_comments !== NULL )
|
||||
{
|
||||
$item->container()->_comments = ( $item->container()->_comments + 1 );
|
||||
$item->container()->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
$template = static::$commentTemplate[1];
|
||||
static::$commentTemplate[0][0] = $this->item()->database()->template_display;
|
||||
return call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), static::$commentTemplate[0] )->$template( $this->item(), $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL for doing stuff
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$url = parent::url( $action );
|
||||
|
||||
if ( $action !== NULL )
|
||||
{
|
||||
$url = $url->setQueryString( 'd', static::$customDatabaseId );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment IDs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attachmentIds()
|
||||
{
|
||||
$item = $this->item();
|
||||
$idColumn = $item::$databaseColumnId;
|
||||
$commentIdColumn = static::$databaseColumnId;
|
||||
return array( $this->item()->$idColumn, $this->$commentIdColumn, static::$customDatabaseId );
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition where needed for fetching comments
|
||||
*
|
||||
* @return array|NULL
|
||||
*/
|
||||
public static function commentWhere()
|
||||
{
|
||||
return array( 'comment_database_id=?', static::$customDatabaseId );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Forum Post Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 8 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Records;
|
||||
|
||||
/* 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 Records Model
|
||||
*/
|
||||
class _CommentTopicSync extends \IPS\cms\Records\Comment
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'pid';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'forums_posts';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = '';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'item' => 'topic_id',
|
||||
'author' => 'author_id',
|
||||
'author_name' => 'author_name',
|
||||
'content' => 'post',
|
||||
'date' => 'post_date',
|
||||
'ip_address' => 'ip_address',
|
||||
'edit_time' => 'edit_time',
|
||||
'edit_show' => 'append_edit',
|
||||
'edit_member_name' => 'edit_name',
|
||||
'edit_reason' => 'post_edit_reason',
|
||||
'hidden' => 'queued',
|
||||
'first' => 'new_topic'
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'forums';
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'comment';
|
||||
|
||||
/**
|
||||
* @brief Reputation Type
|
||||
*/
|
||||
public static $reputationType = 'pid';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Comment Template
|
||||
*/
|
||||
public static $commentTemplate = array( array( 'display', 'cms', 'database' ), 'commentContainer' );
|
||||
|
||||
/**
|
||||
* @brief Bitwise values for post_bwoptions field
|
||||
*/
|
||||
public static $bitOptions = array(
|
||||
'post_bwoptions' => array(
|
||||
'post_bwoptions' => array(
|
||||
'best_answer' => 1
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Get containing item
|
||||
*
|
||||
* @return \IPS\cms\Record
|
||||
*/
|
||||
public function item()
|
||||
{
|
||||
$itemClass = static::$itemClass;
|
||||
return $itemClass::load( \IPS\Request::i()->id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Comment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
parent::delete();
|
||||
|
||||
try
|
||||
{
|
||||
$topic = \IPS\forums\Topic::load( $this->topic_id );
|
||||
$topic->resyncCommentCounts();
|
||||
$topic->resyncLastComment();
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Addition where needed for fetching comments
|
||||
*
|
||||
* @return array|NULL
|
||||
*/
|
||||
public static function commentWhere()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return custom where for SQL delete
|
||||
*
|
||||
* @param int $id Content item to delete from
|
||||
* @return array
|
||||
*/
|
||||
public static function deleteWhereSql( $id )
|
||||
{
|
||||
return array( array( static::$databasePrefix . static::$databaseColumnMap['item'] . '=?', $id ) );
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,182 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Post Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @subpackage Board
|
||||
* @since 8 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Records;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post Model
|
||||
*/
|
||||
class _Review extends \IPS\Content\Review implements \IPS\Content\ReportCenter, \IPS\Content\EditHistory, \IPS\Content\Hideable, \IPS\Content\Reputation, \IPS\Content\Shareable, \IPS\Content\Searchable, \IPS\Content\Embeddable
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Item Class
|
||||
*/
|
||||
public static $itemClass = NULL;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_database_reviews';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'review_';
|
||||
|
||||
/**
|
||||
* @brief Application
|
||||
*/
|
||||
public static $application = 'cms';
|
||||
|
||||
/**
|
||||
* @brief Title
|
||||
*/
|
||||
public static $title = 'content_review';
|
||||
|
||||
/**
|
||||
* @brief Database Column Map
|
||||
*/
|
||||
public static $databaseColumnMap = array(
|
||||
'item' => 'item',
|
||||
'author' => 'author',
|
||||
'author_name' => 'author_name',
|
||||
'content' => 'content',
|
||||
'date' => 'date',
|
||||
'ip_address' => 'ip_address',
|
||||
'edit_time' => 'edit_time',
|
||||
'edit_member_name' => 'edit_member_name',
|
||||
'edit_show' => 'edit_show',
|
||||
'rating' => 'rating',
|
||||
'votes_total' => 'votes_total',
|
||||
'votes_helpful' => 'votes_helpful',
|
||||
'votes_data' => 'votes_data',
|
||||
'approved' => 'approved',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Icon
|
||||
*/
|
||||
public static $icon = 'comment';
|
||||
|
||||
/**
|
||||
* @brief Reputation Type
|
||||
*/
|
||||
public static $reputationType = 'review_id';
|
||||
|
||||
/**
|
||||
* @brief [Content\Comment] Comment Template
|
||||
*/
|
||||
public static $commentTemplate = array( array( 'display', 'cms', 'database' ), 'reviewContainer' );
|
||||
|
||||
/**
|
||||
* @brief Database ID
|
||||
*/
|
||||
public static $customDatabaseId = NULL;
|
||||
|
||||
/**
|
||||
* @brief [Content] Key for hide reasons
|
||||
*/
|
||||
public static $hideLogKey = 'ccs-records-review';
|
||||
|
||||
/**
|
||||
* Create first comment (created with content item)
|
||||
*
|
||||
* @param \IPS\Content\Item $item The content item just created
|
||||
* @param string $comment The comment
|
||||
* @param bool $first Is the first comment?
|
||||
* @param int $rating The rating (1-5)
|
||||
* @param string $guestName If author is a guest, the name to use
|
||||
* @param \IPS\Member|NULL $member The author of this comment. If NULL, uses currently logged in member.
|
||||
* @param \IPS\DateTime|NULL $time The time
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function create( $item, $comment, $first=FALSE, $rating=NULL, $guestName=NULL, $member=NULL, \IPS\DateTime $time=NULL )
|
||||
{
|
||||
$review = call_user_func_array( 'parent::create', func_get_args() );
|
||||
|
||||
$review->database_id = static::$customDatabaseId;
|
||||
$review->save();
|
||||
|
||||
return $review;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return custom where for SQL delete
|
||||
*
|
||||
* @param int $id Content item to delete from
|
||||
* @return array
|
||||
*/
|
||||
public static function deleteWhereSql( $id )
|
||||
{
|
||||
return array( array( static::$databasePrefix . static::$databaseColumnMap['item'] . '=?', $id ), array( static::$databasePrefix . 'database_id=?', static::$customDatabaseId ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
$template = static::$commentTemplate[1];
|
||||
return call_user_func_array( array( \IPS\cms\Theme::i(), 'getTemplate' ), static::$commentTemplate[0] )->$template( $this->item(), $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL for doing stuff
|
||||
*
|
||||
* @param string|NULL $action Action
|
||||
* @return \IPS\Http\Url
|
||||
*/
|
||||
public function url( $action=NULL )
|
||||
{
|
||||
$url = parent::url( $action );
|
||||
|
||||
if ( $action !== NULL )
|
||||
{
|
||||
$url = $url->setQueryString( 'd', static::$customDatabaseId );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment IDs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function attachmentIds()
|
||||
{
|
||||
$item = $this->item();
|
||||
$idColumn = $item::$databaseColumnId;
|
||||
$commentIdColumn = static::$databaseColumnId;
|
||||
return array( $this->item()->$idColumn, $this->$commentIdColumn, static::$customDatabaseId . '-review' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Revisions Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 29 April 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Records;
|
||||
|
||||
/* 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 Records Model
|
||||
*/
|
||||
class _Revisions extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief Multiton Store
|
||||
*/
|
||||
protected static $multitons = array();
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_database_revisions';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'revision_';
|
||||
|
||||
/**
|
||||
* @brief Unpacked data
|
||||
*/
|
||||
protected $_dataJson = NULL;
|
||||
|
||||
/**
|
||||
* Constructor - Create a blank object with default values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if ( $this->_new )
|
||||
{
|
||||
$this->member_id = \IPS\Member::loggedIn()->member_id;
|
||||
$this->date = time();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value by key
|
||||
*
|
||||
* @param string $key Key of value to return
|
||||
* @return mixed
|
||||
*/
|
||||
public function get( $key )
|
||||
{
|
||||
if ( $this->_dataJson === NULL )
|
||||
{
|
||||
$this->_dataJson = $this->data;
|
||||
}
|
||||
|
||||
if ( isset( $this->_dataJson[ $key ] ) )
|
||||
{
|
||||
return $this->_dataJson[ $key ];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute differences
|
||||
*
|
||||
* @param int $databaseId Database ID
|
||||
* @param \IPS\cms\Records $record Record
|
||||
* @param boolean $justChanged Get changed only
|
||||
* @return array
|
||||
*/
|
||||
public function getDiffHtmlTables( $databaseId, $record, $justChanged=FALSE )
|
||||
{
|
||||
$fieldsClass = 'IPS\cms\Fields' . $databaseId;
|
||||
$customFields = $fieldsClass::data( 'view' );
|
||||
$conflicts = array();
|
||||
|
||||
require_once \IPS\ROOT_PATH . "/system/3rd_party/Diff/class.Diff.php";
|
||||
|
||||
/* Build up our data set */
|
||||
foreach( $customFields as $id => $field )
|
||||
{
|
||||
$key = 'field_' . $field->id;
|
||||
|
||||
$conflicts[ $key ] = array( 'revision' => $this->get( $key ), 'record' => $record->$key, 'field' => $field, 'diff' => NULL );
|
||||
|
||||
if ( $record->$key AND $this->get( $key ) )
|
||||
{
|
||||
if ( md5( $record->$key ) != md5( $this->get( $key ) ) )
|
||||
{
|
||||
$conflicts[ $key ]['diff'] = \Diff::toTable( \Diff::compare( $this->get( $key ), $record->$key ) );
|
||||
}
|
||||
else if ( $justChanged !== FALSE )
|
||||
{
|
||||
unset( $conflicts[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $conflicts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "data" field
|
||||
*
|
||||
* @param string|array $value
|
||||
* @return void
|
||||
*/
|
||||
public function set_data( $value )
|
||||
{
|
||||
$this->_data['data'] = ( is_array( $value ) ? json_encode( $value ) : $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "data" field
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_data()
|
||||
{
|
||||
return json_decode( $this->_data['data'], TRUE );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Templates Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 25 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Templates;
|
||||
|
||||
/* 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 Template Model
|
||||
*/
|
||||
class _Container extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons = array();
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'container_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_containers';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'container_key' );
|
||||
|
||||
/**
|
||||
* @brief Have fetched all?
|
||||
*/
|
||||
protected static $gotAll = FALSE;
|
||||
|
||||
/**
|
||||
* Return all containers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function containers()
|
||||
{
|
||||
if ( ! static::$gotAll )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', static::$databaseTable ) as $container )
|
||||
{
|
||||
static::$multitons[ $container['container_id'] ] = static::constructFromData( $container );
|
||||
}
|
||||
|
||||
static::$gotAll = true;
|
||||
}
|
||||
|
||||
return static::$multitons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all containers by type
|
||||
*
|
||||
* @param string $type Type of container (template_block, page, etc)
|
||||
* @return array of Container objects
|
||||
*/
|
||||
public static function getByType( $type )
|
||||
{
|
||||
$return = array();
|
||||
static::containers();
|
||||
|
||||
if ( $type === 'database' )
|
||||
{
|
||||
$type = 'dbtemplate';
|
||||
}
|
||||
|
||||
foreach( static::$multitons as $id => $obj )
|
||||
{
|
||||
if ( $obj->type === $type )
|
||||
{
|
||||
$return[] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new container
|
||||
*
|
||||
* @param array $container Template Data
|
||||
* @return object \IPS\cms\Templates
|
||||
*/
|
||||
public static function add( $container )
|
||||
{
|
||||
$newContainer = new static;
|
||||
$newContainer->_new = TRUE;
|
||||
$newContainer->save();
|
||||
|
||||
/* Create a unique key */
|
||||
if ( empty( $newContainer->key ) )
|
||||
{
|
||||
$newContainer->key = 'template__' . \IPS\Http\Url::seoTitle( $newContainer->name ) . '.' . $newContainer->id;
|
||||
$newContainer->save();
|
||||
}
|
||||
|
||||
return $newContainer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,676 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Templates Model
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 25 Feb 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
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 Template Model
|
||||
*/
|
||||
class _Templates extends \IPS\Patterns\ActiveRecord
|
||||
{
|
||||
/**
|
||||
* @brief [ActiveRecord] Multiton Store
|
||||
*/
|
||||
protected static $multitons;
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database Prefix
|
||||
*/
|
||||
public static $databasePrefix = 'template_';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Table
|
||||
*/
|
||||
public static $databaseTable = 'cms_templates';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] ID Database Column
|
||||
*/
|
||||
public static $databaseColumnId = 'id';
|
||||
|
||||
/**
|
||||
* @brief [ActiveRecord] Database ID Fields
|
||||
*/
|
||||
protected static $databaseIdFields = array( 'template_key', 'template_id' );
|
||||
|
||||
/**
|
||||
* @brief Retusn all types
|
||||
*/
|
||||
const RETURN_ALL = 1;
|
||||
|
||||
/**
|
||||
* @brief Returns block templates
|
||||
*/
|
||||
const RETURN_BLOCK = 2;
|
||||
|
||||
/**
|
||||
* @brief Return page templates
|
||||
*/
|
||||
const RETURN_PAGE = 4;
|
||||
|
||||
/**
|
||||
* @brief Return database templates
|
||||
*/
|
||||
const RETURN_DATABASE = 8;
|
||||
|
||||
/**
|
||||
* @brief Return just css type
|
||||
*/
|
||||
const RETURN_ONLY_CSS = 16;
|
||||
|
||||
/**
|
||||
* @brief Return just js type
|
||||
*/
|
||||
const RETURN_ONLY_JS = 32;
|
||||
|
||||
/**
|
||||
* @brief Return just template type
|
||||
*/
|
||||
const RETURN_ONLY_TEMPLATE = 64;
|
||||
|
||||
/**
|
||||
* @brief Return just contents of cms_templates ignoring IN_DEV and DESIGNERS' MODE
|
||||
*/
|
||||
const RETURN_DATABASE_ONLY = 128;
|
||||
|
||||
/**
|
||||
* @brief Return both IN_DEV and database templates
|
||||
*/
|
||||
const RETURN_DATABASE_AND_IN_DEV = 128;
|
||||
|
||||
/**
|
||||
* Load Record
|
||||
* Overloaded so we can force loading by key by default but still retain the template_id field as the primary key so
|
||||
* save still updates the primary ID.
|
||||
*
|
||||
* @see \IPS\Db::build
|
||||
* @param int|string $id ID
|
||||
* @param string $idField The database column that the $id parameter pertains to (NULL will use static::$databaseColumnId)
|
||||
* @param mixed $extraWhereClause Additional where clause(s) (see \IPS\Db::build for details)
|
||||
* @return static
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
public static function load( $id, $idField=NULL, $extraWhereClause=NULL )
|
||||
{
|
||||
if ( ! is_numeric( $id ) and $idField === NULL )
|
||||
{
|
||||
$idField = 'template_key';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return parent::load( $id, $idField, $extraWhereClause );
|
||||
}
|
||||
catch( \OutOfRangeException $ex )
|
||||
{
|
||||
if ( ! is_numeric( $id ) and ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) )
|
||||
{
|
||||
$templates = \IPS\cms\Theme::i()->getRawTemplates( NULL, NULL, NULL, \IPS\cms\Theme::RETURN_ONLY_TEMPLATE | \IPS\cms\Theme::RETURN_AS_OBJECT );
|
||||
|
||||
if ( isset( $templates[ $id ] ) )
|
||||
{
|
||||
return $templates[ $id ];
|
||||
}
|
||||
}
|
||||
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a group_name readable (Group Name)
|
||||
*
|
||||
* @param string $name Group name from the database
|
||||
* @return string
|
||||
*/
|
||||
public static function readableGroupName( $name )
|
||||
{
|
||||
if ( $name === 'js' )
|
||||
{
|
||||
return 'JS';
|
||||
}
|
||||
else if ( $name === 'css' )
|
||||
{
|
||||
return 'CSS';
|
||||
}
|
||||
|
||||
return ucwords( str_replace( array( '-', '_' ), ' ', $name ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all template group
|
||||
*
|
||||
* @param int|constant $returnType Determines the content returned
|
||||
* @return array
|
||||
*/
|
||||
public static function getGroups( $returnType=1 )
|
||||
{
|
||||
$where = array();
|
||||
$return = array();
|
||||
$locations = NULL;
|
||||
|
||||
if ( is_string( $returnType ) )
|
||||
{
|
||||
switch( $returnType )
|
||||
{
|
||||
case 'all':
|
||||
$returnType = self::RETURN_ALL;
|
||||
break;
|
||||
case 'block':
|
||||
$returnType = self::RETURN_BLOCK;
|
||||
break;
|
||||
case 'page':
|
||||
$returnType = self::RETURN_PAGE;
|
||||
break;
|
||||
case 'database':
|
||||
$returnType = self::RETURN_DATABASE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_ALL )
|
||||
{
|
||||
$where[] = array( 'template_location !=?', NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
$locations = array();
|
||||
|
||||
if ( $returnType & self::RETURN_BLOCK )
|
||||
{
|
||||
$locations[] = 'block';
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_PAGE )
|
||||
{
|
||||
$locations[] = 'page';
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_DATABASE )
|
||||
{
|
||||
$locations[] = 'database';
|
||||
}
|
||||
|
||||
if ( ! count( $locations ) )
|
||||
{
|
||||
throw new \UnexpectedValueException();
|
||||
}
|
||||
|
||||
$where[] = array( "template_location IN ('" . implode( "','", $locations ) . "')" );
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'template_group', static::$databaseTable, $where, 'template_group ASC', NULL, 'template_group' ) as $template )
|
||||
{
|
||||
$return[ $template ] = $template;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all templates
|
||||
*
|
||||
* @param int|constant $returnType Determines the content returned
|
||||
* @return array
|
||||
*/
|
||||
public static function getTemplates( $returnType=1 )
|
||||
{
|
||||
$where = array();
|
||||
$return = array();
|
||||
$locations = NULL;
|
||||
|
||||
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ! ( $returnType & self::RETURN_DATABASE_ONLY ) )
|
||||
{
|
||||
$flags = \IPS\cms\Theme::RETURN_AS_OBJECT;
|
||||
|
||||
if ( $returnType & self::RETURN_ONLY_TEMPLATE )
|
||||
{
|
||||
$flags += \IPS\cms\Theme::RETURN_ONLY_TEMPLATE;
|
||||
}
|
||||
else if ( $returnType & self::RETURN_ONLY_CSS )
|
||||
{
|
||||
$flags += \IPS\cms\Theme::RETURN_ONLY_CSS;
|
||||
}
|
||||
else if ( $returnType & self::RETURN_ONLY_JS )
|
||||
{
|
||||
$flags += \IPS\cms\Theme::RETURN_ONLY_JS;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $returnType & self::RETURN_BLOCK )
|
||||
{
|
||||
$flags += \IPS\cms\Theme::RETURN_BLOCK;
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_PAGE )
|
||||
{
|
||||
$flags += \IPS\cms\Theme::RETURN_PAGE;
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_DATABASE )
|
||||
{
|
||||
$flags += \IPS\cms\Theme::RETURN_DATABASE;
|
||||
}
|
||||
}
|
||||
|
||||
$return = \IPS\cms\Theme::i()->getRawTemplates( 'cms', NULL, NULL, $flags );
|
||||
}
|
||||
|
||||
if ( ! ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) OR ( $returnType & self::RETURN_DATABASE_AND_IN_DEV ) OR ( $returnType & self::RETURN_DATABASE_ONLY ) )
|
||||
{
|
||||
if ( $returnType & self::RETURN_ALL )
|
||||
{
|
||||
$where[] = array( 'template_location !=?', NULL );
|
||||
}
|
||||
else if ( $returnType & self::RETURN_ONLY_TEMPLATE )
|
||||
{
|
||||
$where[] = array( 'template_type = ?', 'template' );
|
||||
}
|
||||
else if ( $returnType & self::RETURN_ONLY_CSS )
|
||||
{
|
||||
$where[] = array( 'template_type = ?', 'css' );
|
||||
}
|
||||
else if ( $returnType & self::RETURN_ONLY_JS )
|
||||
{
|
||||
$where[] = array( 'template_type = ?', 'js' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$locations = array();
|
||||
|
||||
if ( $returnType & self::RETURN_BLOCK )
|
||||
{
|
||||
$locations[] = 'block';
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_PAGE )
|
||||
{
|
||||
$locations[] = 'page';
|
||||
}
|
||||
|
||||
if ( $returnType & self::RETURN_DATABASE )
|
||||
{
|
||||
$locations[] = 'database';
|
||||
}
|
||||
|
||||
if ( !count( $locations ) )
|
||||
{
|
||||
throw new \UnexpectedValueException();
|
||||
}
|
||||
|
||||
$where[] = array( "template_location IN ('" . implode( "','", $locations ) . "')" );
|
||||
}
|
||||
|
||||
foreach ( \IPS\Db::i()->select( '*', static::$databaseTable, $where, 'template_user_edited DESC' ) as $template )
|
||||
{
|
||||
/* user_edited version is returned first, so only add to the array if the key isn't already in $return */
|
||||
if ( !isset( $return[ $template['template_key'] ] ) )
|
||||
{
|
||||
$return[ $template['template_key'] ] = static::constructFromData( $template );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct Load Query
|
||||
* Overloaded so we return the user_edited version where available
|
||||
*
|
||||
* @param int|string $id ID
|
||||
* @param string $idField The database column that the $id parameter pertains to
|
||||
* @param mixed $extraWhereClause Additional where clause(s)
|
||||
* @return \IPS\Db\Select
|
||||
*/
|
||||
protected static function constructLoadQuery( $id, $idField, $extraWhereClause )
|
||||
{
|
||||
$where = array( array( $idField . '=?', $id ) );
|
||||
if( $extraWhereClause !== NULL )
|
||||
{
|
||||
if ( !is_array( $extraWhereClause ) or !is_array( $extraWhereClause[0] ) )
|
||||
{
|
||||
$extraWhereClause = array( $extraWhereClause );
|
||||
}
|
||||
$where = array_merge( $where, $extraWhereClause );
|
||||
}
|
||||
|
||||
return static::db()->select( '*', static::$databaseTable, $where, 'template_user_edited DESC' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a tree of templates
|
||||
*
|
||||
* @param array $templates Template data from the database
|
||||
* @return array
|
||||
*/
|
||||
public static function buildTree( $templates )
|
||||
{
|
||||
$return = array();
|
||||
|
||||
foreach( $templates as $id => $template )
|
||||
{
|
||||
$return[ $template->location ][ $template->group ][ $template->key ] = $template;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new template
|
||||
*
|
||||
* @param array $template Template Data
|
||||
* @return object \IPS\cms\Templates
|
||||
*/
|
||||
public static function add( $template )
|
||||
{
|
||||
$newTemplate = new static;
|
||||
|
||||
foreach( $template as $_k => $_v )
|
||||
{
|
||||
$newTemplate->$_k = $_v;
|
||||
}
|
||||
|
||||
$newTemplate->_new = TRUE;
|
||||
$newTemplate->user_created = 1;
|
||||
$newTemplate->user_edited = 1;
|
||||
$newTemplate->master = 0;
|
||||
|
||||
$newTemplate->save();
|
||||
|
||||
/* Create a unique key */
|
||||
$newTemplate->key = $newTemplate->location . '_' . \IPS\Http\Url::seoTitle( $newTemplate->title ) . '_' . $newTemplate->id;
|
||||
|
||||
/* Make sure there's no double __ in there */
|
||||
foreach( array( 'group', 'title', 'key' ) as $field )
|
||||
{
|
||||
if ( mb_strstr( $newTemplate->$field, '__' ) )
|
||||
{
|
||||
$newTemplate->$field = str_replace( '__', '_', $newTemplate->$field );
|
||||
}
|
||||
}
|
||||
|
||||
$newTemplate->save();
|
||||
|
||||
return $newTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all stored files so they can be rebuilt on the fly
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function deleteCompiledFiles()
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_file_object IS NOT NULL' ) ) as $template )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Theme', $template['template_file_object'] )->delete();
|
||||
}
|
||||
catch( \Exception $ex ) { }
|
||||
}
|
||||
|
||||
\IPS\Db::i()->update( 'cms_templates', array( 'template_file_object' => NULL ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is suitable to be used for a custom wrapper?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSuitableForCustomWrapper()
|
||||
{
|
||||
if ( $this->location == 'page' and preg_match( '#<html([^>]+?)?>#', $this->content ) )
|
||||
{
|
||||
if ( preg_match( '#\$html(\s|=|,)#', $this->params ) and preg_match( '#\$title(\s|=|,|$)#', $this->params ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is suitable to be used for a builder column wrapper?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSuitableForBuilderWrapper()
|
||||
{
|
||||
if ( $this->location == 'page' and mb_stristr( $this->content, '{template="widgetContainer"' ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import templates from an XML file
|
||||
*
|
||||
* @param string $file File to load from (data/ or tmp/)
|
||||
* @param int|null $offset Offset to begin import from
|
||||
* @param int|null $limit Number of rows to import
|
||||
* @param boolean $update If updating, files written as master templates
|
||||
* @return bool Rows imported (true) or none imported (false)
|
||||
*/
|
||||
public static function importXml( $file, $offset=NULL, $limit=NULL, $update=TRUE )
|
||||
{
|
||||
$i = 0;
|
||||
$worked = false;
|
||||
|
||||
if( file_exists( $file ) )
|
||||
{
|
||||
/* First, delete any existing skin data for this app. */
|
||||
if( $offset === NULL OR $offset === 0 )
|
||||
{
|
||||
if ( $update === TRUE )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_master=1' ) );
|
||||
\IPS\cms\Theme::deleteCompiledTemplate( 'cms' );
|
||||
}
|
||||
}
|
||||
|
||||
/* Open XML file */
|
||||
$xml = new \XMLReader;
|
||||
$xml->open( $file );
|
||||
$xml->read();
|
||||
|
||||
while( $xml->read() )
|
||||
{
|
||||
if( $xml->nodeType != \XMLReader::ELEMENT )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$i++;
|
||||
|
||||
if ( $offset !== null )
|
||||
{
|
||||
if ( $i - 1 < $offset )
|
||||
{
|
||||
$xml->next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if( $xml->name == 'template' )
|
||||
{
|
||||
$save = array(
|
||||
'template_content' => $xml->readString(),
|
||||
'template_master' => 1,
|
||||
'template_original_group' => $xml->getAttribute('template_group'),
|
||||
'template_file_object' => NULL
|
||||
);
|
||||
|
||||
foreach( array('key', 'title', 'desc', 'location', 'group', 'params', 'app', 'type' ) as $field )
|
||||
{
|
||||
$save[ 'template_' . $field ] = $xml->getAttribute( 'template_' . $field );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->insert( 'cms_templates', $save );
|
||||
$worked = true;
|
||||
}
|
||||
|
||||
if( $limit !== null AND $i === ( $limit + $offset ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $worked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete
|
||||
* Overloaded to protect inheritence
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
if ( $this->user_added )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_added=?', $this->key, 1 ) );
|
||||
|
||||
if ( isset( static::$multitons[ $this->key ] ) )
|
||||
{
|
||||
unset( static::$multitons[ $this->key ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $this->user_edited )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_edited=?', $this->key, 1 ) );
|
||||
|
||||
if ( isset( static::$multitons[ $this->key ] ) )
|
||||
{
|
||||
unset( static::$multitons[ $this->key ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \OutOfRangeException('CANNOT_DELETE');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the inherited string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get__inherited()
|
||||
{
|
||||
if ( $this->user_created )
|
||||
{
|
||||
return 'custom';
|
||||
}
|
||||
elseif ( $this->user_edited )
|
||||
{
|
||||
return 'changed';
|
||||
}
|
||||
|
||||
return 'original';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file object
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get__file_object()
|
||||
{
|
||||
if ( ! $this->file_object )
|
||||
{
|
||||
$content = $this->content;
|
||||
|
||||
/* Build on demand */
|
||||
if ( mb_stristr( $this->content, "{block=" ) )
|
||||
{
|
||||
$functionName = 'css_' . uniqid();
|
||||
\IPS\Theme::makeProcessFunction( str_replace( '\\', '\\\\', $content ), $functionName );
|
||||
$functionName = "IPS\Theme\\{$functionName}";
|
||||
$content = $functionName();
|
||||
}
|
||||
|
||||
$this->file_object = (string) \IPS\File::create( 'cms_Pages', $this->title, $content, 'page_objects', TRUE );
|
||||
parent::save(); # Go to parent save to prevent $this->save() from wiping file objects
|
||||
}
|
||||
|
||||
return $this->file_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
/* Trash file object if appropriate */
|
||||
if ( $this->file_object )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'cms_Pages', $this->file_object )->delete();
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
/* Just to be sure nothing is throw, we don't care too much if it's not deleted */
|
||||
}
|
||||
|
||||
/* Trash all cached page file objects too */
|
||||
\IPS\cms\Pages\Page::deleteCachedIncludes( $this->file_object );
|
||||
|
||||
$this->file_object = NULL;
|
||||
}
|
||||
|
||||
/* Should we copy this to a new template and then save it? */
|
||||
if ( ! $this->user_edited )
|
||||
{
|
||||
/* Infinite loop is only cool as Apple's address */
|
||||
$clone = new \IPS\cms\Templates;
|
||||
|
||||
$clone->_data = $this->_data;
|
||||
$clone->changed = $this->changed;
|
||||
|
||||
$clone->id = NULL;
|
||||
$clone->user_edited = 1;
|
||||
$clone->master = 0;
|
||||
$clone->_new = TRUE;
|
||||
$clone->save();
|
||||
|
||||
$key = \strtolower( 'template_cms_' . \IPS\cms\Theme::makeBuiltTemplateLookupHash( 'cms', $clone->location, $clone->group ) . '_' . $clone->group );
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = \strtolower( 'template_cms_' . \IPS\cms\Theme::makeBuiltTemplateLookupHash( 'cms', $this->location, $this->group ) . '_' . $this->group );
|
||||
|
||||
parent::save();
|
||||
}
|
||||
|
||||
/* Clear store */
|
||||
unset( \IPS\Data\Store::i()->$key );
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Designer's Mode Theme
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 28 Nov 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Theme\Advanced;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designer's Mode Theme
|
||||
*/
|
||||
class _Theme extends \IPS\cms\Theme
|
||||
{
|
||||
/**
|
||||
* Get currently logged in member's theme
|
||||
*
|
||||
* @return \IPS\Theme
|
||||
*/
|
||||
public static function i()
|
||||
{
|
||||
return new self;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write files to disk
|
||||
*
|
||||
* return void
|
||||
*/
|
||||
public static function export()
|
||||
{
|
||||
foreach( \IPS\Db::i()->select(
|
||||
"*, MD5( CONCAT(template_location, ',', template_group, ',', template_title) ) as bit_key",
|
||||
'cms_templates',
|
||||
NULL,
|
||||
'template_user_edited ASC' /* Ensure we get edited versions, not the master version if one exists */
|
||||
)->setKeyField('bit_key') as $template )
|
||||
{
|
||||
try
|
||||
{
|
||||
static::writeTemplate( $template, TRUE );
|
||||
}
|
||||
catch( \RuntimeException $ex )
|
||||
{
|
||||
throw new \RuntimeException( $ex->getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports templates from the designer's mode directories.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function import()
|
||||
{
|
||||
$seen = array();
|
||||
|
||||
foreach( array( 'block', 'page', 'database', 'js', 'css' ) as $location )
|
||||
{
|
||||
$templates = iterator_to_array( \IPS\Db::i()->select(
|
||||
"*, MD5( CONCAT(template_location, ',', template_group, ',', template_title) ) as bit_key",
|
||||
'cms_templates',
|
||||
array( 'template_location=?', $location ),
|
||||
'template_user_edited ASC' /* Ensure we get edited versions, not the master version if one exists */
|
||||
)->setKeyField('bit_key') );
|
||||
|
||||
$master = iterator_to_array( \IPS\Db::i()->select(
|
||||
"*, MD5( CONCAT(template_location, ',', template_group, ',', template_title) ) as bit_key",
|
||||
'cms_templates',
|
||||
array( 'template_master=1 and template_location=?', $location )
|
||||
)->setKeyField('bit_key') );
|
||||
|
||||
$path = static::_getHtmlPath( 'cms', $location );
|
||||
|
||||
if ( is_dir( $path ) )
|
||||
{
|
||||
foreach( new \DirectoryIterator( $path ) as $group )
|
||||
{
|
||||
if ( $group->isDot() || mb_substr( $group->getFilename(), 0, 1 ) === '.' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $group->isDir() )
|
||||
{
|
||||
$seen = array();
|
||||
|
||||
foreach( new \DirectoryIterator( $path . '/' . $group->getFilename() ) as $file )
|
||||
{
|
||||
if ( $file->isDot() || mb_substr( $file->getFilename(), -6 ) !== '.phtml')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the content */
|
||||
$html = file_get_contents( $path . '/' . $group->getFilename() . '/' . $file->getFilename() );
|
||||
|
||||
/* Parse the header tag */
|
||||
preg_match( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $html, $params );
|
||||
|
||||
/* Strip it */
|
||||
$html = ( isset($params[0]) ) ? str_replace( $params[0], '', $html ) : $html;
|
||||
$title = str_replace( '.phtml', '', $file->getFilename() );
|
||||
$originalGroup = $group->getFilename();
|
||||
|
||||
if ( isset( $params[2] ) and mb_stristr( $params[2], 'original_group' ) )
|
||||
{
|
||||
preg_match( '#original_group="(.+?)"#', $params[2], $submatches );
|
||||
|
||||
if ( isset( $submatches[1] ) )
|
||||
{
|
||||
$originalGroup = $submatches[1];
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're syncing designer mode, check for actual changes */
|
||||
$key = md5( $location . ',' . $group->getFilename() . ',' . $title );
|
||||
|
||||
$seen[] = $title;
|
||||
$added = FALSE;
|
||||
|
||||
if ( isset( $templates[ $key ] ) )
|
||||
{
|
||||
if ( md5( trim( $templates[ $key ]['template_content'] ) ) == md5( trim( $html ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Update */
|
||||
if ( ! $templates[ $key ]['template_master'] )
|
||||
{
|
||||
$added = TRUE;
|
||||
\IPS\Db::i()->update( 'cms_templates', array(
|
||||
'template_content' => $html,
|
||||
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
|
||||
), array( 'template_id=?', $templates[ $key ]['template_id'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $added )
|
||||
{
|
||||
$templateType = 'template';
|
||||
|
||||
if ( $location === 'css' )
|
||||
{
|
||||
$templateType = 'css';
|
||||
}
|
||||
else if ( $location === 'js' )
|
||||
{
|
||||
$templateType = 'js';
|
||||
}
|
||||
|
||||
/* New template */
|
||||
\IPS\Db::i()->insert( 'cms_templates', array(
|
||||
'template_key' => $location . '_' . $group->getFilename() . '_' . $title,
|
||||
'template_title' => $title,
|
||||
'template_desc' => '',
|
||||
'template_content' => $html,
|
||||
'template_location' => $location,
|
||||
'template_group' => $group->getFilename(),
|
||||
'template_original_group' => $originalGroup,
|
||||
'template_container' => 0,
|
||||
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
|
||||
'template_master' => 0,
|
||||
'template_user_edited' => ( isset( $master[ $key ] ) ) ? 1 : 0,
|
||||
'template_user_created' => ( isset( $master[ $key ] ) ) ? 0 : 1,
|
||||
'template_type' => $templateType
|
||||
) );
|
||||
}
|
||||
|
||||
/* remove compiled version */
|
||||
$key = \strtolower( 'template_cms_' .static::makeBuiltTemplateLookupHash( 'cms', $location, $group->getFilename() ) . '_' . static::cleanGroupName( $group->getFilename() ) );
|
||||
|
||||
if ( isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
unset(\IPS\Data\Store::i()->$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove any templates we've not imported for this location/group */
|
||||
if ( count( $seen ) )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'cms_templates', array('template_master=0 and template_location=? and template_group=? and ' . \IPS\Db::i()->in( 'template_title', $seen, TRUE ), $location, $group->getFilename() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path for the IN_DEV .phtml files
|
||||
* @param string $app Application Key
|
||||
* @param string|null $location Location
|
||||
* @param string|null $path Path or Filename
|
||||
* @return string
|
||||
*/
|
||||
protected static function _getHtmlPath( $app, $location=null, $path=null )
|
||||
{
|
||||
return rtrim( \IPS\ROOT_PATH . "/themes/cms/{$location}/{$path}", '/' ) . '/';
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Magic Template Class for IN_DEV mode
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\cms\Theme;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Template Class for IN_DEV mode
|
||||
*/
|
||||
class _Template extends \IPS\Theme\Template
|
||||
{
|
||||
/**
|
||||
* @brief Source Folder
|
||||
*/
|
||||
public $sourceFolder = NULL;
|
||||
|
||||
/**
|
||||
* Extract the data object from the param tag
|
||||
* @note We always assume the tag is in the format of <ips:template parameters="" data="" />
|
||||
*
|
||||
* @param string $tag <ips:template> tag
|
||||
* @param string $key Data key to fetch
|
||||
* @return null|array
|
||||
*/
|
||||
public static function extractDataFromTag( $tag, $key="data" )
|
||||
{
|
||||
if ( ! preg_match( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $tag, $matches ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( preg_match( '#' . $key . '="([^"]+?)"#', $matches[2], $submatches ) )
|
||||
{
|
||||
return $submatches[1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the data object from the param tag
|
||||
* @note We always assume the tag is in the format of <ips:template parameters="" data="" />
|
||||
*
|
||||
* @param string $tag <ips:template> tag
|
||||
* @return null|array
|
||||
*/
|
||||
public static function extractParamsFromTag( $tag )
|
||||
{
|
||||
if ( ! preg_match( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $tag, $matches ) )
|
||||
{
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contructor
|
||||
*
|
||||
* @param string $app Application Key
|
||||
* @param string $templateLocation Template location (admin/public/etc.)
|
||||
* @param string $templateName Template Name
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $app, $templateLocation, $templateName )
|
||||
{
|
||||
parent::__construct( $app, $templateLocation, $templateName );
|
||||
$this->app = $app;
|
||||
$this->templateLocation = $templateLocation;
|
||||
$this->templateName = $templateName;
|
||||
|
||||
if ( \IPS\Theme::designersModeEnabled() )
|
||||
{
|
||||
$this->sourceFolder = \IPS\ROOT_PATH . "/themes/cms/{$templateLocation}/{$templateName}/";
|
||||
}
|
||||
else if ( \IPS\IN_DEV )
|
||||
{
|
||||
$this->sourceFolder = \IPS\ROOT_PATH . "/applications/{$app}/dev/html/{$templateLocation}/{$templateName}/";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Method: Call Template Bit
|
||||
*
|
||||
* @param string $bit Template Bit Name
|
||||
* @param array $params Parameters
|
||||
* @return string
|
||||
*/
|
||||
public function __call( $bit, $params )
|
||||
{
|
||||
if ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() )
|
||||
{
|
||||
/* What are we calling this? */
|
||||
$functionName = "theme_{$this->app}_{$this->templateLocation}_{$this->templateName}_{$bit}";
|
||||
|
||||
/* If it doesn't exist, build it */
|
||||
if( !function_exists( 'IPS\\Theme\\'.$functionName ) )
|
||||
{
|
||||
/* Find the file */
|
||||
$file = $this->sourceFolder . $bit . '.phtml';
|
||||
|
||||
/* Get the content */
|
||||
if ( $file === NULL or !file_exists( $file ) )
|
||||
{
|
||||
/* Try the database */
|
||||
try
|
||||
{
|
||||
$template = \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_location=? and LOWER(template_group)=? and template_title=?', $this->templateLocation, $this->templateName, $bit ) )->first();
|
||||
|
||||
\IPS\cms\Theme::makeProcessFunction( $template['template_content'], $functionName, $template['template_params'], TRUE );
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
throw new \BadMethodCallException( 'NO_TEMPLATE_FILE - ' . $file );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
$output = file_get_contents( $file );
|
||||
|
||||
/* Parse the header tag */
|
||||
if ( !preg_match( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $output, $matches ) )
|
||||
{
|
||||
throw new \BadMethodCallException( 'NO_HEADER - ' . $file );
|
||||
}
|
||||
|
||||
/* Strip it */
|
||||
$output = preg_replace( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', '', $output );
|
||||
|
||||
/* Make it into a lovely function */
|
||||
\IPS\cms\Theme::makeProcessFunction( $output, $functionName, ( isset( $matches[1] ) ? $matches[1] : '' ), TRUE );
|
||||
}
|
||||
}
|
||||
|
||||
/* Run it */
|
||||
ob_start();
|
||||
$return = call_user_func_array( 'IPS\\Theme\\'.$functionName, $params );
|
||||
if( $error = ob_get_clean() )
|
||||
{
|
||||
echo "<strong>{$functionName}</strong><br>{$error}<br><br><pre>{$output}";
|
||||
exit;
|
||||
}
|
||||
|
||||
/* Return */
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,700 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief IN_DEV Skin Set
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 16 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* IN_DEV Skin set
|
||||
*/
|
||||
class _Theme extends \IPS\Theme
|
||||
{
|
||||
/**
|
||||
* @brief Template Classes
|
||||
*/
|
||||
protected $templates;
|
||||
|
||||
/**
|
||||
* @brief [SkinSets] Templates already loaded and evald via getTemplate()
|
||||
*/
|
||||
public static $calledTemplates = array();
|
||||
|
||||
/**
|
||||
* @brief Return type for getRawTemplates/getRawCss: Uses DB if not IN_DEV, otherwise uses disk .phtml look up
|
||||
*/
|
||||
const RETURN_AS_OBJECT = 32;
|
||||
|
||||
/**
|
||||
* @brief Return just template type
|
||||
*/
|
||||
const RETURN_ONLY_TEMPLATE = 64;
|
||||
|
||||
/**
|
||||
* @brief Return just css type
|
||||
*/
|
||||
const RETURN_ONLY_CSS = 128;
|
||||
|
||||
/**
|
||||
* @brief Return just js type
|
||||
*/
|
||||
const RETURN_ONLY_JS = 256;
|
||||
|
||||
/**
|
||||
* @brief Return just page type
|
||||
*/
|
||||
const RETURN_PAGE = 512;
|
||||
|
||||
/**
|
||||
* @brief Return just database type
|
||||
*/
|
||||
const RETURN_DATABASE = 1024;
|
||||
|
||||
/**
|
||||
* @brief Return just block type
|
||||
*/
|
||||
const RETURN_BLOCK = 2048;
|
||||
|
||||
/**
|
||||
* @brief Return just contents of cms_templates ignoring IN_DEV and DESIGNERS' MODE
|
||||
*/
|
||||
const RETURN_DATABASE_ONLY = 4096;
|
||||
|
||||
/**
|
||||
* Get currently logged in member's theme
|
||||
*
|
||||
* @return \IPS\Theme
|
||||
*/
|
||||
public static function i()
|
||||
{
|
||||
if ( \IPS\Theme::designersModeEnabled() )
|
||||
{
|
||||
return new \IPS\cms\Theme\Advanced\Theme;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new self;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports templates from the /dev directories.
|
||||
*
|
||||
* @param string $location Location (database, block)
|
||||
* @return void
|
||||
*/
|
||||
public static function importInDev( $location )
|
||||
{
|
||||
/* Clear out existing template bits */
|
||||
\IPS\Db::i()->delete( 'cms_templates', array( 'template_master=1 and template_user_created=0 and template_user_edited=0 AND template_location=?', $location ) );
|
||||
|
||||
static::importLocation( $location );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write IN_DEV files
|
||||
*
|
||||
* @param boolean $force TRUE to rewrite templates, FALSE to check if exists first
|
||||
* @return void
|
||||
*/
|
||||
public static function writeInDev( $force=FALSE )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_master=?', 1 ) ) as $template )
|
||||
{
|
||||
try
|
||||
{
|
||||
static::writeTemplate( $template, $force );
|
||||
}
|
||||
catch( \RuntimeException $ex )
|
||||
{
|
||||
throw new \RuntimeException( $ex->getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports templates from the /dev directories.
|
||||
*
|
||||
* @param string $location Location (database, block)
|
||||
* @return array
|
||||
*/
|
||||
public static function importLocation( $location )
|
||||
{
|
||||
$master = iterator_to_array( \IPS\Db::i()->select(
|
||||
"*, MD5( CONCAT(template_location, ',', template_group, ',', template_title) ) as bit_key",
|
||||
'cms_templates',
|
||||
array( 'template_master=1 and template_user_created=0 and template_user_edited=0 AND template_location=?', $location )
|
||||
)->setKeyField('bit_key') );
|
||||
|
||||
$path = static::_getHtmlPath( 'cms', $location );
|
||||
$seen = array();
|
||||
|
||||
if ( is_dir( $path ) )
|
||||
{
|
||||
foreach( new \DirectoryIterator( $path ) as $group )
|
||||
{
|
||||
if ( $group->isDot() || mb_substr( $group->getFilename(), 0, 1 ) === '.' || $group->getFilename() == 'index.html' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $group->isDir() )
|
||||
{
|
||||
foreach( new \DirectoryIterator( $path . '/' . $group->getFilename() ) as $file )
|
||||
{
|
||||
if ( $file->isDot() || mb_substr( $file->getFilename(), -6 ) !== '.phtml')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the content */
|
||||
$html = file_get_contents( $path . '/' . $group->getFilename() . '/' . $file->getFilename() );
|
||||
|
||||
/* Parse the header tag */
|
||||
preg_match( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $html, $params );
|
||||
|
||||
/* Strip it */
|
||||
$html = ( isset($params[0]) ) ? str_replace( $params[0], '', $html ) : $html;
|
||||
$title = str_replace( '.phtml', '', $file->getFilename() );
|
||||
|
||||
/* If we're syncing designer mode, check for actual changes */
|
||||
$key = md5( $location . ',' . $group->getFilename() . ',' . $title );
|
||||
|
||||
if ( isset( $master[ $key ] ) )
|
||||
{
|
||||
if ( md5( trim( $master[ $key ]['template_content'] ) ) == md5( trim( $html ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$seen[ $group->getFilename() ] = $title;
|
||||
|
||||
/* remove compiled version */
|
||||
$key = \strtolower( 'template_cms_' .static::makeBuiltTemplateLookupHash( 'cms', $location, $group->getFilename() ) . '_' . static::cleanGroupName( $group->getFilename() ) );
|
||||
|
||||
if ( isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
unset(\IPS\Data\Store::i()->$key);
|
||||
}
|
||||
|
||||
\IPS\Db::i()->insert( 'cms_templates', array(
|
||||
'template_key' => $location . '_' . $group->getFilename() . '_' . $title,
|
||||
'template_title' => $title,
|
||||
'template_desc' => '',
|
||||
'template_content' => $html,
|
||||
'template_location' => $location,
|
||||
'template_group' => $group->getFilename(),
|
||||
'template_original_group' => $group->getFilename(),
|
||||
'template_container' => 0,
|
||||
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
|
||||
'template_master' => 1
|
||||
) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $seen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a template to disk
|
||||
*
|
||||
* @param array $template Template to write
|
||||
* @param boolean $force Force overwrite
|
||||
* @return void
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function writeTemplate( $template, $force=FALSE )
|
||||
{
|
||||
$path = static::_getHtmlPath('cms');
|
||||
|
||||
if ( ! is_dir( $path ) )
|
||||
{
|
||||
if ( ! mkdir( $path, \IPS\IPS_FOLDER_PERMISSION, TRUE ) )
|
||||
{
|
||||
throw new \DomainException();
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! is_dir( $path . '/' . $template['template_location'] ) )
|
||||
{
|
||||
mkdir( $path . '/' . $template['template_location'] );
|
||||
@chmod( $path . '/' . $template['template_location'], \IPS\IPS_FOLDER_PERMISSION );
|
||||
}
|
||||
|
||||
if ( ! is_dir( $path . '/' . $template['template_location'] . '/' . $template['template_group'] ) )
|
||||
{
|
||||
mkdir( $path . '/' . $template['template_location'] . '/' . $template['template_group'] );
|
||||
@chmod( $path . '/' . $template['template_location'] . '/' . $template['template_group'], \IPS\IPS_FOLDER_PERMISSION );
|
||||
}
|
||||
|
||||
$fileName = ( $template['template_type'] === 'template' ) ? $template['template_title'] . '.phtml' : $template['template_title'];
|
||||
|
||||
if ( ! file_exists( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName ) OR $force === TRUE )
|
||||
{
|
||||
$write = '<ips:template parameters="' . $template['template_params'] . '" original_group="' . $template['template_original_group'] . '" key="' . $template['template_key'] . '" />' . "\n";
|
||||
$write .= $template['template_content'];
|
||||
|
||||
if ( ! @\file_put_contents( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName, $write ) )
|
||||
{
|
||||
throw new \RuntimeException( \IPS\Member::loggedIn()->language()->addToStack( 'content_theme_dev_cannot_write_template', FALSE, array( 'sprintf' => array( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName ) ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@chmod( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName, 0777 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw templates. Raw means HTML logic and variables are still in {{format}}
|
||||
*
|
||||
* @param string|array $app Template app (e.g. core, forum)
|
||||
* @param string|array $location Template location (e.g. admin,global,front)
|
||||
* @param string|array $group Template group (e.g. login, share)
|
||||
* @param int|constant $returnType Determines the content returned
|
||||
* @param boolean $returnThisSetOnly Returns rows unique to this set only
|
||||
* @return array
|
||||
*/
|
||||
public function getRawTemplates( $app=array(), $location=array(), $group=array(), $returnType=null, $returnThisSetOnly=false )
|
||||
{
|
||||
$returnType = ( $returnType === null ) ? self::RETURN_ALL : $returnType;
|
||||
$app = ( is_string( $app ) AND $app != '' ) ? array( $app ) : $app;
|
||||
$location = ( is_string( $location ) AND $location != '' ) ? array( $location ) : $location;
|
||||
$group = ( is_string( $group ) AND $group != '' ) ? array( $group ) : $group;
|
||||
$where = array();
|
||||
$templates = array();
|
||||
|
||||
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ! ( $returnType & static::RETURN_DATABASE_ONLY ) )
|
||||
{
|
||||
$fixedLocations = array( 'admin', 'front', 'global' );
|
||||
$results = array();
|
||||
$seenKeys = array();
|
||||
|
||||
foreach( new \DirectoryIterator( static::_getHtmlPath('cms') ) as $location )
|
||||
{
|
||||
if ( ! in_array( $location->getFilename(), $fixedLocations ) AND $location->isDir() AND mb_substr( $location->getFilename(), 0, 1 ) !== '.' )
|
||||
{
|
||||
$allowedLocations = array();
|
||||
if ( $returnType & static::RETURN_ONLY_TEMPLATE )
|
||||
{
|
||||
$allowedLocations = array('page', 'block', 'database');
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $returnType & static::RETURN_ONLY_CSS )
|
||||
{
|
||||
$allowedLocations[] = 'css';
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_ONLY_JS )
|
||||
{
|
||||
$allowedLocations[] = 'js';
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_PAGE )
|
||||
{
|
||||
$allowedLocations[] = 'page';
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_BLOCK )
|
||||
{
|
||||
$allowedLocations[] = 'block';
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_DATABASE )
|
||||
{
|
||||
$allowedLocations[] = 'database';
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $allowedLocations ) and ! in_array( $location->getFilename(), $allowedLocations ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach( new \DirectoryIterator( static::_getHtmlPath( 'cms', $location->getFilename() ) ) as $file )
|
||||
{
|
||||
if ( $file->isDir() AND mb_substr( $file->getFilename(), 0, 1 ) !== '.' )
|
||||
{
|
||||
if ( $group === NULL or ! count( $group ) or ( in_array( $file->getFilename(), $group ) ) )
|
||||
{
|
||||
foreach( new \DirectoryIterator( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) ) as $template )
|
||||
{
|
||||
if ( ! $template->isDir() AND ( mb_substr( $template->getFilename(), -6 ) === '.phtml' or mb_substr( $template->getFilename(), -4 ) === '.css' or mb_substr( $template->getFilename(), -3 ) === '.js' ) )
|
||||
{
|
||||
$title = str_replace( ".phtml", "", $template->getFilename() );
|
||||
|
||||
$contents = file_get_contents( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) . '/' . $template->getFilename() );
|
||||
$key = \IPS\cms\Theme\Template::extractDataFromTag( $contents, 'key' );
|
||||
$key = $key ? $key : \IPS\Http\Url::seoTitle( $title );
|
||||
$ogroup = \IPS\cms\Theme\Template::extractDataFromTag( $contents, 'original_group' );
|
||||
$params = \IPS\cms\Theme\Template::extractParamsFromTag( $contents );
|
||||
$container = NULL;
|
||||
|
||||
if ( in_array( $key, $seenKeys ) )
|
||||
{
|
||||
$key .= filemtime( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) . '/' . $template->getFilename() );
|
||||
}
|
||||
|
||||
$seenKeys[] = $key;
|
||||
|
||||
$contents = preg_replace( "#^<ips:template([^>]+?)>(\r\n|\n)#", "", $contents );
|
||||
|
||||
if ( $returnType & static::RETURN_AS_OBJECT )
|
||||
{
|
||||
$object = new \IPS\cms\Templates;
|
||||
$object->key = $key;
|
||||
$object->title = $title;
|
||||
$object->desc = NULL;
|
||||
$object->rel_id = NULL;
|
||||
$object->content = $contents;
|
||||
$object->location = $location->getFilename();
|
||||
$object->group = $file->getFilename();
|
||||
$object->original_group = isset( $ogroup ) ? $ogroup : $object->group;
|
||||
$object->user_created = 0;
|
||||
$object->user_edited = 0;
|
||||
$object->params = $params;
|
||||
|
||||
$results[ $key ] = $object;
|
||||
}
|
||||
else if ( $returnType & static::RETURN_ALL OR $returnType & static::RETURN_ALL_NO_CONTENT )
|
||||
{
|
||||
$results['cms'][ $location->getFilename() ][ $file->getFilename() ][ $key ] = array(
|
||||
'template_key' => $key,
|
||||
'template_title' => $title,
|
||||
'template_desc' => NULL,
|
||||
'template_rel_id' => NULL,
|
||||
'template_content' => $contents,
|
||||
'template_location' => $location->getFilename(),
|
||||
'template_group' => $file->getFilename(),
|
||||
'template_original_group' => isset( $ogroup ) ? $ogroup : $file->getFilename(),
|
||||
'template_user_created' => 0,
|
||||
'template_user_edited' => 0,
|
||||
'template_params' => $params,
|
||||
);
|
||||
|
||||
if ( $returnType & static::RETURN_ALL_NO_CONTENT )
|
||||
{
|
||||
unset( $results['cms'][ $location->getFilename() ][ $file->getFilename() ][ $key ]['template_content'] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$results[ $key ] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( is_array( $location ) AND count( $location ) )
|
||||
{
|
||||
$where[] = "template_location IN ('" . implode( "','", $location ) . "')";
|
||||
}
|
||||
|
||||
if ( is_array( $group ) AND count( $group ) )
|
||||
{
|
||||
$where[] = "template_group IN ('" . implode( "','", $group ) . "')";
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_ONLY_CSS )
|
||||
{
|
||||
$where[] = "template_type='css'";
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_ONLY_JS )
|
||||
{
|
||||
$where[] = "template_type='js'";
|
||||
}
|
||||
|
||||
foreach(
|
||||
\IPS\Db::i()->select(
|
||||
'*',
|
||||
'cms_templates',
|
||||
implode( " AND ", $where ),
|
||||
'template_location, template_group, template_key, template_user_edited ASC'
|
||||
)
|
||||
as $row
|
||||
) {
|
||||
$row['TemplateKey'] = $row['template_app'] . '_' . $row['template_location'] . '_' . $row['template_group'] . '_' . $row['template_key'];
|
||||
$row['jsDataKey'] = str_replace( '.', '--', $row['TemplateKey'] );
|
||||
$row['template_app'] = 'cms';
|
||||
|
||||
if ( $returnType & static::RETURN_ALL_NO_CONTENT )
|
||||
{
|
||||
unset( $row['template_content'] );
|
||||
$templates[ $row['template_app'] ][ $row['template_location'] ][ $row['template_group'] ][ $row['template_key'] ] = $row;
|
||||
}
|
||||
else if ( $returnType & static::RETURN_ALL )
|
||||
{
|
||||
$templates[ $row['template_app'] ][ $row['template_location'] ][ $row['template_group'] ][ $row['template_key'] ] = $row;
|
||||
}
|
||||
else if ( $returnType & static::RETURN_BIT_NAMES )
|
||||
{
|
||||
$templates[ $row['template_app'] ][ $row['template_location'] ][ $row['template_group'] ][] = $row['template_key'];
|
||||
}
|
||||
else if ( $returnType & static::RETURN_ARRAY_BIT_NAMES )
|
||||
{
|
||||
$templates[] = $row['template_key'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $returnType & static::RETURN_ARRAY_BIT_NAMES )
|
||||
{
|
||||
sort( $templates );
|
||||
return $templates;
|
||||
}
|
||||
|
||||
ksort( $templates );
|
||||
|
||||
/* Pretty sure Mark can turn this into a closure */
|
||||
foreach( $templates as $k => $v )
|
||||
{
|
||||
ksort( $templates[ $k ] );
|
||||
|
||||
foreach( $templates[ $k ] as $ak => $av )
|
||||
{
|
||||
ksort( $templates[ $k ][ $ak ] );
|
||||
|
||||
if ( $returnType & static::RETURN_ALL )
|
||||
{
|
||||
foreach( $templates[ $k ][ $ak ] as $bk => $bv )
|
||||
{
|
||||
ksort( $templates[ $k ][ $ak ][ $bk ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $templates;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a template
|
||||
*
|
||||
* @param string $group Template Group
|
||||
* @param string $app Application key (NULL for current application)
|
||||
* @param string $location Template Location (NULL for current template location)
|
||||
* @return \IPS\Theme\Template
|
||||
*/
|
||||
public function getTemplate( $group, $app=NULL, $location=NULL )
|
||||
{
|
||||
/* Do we have an application? */
|
||||
if( $app === NULL )
|
||||
{
|
||||
$app = \IPS\Dispatcher::i()->application->directory;
|
||||
}
|
||||
|
||||
/* How about a template location? */
|
||||
if( $location === NULL )
|
||||
{
|
||||
$location = \IPS\Dispatcher::i()->controllerLocation;
|
||||
}
|
||||
|
||||
/* Get template */
|
||||
if ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() )
|
||||
{
|
||||
if ( ! isset( $this->templates[ $app ][ $location ][ $group ] ) )
|
||||
{
|
||||
if ( $app === 'cms' AND ! in_array( $location, array( 'admin', 'front', 'global' ) ) )
|
||||
{
|
||||
$this->templates[ $app ][ $location ][ $group ] = new \IPS\cms\Theme\Template( $app, $location, $group );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->templates[ $app ][ $location ][ $group ] = \IPS\Theme::i()->getTemplate( $group, $app, $location );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->templates[ $app ][ $location ][ $group ];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Group is saved clean */
|
||||
$group = static::cleanGroupName( $group );
|
||||
|
||||
if ( ( $app !== 'cms' ) OR ( $app === 'cms' AND in_array( $location, array( 'admin', 'front', 'global' ) ) ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( $group, $app, $location );
|
||||
}
|
||||
|
||||
$key = \strtolower( 'template_cms_' .static::makeBuiltTemplateLookupHash( $app, $location, $group ) . '_' . static::cleanGroupName( $group ) );
|
||||
|
||||
/* Still here */
|
||||
if ( !in_array( $key, array_keys( self::$calledTemplates ) ) )
|
||||
{
|
||||
/* If we don't have a compiled template, do that now */
|
||||
if ( !isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
$this->compileTemplates( $app, $location, $group );
|
||||
}
|
||||
|
||||
/* Still no key? */
|
||||
if ( ! isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
\IPS\Log::i( LOG_WARNING )->write( "Template store key: {$key} missing ({$app}, {$location}, {$group})", "template_store_missing" );
|
||||
|
||||
throw new \ErrorException('template_store_missing ' . $key);
|
||||
}
|
||||
|
||||
/* Load compiled template */
|
||||
$compiledGroup = \IPS\Data\Store::i()->$key;
|
||||
|
||||
if ( @eval( $compiledGroup ) === FALSE )
|
||||
{
|
||||
throw new \UnexpectedValueException;
|
||||
}
|
||||
|
||||
/* Hooks */
|
||||
$class = 'class_' . $app . '_' . $location . '_' . $group;
|
||||
$class = "\IPS\Theme\\{$class}";
|
||||
|
||||
/* Init */
|
||||
self::$calledTemplates[ $key ] = new $class();
|
||||
}
|
||||
|
||||
return self::$calledTemplates[ $key ];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Templates ready for non IN_DEV use
|
||||
* This fetches all templates in a group, converts HTML logic into ready to eval PHP and stores as a single PHP class per template group
|
||||
*
|
||||
* @param string|array $app Templates app (e.g. core, forum)
|
||||
* @param string|array $location Templates location (e.g. admin,global,front)
|
||||
* @param string|array $group Templates group (e.g. forms, members)
|
||||
* @return void
|
||||
*/
|
||||
public function compileTemplates( $app=null, $location=null, $group=null )
|
||||
{
|
||||
$templates = $this->getRawTemplates( $app, $location, static::cleanGroupName( $group ) );
|
||||
|
||||
foreach( $templates as $templateApp => $v )
|
||||
{
|
||||
foreach( $templates[ $templateApp ] as $location => $groups )
|
||||
{
|
||||
foreach( $templates[ $templateApp ][ $location ] as $group => $bits )
|
||||
{
|
||||
|
||||
/* Any template hooks? */
|
||||
$templateHooks = array();
|
||||
if( isset( \IPS\IPS::$hooks[ "\IPS\Theme\class_{$app}_{$location}_{$group}" ] ) )
|
||||
{
|
||||
foreach ( \IPS\IPS::$hooks[ "\IPS\Theme\class_{$app}_{$location}_{$group}" ] as $k => $data )
|
||||
{
|
||||
if ( !class_exists( "IPS\Theme\hook{$k}", FALSE ) )
|
||||
{
|
||||
if ( @eval( "namespace IPS\Theme;\n\n" . str_replace( ' extends _HOOK_CLASS_', '', file_get_contents( \IPS\ROOT_PATH . '/' . $data['file'] ) ) ) !== FALSE )
|
||||
{
|
||||
$class = "IPS\Theme\hook{$data['class']}";
|
||||
$templateHooks = array_merge( $templateHooks, $class::hookData() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build all the functions */
|
||||
$functions = array();
|
||||
foreach( $templates[ $templateApp ][ $location ][ $group ] as $name => $data )
|
||||
{
|
||||
if ( isset( $templateHooks[ $name ] ) )
|
||||
{
|
||||
$data['template_content'] = static::themeHooks( $data['template_content'], $templateHooks[ $name ] );
|
||||
}
|
||||
|
||||
$functions[ $name ] = static::compileTemplate( $data['template_content'], $data['template_title'], $data['template_params'], true, false, $app, $location, $group );
|
||||
}
|
||||
|
||||
/* Put them in a class */
|
||||
$template = <<<EOF
|
||||
namespace IPS\Theme;
|
||||
class class_{$app}_{$location}_{$group}
|
||||
{
|
||||
|
||||
EOF;
|
||||
$template .= implode( "\n\n", $functions );
|
||||
|
||||
$template .= <<<EOF
|
||||
}
|
||||
EOF;
|
||||
|
||||
/* Store it */
|
||||
$key = \strtolower( 'template_cms_' . static::makeBuiltTemplateLookupHash( $app, $location, $group ) . '_' . static::cleanGroupName( $group ) );
|
||||
|
||||
\IPS\Data\Store::i()->$key = $template;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete compiled templates
|
||||
* Removes compiled templates bits for all themes that match the arguments
|
||||
*
|
||||
* @param string $app Application Directory (core, forums, etc)
|
||||
* @param string|null $location Template location (front, admin, global, etc)
|
||||
* @param string|null $group Template group (forms, messaging, etc)
|
||||
* @param int|null $themeId Limit to a specific theme (and children)
|
||||
* @return void
|
||||
*/
|
||||
public static function deleteCompiledTemplate( $app=null, $location=null, $group=null, $themeId=null )
|
||||
{
|
||||
$templates = \IPS\cms\Theme::i()->getRawTemplates( $app, $location, $group );
|
||||
|
||||
foreach( $templates as $templateApp => $v )
|
||||
{
|
||||
foreach( $templates[ $templateApp ] as $location => $groups )
|
||||
{
|
||||
foreach( $templates[ $templateApp ][ $location ] as $group => $bits )
|
||||
{
|
||||
$key = \strtolower( 'template_cms_' . static::makeBuiltTemplateLookupHash( $app, $location, $group ) . '_' . static::cleanGroupName( $group ) );
|
||||
|
||||
if ( isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$key );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent::deleteCompiledTemplate( $app, $location, $group, $themeId );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path for the IN_DEV .phtml files
|
||||
* @param string $app Application Key
|
||||
* @param string|null $location Location
|
||||
* @param string|null $path Path or Filename
|
||||
* @return string
|
||||
*/
|
||||
protected static function _getHtmlPath( $app, $location=null, $path=null )
|
||||
{
|
||||
return rtrim( \IPS\ROOT_PATH . "/applications/{$app}/dev/html/{$location}/{$path}", '/' ) . '/';
|
||||
}
|
||||
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief CMS Widgets
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 13 Oct 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* CMS Widgets
|
||||
*/
|
||||
class _Widget extends \IPS\Widget
|
||||
{
|
||||
/**
|
||||
* Fetch the configuration for this unqiue ID. Looks in active tables and trash. When a widget is moved, saveOrder is called twice,
|
||||
* once to remove the widget from column A and again to add it to column B. We store the widget removed from column A into the trash
|
||||
* table.
|
||||
*
|
||||
* @param string $uniqueId Widget's unique ID
|
||||
* @return array
|
||||
*/
|
||||
public static function getConfiguration( $uniqueId )
|
||||
{
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_page_widget_areas' ) as $item )
|
||||
{
|
||||
$widgets = json_decode( $item['area_widgets'], TRUE );
|
||||
|
||||
foreach( $widgets as $widget )
|
||||
{
|
||||
if ( $widget['unique'] == $uniqueId )
|
||||
{
|
||||
if ( isset( $widget['configuration'] ) )
|
||||
{
|
||||
return $widget['configuration'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still here? rummage in the trash */
|
||||
return parent::getConfiguration( $uniqueId );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete caches. We need a different name from the parent class otherwise the Pages app hook will get stuck in infinite recursion
|
||||
*
|
||||
* @param String $key Widget key
|
||||
* @param String $app Parent application
|
||||
* @param String $plugin Parent plugin
|
||||
* @return void
|
||||
*/
|
||||
static public function deleteCachesForBlocks( $key=NULL, $app=NULL, $plugin=NULL )
|
||||
{
|
||||
/* Delete any custom block caches relevant to this plug in */
|
||||
if ( $key OR $app )
|
||||
{
|
||||
$where = array( array( 'block_type=?', 'plugin' ) );
|
||||
|
||||
if( $key )
|
||||
{
|
||||
$where[] = array( 'block_plugin=?', (string) $key );
|
||||
}
|
||||
|
||||
if( $app )
|
||||
{
|
||||
$where[] = array( 'block_plugin_app=?', (string) $app );
|
||||
}
|
||||
|
||||
$blocks = array();
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_blocks', $where ) as $row )
|
||||
{
|
||||
$blocks[ $row['block_key'] ] = $row;
|
||||
}
|
||||
|
||||
if ( count( $blocks ) )
|
||||
{
|
||||
$uniqueIds = array();
|
||||
foreach( \IPS\Db::i()->select( '*', 'cms_page_widget_areas' ) as $item )
|
||||
{
|
||||
$widgets = json_decode( $item['area_widgets'], TRUE );
|
||||
|
||||
foreach( $widgets as $widget )
|
||||
{
|
||||
if ( $widget['app'] === 'cms' and $widget['key'] === 'Blocks' and isset( $widget['unique'] ) and isset( $widget['configuration'] ) and isset( $widget['configuration']['cms_widget_custom_block'] ) )
|
||||
{
|
||||
if ( in_array( $widget['configuration']['cms_widget_custom_block'], array_keys( $blocks ) ) )
|
||||
{
|
||||
$uniqueIds[] = $widget['unique'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $uniqueIds ) )
|
||||
{
|
||||
$widgetRow = \IPS\Db::i()->select( '*', 'core_widgets', array( '`key`=? and app=?', 'Blocks', 'cms' ) )->first();
|
||||
|
||||
if ( ! empty( $widgetRow['caches'] ) )
|
||||
{
|
||||
$caches = json_decode( $widgetRow['caches'], TRUE );
|
||||
|
||||
if ( is_array( $caches ) )
|
||||
{
|
||||
$save = $caches;
|
||||
foreach( $caches as $key => $time )
|
||||
{
|
||||
foreach( $uniqueIds as $id )
|
||||
{
|
||||
if ( mb_stristr( $key, 'widget_Blocks_' . $id ) )
|
||||
{
|
||||
if ( isset( \IPS\Data\Store::i()->$key ) )
|
||||
{
|
||||
unset( \IPS\Data\Store::i()->$key );
|
||||
}
|
||||
|
||||
unset( $save[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $save ) !== count( $caches ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_widgets', array( 'caches' => ( count( $save ) ? json_encode( $save ) : NULL ) ), array( 'id=?', $widgetRow['id'] ) );
|
||||
unset( \IPS\Data\Store::i()->widgets );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Whitespace-only changes.
Whitespace-only changes.
Reference in new issue
Block a user