plugins/tpl/admin_modules/yf_template_editor.class.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

/**
 * Templates handling class.
 *
 * @author        YFix Team <yfix.dev@gmail.com>
 * @version        1.0
 */
class yf_template_editor
{
    /***/
    public $CACHE_NAME = 'themes_num_stpls';

    /***/
    private $_preload_complete = false;

    /**
     * @param mixed $name
     */
    public function __get($name)
    {
        if ( ! $this->_preload_complete) {
            $this->_preload_data();
        }
        return $this->$name;
    }

    /**
     * @param mixed $name
     * @param mixed $value
     */
    public function __set($name, $value)
    {
        if ( ! $this->_preload_complete) {
            $this->_preload_data();
        }
        $this->$name = $value;
        return $this->$name;
    }


    public function _preload_data()
    {
        if ($this->_preload_complete) {
            return true;
        }
        $this->_preload_complete = true;
        $themes_path = tpl()->_THEMES_PATH;
        $this->_dir_array = [
            'app' => APP_PATH . $themes_path,
            'app_plugins' => APP_PATH . 'plugins/*/' . $themes_path,
            'project' => PROJECT_PATH . $themes_path,
            'project_plugins' => PROJECT_PATH . 'plugins/*/' . $themes_path,
            'yf' => YF_PATH . $themes_path,
            'yf_plugins' => YF_PATH . 'plugins/*/' . $themes_path,
        ];
        //        foreach ((array)_class('sites_info')->info as $site_dir_array) {
//            $this->_dir_array[$site_dir_array['name']] = $site_dir_array['REAL_PATH'].'templates/';
//        }
    }


    public function show()
    {
        $deepness = 3;
        $ext = '.stpl';
        $ext_len = strlen($ext);
        foreach ((array) $this->_dir_array as $gname => $glob) {
            foreach (range(1, $deepness) as $deep) {
                $glob_pattern = $glob . '*' . str_repeat('/*', $deep) . $ext;
                foreach (glob($glob_pattern) as $path) {
                    $name = substr(implode('/', array_reverse(array_slice(array_reverse(explode('/', $path)), 0, $deep))), 0, -$ext_len);
                    $names[$name][$path] = $path;
                    $theme = implode(array_slice(array_reverse(explode('/', $path)), $deep, 1));
                    $found_in[$path] = $gname . ' | ' . $theme;
                }
            }
        }
        ksort($names);
        foreach ((array) $names as $name => $paths) {
            $links = [];
            foreach ($paths as $path) {
                $links[] = a('/file_manager/edit/' . urlencode($path), 'Edit ' . $path, 'fa fa-edit', $found_in[$path]);
            }
            $body['<b>' . $name . '</b>'] = implode(' ', $links);
        }
        return html()->simple_table($body, ['condensed' => 1]);
    }


    public function _show_themes()
    {
        $themes = $this->_get_themes();

        $num_stpls_array = cache_get($this->CACHE_NAME, 60);
        if (empty($num_stpls_array)) {
            foreach ((array) $themes as $theme_class => $theme_attr) {
                foreach ((array) $theme_attr as $theme_path => $theme_name) {
                    $num_stpls_array[$theme_name][$this->_dir_array[$theme_class]] = count((array) $this->_get_stpls_in_theme($theme_name, $this->_dir_array[$theme_class]));
                }
            }
            cache_set($this->CACHE_NAME, $num_stpls_array);
        }
        // Process records
        $rp = realpath($this->_dir_array['project']);
        foreach ((array) $themes as $theme_class => $theme_attr) {
            if ($rp == realpath($this->_dir_array[$theme_class]) && $theme_class != 'project') {
                continue;
            }
            $replace3 = [
                'location' => $theme_class,
                'themes_lib_dir' => realpath($this->_dir_array[$theme_class]),
                'add_url' => './?object=' . $_GET['object'] . '&action=add_theme_form&location=' . $theme_class,
            ];
            $items .= tpl()->parse('@object/themes_location_item', $replace3);

            foreach ((array) $theme_attr as $theme_path => $theme_name) {
                $replace2 = [
                    'num' => ++$i,
                    'bg_class' => 'bg2',
                    'name' => $theme_name,
                    'num_stpls' => $num_stpls_array[$theme_name][$this->_dir_array[$theme_class]],
                    'theme_url' => './?object=' . $_GET['object'] . '&action=show_stpls_in_theme&theme=' . $theme_name . '&location=' . $theme_class,
                    'edit_url' => './?object=' . $_GET['object'] . '&action=edit_theme&theme=' . $theme_name . '&location=' . $theme_class,
                    'location' => $theme_class,
                ];
                $items .= tpl()->parse('@object/themes_item', $replace2);
            }
        }
        $replace = [
            'items' => $items,
            'add_url' => './?object=' . $_GET['object'] . '&action=add_theme_form',
            'import_url' => './?object=' . $_GET['object'] . '&action=import',
        ];
        return tpl()->parse('@object/themes_main', $replace);
    }


