Index: branches/RC/core/units/general/helpers/template_helper.php =================================================================== diff -u -N --- branches/RC/core/units/general/helpers/template_helper.php (revision 11963) +++ branches/RC/core/units/general/helpers/template_helper.php (revision 0) @@ -1,448 +0,0 @@ -_initMade) { - return ; - } - - define('DBG_IGNORE_FATAL_ERRORS', 1); - - // 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 StructureEventHandler */ - - $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 = '') - { - // 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( $this->_getThemeName() ); // we have no parser when saving block content - - $this->_getSourceTemplate(); - - // design templates have leading "/" in the beginning - $this->Application->Parser->Run($this->_sourceTemplate . $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'); - $object->SetError('FileContents', 'template_delete_failed', '+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); - $object->SetError('FileContents', 'template_restore_failed', '+Failed to restore template "' . $error_file . '" 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 = 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>)/s', $data, $divs, PREG_SET_ORDER + PREG_OFFSET_CAPTURE); - - $skip_count = 0; - $pairs = Array (); - - foreach ($divs as $div) { - if (strpos($div[0][0], '/') === false) { - // opening div - if (strpos($div[0][0], $class) !== false) { - $pair = Array ('open_pos' => $div[0][1], 'open_len' => strlen($div[0][0])); - $skip_count = 0; - } - else { - $skip_count++; - } - } - else { - // closing div - if ($skip_count == 0) { - $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_count--; - } - } - } - - return $pairs; - } - - /** - * 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': - $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 - * - * @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 "' . $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'); - $object->SetError('FileContents', 'template_changes_save_failed', '+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($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:
' . 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); - $object->SetError('FileContents', 'template_save_failed', '+Failed to save template "' . $error_file . '".'); - 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; - } - - function _saveError($errno, $errstr, $errfile, $errline, $errcontext) - { - if ($errno != E_USER_ERROR) { - // ignore all minor errors, except fatals from parser - return true; - } - - /*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; - } - } \ No newline at end of file