MODX Revolution meets Fenom

recently in the English-speaking community of MODX a lot of discussion on the topic "how we live". All at stoppage to discuss the upcoming (in a few years, I believe) major version 3, and we still are improving their add-ons current.

A new event that I would like to share with a wider audience is the new release of pdoTools Fenom template engine, which will allow you to get rid of the clutter of tags in terms of chunks and rewrite them in plain language the template engine.

The procedure does not require changes in the site, simply update pdoTools to version 2.0 and you can use new syntax. The best part is that the MODX tags are the perfect complement to Fenom and work together without any problems. A simple example for starters:
the
{if $parent == 3}
[[!pdoMenu?parents=`0`]]
{else}
[[!pdoResources?parents=`1,2,3`]]
{/if}
Under the cut is a huge amount of information about the parser pdoTools that I have never collected in one place.

So, the parser pdoTools is a separate class that is prescribed in the system settings MODX and intercepts the processing of the tags on the page.
In older versions of the component, the inclusion of the parser had to confirm with the installation, but with version 2.1.1-pl it is enabled by default. If, for some reason, you do not like it, delete the system settings.
the
    the
  • parser_class — the class name of parser
  • the
  • parser_class_path — the class path of the parser

By default MODX does not have these settings, they only need to connect a third-party parser, as in our case.

the

working Principle


pdoParser can be used in two cases:
the
    the
  • when rendering a chunk with a snippet — it happens always and in all the snippets that use pdoTools, regardless of the system settings.
  • the
  • when rendering the page — but only if parser is enabled in the system settings.


the

Processing chunk


In the class pdoTools for this there are 2 methods that are very similar to those in the class modX:

the
    the
  • getChunk complete processing of a chunk, it can use the native parser MODX
  • the
  • parseChunk — just substitute the placeholders for the values modParser is not called

The main feature of these methods is that to download the chunk used protected method _loadChunk, which can not only load the chunk from the database and converts them into arbitrary strings.

the

chunks


So, both methods pdoTools support the following types of names of chunks:

@INLINE or @CODE


One of the most popular options — an indication of the body of the chunk right on the page. For example:
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;INLINE <p>{{+id}} - {{+pagetitle}}</p>`
]]

This indication is a feature which many people do not think — all the placeholders inside the chunk will be processed by the parser up of the call to the snippet.

That is, if you call the snippet on the page like so:
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;INLINE <p>[[+id]] - [[+pagetitle]]</p>`
]]

and in the memory of the system exhibited the placeholders [[+id]] or [[+pagetitle]], then the snippet will be processed as a chunk and you get on the page same line, like:
the
15 test
15 test
15 - test

Just the same value, which put some other snippet before. That is why in the example we have such unusual placeholders — {{+}} is [[+]]. The system parser will not touch them, and pdoTools replaces them with normal during operation.

You can use curly brackets as a frame of placeholders in all chunks pdoTools — he will turn them into [[+]] at startup.

For this reason, you will never work challenges snippets and filters to INLINE chunks. the so will not work:
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;INLINE <p>[[+id]] - [[+pagetitle:default=`page title`]]</p>`

And so — without problems.
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;INLINE <p>{{+id}} - {{+pagetitle:default=`page title`}}</p>`
]]

Be aware of this caveat when using INLINE chunks.

&commat;FILE


Many people accuse MODX is that it cannot store chunks in file and forces the extra time to work with the database. It is inconvenient for a version control system, and slower.

With version 2.2 of MODX proposes to use for these purposes, the static elements, but for several reasons, this method may still be less convenient than direct work with the files.

pdoTools offers such an opportunity when specifying &commat;FILE:
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;FILE resources/mychank.tpl`
]]

For security purposes, you can only use files with rasshireniem html and tpl, and only from a certain, predetermined directory. The default is: /assets/elements/chunks/.

You can specify your own directory for files using the &tplPath:
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;FILE resources/mychunk.tpl`
&tplPath=`/core/elements`
]]

The file will be loaded from the file /core/elements/resources/mychunk.tpl from the root of the site.

&commat;TEMPLATE


This type of the chunk allows you to use the system templates (i.e. objects modTemplate) to receive the output.
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;TEMPLATE Base Template`
]]

If you specify an empty pattern and in the selected records field template with the id or name of the template, the record will be wrapped in this template:
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;TEMPLATE`
]]

It's such an analogue of a snippet renderResources.