    public function edit_theme()
    {
        if (false !== strpos($_GET['location'], 'framework')) {
            return $this->_framework_warning();
        }
        $new_theme_name = $_POST['theme_name'];
        if (empty($_GET['theme']) && empty($new_theme_name)) {
            return _e('Theme name required!');
        }
        if (main()->is_post()) {
            if ($_GET['theme'] != $new_theme_name) {
                rename($this->_dir_array[$_GET['location']] . $_GET['theme'], $this->_dir_array[$_GET['location']] . $new_theme_name);
            }
            return js_redirect(url('/@object'));
        }
        $replace = [
            'form_action' => './?object=' . $_GET['object'] . '&action=' . $_GET['action'] . '&theme=' . $_GET['theme'] . '&location=' . $_GET['location'],
            'back_url' => './?object=' . $_GET['object'] . '&action=show',
            'theme_name' => _prepare_html($_GET['theme']),
            'location' => $_GET['location'],
        ];
        return tpl()->parse('@object/edit_theme', $replace);
    }


    public function show_stpls_in_theme()
    {
        $this->theme_name = $_GET['theme'];
        $this->_cur_theme_path = $this->_dir_array[$_GET['location']] . $this->theme_name;
        $files_array = _class('dir')->scan_dir($this->_cur_theme_path, false);
        $items_array = $this->_show_stpls_list($files_array);

        list($items_array, $pages, $total) = common()->divide_pages($items_array, null, null, $PER_PAGE);
        $items = implode('', $items_array);

        $replace = [
            'items' => $items,
            'pages' => $pages,
            'total' => (int) $total,
            'theme_name' => $this->theme_name,
            'back_url' => url('/@object'),
            'form_action' => './?object=' . $_GET['object'] . '&action=save_stpl&theme=' . $this->theme_name . '&location=' . $_GET['location'],
            'location' => $_GET['location'],
        ];
        return tpl()->parse('@object/stpls_list_main', $replace);
    }

    /**
     * External API method.
     * @param mixed $type
     */
    public function _get_stpls_for_type($type = 'user')
    {
        $theme_name = $type == 'admin' ? 'admin' : 'user';

        $CACHE_NAME = 'stpls_list_for_' . $type;
        $TTL = 600;
        $items = cache_get($CACHE_NAME, $TTL);
        if ( ! empty($items)) {
            return $items;
        }
        $items = [];

        $STPL_EXT = '.stpl';
        $pattern_include = ['', '#\.stpl$#i'];
        $pattern_exclude = '#(svn|git)#i';

        $cur_theme_path = $this->_dir_array['framework'] . $theme_name . '/';
        foreach ((array) _class('dir')->scan_dir($cur_theme_path, true, $pattern_include, $pattern_exclude) as $v) {
            $name = substr($v, strlen($cur_theme_path), -strlen($STPL_EXT));
            $items[$name] = $name;
        }
        /*        $cur_theme_path = $this->_dir_array['framework_p2']. $theme_name. '/';
                foreach ((array)_class('dir')->scan_dir($cur_theme_path, true, $pattern_include, $pattern_exclude) as $v) {
                    $name = substr($v, strlen($cur_theme_path), -strlen($STPL_EXT));
                    $items[$name] = $name;
                }
        */        $cur_theme_path = $this->_dir_array['project'] . $theme_name . '/';
        foreach ((array) _class('dir')->scan_dir($cur_theme_path, true, $pattern_include, $pattern_exclude) as $v) {
            $name = substr($v, strlen($cur_theme_path), -strlen($STPL_EXT));
            $items[$name] = $name;
        }
        /*        $cur_theme_path = $this->_dir_array['project_p2']. $theme_name. '/';
                foreach ((array)_class('dir')->scan_dir($cur_theme_path, true, $pattern_include, $pattern_exclude) as $v) {
                    $name = substr($v, strlen($cur_theme_path), -strlen($STPL_EXT));
                    $items[$name] = $name;
                }
        */        // Inherit user templates from framework and project
        if ($type == 'admin') {
            $cur_theme_path = $this->_dir_array['framework'] . 'user' . '/';
            foreach ((array) _class('dir')->scan_dir($cur_theme_path, true, $pattern_include, $pattern_exclude) as $v) {
                $name = substr($v, strlen($cur_theme_path), -strlen($STPL_EXT));
                $items[$name] = $name;
            }

            $cur_theme_path = $this->_dir_array['project'] . 'user' . '/';
            foreach ((array) _class('dir')->scan_dir($cur_theme_path, true, $pattern_include, $pattern_exclude) as $v) {
                $name = substr($v, strlen($cur_theme_path), -strlen($STPL_EXT));
                $items[$name] = $name;
            }
        }
        if (isset($items[''])) {
            unset($items['']);
        }
        ksort($items);
        cache_set($CACHE_NAME, $items);
        return $items;
    }

