📜 ⬆️ ⬇️

Easyweb - XSLT Web Engine

Easyweb is a general-purpose versioning engine written in PHP and intended for issuing an XML response using an HTTP request. It is based on the XSLT template engine, and the engine itself is a set of solutions to the main tasks on the web: routing requests, differentiating access rights, separating data retrieval methods and presentation methods, localization, PHP auxiliary classes and facilitity, and so on. The project is a collection of architectural and conceptual ideas that have accumulated over six to seven years of development for the web.

If we talk about classification, then Easyweb is probably the most similar to the Content Management Framework. It is, in a sense, a little higher level than most software frameworks, since the main part of the product created on Easyweb is built on XML technologies. At the same time, it is much lower than the usual CMS - there is no built-in user interface, ready-made page templates or a pre-set set of SQL queries.

In a nutshell, an Easyweb website or XML service is an XML config, a set of page templates, a database, and scripts for handling POST requests. All of the above is created by the webmaster independently in his favorite text editor, as well as in the admin area of ​​his favorite DBMS. Easyweb will be interesting to those for whom all the listed conditions are met:
')
  1. If you for some reason are not satisfied with the existing CMS;
  2. If you think about what you need to "write everything yourself";
  3. If you are afraid of the complexity of existing software frameworks;
  4. If you like XHTML, as well as a friendly family of XML technologies.


Prehistory


My acquaintance with the development for the web began quite standardly: the sites coming out from under my keyboard were porridge from HTML-I mixed with PHP inserts and direct database access via the mysql_ * API. However, since I had been programming in a wide variety of languages ​​for quite some time, starting from assembler and ending with SQL, shaders, and Alexandrek-like C ++, I quickly realized that no one was interested in such a web, and something needed to be changed. It took quite some time, and I learned from my friend about the existence of XSLT. Having studied the materiel, I realized: here it is, the technology of my dreams! However, XSLT is just a templating engine, while web development consists of a wider range of tasks. Therefore, I decided that I need to do a full-fledged engine.

After that, the development of Easyweb went according to the following scenario: I wrote the engine and used it until a critical mass of new ideas accumulated (it usually took a little over a year), then threw out a new version in which implemented everything that had accumulated and became painful during the time of work with Easyweb's previous reincarnation.

Between the third and fourth versions, I had a whole range of technological gaps, and therefore I even seriously thought about writing a fourth version of Easyweb in a different language. In one way or another, certain attempts were made on C ++, Java, Scala, Ruby, Perl, Erlang, and even Microsoft technologies with their .NET and other IISs. However, after more than six months of viewing the same problems from different sides, in the end, still managed to overcome all obstacles in the framework of PHP. Hurray, the solution is found!

While writing the fourth version of the engine, I came to the conclusion that I was able to solve all the key problems that had arisen for me personally in all the development time on the web, and therefore it was decided that Easyweb had matured to become a public project.

Current state


The fourth version of the engine is still at the stage of testing and periodic subdirecting of some trifles. It is planned that the first version, which can be called stable and completely usable, will appear before the end of the year.

The documentation is written in English, however, has not yet been corrected by a native speaker, so try not to laugh very much with my Ryazan accent.

Closer to the point


I will not provide detailed documentation in this article, since it is in the Wiki section of the project on GitHub. On the contrary, I will try to set forth the minimum that should be enough for you to understand if Easyweb is interesting for you and you want to study it, or if you are comfortable with the technologies you are working with at the moment and you don’t need this project.

Easyweb is the engine in which you have to do everything yourself. In general, everything: design a database, write SQL procedures, impose XHTML, set CSS styles, JavaScript, and POST requests handlers. The goal and meaning of Easyweb is to allow you to make this “everything” as simple as possible, compact, readable, intuitive, safe, and with a dozen more beautiful adverbs.

As mentioned above, a website created on Easyweb consists of a database, an XML config, page templates, localization, and POST request handlers. Let's discuss each of these entities, and give examples of XML and PHP snippets.

