Good health to all!
It has been almost exactly two years since my
first publication on the QuadBraces parser , an MODX Evolution alternative for the simplest projects that require standardization. These can be single pages with typical publications, portfolios, business cards, consisting of almost static pages, and so on. Since then, I updated my development and unnoticed by the community crawled to the third version. The current version of the QuadBraces parser contains so many changes that I just have to publish a detailed tutorial. So…
Tags
Let's start with tag handlers. In QuadBraces, 3 tag handlers are rendered into separate classes. Now the developer is free to define his tag types without changing the code of the parser itself. To do this, create a descendant of the QuadBracesTagPrototype class, where you need to define the following:
- $ _name - tag name
- $ _start - initial tag sequence
- $ _rstart is the initial tag sequence for the MODX Revolution syntax mode. Without square brackets.
- $ _finish - final tag sequence
- $ _order - optional; processing order
- function main (array $ m, $ key = '') - a function that returns the result of processing the tag. $ m - data of PCRE-regular, key (most important) - key of the found tag.
On the example of a constant tag handler:
')
class QuadBracesTagConstant extends QuadBracesTagPrototype { protected $_name = 'constant'; protected $_start = '\{\*'; protected $_rstart = '\/'; protected $_finish = '\*\}'; protected $_order = 5; public function main(array $m,$key='') { $v = ''; if (empty($key) || !defined($key)) { $this->_error = 'not found'; } else { $v = constant($key); } return $v; } }
Yeah, right - everything is just that simple. Although I, as a programmer of the old school, are terribly enraged by the need to store files of microscopic size. But this is a personal matter, as they say.
For those who have not read the previous publication. The syntax of QuadBraces tags is the same for all tag types:
- The initial sequence of characters. For example, "{{".
- Entity ID. It should consist of Latin, numerals, "logs", a dash and / or a dot. For example, "my-chunk". Note! The point in the identifier plays the role of a nesting level separator. That is, looking ahead, for example, the variable "my.var" will be located in fact here - $ parser-> data ['my'] ['var']. About chunks, snippets and templates - below.
- A number of handler extensions (optional). Each is a construction of the form ": some_id" or ": some_id =` some_data` "(without a space between the colon and the identifier). Handler extensions work with the end result of tag processing. That is, for example, we received a variable containing a phone number, and then formatted it for human comprehension.
- For compatibility with the MODX syntax, a question mark may follow.
- A certain number of arguments (optional). Each argument is a construction of the form "& some_name =` certain_value` ". Yes, variables can even have arguments. Yes, they work. In most cases, the arguments passed are used in local placeholders.
- The final sequence of characters. For example, "}}".
In the third version of the parser, as you probably already understood, there is a MODX Revolution syntax mode. In this mode, tags start with two opening square brackets, followed by some symbol that defines the type of tag. And the tag is always closed with two closing square brackets.
An example of a certain chunk tag:
{{news-item? &title=` ` &date=`15-09-17` &url=`/news/150917.html`}}
If the chunk is:
<article> <h3>[+title+]</h3> <span class="date">[+date+]</span> <a href="[+url+]"> </a> </article>
Then, as a result, on the site of the chunk will be displayed:
<article> <h3> </h3> <span class="date">15-09-17</span> <a href="/news/150917.html"> </a> </article>
Speaking of flies. Didn’t they eat the HTML item from the “source code” menu of the editor in our Cozy?Out of the box, QuadBraces supports the following types of tags (the starting and ending sequences for two modes are indicated):
- [+ +] or [[+]] - Local variables . In most cases, are used for variable snippets, in cycles. When setting the arguments of any element, except for snippets, the local placeholders of the element are replaced by the values from the arguments.
- {{}} or [[$]] - Chunks . Pieces of html code. One file contains one chunk. One of the main elements of templating.
- {[]} or [[-]] - Single-line library chunks . Pieces of html code. One file contains several chunks. Each row contains one chunk.
- {()} or [[=]] - Multiline library chunks . Pieces of html code. One file contains several chunks. Chunks are separated by the construction: "<! - tags: splitter ->"
- {* *} or [[/]] - PHP Constants . Display the PHP constants defined in the system (including the user).
- [()] or [[++]] - Settings . Variables from the SETTINGS array. Usually used to display CMS variables using a parser.
- [* *] or [[*]] - Variables . Parser variables One of the main elements of templating.
- [^ ^] or [[^]] - Debug data . Parser debug data.
- [%%] or [[%]] - Language variables . Vocabulary variables. Replaced depending on the current language when the language system is enabled.
- [! !] or [[! ]] - Snippies . Essentially pieces of PHP code.
- [[]] or [[]] - Snippeta with caching flag . Same as above, only with the caching flag set. Roughly speaking, the $ cached argument with the value true is passed to the execute function of the parser.
- [~ ~] or [[~]] - Links from resource identifiers . Turn the number placed inside the link to the resource. About resources below.
- [::] or [[:]] - Custom variable handlers . About them separately.
In the current version of the parser, it is possible to cram a so-called set into the parser object. resources. In essence, this is about the same as the resources in MODX. Roughly speaking, a table is stored in the database of the final project, in which the entries with posts for the blog are stored. The main thing is to remember that each entry must contain a numeric ID, a parent ID or NULL and an alias for creating a URL. Setting the resources property of the parser object sets the idx property of the parser object. It is an index of the branches of the resource tree. This allows you to work with the structure of the final set of resources. Actually, the link tag works with all this
garbage functionality.
Custom variable handlers are such micro-parsers that arbitrarily process parser variables. For example, if a certain variable of the parser (let's call it, say, top-menu) contains an array with URLs of the form:
array( array('url' => '/','title' => ''), array('url' => '/about.html','title' => ' '), array( 'url' => '/news/','title' => '','children' => array( array('url' => '/news/10-09-17.html','title' => ' '), array('url' => '/news/15-09-17.html','title' => ' ') ) ), array('url' => '/contacts.html','title' => ''), );
From it you can make a menu. To do this, it is enough to place the structure in the right place:
[:menu@top-menu:]
In its place will be displayed menu with the help of bulleted lists. In the best traditions of Wayfinder, so to speak.
In general, on custom handlers, I think, you will need to write a separate article.
Separately, about one important piece of templates, namely about the metafield. Almost from the first version, it is possible to set meta fields in the template code. They are essentially variables defined in the template itself by this construction:
<!-- FIELD:_? [] -->
Arguments are about the same as in parser tags. Regardless of which arguments will be specified in the field, the final field will contain three attributes:
- default (text) is the default
- type (integer) - type
- caption (string) - header
All metafields will be available through the parser's fields property.
Meta values are no less important. Imagine that in our parser the variable somevar is defined. The meta value in the set pattern can override the current value of the variable. Meta values are determined by the construction:
<!-- DATA:_ ` ` -->
When a template is installed, both are removed from the final template code.
Class API
Class properties (most important)
:
- owner (object) - object owner (read only; set during initialization);
- paths (array) - pattern paths; can be set as an array, it can be a string, where comma-separated paths are listed;
- fields (array) - template fields (read only);
- data (array) - variable parsers;
- settings (array) - "settings";
- debug (array) - debug data;
- language (string) - current language; signature according to generally accepted standards;
- loadLanguage (flag) - autoloading of the language (false by default);
- dictionary (array) - the current dictionary; can be set by raw text, divided into lines;
- maxLevel (integer) - the maximum level of nesting (by default 32);
- level (integer) - current level;
- notice (array) - the level of notifications; understands the meaning of "strict" - all elements, "common" (by default) - chunks and snippets.
- template (text) - template; when setting to specify the name, returns the contents;
- templateName (string) - the name of the current template (read only);
- autoTemplate (flag) - flag of automatic extraction and installation of a template from installed content; roughly speaking, if the flag is enabled to feed content to the parser with the template metafield, the parser will automatically install the template (false by default);
- content (text) - content; in general, essentially a variable called "content";
- resources (array) - an array of resources;
- idx (array) - index of the branches of the resource tree (read only);
- SEOStrict (flag) - compliance with SEOStrict standards (false by default);
- MODXRevoMode (flag) - switch to the MODX Revolution syntax mode (false by default);
Methods
:
- registerTag (QuadBracesTagPrototype $ o) - registration tag; accepts an initialized tag; returns the registered tag;
- parseStart ($ m) - start processing; accepts input from the preg_match_callback function; returns item key;
- parseFinish ($ m, $ t, $ k, $ v) - end of processing; accepts input from regular data, tag type, tag key, current processing value; returns the processed result;
- setting ($ key, $ value = null) - read / write settings; if null, read;
- variable ($ key, $ value = null) - read / write variable; if null, read;
- search ($ type, $ name) - search for the item file; takes into account localization; returns the name of the found file;
- setTemplate ($ v) - set the template by name; a very necessary method when working with callbacks for setting a template;
- getChunk ($ key, $ type = 'chunk') - getting the contents of the chunk; returns the contents of the found chunk or false;
- execute ($ name, $ args = array (), $ input = '', $ cached = false) - execute a snippet or extension; accepts a snippet name, arguments, input text and caching flag; returns the result of processing;
- parse ($ t = '', $ d = null, $ e = '', $ k = '') - the main method of the parser is processing; there is no need to set arguments for processing the entire template; arguments are needed for internal needs or discrete processing (a piece of code QuadBraces); input arguments - input code, data variables, element, key element; output - processed data;
- sanitize ($ t = '') - sanitizes the input code from QuadBraces;
- extensions ($ v, $ e) - the implementation of extensions; input - current code and string with extensions;
- registerEvent ($ n, $ f) - event registration; at the entrance - the name of the event and the function;
- registerMethod ($ n, $ f) - register API method; at the entrance - the name of the method and the function;
- invoke () - call the event; the first argument is the name of the event, the rest is the call arguments;
Where to look?
One of the most important properties of the QuadBraces parser is the paths property. It determines where the parser will look for chunks, snippets, extensions, templates. The language system works a bit isolated. In the process of searching for an element, the parser iterates through all the registered paths. Each time, the search function adds a folder to the selected path, depending on the type of item. Chunks - chunks, templates - snippets - snippets. And already there is searched for the desired item. I recall that the dot in the keys of the chunks, snippets and templates in fact replaces the directory separator.
Example:
$parser->paths = 'D:/projects/mysite/content,D:/repo/templates/default'; $fn = $parser->search('snippet','basis.snipcon');
In fact, the parser in this case will check for the existence of the following files:
D:/projects/mysite/content/snippets/basis/snipcon.php
D:/repo/templates/default/snippets/basis/snipcon.php
The last found file will be returned. When the language system is enabled, paths with language signatures are actually added to the search. Suppose the installed language is Russian, that is, the signature is “ru”. Thus the file list is as follows:
D:/projects/mysite/content/snippets/basis/snipcon.php
D:/projects/mysite/content/snippets/basis/ru/snipcon.php
D:/repo/templates/default/snippets/basis/snipcon.php
D:/repo/templates/default/snippets/basis/ru/snipcon.php
Everything else is obtained through properties and methods.
Language system
First, at once I will make a reservation that the language system should be included explicitly. This is done by connecting the QuadBracesLang class. This is done with the simplest code
before the main class includes:
define("QUADBRACES_LOCALIZED",true);
It is best to enable the loadLanguage flag. Then the dictionaries will be loaded automatically. In principle, by default, when installing parser paths, the paths of the language system are set. In fact, the language system is looking for its files on the same principle as the search engine of elements. Only the language system folder is lang.
Example:
$parser->paths = 'D:/projects/mysite/content,D:/repo/templates/default'; $parser->language = 'ru';
Folders will be scanned:
D:/projects/mysite/content/lang/ru/
D:/repo/templates/default/lang/ru/
In this, all files with the extension “lng” will be searched. Each file is read line by line. Each line contains four elements - a language key, title, description, placeholder. The language key is what is later used in the language tag. Caption - replaces the default language tag. Description (description) - usually used for hints or descriptions of fields. Placeholder (placeholder) - most often used for the corresponding attribute of input elements.
Developments
The parser object supports events. Handlers, as I wrote above, are installed by the registerEvent method.
Supported events (everywhere $ p is a parser object):
- init ($ p) - Completion of the constructor;
- beforeChangeData ($ v, $ p) - Before changing these variables; $ v - settable variables;
- changeData ($ v, $ p) - Change of data variables; $ v - settable variables;
- beforeChangeSettings ($ v, $ p) - Before changing these settings; $ v - set options;
- changeSettings ($ v, $ p) - Change settings data; $ v - set options;
- beforeLoadDictionary ($ v, $ p) - Before the dictionary is loaded; $ v - dictionary;
- loadDictionary ($ v, $ p) - Download dictionary; $ v - dictionary;
- methodNotFound ($ n, $ p) - Method not found; $ n - Name of the method;
- beforeSetLanguage ($ v, $ p) - Before setting the language; $ v - language;
- setLanguage ($ v, $ p) - When setting the language; $ v - language;
- setContent ($ v, $ p) - When setting content; $ v - content;
- setResources ($ v, $ p) - When setting resources; $ v - resource data;
- invalidHandler ($ n, $ a, $ p) - In the absence of an event handler; $ n is the name of the handler, $ a is the arguments passed;
- setResources ($ v, $ p) - When setting resources; $ v - resource data;
- defaultTemplate ($ p) - Default template (attempt to set an empty template);
- loadTemplate ($ v, $ p) - When the template is installed; $ v - the name of the template;
- templateMotFound ($ v, $ p) - In the absence of a template; $ v - the name of the template;
- templateFields ($ v, $ p) - Get template fields; $ v - template fields;
- templateData ($ v, $ p) - Receive template data; $ v - template data;
- beforeLocalParse ($ v, $ d, $ p) - Before local processing; $ v - processed code, $ d - data;
- beforeParse ($ v, $ p) - Before processing; $ v - processed code;
- localParse ($ v, $ p) - After processing the local template (before sanitizing); $ v - processed code;
- parse ($ v, $ p) - After template processing (before sanitization); $ v - processed code;
I repent, unknowingly ran into one feature of PHP. If, say, you assign a function to the event handler for templateNotFound, and in it try to set the template property, nothing happens. This is due to the limitations of recursion when calling accessors on properties of a PHP object. In short, you cannot set a property through an accessor and the accessor of the same property. No From the word "absolutely." So if you want to make the 404th through the templateNotFound event handler, call the
setTemplate method inside it.
Handler Extensions
All tags support final value handlers. For example, we received a variable, and it is empty. The notempty handler allows you to set the output text for this case. Some extensions have additional "extensions". For example, the base logic has the extensions “then” and “else”.
Supported Handlers
- is, eq - equality (compared value, then, else)
- isnot, neq - inequality (compared value, then, else)
- lt - less than (compared value, then, else)
- lte - less than, or equal to (compared value, then, else)
- gt - more than (compared value, then, else)
- gte - greater than or equal to (compared value, then, else)
- even - a sign of parity (compared value, then, else)
- odd - a sign of oddness (compared value, then, else)
- empty - a sign of an empty value (the value of "then", else)
- notempty - sign of a non-empty value (the value of "then", else)
- null, isnull - whether the value is NULL (value "then", else)
- notnull - whether the value is not NULL (value "then", else)
- isarray - whether the value is an array (value “then”, else)
- for - integer iterator (number of iterations, start, splitter)
- foreach - index iterator (comma-separated list of indexes, splitter)
- js-link - turns the value into a link to the script
- css-link - turns a value into a link to a style sheet
- import - turns a value into a link to a style sheet (@import for CSS)
- link - turns a value into a link (title)
- link-external - turns a value into an external link (title)
- links - converts all URLs in the value into links (link attributes)
- ul, ol - turns a multi-line value into a list (list item template)
The ul / ol extension has two internal placeholders: [+ classes +] - element classes (first, last), [+ item +] - the actual string. An internal placeholder [+ iterator +] is available for the for extension, containing the current iteration number. For the foreach extension, internal placeholders are available: [+ iterator.index +] - the position number of the current iteration, [+ iterator +] - the current index.
Practical work
Actually, working with the parser class is very easy. Basic example:
<?php require 'quadbraces/parser.php'; $parser = new QuadBracesParser('//__'); $parser->template = 'my-template'; echo $parser->parse(); ?>
In it, we connect the class of the parser, initialize the object with passing the path to the template data, set the template and parsim. Of course, prior to processing, you can pass in the "settings" parser, variables. And before turning on the class of the parser, turn on the language system, as described above. A more practical example:
<?php define("QUADBRACES_LOCALIZED",true); require 'quadbraces/parser.php'; $parser = new QuadBracesParser('D:/projects/foo/content/template'); $parser->language = 'ru'; $parser->data = array( 'pagetitle' => ' ', 'date' => '20-09-17', 'image' => 'content/images/flies.jpg' ); $parser->template = 'news.single'; echo $parser->parse(); ?>
The template will be searched in the following files:
D:/projects/foo/content/template/templates/news/single.html
D:/projects/foo/content/template/templates/news/ru/single.html
Outcome-disclaimer
Immediately I apologize for my inability to write tutorials and documentation! If the community is really interesting, the most interesting moments will be revealed in subsequent publications. Ask questions - I will answer with pleasure. If you notice an error, write issues on the
github here .