    /**
     * Internal method.
     * @param mixed $files_array
     * @param mixed $level
     */
    public function _show_stpls_list($files_array = [], $level = 0)
    {
        asort($files_array);
        $body = [];
        foreach ((array) $files_array as $cur_file_path => $file_name) {
            if (false !== strpos($cur_file_path, '.svn')) {
                continue;
            }
            if (false !== strpos($cur_file_path, '.git')) {
                continue;
            }
            if (is_array($file_name)) {
                $body[$cur_file_path . '_dir'] = $this->_show_stpls_item($cur_file_path, $level, true);
                $body = array_merge($body, (array) $this->_show_stpls_list($file_name, $level + 1));
            } else {
                if (common()->get_file_ext($file_name) != 'stpl') {
                    continue;
                }
                $body[$cur_file_path] = $this->_show_stpls_item($cur_file_path, $level);
            }
        }
        return $body;
    }

    /**
     * Internal method.
     * @param mixed $file_path
     * @param mixed $level
     * @param mixed $is_folder
     */
    public function _show_stpls_item($file_path = '', $level = 0, $is_folder = false)
    {
        static $i, $j;
        $name = str_replace([$this->_cur_theme_path . '/', '.stpl'], '', $file_path);
        if (substr($name, 0, 6) == 'images') {
            return false;
        }
        $replace = [
            'name' => $is_folder ? '<b>' . $name . '</b>' : $name,
            'bg_class' => ! ($i++ % 2) ? 'bg1' : 'bg2',
            'num' => ! $is_folder ? ++$j : '',
            'pad' => $level * 50/* + ($is_folder ? 20 : 0)*/, // In pixels
            'stpl_size' => ! $is_folder ? filesize($file_path) : '',
            'edit_stpl_url' => './?object=' . $_GET['object'] . '&action=' . ($is_folder ? 'edit_dir' : 'edit_stpl') . '&name=' . $name . '&theme=' . $this->theme_name . '&location=' . $_GET['location'],
            'location' => $_GET['location'],
        ];
        return tpl()->parse('@object/stpls_list_item', $replace);
    }