Database

Easyweb does not impose any restrictions on the database structure, so its design should be approached taking into account all the good things you know about databases: keys, indices, foreign key constraints, triggers, views, and so on. Open, for example, phpMyAdmin, and - go ahead.

XML config

The config describes what pages are on the site, what data sources are, what procedures are used to access this data (and what they look like), as well as how rights to access pages, procedures and template fragments are regulated.

Page:
<page name="book" url="/book/(book_id -> natural)/"> <template src="/tpl/main.xsl" xml="book:info(book_id -> $book_id)"> <template name="head" src="/tpl/home/head.xsl" /> <template name="body" src="/tpl/home/body.xsl" /> </template> </page> 

Data source:
 <datasource name="library" type="postgresql" server="192.168.10.230" username="guest" password="mZrCe3qlj92H" database="library" charset="UNICODE" /> 

Procedure:
 <procedure name="book:list" datasource="library" root="books" item="book" empty="true"> <param name="author_id" type="natural" /> select id, title, description from book where author_id = $author_id; </procedure> 

Group membership:
 <group name="editor"> <param name="account_id" type="natural" /> account:type(account_id -> $account_id) = 'editor' </group> 

Resolution:
 <permission name="book:edit"> <param name="account_id" type="natural" /> <param name="book_id" type="natural" /> editor(account_id -> $account_id) and public(book_id -> $book_id) </permission> 


Page Templates

All page templates are XSL-valid documents, in which the page is made up using standard XSL and XPath entities, as well as extensions provided by the engine. Easyweb extensions are in the www namespace. An example of a simple root pattern:
 <?xml version="1.0" encoding="utf-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:php="http://php.net/xsl" xmlns:www="https://github.com/nyan-cat/easyweb" exclude-result-prefixes="xi php www"> <xsl:template match="/"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <xi:include href="head.xml" /> <www:template name="head" /> </head> <body> <www:xslt xsl="/xsl/menu.xsl" xml="/xml/menu.xml" /> <www:template name="body" /> <footer> <xsl:value-of select="www:local('footer')" /> </footer> </body> </html> </xsl:template> </xsl:stylesheet> 

Example of menu layout (menu.xsl from the example above):
 <?xml version="1.0" encoding="utf-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" xmlns:www="https://github.com/nyan-cat/easyweb" exclude-result-prefixes="php www"> <xsl:template match="menu"> <xsl:for-each select="item"> <a href="{@href}"> <xsl:value-of select="www:local(@name)" /> </a><xsl:if test="position() != last()"> | </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

Layout of the list of books received by the procedure. The XSL template is stored in a separate file:
 <www:xslt xsl="/xsl/book-list.xsl" xml="book:list(author_id -> $author_id)" /> 

Layout immediately in the current template:
 <xsl:for-each select="www:query('book:list', 'author_id -> $author_id')/books/book"> <h3><xsl:value-of select="title" /></h3> <xsl:copy-of select="description" /> </xsl:for-each> 


Localization

Easyweb-e provides a special format XML file for storing texts from multilingual websites. An example of such a file:
 <?xml version="1.0" encoding="utf-8" ?> <local> <home> <title> <en>Chinese Cuisine</en> <ru> </ru> <zh>中国菜</zh> </title> <description> <en> Welcome to Nannan Zhang personal website about chinese cuisine. Feel free to contact me at <a href="mailto:nannan@zhang.com">nannan@zhang.com</a>. </en> <ru>       ,   .        <a href="mailto:nannan@zhang.com">nannan@zhang.com</a>. </ru> <zh>关于中式美食,欢迎访问张南南个人网站。垂询邮箱:<a href="mailto:nannan@zhang.com">nannan@zhang.com</a> </zh> </description> </home> </local> 

