VasiliyBondarenko 29 апреля 2014 1 2
возникла идея — отключить modx-парсер вообще на тех страницах где он не нужен. и использовать исключительно возможности smarty. попутно появилась возможность работать с дебаггером smarty.

я недавно вникаю в разработку на modx, поэтому мое решение наверняка крайне кривое — просьба просто его рассмотреть, и наставить на путь истиный. может кто-то сможет сделать более правильно и добавить в следующую версию пакета.

по результатам экспериментов рендеринг страниц без modx-парсера ускоряется очень существенно.


вот некоторые результаты:
обычный вывод через modx-парсер:

mbpv:~ info$ ab -n 100 -c 4 www.na.ru/tyres/manufacturers/Nokian/Hakka_Z/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, www.zeustech.net/
Licensed to The Apache Software Foundation, www.apache.org/

Benchmarking www.na.ru (be patient).....done

Server Software: Apache/2.2.23
Server Hostname: www.na.ru
Server Port: 80

Document Path: /tyres/manufacturers/Nokian/Hakka_Z/
Document Length: 17622 bytes

Concurrency Level: 4
Time taken for tests: 33.511 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 1809300 bytes
HTML transferred: 1762200 bytes
Requests per second: 2.98 [#/sec] (mean)
Time per request: 1340.421 [ms] (mean)
Time per request: 335.105 [ms] (mean, across all concurrent requests)
Transfer rate: 52.73 [Kbytes/sec] received

Connection Times (ms)
min mean[±sd] median max
Connect: 0 0 1.0 0 10
Processing: 293 1338 354.8 1430 1902
Waiting: 284 1303 348.9 1390 1870
Total: 293 1338 355.0 1431 1902

Percentage of the requests served within a certain time (ms)
50% 1431
66% 1493
75% 1529
80% 1549
90% 1680
95% 1762
98% 1900
99% 1902
100% 1902 (longest request)

вывод с отключенным modx-парсером (при это НЕ кешируются ресурсы и шаблоны!):

mbpv:~ info$ ab -n 100 -c 4 www.na.ru/tyres/manufacturers/Nokian/Hakka_Z/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, www.zeustech.net/
Licensed to The Apache Software Foundation, www.apache.org/

Benchmarking www.na.ru (be patient).....done

Server Software: Apache/2.2.23
Server Hostname: www.na.ru
Server Port: 80

Document Path: /tyres/manufacturers/Nokian/Hakka_Z/
Document Length: 14050 bytes

Concurrency Level: 4
Time taken for tests: 5.860 seconds
Complete requests: 100
Failed requests: 0
Write errors: 0
Total transferred: 1452100 bytes
HTML transferred: 1405000 bytes
Requests per second: 17.07 [#/sec] (mean)
Time per request: 234.394 [ms] (mean)
Time per request: 58.599 [ms] (mean, across all concurrent requests)
Transfer rate: 242.00 [Kbytes/sec] received

Connection Times (ms)
min mean[±sd] median max
Connect: 0 0 0.1 0 1
Processing: 81 232 80.1 238 376
Waiting: 73 214 74.7 220 349
Total: 81 233 80.2 239 377

Percentage of the requests served within a certain time (ms)
50% 239
66% 279
75% 307
80% 313
90% 336
95% 353
98% 361
99% 377
100% 377 (longest request)
mbpv:~ info$

если включить кеширование шаблона — еще ускорится. в общем — очень быстро работает :)

как это сделано


Шаблон base.php:

<?php

$properties = $modx->resource->getOne('Template')->getProperties();

if(!empty($properties['tpl'])){
    $tpl = $properties['tpl'];
}
else{
    $tpl = 'index.tpl';
}

/*
// управление кешем через галочку "кешируемый" у каждого ресурса
// при этом будет работать modx=парсер каждый раз
if ($modx->resource->cacheable != '1') {
    $modx->smarty->caching = false;
}
return $modx->smarty->fetch("tpl/{$tpl}");
*/

// управление кешем через установку переменной caching = true; прямо тут в шаблоне. 
// при этом галочка "кешируемый" у ресурса игнорируется 
// и modx-парсер не работает! скорость генерации страницы растет ОЧЕНЬ существенно!
// + можно использовать дебаггер
//$modx->smarty->debugging=TRUE; 
$modx->smarty->caching = false;
$modx->smarty->display("tpl/{$tpl}");
return ""; // отпрвить $ничего на вывод через modx-парсер. :)


modsmarty.class.php:

    public function display($template, $cache_id = null, $compile_id = null, $parent = null) {
        echo $this->fetch($template, $cache_id, $compile_id, $parent);
    }


меняем на

    public function display($template, $cache_id = null, $compile_id = null, $parent = null) {
        echo $this->fetch($template, $cache_id, $compile_id, $parent, true);
    }

честно говоря не понимаю кто оттуда убрал последний параметр — ибо в оригинальном класе он там был.
хотя кажется я догадываюсь кто это сделал. но вот зачем — не понятно ибо эта функция как бы и не использовалась в шаблоне :)

собственно последний параметр true как раз и заставляет делать именно echo $_output;;, а не return $_output;