When you output the template, you can specify a set of parameters (as in snippets):
the
[[!pdoResources?
&parents=`0`
&tpl=`&commat;TEMPLATE Base Template&commat;MyPropertySet`
]]

Then the values from this set will be inserted into the template.

Common chunks


This is the default mode that loads the chunk from the database:
the
[[!pdoResources?
&parents=`0`
&tpl=`MyChunk`
]]

Similarly, the supported parameter sets are:
the
[[!pdoResources?
&parents=`0`
&tpl=`MyChunk&commat;MyPropertySet`
]]

These ways of loading chunks work all native pdoTools snippets and all others that use methods pdoTools getChunk and parseChunk.

the

getChunk Method


The Declaration of this method looks like this:
the
getChunk(string $chunkName, array $properties, bool $fastMode = false)

Method loads the specified chunk (following the instructions &commat;BINDING, if any) and fully ablative it, replacing all the placeholders on the passed value (parameter $properties).

The third parameter, fastMode cuts out all the remaining unprocessed placeholders, to avoid unnecessary tags on the page. If this is not done, then the parser will attempt to recursively parse tags (up to 10 iterations by default), which can lead to slow down.

Recursive parser is one of the advantages of MODX and intentionally left tags are very common in the logic of the snippets system. Therefore, fastMode is disabled by default and you need to use it only if you are confident in what you do.

Parser pdoTools will not cause the system parser if was able to parse all placeholders. If the chunk were some calls filters or snippets, the work is passed to modParser that requires additional processing time.

the

Method parseChunk


And this method is declared like this:
the
parseChunk(string $name, array $properties, string $prefix = '[[+', string $suffix = ']]')

It also creates a chunk from the specified name, sorting &commat;BINDING, if any, and then simply replace the placeholders with values, without special treatments.

This is the easiest and fastest way of processing data in chunks.

the

Edit page


If pdoParser enabled in the settings, it is called to process the entire page when displaying it to the user.
When you use this parser all the chunks and add MODX processed a little faster. Only "little" because it does not take filters and conditions, processing only simple tags, like [[+id]] and [[~15]]. However, he does modParser faster, because it does not create any objects.

In addition to possible gain speed, you get more and new opportunities for convenient output of data from different resources.

the

Tags fastField


At the end of 2012 the public were presented small plugin to add new tags to the MODX parser, which then grew into component fastField.