    public function edit_stpl()
    {
        $theme_name = $_GET['theme'];
        $stpl_name = $_GET['name'];
        if ( ! validate([$theme_name, $stpl_name], 'trim|required')) {
            return _e('Template name and theme required!');
        }
        if (main()->is_post()) {
            if (false !== strpos($_GET['location'], 'framework')) {
                // TODO: use readonly mode with message and ability to save changed file inside project
                return $this->_framework_warning();
            }
            $lib_stpl_path = $this->_dir_array[$_GET['location']] . $theme_name . '/' . $stpl_name . tpl()->_STPL_EXT;
            foreach (glob($lib_stpl_path) as $path) {
                $lib_stpl_path = $path;
                break;
            }
            $text = $_POST['stpl_text'] ?: $_POST['stpl_text_hidden'];
            if ( ! file_exists($lib_stpl_path)) {
                _mkdir_m(dirname($lib_stpl_path));
            }
            file_put_contents($lib_stpl_path, $text);
            return js_redirect('./?object=' . $_GET['object'] . '&action=show_stpls_in_theme&theme=' . $theme_name . '&location=' . $_GET['location']);
        }
        if (substr($_GET['location'], -strlen('_user')) == '_user' && $theme_name == 'admin') {
            $theme_name = 'user';
        }
        $stpl_path = $this->_dir_array[$_GET['location']] . $theme_name . '/' . $stpl_name . tpl()->_STPL_EXT;
        foreach (glob($stpl_path) as $path) {
            $stpl_path = $path;
            break;
        }
        if ( ! file_exists($stpl_path)) {
            return _e('Cannot find template: ' . $stpl_path);
        }
        $stpl_text = file_get_contents($stpl_path);
        $stpl_text = _prepare_html($stpl_text, 0);
        $replace = [
            'form_action' => './?object=' . $_GET['object'] . '&action=' . $_GET['action'] . '&name=' . $stpl_name . '&theme=' . $theme_name . '&location=' . $_GET['location'],
            'theme_name' => $theme_name,
            'stpl_name' => $stpl_name,
            'stpl_text' => $stpl_text,
            'back_url' => './?object=' . $_GET['object'] . '&action=show_stpls_in_theme&theme=' . $theme_name . '&location=' . $_GET['location'],
            'location' => $_GET['location'],
        ];
        $div_id = 'editor_html';
        $hidden_id = 'stpl_text_hidden';
        return '<h4>edit: ' . $replace['stpl_name'] . ' for theme: ' . $replace['theme_name'] . ', inside: ' . $replace['location'] . '</h4>' .
            form($replace, [
                'data-onsubmit' => '$(this).find("#' . $hidden_id . '").val( $("#' . $div_id . '").data("ace_editor").session.getValue() );',
            ])
            ->container('<div id="' . $div_id . '" style="width: 90%; height: 500px;">' . $stpl_text . '</div>', '', [
                'id' => $div_id,
                'wide' => 1,
                'ace_editor' => ['mode' => 'html'],
            ])
            ->hidden($hidden_id)
            ->save_and_back();
    }

    /**
     * Show STPL template's content stored in file.
     */
    public function show_file_src()
    {
        $path = base64_decode($_GET['path']);
        $stpl_text = file_get_contents($path);

        $replace = [
            'stpl_text' => trim($stpl_text),
            'location' => $path,
        ];
        return tpl()->parse('@object/view_content', $replace);
    }

    /**
     * Get themes full paths and names.
     */
    public function _get_themes()
    {
        $themes = [];
        foreach ((array) $this->_dir_array as $glob_name => $glob) {
            foreach (glob($glob . '*/', GLOB_ONLYDIR) as $path) {
                $dir = basename($path);
                if ($dir) {
                    $themes[$glob_name][$path] = $dir;
                }
            }
        }
        return $themes;
    }


    public function _get_themes_names()
    {
        $names = [];
        foreach ((array) $this->_get_themes() as $where => $themes) {
            foreach ((array) $themes as $_path => $_name) {
                $names[$where][$_name] = $_name;
            }
        }
        return $names;
    }

    /**
     * @param mixed $theme_name
     * @param mixed $theme_path
     */
    public function _get_stpls_in_theme($theme_name, $theme_path)
    {
        foreach ((array) _class('dir')->scan_dir($theme_path . $theme_name) as $file_name) {
            if (common()->get_file_ext($file_name) != 'stpl') {
                continue;
            }
            $stpls[$file_name] = $file_name;
        }
        return $stpls;
    }


    public function _get_themes_for_select()
    {
        $cache_name = 'themes_for_select';
        $data = cache_get($cache_name);
        if ( ! $data) {
            foreach ((array) $this->_get_themes_names() as $_location => $_themes) {
                foreach ((array) $_themes as $_theme) {
                    $data[$_theme] = $_theme;
                }
            }
            cache_set($cache_name, $data);
        }
        return $data;
    }


    public function _framework_warning()
    {
        return _e(tpl()->parse('@object/framework_warning'));
    }


    public function _hook_settings(&$selected = [])
    {
        //        return array(
//            array('text', 'template_editor__ACE_THEME'),
//        );
    }
}