ну и чтобы заработал дебаггер делаем изменение в файле debug.tpl:

<table id="table_assigned_vars">
    {foreach $assigned_vars as $vars}
	       <tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">   
	       <th>${$vars@key|escape:'html'}</th>
	       <td>{$vars|debug_print_var}</td></tr>
    {/foreach}
</table>


меняем на:

<table id="table_assigned_vars">
    {foreach $assigned_vars as $vars}
    	{if $vars@key != "modx"}
	       <tr class="{if $vars@iteration % 2 eq 0}odd{else}even{/if}">   
	       <th>${$vars@key|escape:'html'}</th>
	       <td>{$vars|debug_print_var}</td></tr>
	{/if}
    {/foreach}
</table>


это нужно чтобы не выводить объект modx который порушит дебаггер из-за переполнения памяти. ну или можно его вывести но как-то упрощенно.

вот такой эксперимент.
2 комментария
Fi1osof1
Fi1osof 30 апреля 2014г в 13:16 #
Добрый день!

Интересный эксперимент :)
Но все же есть пара моментов. И вот основной:
$modx->smarty->display(«tpl/{$tpl}»);
return ""; // отпрвить $ничего на вывод через modx-парсер. :)

Таким образом рушится механизм кеширования MODX, так как он не получает отрабатываемого контента. Ежели вы хотите именно отключить MODX-парсер, то есть более лаконичное решение — системная настройка parser_class. Она учитывается в методе MODx::getParser()
public function getParser() {
    return $this->getService('parser', $this->getOption('parser_class', null, 'modParser'), 
        $this->getOption('parser_class_path', null, ''));
}


То есть пишете парсер на замену modParser и все. А в нем, где надо, облегчаете методы по максимум, чтобы просто возвращали по минимуму и все.

Только вешайте его именно на внешний контекст, то есть в настройки контекста прописывайте, а не в системные, чтобы в mgr работал родной парсер, а во фронте ваш. Потому что системный парсер используется в том числе и для обработки системных настроек и т.п.
Fi1osof1
Fi1osof 30 апреля 2014г в 20:41 #
В общем, я решил тоже поучаствовать в этом эксперименте, и написать свой парсер на замену. Облегчить его на 100% не получается в любом случае. Во-первых, MODX довольно активно использует его отдельные методы, так что как минимум пустые методы надо прописать. Во-вторых, в тех же шаблонах у нас в параметрах есть необходимые параметры, типа tpl или phptemplates.non-cached, и чтобы они учитывались в системе, пришлось один метод более живым оставить. Вот такой класс у меня получился:
<?php


class modWebParser {
    /**
     * A reference to the modX instance
     * @var modX $modx
     */
     
    public $modx= null; 
    
    /**
     * @param xPDO $modx A reference to the modX|xPDO instance
     */
    function __construct(xPDO &$modx) {
        $this->modx =& $modx;
    }
 
    public function setProcessingElement($arg = null) {
    } 
    
    public function processElementTags($parentTag, & $content, 
        $processUncacheable= false, $removeUnprocessed= false, $prefix= "[[", 
        $suffix= "]]", $tokens= array (), $depth= 0) {
        return $processed;
    } 
    
    public function collectElementTags($origContent, array &$matches, $prefix= '[[', $suffix= ']]') {
        return 0;
    }

    /**
     * Parses an element/tag property string or array definition.
     *
     * @param string $propSource A valid property string or array source to
     * parse.
     * @return array An associative array of property values parsed from
     * the property string or array definition.
     */
    public function parseProperties($propSource) {
        
        $properties= array ();
        
        if (!empty ($propSource)) {
            if (is_string($propSource)) {
                $properties = $this->parsePropertyString($propSource, true);
            } elseif (is_array($propSource)) {
                foreach ($propSource as $propName => $property) {
                    if (is_array($property) && array_key_exists('value', $property)) {
                        $properties[$propName]= $property['value'];
                    } else {
                        $properties[$propName]= $property;
                    }
                }
            }
        }
        return $properties;
    }
    
    public function isProcessingUncacheable() {
        $result = false;
        return $result;
    }
    
    public function isRemovingUnprocessed() {
        $result = false;
        return $result;
    }

    public function parsePropertyString($string, $valuesOnly = false) {
        $properties = array();
        return $properties;
    }
}


Закинул его в core/components/modxsite/model/modxsite/model/modwebparser.class.php

В настройках контекста web прописал:
parser_class = modWebParser
parser_class_path = {core_path}components/modxsite/model/modxsite/

В целом все работает, и API MODX-а получается использовать, к примеру {$modx->getOption('site_url')}

Попробуйте установить ShopModxBox и погонять с этим парсером и без него. Но здесь надо учитывать, что многое не будет работать в принципе. Лично мне кажется, что овчинка не будет стоить выделки. К примеру, мы не сможем использовать некешируемые блоки через [[!smarty?tpl=`....`]] и т.п. Конечно же мы можем просто отрабатывать шаблоны каждый раз, включив кеширование самого Smarty, но это гораздо более заморочено.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.