Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1171280
template_helper.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Sep 28, 12:38 AM
Size
12 KB
Mime Type
text/x-php
Expires
Tue, Sep 30, 12:38 AM (1 d, 14 h)
Engine
blob
Format
Raw Data
Handle
758930
Attached To
rINP In-Portal
template_helper.php
View Options
<?php
/**
* @version $Id: template_helper.php 15137 2012-03-04 08:06:21Z alex $
* @package In-Portal
* @copyright Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/
defined
(
'FULL_PATH'
)
or
die
(
'restricted access!'
);
class
TemplateHelper
extends
kHelper
{
/**
* parser element location information
*
* @var Array
*/
var
$_blockLocation
=
Array
();
/**
* Block name, that will be used
*
* @var string
*/
var
$_blockName
=
''
;
/**
* Function name, that represents compiled block
*
* @var sting
*/
var
$_functionName
=
''
;
/**
* Errors found during template parsing
*
* @var Array
*/
var
$_parseErrors
=
Array
();
/**
* Source template, that is being edited
*
* @var string
*/
var
$_sourceTemplate
=
''
;
var
$_initMade
=
false
;
/**
* Performs init ot helper
*
* @param kDBItem $object
*/
function
InitHelper
(&
$object
)
{
if
(
$this
->
_initMade
)
{
return
;
}
// 1. get block information
$block_info
=
$this
->
Application
->
GetVar
(
'block'
);
list
(
$this
->
_blockName
,
$this
->
_functionName
)
=
explode
(
':'
,
$block_info
);
$this
->
_parseTemplate
(
$object
);
if
(
array_key_exists
(
$this
->
_functionName
,
$this
->
Application
->
Parser
->
ElementLocations
))
{
$this
->
_blockLocation
=
$this
->
Application
->
Parser
->
ElementLocations
[
$this
->
_functionName
];
}
$this
->
_initMade
=
true
;
}
function
_getSourceTemplate
()
{
// get source template
$t
=
$this
->
Application
->
GetVar
(
'source'
);
if
(!
$this
->
Application
->
TemplatesCache
->
TemplateExists
(
$t
))
{
$cms_handler
=
$this
->
Application
->
recallObject
(
'st_EventHandler'
);
/* @var $cms_handler CategoriesEventHandler */
$t
=
ltrim
(
$cms_handler
->
GetDesignTemplate
(
$t
),
'/'
);
}
$this
->
_sourceTemplate
=
$t
;
}
function
_getThemeName
()
{
$theme_id
=
(
int
)
$this
->
Application
->
GetVar
(
'theme_id'
);
$sql
=
'SELECT Name
FROM '
.
$this
->
Application
->
getUnitOption
(
'theme'
,
'TableName'
)
.
'
WHERE '
.
$this
->
Application
->
getUnitOption
(
'theme'
,
'IDField'
)
.
' = '
.
$theme_id
;
return
$this
->
Conn
->
GetOne
(
$sql
);
}
/**
* Render source template to get parse errors OR it's element locations
*
* @param kDBItem $object
* @param string $append
* @return bool
*/
function
_parseTemplate
(&
$object
,
$append
=
''
)
{
try
{
// 1. parse template
$this
->
Application
->
InitParser
(
$this
->
_getThemeName
()
);
// we have no parser when saving block content
$this
->
_getSourceTemplate
();
// 2. design templates have leading "/" in the beginning
$this
->
Application
->
Parser
->
Run
(
$this
->
_sourceTemplate
.
$append
);
}
catch
(
ParserException
$e
)
{
$this
->
_parseErrors
[]
=
Array
(
'msg'
=>
$e
->
getMessage
(),
'file'
=>
$e
->
getFile
(),
'line'
=>
$e
->
getLine
());
}
if
(
$this
->
_parseErrors
)
{
if
(
$this
->
_isMainTemplate
())
{
// 2.1. delete temporary file, that was parsed
$filename
=
$this
->
_getTemplateFile
(
false
,
$append
.
'.tpl'
);
if
(!
unlink
(
$filename
))
{
$error_file
=
$this
->
_getTemplateFile
(
true
,
$append
.
'.tpl'
);
$object
->
SetError
(
'FileContents'
,
'template_delete_failed'
,
'+Failed to delete temporary template "<strong>'
.
$error_file
.
'</strong>"'
);
return
false
;
}
}
else
{
// 2.2. restore backup
if
(!
rename
(
$this
->
_getTemplateFile
(
false
,
'.tpl.bak'
),
$this
->
_getTemplateFile
(
false
)))
{
$error_file
=
$this
->
_getTemplateFile
(
true
);
$object
->
SetError
(
'FileContents'
,
'template_restore_failed'
,
'+Failed to restore template "<strong>'
.
$error_file
.
'</strong>" from backup.'
);
return
false
;
}
}
return
false
;
}
return
true
;
}
/**
* Move elements in template and save changes, when possible
*
* @param Array $target_order
* @return bool
*/
function
moveTemplateElements
(
$target_order
)
{
// 2. parse template
$this
->
Application
->
InitParser
();
// we have no parser when saving block content
$this
->
_getSourceTemplate
();
$filename
=
$this
->
Application
->
TemplatesCache
->
GetRealFilename
(
$this
->
_sourceTemplate
)
.
'.tpl'
;
if
(!
is_writable
(
$filename
))
{
// we can't save changes, don't bother calculating new template contents
return
false
;
}
$data
=
file_get_contents
(
$filename
);
$line_ending
=
strpos
(
$data
,
"
\r
"
)
!==
false
?
"
\r\n
"
:
"
\n
"
;
// 1. get location of movable areas
$mask
=
''
;
$start_pos
=
0
;
$elements
=
$area
=
Array
();
$areas
=
$this
->
_getDivPairs
(
$data
,
'movable-area'
);
foreach
(
$areas
as
$area_index
=>
$area
)
{
// 1.1. get locations of all movable elements inside given area
$area_content
=
substr
(
$area
[
'data'
],
$area
[
'open_len'
],
-
$area
[
'close_len'
]);
$elements
=
array_merge
(
$elements
,
$this
->
_getDivPairs
(
$area_content
,
'movable-element'
,
$area_index
,
$area
[
'open_pos'
]
+
$area
[
'open_len'
]));
// 1.2. prepare mask to place movable elements into (don't include movable area div ifself)
$mask
.=
"
\t
"
.
substr
(
$data
,
$start_pos
,
$area
[
'open_pos'
]
+
$area
[
'open_len'
]
-
$start_pos
)
.
$line_ending
.
"
\t\t
"
.
'#AREA'
.
$area_index
.
'#'
.
$line_ending
;
$start_pos
=
$area
[
'close_pos'
]
-
$area
[
'close_len'
];
}
$mask
=
trim
(
$mask
.
"
\t
"
.
substr
(
$data
,
$area
[
'close_pos'
]
-
$area
[
'close_len'
]));
if
(!
$elements
)
{
// no elements found
return
false
;
}
foreach
(
$areas
as
$area_index
=>
$area
)
{
$area_content
=
''
;
$target_elements
=
$target_order
[
$area_index
];
foreach
(
$target_order
[
$area_index
]
as
$old_location
)
{
$area_content
.=
$elements
[
$old_location
][
'data'
]
.
$line_ending
.
"
\t\t
"
;
}
$mask
=
str_replace
(
'#AREA'
.
$area_index
.
'#'
,
trim
(
$area_content
),
$mask
);
}
$fp
=
fopen
(
$filename
,
'w'
);
fwrite
(
$fp
,
$mask
);
fclose
(
$fp
);
return
true
;
}
/**
* Extracts div pairs with given class from given text
*
* @param string $data
* @param string $class
* @param int $area
* @param int $offset
* @return Array
*/
function
_getDivPairs
(&
$data
,
$class
,
$area
=
null
,
$offset
=
0
)
{
preg_match_all
(
'/(<div[^>]*>)|(<
\/
div>)/s'
,
$data
,
$divs
,
PREG_SET_ORDER
+
PREG_OFFSET_CAPTURE
);
$deep_level
=
0
;
$pairs
=
Array
();
$skip_count
=
Array
();
// by deep level!
foreach
(
$divs
as
$div
)
{
if
(
strpos
(
$div
[
0
][
0
],
'/'
)
===
false
)
{
// opening div
$skip_count
[
$deep_level
]
=
0
;
if
(
strpos
(
$div
[
0
][
0
],
$class
)
!==
false
)
{
// ours opening (this deep level) -> save
$pair
=
Array
(
'open_pos'
=>
$div
[
0
][
1
],
'open_len'
=>
strlen
(
$div
[
0
][
0
]));
}
else
{
// not ours opening -> skip next closing (this deep level)
$skip_count
[
$deep_level
]++;
}
$deep_level
++;
}
else
{
// closing div
$deep_level
--;
if
(
$skip_count
[
$deep_level
]
==
0
)
{
// nothing to skip (this deep level) -> save
$pair
[
'close_len'
]
=
strlen
(
$div
[
0
][
0
]);
$pair
[
'close_pos'
]
=
$div
[
0
][
1
]
+
$pair
[
'close_len'
];
$pair
[
'data'
]
=
substr
(
$data
,
$pair
[
'open_pos'
],
$pair
[
'close_pos'
]
-
$pair
[
'open_pos'
]);
if
(
isset
(
$area
))
{
$pair
[
'open_pos'
]
+=
$offset
;
$pair
[
'close_pos'
]
+=
$offset
;
// index indicates area
$pairs
[
'a'
.
$area
.
'e'
.
count
(
$pairs
)]
=
$pair
;
}
else
{
$pairs
[]
=
$pair
;
}
}
else
{
// skip closing div as requested
$skip_count
[
$deep_level
]--;
}
}
}
return
$pairs
;
}
/**
* Returns information about parser element locations in template
*
* @param string $info_type
* @return mixed
*/
function
blockInfo
(
$info_type
)
{
switch
(
$info_type
)
{
case
'block_name'
:
return
$this
->
_blockName
;
break
;
case
'function_name'
:
return
$this
->
_functionName
;
break
;
case
'start_pos'
:
case
'end_pos'
:
case
'template'
:
if
(!
array_key_exists
(
$info_type
,
$this
->
_blockLocation
))
{
// invalid block name
return
'invalid block name'
;
}
return
$this
->
_blockLocation
[
$info_type
];
break
;
case
'template_file'
:
return
$this
->
_getTemplateFile
(
true
);
break
;
case
'content'
:
$template_body
=
file_get_contents
(
$this
->
_getTemplateFile
()
);
$length
=
$this
->
_blockLocation
[
'end_pos'
]
-
$this
->
_blockLocation
[
'start_pos'
];
return
substr
(
$template_body
,
$this
->
_blockLocation
[
'start_pos'
],
$length
);
break
;
}
return
'undefined'
;
}
/**
* Main template being edited (parse copy, instead of original)
*
* @return bool
*/
function
_isMainTemplate
()
{
return
$this
->
_blockLocation
[
'template'
]
==
$this
->
_sourceTemplate
;
}
/**
* Returns filename, that contains template, where block is located
*
* @param bool $relative
* @param string $extension
* @return string
*/
function
_getTemplateFile
(
$relative
=
false
,
$extension
=
'.tpl'
)
{
$filename
=
$this
->
Application
->
TemplatesCache
->
GetRealFilename
(
$this
->
_blockLocation
[
'template'
]
)
.
$extension
;
if
(
$relative
)
{
$filename
=
preg_replace
(
'/^'
.
preg_quote
(
FULL_PATH
,
'/'
)
.
'/'
,
''
,
$filename
,
1
);
}
return
$filename
;
}
/**
* Saves new version of block to template, where it's located
*
* @param kDBItem $object
*/
function
saveBlock
(&
$object
)
{
$main_template
=
$this
->
_isMainTemplate
();
$filename
=
$this
->
_getTemplateFile
(
false
);
// 1. get new template content
$new_template_body
=
$this
->
_getNewTemplateContent
(
$object
,
$filename
,
$lines_before
);
if
(
is_bool
(
$new_template_body
)
&&
(
$new_template_body
===
true
))
{
// when nothing changed -> stop processing
return
true
;
}
// 2. backup original template
if
(!
$main_template
&&
!
copy
(
$filename
,
$filename
.
'.bak'
))
{
// backup failed
$error_file
=
$this
->
_getTemplateFile
(
true
,
'.tpl.bak'
);
$object
->
SetError
(
'FileContents'
,
'template_backup_failed'
,
'+Failed to create backup template "<strong>'
.
$error_file
.
'</strong>" backup.'
);
return
false
;
}
// 3. save changed template
$save_filename
=
$this
->
_getTemplateFile
(
false
,
$main_template
?
'.tmp.tpl'
:
'.tpl'
);
$fp
=
fopen
(
$save_filename
,
'w'
);
if
(!
$fp
)
{
// backup template create failed OR existing template save
$error_file
=
$this
->
_getTemplateFile
(
true
,
$main_template
?
'.tmp.tpl'
:
'.tpl'
);
$object
->
SetError
(
'FileContents'
,
'template_changes_save_failed'
,
'+Failed to save template "<strong>'
.
$error_file
.
'</strong>" changes.'
);
return
false
;
}
fwrite
(
$fp
,
$new_template_body
);
fclose
(
$fp
);
// 3. parse template to check for errors
$this
->
_parseTemplate
(
$object
,
$main_template
?
'.tmp'
:
''
);
if
(
$this
->
_parseErrors
)
{
$error_msg
=
Array
();
foreach
(
$this
->
_parseErrors
as
$error_data
)
{
if
(
preg_match
(
'/line ([
\d
]+)/'
,
$error_data
[
'msg'
],
$regs
))
{
// another line number inside message -> patch it
$error_data
[
'msg'
]
=
str_replace
(
'line '
.
$regs
[
1
],
'line '
.
(
$regs
[
1
]
-
$lines_before
),
$error_data
[
'msg'
]);
}
$error_msg
[]
=
$error_data
[
'msg'
]
.
' at line '
.
(
$error_data
[
'line'
]
-
$lines_before
);
}
$object
->
SetError
(
'FileContents'
,
'template_syntax_error'
,
'+Template syntax errors:<br/>'
.
implode
(
'<br/>'
,
$error_msg
));
return
false
;
}
if
(
$main_template
)
{
// 4.1. replace original file with temporary
if
(!
rename
(
$this
->
_getTemplateFile
(
false
,
'.tmp.tpl'
),
$filename
))
{
// failed to save new content to original template
$error_file
=
$this
->
_getTemplateFile
(
true
);
$object
->
SetError
(
'FileContents'
,
'template_save_failed'
,
'+Failed to save template "<strong>'
.
$error_file
.
'</strong>".'
);
return
false
;
}
}
else
{
// 4.2. delete backup
unlink
(
$this
->
_getTemplateFile
(
false
,
'.tpl.bak'
)
);
}
return
true
;
}
/**
* Returns new template content of "true", when nothing is changed
*
* @param kDBItem $object
* @param string $filename
* @param int $lines_before
* @return mixed
*/
function
_getNewTemplateContent
(&
$object
,
$filename
,
&
$lines_before
)
{
$new_content
=
$object
->
GetDBField
(
'FileContents'
);
$template_body
=
file_get_contents
(
$filename
);
$lines_before
=
substr_count
(
substr
(
$template_body
,
0
,
$this
->
_blockLocation
[
'start_pos'
]),
"
\n
"
);
$new_template_body
=
substr
(
$template_body
,
0
,
$this
->
_blockLocation
[
'start_pos'
])
.
$new_content
.
substr
(
$template_body
,
$this
->
_blockLocation
[
'end_pos'
]);
return
crc32
(
$template_body
)
==
crc32
(
$new_template_body
)
?
true
:
$new_template_body
;
}
}
Event Timeline
Log In to Comment