📜 ⬆️ ⬇️

Step-by-step instructions for creating a portlet platform: Portlet description

In this series of articles, I want to show how to create a portlet platform . My main goal is to present the project at its best, the development of which I return from time to time. Each article will be provided with a link to GitHub. At the end of the cycle, the source code of the entire project will be opened there. The materials of the first article are already there .

At the moment I have a portlet platform written in PHP. Immediately I ask web developers who are not familiar with PHP, but using Java, C #, Python or any other language in their work, do not pass by. I myself, first of all, a Java-developer, and the focus in the series of articles will be put not on the code, but on the techniques and architectural techniques. In addition, the result may be useful to the developer in any language. To me, even in projects developed in Java, the result is very useful.

It seems to me wrong to start the cycle with a “big table of contents”, since it will surely be too lengthy, and the author's logic contained in it may still be unobvious and uninteresting. Therefore, I will begin by describing the magic elements on which everything else is based. Further, if there is interest, we will clarify and deepen.

Step 1. Portlet description


To describe why portlets are needed, I have to give two links at once. First, on the article about portlets in Wikipedia , I have already given. Let the second link be to the description of the Composite View pattern on the Apache Tiles project page . I suggest looking at the page elements ( header, menu, block of text, table with data, search form ) as portlets or even widgets placed on the page. In this case, the main thing when building an interface consisting of such a set of components is not the ability to assemble everything from small bricks, but the ability to inherit and expand already existing interfaces.
')
It is important that in the future we will use the Composite View, and not the Decorator. Comparison of both patterns is on the second link.

The portlet description will look something like this:

<?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <definition name="widget-menu" extends="widget" template="public/widgets/menu/menu-content.tpl"> <put-attribute name="title" value="Menu" /> <put-attribute name="controller" value="/widgets/widget.php" /> <!--   --> </definition> </structure> 

Starting with some article, it becomes clear why we need such a description, and why it is in the form of an XML document. In the first article, I propose only to figure out how to use XML descriptions and the CV pattern conveniently when building user interfaces.

Imagine the task:
We develop our own tourism portal and we have about 30 pages in our development, made up of various elements, including: various lists with service sets, search and booking forms, sections with advertising banners, sections with maps and weather widgets. About 20 elements are used on the main page at the same time, 10-15 at the internal ones. At the same time, we have quite a large number of similar pages.

In this case, it is important for us to be able to “inherit” the pages, for this we will use a special XML notation for the description of the template and the page.

The long and nasty text of an XML document
 <?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <definition name="public-layout" template="content/public/public-layout.tpl"> <put-attribute name="header" value="content/public/public-header.tpl" /> <put-attribute name="content" value="content/public/public-content.tpl" /> <put-attribute name="footer" value="content/public/public-footer.tpl" /> <put-list-attribute name="jsFiles"> <put-attribute value="//code.jquery.com/jquery-2.1.3.min.js" /> <put-attribute value="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" /> <put-attribute value="/assets/js/app.js" /> </put-list-attribute> <put-list-attribute name="cssFiles"> <put-attribute value="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" /> <put-attribute value="/assets/css/layout.css" /> </put-list-attribute> </definition> <definition name="home" extends="public-layout"> <put-attribute name="content" value="content/public/home/home-content.tpl" /> <put-list-attribute name="jsFiles"> <put-attribute value="/assets/js/home.js" /> </put-list-attribute> </definition> <definition name="about" extends="public-layout"> <put-attribute name="content" value="content/public/about/about-content.tpl" /> <put-list-attribute name="jsFiles"> <put-attribute value="/assets/js/about.js" /> </put-list-attribute> </definition> </structure> 


The root XML structure element consists of the <definition> ... </ definition> declaration set. Each such announcement can be found by a unique name. And each ad contains a set of its own properties and can be inherited from the other. In our case, the public-layout template is declared and 2 pages are inherited from it: home and about .

Most critics of the CV pattern hate such XML documents and refuse to use them in their daily practice. Some of them are more suitable for Decorator (Java and Groovy programmers may recall SiteMesh), some use CVs implicitly, shifting page management functions to the used CMS system.

We will not use the Decorator, because it is not functional enough for our task, and the CMS system is because we, to some extent, adhere to “alternative views” on web development and, in fact, want to show how do not use CMS and not lose in development speed, and also preserve the continuity of the code and reduce the entry threshold for novice developers.

But we will not repeat the mistakes of those who are still too keen on writing XML-like languages. We simply use a couple of well-established practices when working with such descriptions:

  1. Divide one description into many small ones using the XML schema xi .
  2. When parsing an XML document, we use the dynamic nature of the PHP language and the capabilities of the SimpleXML library.

structure.xml
 <?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include xpointer="xpointer(//definition)" href="structure-private.xml" /> <xi:include xpointer="xpointer(//definition)" href="structure-public.xml" /> </structure> 


