Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

+173 -151
View File
@@ -13,11 +13,39 @@ namespace IPS\cms;
/* To prevent PHP errors (extending class does not exist) revealing path */
use BadMethodCallException;
use Exception;
use InvalidArgumentException;
use IPS\cms\Pages\Page;
use IPS\Data\Store;
use IPS\Db;
use IPS\Db\Select;
use IPS\File;
use IPS\Helpers\Form;
use IPS\Helpers\Form\CheckboxSet;
use IPS\Http\Url;
use IPS\Http\Url\Friendly;
use IPS\Http\Url\Internal;
use IPS\Member;
use IPS\Patterns\ActiveRecord;
use IPS\Theme;
use OutOfRangeException;
use SimpleXMLElement;
use UnderflowException;
use UnexpectedValueException;
use XMLReader;
use XMLWriter;
use function count;
use function defined;
use function in_array;
use function is_array;
use function is_numeric;
use function strtolower;
use function substr;
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
@@ -32,47 +60,47 @@ if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*
* Updating templates: Update where user_edited is FALSE and user_created is FALSE OR user_created is TRUE and original_group is in master groups
*/
class _Templates extends \IPS\Patterns\ActiveRecord
class Templates extends ActiveRecord
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
protected static array $multitons;
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'template_';
public static string $databasePrefix = 'template_';
/**
* @brief [ActiveRecord] ID Database Table
*/
public static $databaseTable = 'cms_templates';
public static ?string $databaseTable = 'cms_templates';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
public static string $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array( 'template_key', 'template_id' );
protected static array $databaseIdFields = array( 'template_key', 'template_id' );
/**
* @brief [ActiveRecord] Multiton Map
*/
protected static $multitonMap = array();
protected static array $multitonMap = array();
/**
* @brief Master groups
*/
protected static $masterGroups = NULL;
protected static ?array $masterGroups = NULL;
/**
* @brief Master templates
*/
protected static $masterTemplates = NULL;
protected static ?array $masterTemplates = NULL;
/**
* @brief Retusn all types
@@ -110,7 +138,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
const RETURN_ONLY_TEMPLATE = 64;
/**
* @brief Return just contents of cms_templates ignoring IN_DEV and DESIGNERS' MODE
* @brief Return just contents of cms_templates ignoring IN_DEV
*/
const RETURN_DATABASE_ONLY = 128;
@@ -122,8 +150,8 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/**
* @brief Default database template group names
*/
public static $databaseDefaults = array(
'featured' => 'category_articles',
public static array $databaseDefaults = array(
'index' => 'category_articles',
'form' => 'form',
'display' => 'display',
'listing' => 'listing',
@@ -136,9 +164,9 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* @param string $group Group to load templates from
* @return void
*/
public static function fixTemplateTags( $group )
public static function fixTemplateTags( string $group ) : void
{
$templates = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_templates', array( array( 'template_group=?', $group ) ) )->setKeyField('template_title') );
$templates = iterator_to_array( Db::i()->select( '*', 'cms_templates', array( array( 'template_group=?', $group ) ) )->setKeyField('template_title') );
foreach( $templates as $template )
{
@@ -167,18 +195,18 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( isset( $options['app'] ) and $options['app'] == 'cms' and isset( $options['location'] ) and $options['location'] == 'database' and isset( $options['group'] ) and $options['group'] != $template['template_original_group'] )
{
if ( \in_array( $value, array_keys( $templates ) ) )
if ( in_array( $value, array_keys( $templates ) ) )
{
$options['group'] = $group;
$replace = '{template="' . $value . '" app="' . $options['app'] . '" location="' . $options['location'] . '" group="' . $options['group'] . '" params="' . ( isset($options['params']) ? $options['params'] : NULL ) . '"}';
$replace = '{template="' . $value . '" app="' . $options['app'] . '" location="' . $options['location'] . '" group="' . $options['group'] . '" params="' . ( $options['params'] ?? NULL ) . '"}';
$save['template_content'] = str_replace( $matches[$index][0], $replace, $template['template_content'] );
}
}
if ( \count( $save ) )
if ( count( $save ) )
{
\IPS\Db::i()->update( 'cms_templates', $save, array( 'template_id=?', $template['template_id'] ) );
Db::i()->update( 'cms_templates', $save, array( 'template_id=?', $template['template_id'] ) );
}
}
}
@@ -191,24 +219,24 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* 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)
* @see Db::build
* @param int|string|null $id ID
* @param string|null $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
* @return ActiveRecord|static
* @throws InvalidArgumentException
* @throws OutOfRangeException
*/
public static function load( $id, $idField=NULL, $extraWhereClause=NULL )
public static function load( int|string|null $id, string $idField=NULL, mixed $extraWhereClause=NULL ): ActiveRecord|static
{
if ( !\is_numeric( $id ) and $idField === NULL )
if ( !is_numeric( $id ) and $idField === NULL )
{
$idField = 'template_key';
}
if ( !\is_numeric( $id ) and ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) )
if ( !is_numeric( $id ) and \IPS\IN_DEV )
{
$templates = \IPS\cms\Theme::i()->getRawTemplates( NULL, NULL, NULL, \IPS\cms\Theme::RETURN_AS_OBJECT );
$templates = Theme::i()->getAllTemplates( '', '', '', \IPS\cms\Theme::RETURN_AS_OBJECT );
if ( isset( $templates[ $id ] ) )
{
@@ -220,7 +248,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
{
return parent::load( $id, $idField, $extraWhereClause );
}
catch( \OutOfRangeException $ex )
catch( OutOfRangeException $ex )
{
throw $ex;
}
@@ -232,7 +260,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* @param string $name Group name from the database
* @return string
*/
public static function readableGroupName( $name )
public static function readableGroupName( string $name ) : string
{
if ( $name === 'js' )
{
@@ -256,7 +284,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
{
if ( static::$masterTemplates === NULL )
{
static::$masterTemplates = iterator_to_array( \IPS\Db::i()->select( '*, MD5( CONCAT( template_location, \'.\', template_group, \'.\', template_title ) ) as bit_key', 'cms_templates', array( 'template_master=1' ) )->setKeyField( 'bit_key' ) );
static::$masterTemplates = iterator_to_array( Db::i()->select( '*, MD5( CONCAT( template_location, \'.\', template_group, \'.\', template_title ) ) as bit_key', 'cms_templates', array( 'template_master=1' ) )->setKeyField( 'bit_key' ) );
}
return static::$masterTemplates;
@@ -265,9 +293,9 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/**
* Get the master template version of this template
*
* @return \IPS\cms\Templates|NULL
* @return Templates|null
*/
public function getMasterOfThis()
public function getMasterOfThis(): ?Templates
{
if ( $this->master )
{
@@ -275,12 +303,13 @@ class _Templates extends \IPS\Patterns\ActiveRecord
}
$key = md5( $this->location . '.'. $this->original_group . '.' . $this->title );
if ( \in_array( $key, array_keys( static::getMasterTemplates() ) ) )
if ( in_array( $key, array_keys( static::getMasterTemplates() ) ) )
{
/* @var static Templates */
return static::constructFromData( static::$masterTemplates[ $key ] );
}
return NULL;
return null;
}
/**
@@ -294,7 +323,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( static::$masterGroups === NULL )
{
static::$masterGroups = array();
foreach( \IPS\Db::i()->select( 'template_group', static::$databaseTable, array( 'template_master=1 and template_original_group=template_group' ), 'template_group ASC', NULL, 'template_group' ) as $template )
foreach( Db::i()->select( 'template_group', static::$databaseTable, array( 'template_master=1 and template_original_group=template_group' ), 'template_group ASC', NULL, 'template_group' ) as $template )
{
static::$masterGroups[ $template ] = $template;
}
@@ -306,32 +335,28 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/**
* Get all template group
*
* @param int|constant $returnType Determines the content returned
* @param string $returnType Determines the content returned
* @return array
*/
public static function getGroups( $returnType=1 )
public static function getGroups( string $returnType ): array
{
$where = array();
$return = array();
$locations = NULL;
if ( \is_string( $returnType ) )
switch( $returnType )
{
switch( $returnType )
{
case 'all':
$returnType = self::RETURN_ALL;
case 'all':
$returnType = self::RETURN_ALL;
break;
case 'block':
$returnType = self::RETURN_BLOCK;
case 'block':
$returnType = self::RETURN_BLOCK;
break;
case 'page':
$returnType = self::RETURN_PAGE;
case 'page':
$returnType = self::RETURN_PAGE;
break;
case 'database':
$returnType = self::RETURN_DATABASE;
case 'database':
$returnType = self::RETURN_DATABASE;
break;
}
}
if ( $returnType & self::RETURN_ALL )
@@ -357,15 +382,15 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$locations[] = 'database';
}
if ( ! \count( $locations ) )
if ( ! count( $locations ) )
{
throw new \UnexpectedValueException();
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 )
foreach( Db::i()->select( 'template_group', static::$databaseTable, $where, 'template_group ASC', NULL, 'template_group' ) as $template )
{
$return[ $template ] = $template;
}
@@ -376,16 +401,15 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/**
* Get all templates
*
* @param int|constant $returnType Determines the content returned
* @param int $returnType Determines the content returned
* @return array
*/
public static function getTemplates( $returnType=1 )
public static function getTemplates( int $returnType=1 ): array
{
$where = array();
$return = array();
$locations = NULL;
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ( $returnType & self::RETURN_DATABASE_AND_IN_DEV ) AND ! ( $returnType & self::RETURN_DATABASE_ONLY ) )
if ( ( \IPS\IN_DEV ) AND ( $returnType & self::RETURN_DATABASE_AND_IN_DEV ) AND ! ( $returnType & self::RETURN_DATABASE_ONLY ) )
{
$flags = \IPS\cms\Theme::RETURN_AS_OBJECT;
@@ -419,10 +443,10 @@ class _Templates extends \IPS\Patterns\ActiveRecord
}
}
$return = \IPS\cms\Theme::i()->getRawTemplates( 'cms', NULL, NULL, $flags );
$return = Theme::i()->getAllTemplates( 'cms', '', '', $flags );
}
if ( ! ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) OR ( $returnType & self::RETURN_DATABASE_AND_IN_DEV ) OR ( $returnType & self::RETURN_DATABASE_ONLY ) )
if ( ! ( \IPS\IN_DEV ) OR ( $returnType & self::RETURN_DATABASE_AND_IN_DEV ) OR ( $returnType & self::RETURN_DATABASE_ONLY ) )
{
if ( $returnType & self::RETURN_ALL )
{
@@ -459,15 +483,15 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$locations[] = 'database';
}
if ( !\count( $locations ) )
if ( !count( $locations ) )
{
throw new \UnexpectedValueException();
throw new UnexpectedValueException();
}
$where[] = array( "template_location IN ('" . implode( "','", $locations ) . "')" );
}
foreach ( \IPS\Db::i()->select( '*', static::$databaseTable, $where, 'template_user_edited DESC' ) as $template )
foreach ( 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'] ] ) )
@@ -487,14 +511,14 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* @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
* @return Select
*/
protected static function constructLoadQuery( $id, $idField, $extraWhereClause )
protected static function constructLoadQuery( int|string $id, string $idField, mixed $extraWhereClause ): Select
{
$where = array( array( $idField . '=?', $id ) );
if( $extraWhereClause !== NULL )
{
if ( !\is_array( $extraWhereClause ) or !\is_array( $extraWhereClause[0] ) )
if ( !is_array( $extraWhereClause ) or !is_array( $extraWhereClause[0] ) )
{
$extraWhereClause = array( $extraWhereClause );
}
@@ -510,13 +534,13 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* @param array $templates Template data from the database
* @return array
*/
public static function buildTree( $templates )
public static function buildTree( array $templates ) : array
{
$return = array();
foreach( $templates as $id => $template )
{
if ( ! ( $template->location === 'database' and ! \IPS\Member::loggedIn()->hasAcpRestriction( 'cms', 'databases', 'databases_use' ) ) )
if ( ! ( $template->location === 'database' and ! Member::loggedIn()->hasAcpRestriction( 'cms', 'databases', 'databases_use' ) ) )
{
$return[$template->location][$template->group][$template->key] = $template;
}
@@ -529,9 +553,9 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* Add a new template
*
* @param array $template Template Data
* @return object \IPS\cms\Templates
* @return static
*/
public static function add( $template )
public static function add( array $template ) : static
{
$newTemplate = new static;
@@ -548,7 +572,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$newTemplate->save();
/* Create a unique key */
$newTemplate->key = $newTemplate->location . '_' . \IPS\Http\Url\Friendly::seoTitle( $newTemplate->title ) . '_' . $newTemplate->id;
$newTemplate->key = $newTemplate->location . '_' . Friendly::seoTitle( $newTemplate->title ) . '_' . $newTemplate->id;
/* Make sure there's no double __ in there */
foreach( array( 'group', 'title', 'key' ) as $field )
@@ -569,18 +593,18 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return void
*/
public static function deleteCompiledFiles()
public static function deleteCompiledFiles() : void
{
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_file_object IS NOT NULL' ) ) as $template )
foreach( 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();
File::get( 'core_Theme', $template['template_file_object'] )->delete();
}
catch( \Exception $ex ) { }
catch( Exception $ex ) { }
}
\IPS\Db::i()->update( 'cms_templates', array( 'template_file_object' => NULL ) );
Db::i()->update( 'cms_templates', array( 'template_file_object' => NULL ) );
}
/**
@@ -588,15 +612,15 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @param bool $appPluginBuild TRUE to customise form for app/plugin builds
* @param array $preSelected Array of default values for checkboxSet
* @return \IPS\Helpers\Form
* @return Form
*/
public static function exportForm( bool $appPluginBuild=FALSE, array $preSelected=array() ): \IPS\Helpers\Form
public static function exportForm( bool $appPluginBuild=FALSE, array $preSelected=array() ): Form
{
$form = new \IPS\Helpers\Form( 'form', $appPluginBuild ? 'save' : 'next' );
$form = new Form( 'form', $appPluginBuild ? 'save' : 'next' );
if( !$appPluginBuild )
{
$form->addMessage( 'cms_templates_export_description', 'ipsMessage ipsMessage_information' );
$form->addButton( 'cms_templates_export_return', 'link', \IPS\Http\Url::internal( "app=cms&module=pages&controller=templates" ) );
$form->addButton( 'cms_templates_export_return', 'link', Url::internal( "app=cms&module=pages&controller=templates" ) );
}
else
{
@@ -605,9 +629,9 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$templates = [];
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_DATABASE_ONLY + \IPS\cms\Templates::RETURN_ALL ) as $template )
foreach(Templates::getTemplates( Templates::RETURN_DATABASE_ONLY + Templates::RETURN_ALL ) as $template )
{
$title = \IPS\cms\Templates::readableGroupName( $template->group );
$title = Templates::readableGroupName( $template->group );
if ( $template->location === 'database' )
{
@@ -626,7 +650,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
foreach( $templates as $location => $data )
{
$defaultValue = $preSelected[ 'templates_' . $location ] ?? FALSE;
$form->add( new \IPS\Helpers\Form\CheckboxSet( 'templates_' . $location, $defaultValue, FALSE, array( 'options' => $data ) ) );
$form->add( new CheckboxSet( 'templates_' . $location, $defaultValue, FALSE, array( 'options' => $data ) ) );
}
return $form;
@@ -636,23 +660,23 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* Export requested templates as XML
*
* @param array $values Checkbox set values
* @return \XMLWriter|null
* @return XMLWriter|null
*/
public static function exportAsXml( array $values ):? \XMLWriter
public static function exportAsXml( array $values ):? XMLWriter
{
$templates = array();
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_DATABASE_ONLY + \IPS\cms\Templates::RETURN_ALL ) as $template )
foreach(Templates::getTemplates( Templates::RETURN_DATABASE_ONLY + Templates::RETURN_ALL ) as $template )
{
$templates[ $template->location ][ $template->group ] = $template->title;
}
$exportTemplates = array();
foreach ( $templates as $location => $data )
foreach ( $templates as $location => $outerData )
{
if ( isset( $values[ 'templates_' . $location ] ) and \count( $values[ 'templates_' . $location ] ) )
if ( isset( $values[ 'templates_' . $location ] ) and count( $values[ 'templates_' . $location ] ) )
{
if ( $location === 'database' )
{
$tmp = \IPS\cms\Theme::i()->getRawTemplates( 'cms', array( 'database' ), array_values( $values[ 'templates_' . $location ] ), \IPS\cms\Theme::RETURN_DATABASE_ONLY + \IPS\cms\Theme::RETURN_ALL );
$tmp = \IPS\cms\Theme::i()->getAllTemplates( 'cms', array( 'database' ), array_values( $values[ 'templates_' . $location ] ), \IPS\cms\Theme::RETURN_DATABASE_ONLY + Theme::RETURN_ALL );
foreach ( $tmp['cms'] as $loc => $data )
{
@@ -670,7 +694,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
}
else
{
$tmp = \IPS\cms\Theme::i()->getRawTemplates( 'cms', array( $location ), NULL, \IPS\cms\Theme::RETURN_DATABASE_ONLY + \IPS\cms\Theme::RETURN_ALL );
$tmp = \IPS\cms\Theme::i()->getAllTemplates( 'cms', array( $location ), [], \IPS\cms\Theme::RETURN_DATABASE_ONLY + Theme::RETURN_ALL );
foreach ( $tmp['cms'] as $loc => $data )
{
@@ -680,7 +704,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
{
foreach ( $tdata as $tkey => $tkdata )
{
if ( \in_array( $tkey, $values[ 'templates_' . $location ] ) )
if ( in_array( $tkey, $values[ 'templates_' . $location ] ) )
{
$exportTemplates['cms'][ $location ][ $key ][ $tkey ] = $tkdata;
}
@@ -692,10 +716,10 @@ class _Templates extends \IPS\Patterns\ActiveRecord
}
}
if ( \count( $exportTemplates ) )
if ( count( $exportTemplates ) )
{
/* Init */
$xml = new \XMLWriter;
$xml = new XMLWriter;
$xml->openMemory();
$xml->setIndent( TRUE );
$xml->startDocument( '1.0', 'UTF-8' );
@@ -716,7 +740,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
foreach ( $templateData as $k => $v )
{
if ( !\in_array( \substr( $k, 9 ), array( 'content', 'params' ) ) )
if ( !in_array( substr( $k, 9 ), array( 'content', 'params' ) ) )
{
$xml->startAttribute( $k );
$xml->text( $v );
@@ -730,7 +754,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( isset( $templateData[ $field ] ) )
{
$xml->startElement( $field );
if ( preg_match( '/<|>|&/', $templateData[ $field ] ) )
if ( preg_match( '/[<>&]/', $templateData[ $field ] ) )
{
$xml->writeCData( str_replace( ']]>', ']]]]><![CDATA[>', $templateData[ $field ] ) );
}
@@ -763,7 +787,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return boolean
*/
public function isSuitableForCustomWrapper()
public function isSuitableForCustomWrapper(): bool
{
if ( $this->location == 'page' and preg_match( '#<html([^>]+?)?>#', $this->content ) )
{
@@ -781,7 +805,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return boolean
*/
public function isSuitableForBuilderWrapper()
public function isSuitableForBuilderWrapper() : bool
{
if ( $this->location == 'page' and mb_stristr( $this->content, '{template="widgetContainer"' ) )
{
@@ -812,13 +836,11 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/**
* Import User Template XML
*
* @param string $filePath Path to XML file
* @param string $fileContents XML Contents as string
* @throws \UnexpectedValueException
* @throws \BadMethodCallException
* @return \IPS\Http\Url\Internal|null
* @param string|null $filePath Path to XML file
* @param string|null $fileContents XML Contents as string
* @return Internal|null
*/
public static function importUserTemplateXml( string $filePath=NULL, string $fileContents=NULL ):? \IPS\Http\Url\Internal
public static function importUserTemplateXml( string $filePath=NULL, string $fileContents=NULL ):? Internal
{
/* Open XML file */
if( $filePath )
@@ -831,28 +853,28 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if( !$xml->xml( $fileContents, NULL, LIBXML_NONET ) )
{
throw \UnexpectedValueException('bad_xml_string');
throw new UnexpectedValueException('bad_xml_string');
}
}
else
{
throw new \BadMethodCallException('path_or_data_missing');
throw new BadMethodCallException('path_or_data_missing');
}
$conflictKey = md5( microtime() );
$templates = \IPS\cms\Theme::i()->getRawTemplates( 'cms', NULL, NULL, \IPS\cms\Theme::RETURN_DATABASE_ONLY + \IPS\cms\Theme::RETURN_ALL );
$templates = Theme::i()->getAllTemplates( 'cms', NULL, NULL, \IPS\cms\Theme::RETURN_DATABASE_ONLY + Theme::RETURN_ALL );
if ( ! @$xml->read() )
{
throw new \UnexpectedValueException('xml_file_bad_format');
throw new UnexpectedValueException('xml_file_bad_format');
}
$xml->read();
while ( $xml->read() )
{
if ( $xml->name === 'template' )
{
$node = new \SimpleXMLElement( $xml->readOuterXML() );
$node = new SimpleXMLElement( $xml->readOuterXML() );
$attrs = array();
foreach( $node->attributes() as $k => $v )
@@ -864,7 +886,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
foreach( $node->children() as $k => $v )
{
$tryJson = json_decode( $v, TRUE );
$attrs[ $k ] = ( $tryJson ) ? $tryJson : (string) $v;
$attrs[ $k ] = ( $tryJson ) ?: (string) $v;
}
@@ -889,7 +911,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( $exists['template_master'] )
{
/* This is a master template bit, so it's totes fine to create a new one, as it will 'overload' this one */
$obj = new \IPS\cms\Templates;
$obj = new Templates;
$obj->location = $attrs['template_location'];
$obj->group = $attrs['template_group'];
$obj->title = $attrs['template_title'];
@@ -909,7 +931,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( $exists['template_user_edited'] )
{
/* User has edited this, so we should just log a conflict... */
\IPS\Db::i()->insert( 'cms_template_conflicts', array(
Db::i()->insert( 'cms_template_conflicts', array(
'conflict_key' => $conflictKey,
'conflict_item_id' => $exists['template_id'],
'conflict_type' => $attrs['template_type'],
@@ -927,18 +949,18 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/* Not edited, so just update */
try
{
$template = \IPS\cms\Templates::load( $exists['template_key'], 'template_key' );
$template = Templates::load( $exists['template_key'], 'template_key' );
$template->params = $attrs['template_params'];
$template->content = $attrs['template_content'];
$template->save();
}
catch( \Exception $e ) { }
catch( Exception $e ) { }
}
}
else
{
/* This is an overloaded master template, so just update */
$template = \IPS\cms\Templates::load( $exists['template_key'], 'template_key' );
$template = Templates::load( $exists['template_key'], 'template_key' );
$template->user_edited = 1;
$template->params = $attrs['template_params'];
$template->content = $attrs['template_content'];
@@ -949,7 +971,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( $exists === NULL )
{
$obj = new \IPS\cms\Templates;
$obj = new Templates;
$obj->location = $attrs['template_location'];
$obj->group = $attrs['template_group'];
$obj->title = $attrs['template_title'];
@@ -968,9 +990,9 @@ class _Templates extends \IPS\Patterns\ActiveRecord
{
try
{
$check = \IPS\Db::i()->select( 'template_id', 'cms_templates', array( 'template_key=?', $attrs['template_key'] ) )->first();
$check = Db::i()->select( 'template_id', 'cms_templates', array( 'template_key=?', $attrs['template_key'] ) )->first();
if ( $check['template_master'] == 1 and \in_array( $attrs['template_group'], \IPS\cms\Templates::getMasterGroups() ) )
if ( $check['template_master'] == 1 and in_array( $attrs['template_group'], Templates::getMasterGroups() ) )
{
/* it's OK to overload this with a user edited version */
$obj->user_created = 0;
@@ -979,14 +1001,14 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$key = $attrs['template_key'];
}
}
catch( \UnderflowException $e )
catch( UnderflowException $e )
{
/* It doesn't exist! */
$key = $attrs['template_key'];
}
}
$obj->key = ( $key ) ? $key : $obj->location . \IPS\Http\Url\Friendly::seoTitle( $obj->group ) . '_' . \IPS\Http\Url\Friendly::seoTitle( $obj->title ) . '_' . $obj->id;
$obj->key = ( $key ) ?: $obj->location . Friendly::seoTitle( $obj->group ) . '_' . Friendly::seoTitle( $obj->title ) . '_' . $obj->id;
$obj->save();
}
}
@@ -996,10 +1018,10 @@ class _Templates extends \IPS\Patterns\ActiveRecord
}
/* Check for conflicts */
$conflicts = \IPS\Db::i()->select( 'count(*)', 'cms_template_conflicts', array( 'conflict_key=?', $conflictKey ) )->first();
$conflicts = Db::i()->select( 'count(*)', 'cms_template_conflicts', array( 'conflict_key=?', $conflictKey ) )->first();
if( $conflicts )
{
return \IPS\Http\Url::internal( 'app=cms&module=pages&controller=templates&do=conflicts&key=' . $conflictKey );
return Url::internal( 'app=cms&module=pages&controller=templates&do=conflicts&key=' . $conflictKey );
}
return NULL;
@@ -1014,7 +1036,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
* @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 )
public static function importXml( string $file, ?int $offset=NULL, ?int $limit=NULL, bool $update=TRUE ) : bool
{
$i = 0;
$worked = false;
@@ -1026,8 +1048,8 @@ class _Templates extends \IPS\Patterns\ActiveRecord
{
if ( $update === TRUE )
{
\IPS\Db::i()->delete( 'cms_templates', array( 'template_master=1' ) );
\IPS\cms\Theme::deleteCompiledTemplate( 'cms' );
Db::i()->delete( 'cms_templates', array( 'template_master=1' ) );
Theme::deleteCompiledTemplate( 'cms' );
}
}
@@ -1037,7 +1059,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
while( $xml->read() )
{
if( $xml->nodeType != \XMLReader::ELEMENT )
if( $xml->nodeType != XMLReader::ELEMENT )
{
continue;
}
@@ -1067,7 +1089,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$save[ 'template_' . $field ] = $xml->getAttribute( 'template_' . $field );
}
\IPS\Db::i()->insert( 'cms_templates', $save );
Db::i()->insert( 'cms_templates', $save );
$worked = true;
}
@@ -1091,10 +1113,10 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return void
*/
public static function updateAllInheritedMasterTemplates()
public static function updateAllInheritedMasterTemplates() : void
{
/* Update existing template bits */
foreach( \IPS\Db::i()->select( '*', 'cms_templates', array( 'template_master=0 and template_user_created=1 and template_user_edited=0' ) ) as $key => $template )
foreach( Db::i()->select( '*', 'cms_templates', array( 'template_master=0 and template_user_created=1 and template_user_edited=0' ) ) as $key => $template )
{
$obj = static::constructFromData( $template );
@@ -1114,14 +1136,14 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$masterByGroup[ $template['template_group'] ][ $template['template_title'] ] = $template;
}
$customGroups = iterator_to_array( \IPS\Db::i()->select( 'template_group, MIN(template_original_group) as template_original_group', static::$databaseTable, array( 'template_master=0 and template_original_group != template_group' ), 'template_group ASC', NULL, 'template_group' )->setKeyField('template_group')->setValueField('template_original_group') );
$customGroups = iterator_to_array( Db::i()->select( 'template_group, MIN(template_original_group) as template_original_group', static::$databaseTable, array( 'template_master=0 and template_original_group != template_group' ), 'template_group ASC', NULL, 'template_group' )->setKeyField('template_group')->setValueField('template_original_group') );
foreach( $customGroups as $customGroup => $masterGroup )
{
if ( $masterGroup )
{
$groupByGroup = array();
foreach ( \IPS\Db::i()->select( '*', static::$databaseTable, array('template_group=?', $customGroup) ) as $bit )
foreach ( Db::i()->select( '*', static::$databaseTable, array('template_group=?', $customGroup) ) as $bit )
{
$groupByGroup[$bit['template_title']] = $bit;
}
@@ -1129,7 +1151,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/* Now, see if we're missing any */
foreach( $masterByGroup[ $masterGroup ] as $title => $template )
{
if ( ! \in_array( $title, array_keys( $groupByGroup ) ) )
if ( ! in_array( $title, array_keys( $groupByGroup ) ) )
{
$copy = $template;
foreach( array( 'template_id', 'template_file_object', 'bit_key' ) as $field )
@@ -1142,7 +1164,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$copy['template_group'] = $customGroup;
$copy['template_key'] = $copy['template_location'] . '_' . $customGroup . '_' . $title;
\IPS\Db::i()->insert( 'cms_templates', $copy );
Db::i()->insert( 'cms_templates', $copy );
}
}
}
@@ -1155,13 +1177,13 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return void
*/
public function delete()
public function delete(): void
{
\IPS\cms\Theme::deleteCompiledTemplate( 'cms', $this->location, $this->group );
Theme::deleteCompiledTemplate( 'cms', $this->location, $this->group );
if ( $this->user_created )
{
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_created=?', $this->key, 1 ) );
Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_created=?', $this->key, 1 ) );
if ( isset( static::$multitons[ $this->id ] ) )
{
@@ -1182,7 +1204,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
{
if ( $this->user_edited )
{
\IPS\Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_edited=?', $this->key, 1 ) );
Db::i()->delete( 'cms_templates', array( 'template_key=? AND template_user_edited=?', $this->key, 1 ) );
if ( isset( static::$multitons[ $this->id ] ) )
{
@@ -1201,7 +1223,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
}
else
{
throw new \OutOfRangeException('CANNOT_DELETE');
throw new OutOfRangeException('CANNOT_DELETE');
}
}
}
@@ -1211,9 +1233,9 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return string
*/
public function get__inherited()
public function get__inherited() : string
{
if ( $this->user_created and ! \in_array( $this->original_group, static::getMasterGroups() ) )
if ( $this->user_created and ! in_array( $this->original_group, static::getMasterGroups() ) )
{
return 'custom';
}
@@ -1234,7 +1256,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return string
*/
public function get__file_object()
public function get__file_object(): string
{
if ( ! $this->file_object )
{
@@ -1244,12 +1266,12 @@ class _Templates extends \IPS\Patterns\ActiveRecord
if ( $this->type != 'js' and ( mb_stristr( $this->content, "{block=" ) or mb_stristr( $this->content, "{{if" ) or mb_stristr( $this->content, "{media=" ) ) )
{
$functionName = 'css_' . mt_rand();
\IPS\Theme::makeProcessFunction( str_replace( '\\', '\\\\', $content ), $functionName );
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 );
$this->file_object = (string) File::create( 'cms_Pages', $this->title, $content ?: ' ', 'page_objects', TRUE );
parent::save(); # Go to parent save to prevent $this->save() from wiping file objects
}
@@ -1261,22 +1283,22 @@ class _Templates extends \IPS\Patterns\ActiveRecord
*
* @return void
*/
public function save()
public function save(): void
{
/* Trash file object if appropriate */
if ( $this->file_object )
{
try
{
\IPS\File::get( 'cms_Pages', $this->file_object )->delete();
File::get( 'cms_Pages', $this->file_object )->delete();
}
catch ( \Exception $e )
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 );
Page::deleteCachedIncludes( $this->file_object );
$this->file_object = NULL;
}
@@ -1284,7 +1306,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
parent::save();
/* Clear store */
$key = \strtolower( 'template_cms_' . \IPS\cms\Theme::makeBuiltTemplateLookupHash( 'cms', $this->location, $this->group ) . '_' . $this->group );
unset( \IPS\Data\Store::i()->$key );
$key = strtolower( 'template_cms_' . Theme::makeBuiltTemplateLookupHash( 'cms', $this->location, $this->group ) . '_' . $this->group );
unset( Store::i()->$key );
}
}