It adds to the system processing more of the placeholders, type [[#15.pagetitle]]. With permission, this functionality is already included in pdoParser, and even slightly expanded.

FastField tags all begin with # and then contain or id of the desired resource, or the name of the global array.

Conclusion conventional resource fields:
the
[[#15.pagetitle]]
[[#20.content]]

TV resource settings:
the
[[#15.date]]
[[#20.some_tv]]

Goods field miniShop2:
the
[[#21.price]]
[[#22.article]]

Arrays of resources and products:
the
[[#12.properties.somefield]]
[[#15.size.1]]

Superglobal arrays:
the
[[#POST.key]]
[[#SESSION.another_key]]
[[#GET.key3]]
[[#REQUEST.key]]
[[#SERVER.key]]
[[#FILES.key]]
[[#COOKIE.some_key]]

You can specify any fields in arrays:
the
[[#15.properties.key1.key2]]

If you don't know what values are inside the array — just select it and it will be printed in full:
the
[[#GET]]
[[#15.colors]]
[[#12.properties]]

Tags fastField can be combined with MODX tags:
the
[[#[[++site_start]].pagetitle]]

[[#[[++site_start]]]]

the

Fenom Template engine


Support Fenom template engine appeared in pdoTools with version 2.0, after which it began to require PHP 5.3+.

It works much faster than native modParser and if you rewrite your chunk so that it will not be a single tag, MODX, modParser and not to run. Of course, simultaneous operation of the old tags and the new in one chunk allowed.

Processed by the template engine be affected by the following system settings:
the
    the
  • pdotools_fenom_default — enables processing via Fenom chunks pdoTools. Enabled by default.
  • the
  • pdotools_fenom_parser — enables the processing of a template of all pages of the website. That is, not only of chunks and templates.
  • the
  • pdotools_fenom_php — includes support for PHP functions in the template engine. Very dangerous, as any Manager will have access to PHP right out of the chunk.
  • the
  • pdotools_fenom_modx — adds system variables {$modx} and {$pdoTools} in the templates Fenom. Also very dangerous — any Manager can manage objects of MODX chunks.
  • the
  • pdotools_fenom_options — a JSON string with an array of customization according to the official documentation. For example: {"auto_escape":true,"force_include":true}
  • the
  • pdotools_fenom_cache — caching Kopeliovich templates. Only makes sense for complex chunks on working sites, is disabled by default.

So, by default, Fenom included only in chunks that pass through pdoTools. It is quite safe and the managers of the system do not acquire any additional than a more convenient syntax and high-speed operation.

The inclusion of pdotools_fenom_parser allows you to use the syntax Fenom directly in the content of documents and page templates, but there is one caveat — the template engine may not react to the curly parenthesis that in MODX very much.

In such cases, the author recommends to use the tag {ignore}.

If you plan to include Fenom globally for the whole site, you need to check whether all pages it works fine.

Syntax


For a start I advise to read official documentation, and then we will discuss syntax in relation to MODX.

All variables from the snippets passed to the chunk as they are and overwrite the old chunks to the new syntax — a real pleasure.
the the the the
MODX Fenom
[[+id]] {$id}
[[+id:default=`test`]] {$id ?: 'test'}
[[+id:is=`:then=`test`:else=`[[+pagetitle]]`]] {$id == "? 'test': $pagetitle}

To use a more complex entity, provided pdoParser service variable {$_modx}, which gives secure access to some variables and methods in the system.
the the the the the the the
MODX Fenom
[[*id]] {$_modx->resource.id}
[[*tv_param]] {$_modx->resource.tv_param}
[[%lexicon]] {$_modx->lexicon('lexicon')}
[[~15]] {$_modx->makeUrl(15)}
[[~[[*id]]]] {$_modx->makeUrl($_modx->resource.id)}
[[++system_setting]] {$_modx->config.system_setting}

In addition, you available variables:
the {$_modx->config} system settings
the
{$_modx->config.site_name}
{$_modx->config.emailsender}
{$_modx->config['site_url']}
{$_modx->config['any_system_setting']}

the {$_modx->user} — an array of the current user. If it is authorized, then added the data from the profile:
the
{if $_modx->user.id > 0}
Hi, {$_modx->user.fullname}!
{else}
You need to log in.
{/if}

the {$_modx->context} — an array with the current context
the
You are in the context of {$_modx->context.key}

the {$_modx- > resource} — an array with the current resource, you have seen in the examples above
the
{$_modx->resource.id}
{$_modx->resource.pagetitle}
{$_modx->makeUrl($_modx->resource.id)}

the {$_modx->lexicon} is the object (not array!) the modLexicon that can be used to download arbitrary dictionaries:
the
{$_modx- > lexicon- > load('msearch2:default')}
Check dictionaries msearch2: {$_modx->lexicon('ms2gallery_err_gallery_exists')}

The output records are handled by a separate function {$_modx->lexicon()}.

Placeholders with the point


Fenom uses a point to access the array value, and so usually fistulae MODX placeholders array. Appropriately, the tag [[+tag.sub_tag]] analogues in the Fenom is not provided.

Therefore, for these placeholders you need to use the second service variable is {$_pls}:
the
{$_pls['tag.subtag']}

Output of snippets and chunks


Variable {$_modx} actually is a simple and safe class microMODX

Therefore, snippets and chunks are called
the
{$_modx- > runSnippet('!pdoPage&commat;PropertySet', [
'parents' => 0,
'showLog' = > 1,
'element' => 'psoResources',
'where' => ['isfolder' = > 1],
'showLog' = > 1,
])}
{$_modx- > getPlaceholder('the page.total')}
{$_modx- > getPlaceholder('the page.nav')}

As you can see, the syntax is almost identical to PHP that opens new opportunities. For example, you can define arrays, instead of JSON strings.

By default, all snippets are called cached, but you can add ! before the name — tags in MODX.

If the call to the snippet uses the native method MODX, then the output chunks start pdoTools, and you can use all of its features:
the
{$_modx->getChunk('MyChunk&commat;PropertySet')}

{$_modx- > parseChunk('MyChunk', [
'pl1' => 'placeholder1',
'pl2' => 'placeholder2',
])}

{$_modx->getChunk('&commat;TEMPLATE Base Template')}

{$_modx->getChunk('&commat;INLINE
Site name: {$_modx->config.site_name}
')}

{$_modx->getChunk(
'&commat;INLINE Transmission peremennoi in chunk: {$var}',
['var' => 'Test']
)}

{$_modx->getChunk('
&commat;INLINE pass a variable in the snippet call:
{$_modx- > runSnippet("pdoResources", [
"parents" => $parents
])}
Total results: {$_modx- > getPlaceholder ('total')}
',
['parents' => 0]
)}

The above examples are a little crazy, but it is currently working.

cache Management


The object {$_modx} available services modX::cacheManager, which allows you to set an arbitrary time caused by the caching of snippets:
the
{if !$snippet = $_modx- > cacheManager- > get('cache_key')}

'parents' => 0,
'tpl' => '&commat;INLINE {$id} - {$pagetitle}',
'showLog' = > 1,
])}
{set $null = $_modx- > cacheManager- > set('cache_key', $snippet, 1800)}
{/if}

{$snippet}

To see this cache in /core/cache/default/ in the example it is saved for 30 minutes.

set $null = ... is needed to cacheManager- > set gave 1 (i.e. true) to the page.

And you can run the system processors (if you have enough)
the
{$_modx- > runProcessor('resource/update', [
'id' => 10,
'alias' => 'test',
'context_key' => 'web',
])}

authorization Check


As the object user in the {$_modx}, the methods of verification and authorization of access rights is outside the class:
the
{$_modx->isAuthenticated()}
{$_modx->hasSessionContext('web')}
{$_modx->hasPermission('load')}

Other methods


These methods should be familiar to all developers of MODX, so just show them examples:
the
{$_modx->regClientCss('/assets/css/style.css')}
{$_modx- > regClientScript('/assets/css/script.js')}

{$_modx->sendForward(10)}
{$_modx- > sendRedirect('http://yandex.ru')}

{$_modx->setPlaceholder('key', 'value')}
{$_modx- > getPlaceholder('key')}

{if $res = $_modx- > findResource('url to/doc/')}
{$_modx- > sendRedirect( $_modx->makeUrl($res) )}
{/if}

the

Extension templates


Use of Fenom template engine allows you to include some chunks (in other templates) and even to expand them.

For example, you can just load the contents of the chunk:
the
Common chunk {include 'chunk'}
Template modTemplate {include 'template:name of template'}
Chunk with a set of parameters
{include 'chunk&commat;propertySet'}
{include 'template:Name&commat;propertySet'}

Read more about {include} read in the official documentation.

A much more interesting feature — {extends} templates, it requires an enabled system settings pdotools_fenom_parser.

Write a basic template "Fenom Base":
the
<!DOCTYPE html>
<html lang="en">
<head>
{include 'head'}
</head>
<body>
{block 'navbar'}
{include 'navbar'}
{/block}
<div class="container">
<div class="row">
<div class="col-md-10">
{block 'content'}
{$_modx->resource.content}
{/block}
</div>
<div class="col-md-2">
{block 'sidebar'}
Sidebar
{/block}
</div>
</div>
{block 'footer'}
{include 'footer'}
{/block}
</div>
</body>
</html>

It includes the usual chunks (which, by the way, the usual placeholders from MODX component Theme.Bootstrap) and defines several block{block}, which can be expanded in a different template.

Now write "Fenom Extended":
the
{extends 'template:Fenom Base'}
{block 'content'}
<h3>{$_modx->resource.pagetitle}</h3>
<div class="jumbotron">
{parent}
</div>
{/block}

So you can write a base template and extend its child.

It is also possible to write and extend chunks, just note that to work with modTemplate you need to specify the prefix template:, and no chunks — they work by default in all {include} and {extends}.

the

performance Testing


Create a new site and add to it a 1000 resources so the console script:
the
<?php
define('MODX_API_MODE', true);
require 'index.php';

$modx- > getService('error','error.modError');
$modx- > setLogLevel(modX::LOG_LEVEL_FATAL);
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

for ($i = 1; $i <= 1000; $i++) {
$modx- > runProcessor('resource/create', array(
'parent' => 1,
'pagetitle' = > 'page_' . rand ()
'template' => 1,
'published' => 1,
));
}

Then create 2 chunk: modx and fenom with the following content, respectively:
the
<p>[[+id]] - [[+pagetitle]]</p>

and
the
<p>{$id} - {$pagetitle}</p>

And add two cantilever test script. For the native parser MODX
the
<?php
define('MODX_API_MODE', true);
require 'index.php';

$modx- > getService('error','error.modError');
$modx- > setLogLevel(modX::LOG_LEVEL_FATAL);
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');

$res = array();
$c = $modx- > newQuery('modResource');
$c->select($modx- > getSelectColumns('modResource'));
$c->limit(10);
if ($c->prepare() && $c->stmt->execute()) {
while ($row = $c->stmt->fetch(PDO::FETCH_ASSOC)) {
$res .= $modx- > getChunk('modx', $row);
}
}
echo number_format(microtime(true) - $modx- > startTime, 4), 's<br>';
echo number_format(memory_get_usage() / 1048576, 4), 'mb<br>';
echo $res;

And pdoTools:
define('MODX_API_MODE', true); require 'index.php'; $modx- > getService('error','error.modError'); $modx- > setLogLevel(modX::LOG_LEVEL_FATAL); $modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML'); $pdoTools = $modx- > getService('pdoTools'); $res = array(); $c = $modx- > newQuery('modResource'); $c->select($modx- > getSelectColumns('modResource')); $c->limit(10); if ($c->prepare() && $c->stmt->execute()) { while ($row = $c->stmt->fetch(PDO::FETCH_ASSOC)) { $res .= $pdoTools- > getChunk('fenom', $row); //$res .= $pdoTools- > getChunk('modx', $row); } } echo number_format(microtime(true) - $modx- > startTime, 4), 's<br>'; echo number_format(memory_get_usage() / 1048576, 4), 'mb<br>'; echo $res;

As pdoTools understands both the syntax for it test 2 — mode MODX tags and Fenom.
In the scripts there is an indication limit = 10, then in table I include the figures with his increase:
the the the the the
Limit MODX pdoTools (MODX) pdoTools (Fenom)
10 0.0369 s 8.1973 mb 0.0136 s 7.6760 mb 0.0343 s 8.6503 mb
100 0.0805 s 8.1996 mb 0.0501 s 7.6783 mb 0.0489 s 8.6525 mb
500 0.2498 s 8.2101 mb 0.0852 s 7.6888 mb 0.0573 s 8.6630 mb
1000 0.4961 s 8.2232 mb 0.1583 s 7.7019 mb 0.0953 s 8.6761 mb

Now, let's complicate chunks — add them in the generation of links for a resource and the output menutitle:
the
<p><a href="[[~[[+id]]]]">[[+id]] - [[+menutitle:default=`[[+pagetitle]]`]]</a></p>

and
the
<p><a href="{$_modx->makeUrl($id)}">{$id} - {$menutitle ?: $pagetitle}</a></p>

the the the the the
Limit MODX pdoTools (MODX) pdoTools (Fenom)
10 0.0592 s 8.2010 mb 0.0165 s 7.8505 mb 0.0346 s 8.6539 mb
100 0.1936 s 8.2058 mb 0.0793 s 7.8553 mb 0.0483 s 8.6588 mb
500 0.3313 s 8.2281 mb 0.2465 s 7.8776 mb 0.0686 s 8.6811 mb
1000 0.6073 s 8.2560 mb 0.4733 s 7.9055 mb 0.1047 s 8.7090 mb

As you can see, processing chunks via pdoTools in all cases faster.
Much that chunks Fenom there is a minimum to start, which is due to the need to compile the template.

the

Conclusion


Let's summarize the capabilities of the parser pdoTools:
the
    the
  • Quick operation
  • the
  • Download of chunks from different sources, including files
  • the
  • tag Support fastField
  • the
  • Support Fenom template engine
    the
      the
    • template Inheritance
    • the
    • Extension templates
    • the
    • Secure access to advanced features of MODX


At the moment pdoTools downloaded more than 40,000 times from official repository and more than 10 000 of repository modstore.pro, which gives hope for a wide spread of new technologies of standardization in MODX.

A big thank you to abrowser aco a great templating engine!
Article based on information from habrahabr.ru

Комментарии

  1. How would you get these in fenom:
    [[#POST.key]]
    [[#SESSION.another_key]]
    [[#GET.key3]]
    [[#REQUEST.key]]
    [[#SERVER.key]]
    [[#FILES.key]]
    [[#COOKIE.some_key]]

    ОтветитьУдалить

Отправить комментарий

Популярные сообщения из этого блога

March Habrameeting in Kiev

PostgreSQL load testing using JMeter, Yandex.Tank and Overload

Monitoring PostgreSQL with Zabbix