structure-public.xml
 <?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include xpointer="xpointer(//definition)" href="structure-public-layout.xml" /> <xi:include xpointer="xpointer(//definition)" href="structure-public-home.xml" /> <xi:include xpointer="xpointer(//definition)" href="structure-public-about.xml" /> </structure> 


structure-public-layout.xml
 <?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <definition name="public-layout" template="content/public/public-layout.tpl"> <put-attribute name="header" value="content/public/public-header.tpl" /> <put-attribute name="content" value="content/public/public-content.tpl" /> <put-attribute name="footer" value="content/public/public-footer.tpl" /> <put-list-attribute name="jsFiles"> <put-attribute value="//code.jquery.com/jquery-2.1.3.min.js" /> <put-attribute value="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" /> <put-attribute value="/assets/js/app.js" /> </put-list-attribute> <put-list-attribute name="cssFiles"> <put-attribute value="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" /> <put-attribute value="/assets/css/layout.css" /> </put-list-attribute> </definition> </structure> 


structure-public-home.xml
 <?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <definition name="home" extends="public-layout"> <put-attribute name="content" value="content/public/home/home-content.tpl" /> <put-list-attribute name="jsFiles"> <put-attribute value="/assets/js/home.js" /> </put-list-attribute> </definition> </structure> 


structure-public-about.xml
 <?xml version="1.0" encoding="UTF-8"?> <structure xmlns:xi="http://www.w3.org/2001/XInclude"> <definition name="about" extends="public-layout"> <put-attribute name="content" value="content/public/about/about-content.tpl" /> <put-list-attribute name="jsFiles"> <put-attribute value="/assets/js/about.js" /> </put-list-attribute> </definition> </structure> 


In our further research, 2 things will be important to us:

  1. Such "small" XML documents can be "dynamically delivered";
  2. The structure of an XML document can be fixed through the use of a schema.

I can’t think of anything smarter any further than offering to court about 250 lines of PHP code that handle the described XML documents. To whom it is interesting, look, the rest can accept as given that it is easy to write such code and focus on the mechanisms of use.

Link handler of XML documents on GitHub

But the code that uses the functions of the StructureBuilder class, which is responsible for processing, can be more fully quoted:

 <?php $root = __DIR__; require_once "$root/classes/StructureBuilder.class.php"; $structure = StructureBuilder::buildFromFile("$root/structure/structure.xml"); $fragments = empty($_SERVER['PATH_INFO']) ? array() : explode('/', parse_url($_SERVER['PATH_INFO'], PHP_URL_PATH)) ; $directory = count($fragments) > 1 && !empty($fragments[2]) ? urldecode($fragments[2]) : 'home' ; $definition = isset($structure[$directory]) ? $structure[$directory] : $structure['home'] ; require $definition->template; ?> 

In this code, the following happens:

From URL like http: // example.com / about we extract the name of the “section”, for example about . Next, load the page descriptions from the structure.xml file. All internal XML documents are loaded and parsed automatically.

We did not mark only the contents of the public-layout template and all files with the tpl extension marked in the XML description. These files should contain the presentation layer code. For maximum simplicity, we give an example of such a code with simple <? Php?> - inclusions:

 <!DOCTYPE html> <html> <head> <?php foreach ($definition->params['cssFiles'] as $key=>$value) { ?> <link href="<?php echo $value; ?>" rel="stylesheet" type="text/css" /> <?php } ?> <?php foreach ($definition->params['jsFiles'] as $key=>$value) { ?> <script type="text/javascript" src="<?php echo $value; ?>"></script> <?php } ?> </head> <body> <div class="l_header"><?php include "$root/{$definition->params['header']}"; ?></div> <div class="l_content"><?php include "$root/{$definition->params['content']}"; ?></div> <div class="l_foorer"><?php include "$root/{$definition->params['footer']}"; ?></div> </body> </html> 

It can be seen that we:

  1. Each page is composed of "fragments", "petals" or, further, "portlets";
  2. On each page we include the necessary resources, scripts and styles, and the lists of resources are inherited by pages from each other.

The end page code is very simple:

 <section class="home-content"> Home Content </section> 

That's all, for the first article in the cycle - quite enough. Now everyone who needs it can use the CV pattern and the project template posted on GitHub in their projects.

In the next article, most likely, we will clarify the concept of a portlet and I will talk a bit about the Request Dispatcher pattern. And I will do it (as it is connected, you ask) using the undeservedly forgotten Smarty template engine. And to Java developers, I promise in the next article to also tell you about the Servlet API device.

useful links


The Java Composite View implementation , which served as the prototype for our PHP implementation. Good friends with JSP, Struts 2, Jersey MVC.

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


All Articles