To request data fragments from this XML, a special XPath extension and string aliases are provided, which represent a simplified form of recording the path to the corresponding node. An example of text output in an XSL template:
 <xsl:copy-of select="www:local('home:description')" /> 


Handling POST Requests

Configuring the page in the config:
 <page name="book:edit:post" url="/book/edit/post/" action="/php/book-edit.php" permission="book:edit(account_id -> $session:account_id, book_id -> $post:id)" /> 

Content book-edit.php:
 <?php function action($www, $response) { $www->query('book:edit', array ( 'book_id' => post::hidden('id'), 'title' => post::text('title'), 'description' => post::textarea('description') )); $response->location('/book/' . post::hidden('id') . /); } ?> 

An example of saving downloaded images by POST request:
 <?php function action($www, $response) { foreach(files::get('picture.+') as $file) { $image = image::load($file['name']); $scaled = $image->fit_to_width_copy(800); $image_id = $www->evaluate('image:create'); $scaled->save(fs::normalize('/images/pictures/' . $image_id)); } } ?> 


Work with session

Among the PHP classes provided by the engine, there is a class session, designed to store objects in the session and retrieve them from it. Easyweb allows you to store in the session as simple values ​​like strings and numbers, as well as more complex entities, namely: index arrays, associative arrays, xml Easyweb objects, as well as any PHP objects serialized in JSON and back:
 <?php session::start(); session::value('account_id', $account_id); var_dump( session::value('account_id') ); session::vector('numbers', array(1, 2, 3)); var_dump( session::vector('numbers') ); session::map('food', array('Apple' => 'Fruit', 'Potato' => 'Vegitable')); var_dump( session::map('food') ); $xml = xml::load('/xml/menu.xml'); session::xml('menu', $xml); var_dump( session::xml('menu') ); session::object('user', new user('Mark', user::type_editor, 35)); var_dump( session::object('user') ); ?> 

All objects stored in the session are accessible from their XSL templates as an XML representation through a special XPath extension:
 <xsl:for-each select="www:session('xml', 'menu')/menu/item"> <a href="{@url}"><xsl:value-of select="@name" /></a> </xsl:for-each> 


Technical issues


At the moment, the engine works through the PHP class XSLTProcessor, which, in turn, uses libxslt. This means that only XSLT 1.0 and XPath 1.0 can be used. The good news is that the XSLTProcessor in the standard build supports the main part of EXSLT. As soon as / if a standard XSLT / XPath 2.0 module appears in PHP, it will immediately be built into Easyweb.

PHP PDO is used as an API for accessing the DBMS, therefore, theoretically, Easyweb supports 12 DBMS types ( http://php.net/manual/ru/pdo.drivers.php ), and can also be easily adapted to any other DBMS which has a PDO driver (it’s enough to add a feature request with the name of the DBMS and a link to its PDO driver). In addition, the architecture of Easyweb easily allows (the author of the engine, that is, me) to embed support for other DBMS that do not have a PDO driver (for example, MongoDB), which is actually planned for the future.

Academic-detailed performance tests were not conducted, so I can only share the results of visual observations, kneaded timings, and analysis of Apache logs with parallel peering at htop. So, this is what is known:



Further plans and reflections


At the moment, the following big tasks are planned for some uncertain future (developing your own, or choosing a ready solution and integrating with it):
  1. Support for various DBMS that do not have a PDO driver, as any wishes arise;
  2. Translation of some parts of the parsing from regular to full LL (1);
  3. ORM-system or its similarity;
  4. Faceted search;
  5. Full text search;
  6. A framework to facilitate solving certain tasks on the client (AJAX or WebSockets on the client side, and, probably, JSON-over-HTTP on the server side).


Links


Easyweb repository: github.com/nyan-cat/easyweb
Documentation: github.com/nyan-cat/easyweb/wiki
Study Guestbook example: github.com/nyan-cat/easybook

Thanks for attention. In the comments I will answer your questions.

Source: https://habr.com/ru/post/162997/


All Articles