Application->GetVar('block');
list ($this->_blockName, $this->_functionName) = explode(':', $block_info);
$this->_parseTemplate();
if (array_key_exists($this->_functionName, $this->Application->Parser->ElementLocations)) {
$this->_blockLocation = $this->Application->Parser->ElementLocations[$this->_functionName];
}
}
/**
* Render source template to get parse errors OR it's element locations
*
*/
function _parseTemplate($append = '')
{
// 1. set internal error handler to catch all parsing errors
$error_handlers = $this->Application->errorHandlers;
$this->Application->errorHandlers = Array (
Array (&$this, '_saveError'),
);
// 2. parse template
$this->Application->InitParser(); // we have no parser when saving block content
$this->Application->Parser->Run($this->Application->GetVar('source') . $append);
// 3. restore original error handler
$this->Application->errorHandlers = $error_handlers;
if ($this->_parseErrors) {
if ($this->_isMainTemplate()) {
// 3.1. delete temporary file, that was parsed
$filename = $this->_getTemplateFile(false, $append . '.tpl');
if (!unlink($filename)) {
$error_file = $this->_getTemplateFile(true, $append . '.tpl');
$this->Application->SetVar('Failed to delete temporary template "' . $error_file . '"');
return false;
}
}
else {
// 3.2. restore backup
if (!rename($this->_getTemplateFile(false, '.tpl.bak'), $this->_getTemplateFile(false))) {
$error_file = $this->_getTemplateFile(true);
$this->Application->SetVar('Failed to restore template "' . $error_file . '" from backup.');
return false;
}
}
return false;
}
return true;
}
/**
* Returns information about parser element locations in template
*
* @param Array $params
* @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':
$function_body = $this->Application->GetVar('function_body');
if ($function_body !== false) {
// error happened -> use unsaved template content
return unhtmlentities( $function_body );
}
$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->Application->GetVar('source');
}
/**
* Returns filename, that contains template, where block is located
*
* @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 kEvent $event
*/
function saveBlock(&$event)
{
$main_template = $this->_isMainTemplate();
$filename = $this->_getTemplateFile(false);
// 1. get new template content
$new_template_body = $this->_getNewTemplateContent($filename, $lines_before);
if (is_bool($new_template_body) && ($new_template_body === true)) {
// when nothing changed -> stop processing
echo '0';
return true;
}
// 2. backup original template
if (!$main_template && !copy($filename, $filename . '.bak')) {
// backup failed
$error_file = $this->_getTemplateFile(true, '.tpl.bak');
$this->Application->SetVar('error_msg', 'Failed to create backup template "' . $error_file . '" 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');
$this->Application->SetVar('error_msg', 'Failed to save template "' . $error_file . '" changes.');
return false;
}
fwrite($fp, $new_template_body);
fclose($fp);
// 3. parse template to check for errors
$this->_parseTemplate($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);
}
$this->Application->SetVar('error_msg', 'Template syntax errors:
' . implode('
', $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);
$this->Application->SetVar('error_msg', 'Failed to save template "' . $error_file . '".');
return false;
}
}
else {
// 4.2. delete backup
unlink( $this->_getTemplateFile(false, '.tpl.bak') );
}
echo 1; // were changes
return true;
}
/**
* Returns new template content of "true", when nothing is changed
*
* @param string $filename
* @param int $lines_before
* @return mixed
*/
function _getNewTemplateContent($filename, &$lines_before)
{
$new_content = unhtmlentities( $this->Application->GetVar('function_body') );
$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;
}
function _saveError($errno, $errstr, $errfile, $errline, $errcontext)
{
if (defined('E_STRICT') && ($errno == E_STRICT)) {
// always ignore strict errors here (specially when not in debug mode)
return true;
}
$this->_parseErrors[] = Array ('msg' => $errstr, 'file' => $errfile, 'line' => $errline);
return true;
}
}