Computer lessons

PHP library for working with the Yandex.Money API. Demons - message queues Bad message php

3.3K

Displaying messages to the user is a fairly common action that a web application should perform. It can occur when processing forms, it can be error messages, messages that tell you to register when a user tries to access a restricted part of the site, and in many other cases.

Very often, the creation and output of messages are separated into different HTTP requests. As a rule, it is convenient to use a redirect after processing forms (to avoid problems with the Back and Refresh buttons), but at the same time, the natural moment for creating a message is precisely the moment of processing forms and performing actions accompanying it. Why? Imagine that the message text should look something like this: “The number of units ordered for the product ‘Mouse Pad’ has been successfully changed from 7 to 12.” After a redirect, perhaps to a completely different page in terms of functionality, it will be an extra headache to determine what was done before.

Most often, messages are displayed in the POST request that processes the form - this is not good, the words “this page is out of date” ruin life (when the user decides to try the Back button).

Someone uses a redirect, giving up on friendly messages.

At the same time, there is a simple and obvious way to make life better. Despite the obviousness, for some reason I never saw anyone use it - at least when I looked at other people's sources.

So, we have a problem - the message must “live” in different requests. We need a mechanism to transfer the text of the message to the page that should display it. You probably already remembered about the sessions.

Yes, in general you are right. Other methods, for example through a global variable, do not allow saving data in the case when a redirect is used (note by Maxim Naumenko). Plus, I usually make sure that each screen in the application has the ability, along with other information, to display messages that were generated on previous screens. This is convenient because there is no need to prepare separate screens for displaying messages, and the user does not have to click the mouse again. But, really, the designer needs to think here - to highlight the area in which messages would appear.

The idea is very simple and can be implemented with a couple of classes.

The first thing that comes to mind is to create a Message class, which would, in fact, represent a message in our simple class diagram. The message must be able to save itself in the session, as well as display itself on the screen.

class Message ( /** * Message content. */ var $content; /** * Constructor for initializing the message text. * * @param content message content */ function Message($content) ( $this->content = $content ; ) /** * Write a message to the session. */ function send() ( $_SESSION["session_messages"] = $this->content; ) /** * Output a message to the page. */ function toPage() ( echo " - " . $this->content . "
"; } }

The $_SESSION variable is used to access the session.

Note that $_SESSION is an array, we are using just one element of this array with the index ‘session_message’.

In this case, we are dealing with an “array of arrays” - what we store in the ‘session_message’ element is an array, this is the list of transmitted messages (of course, there can be several of them).

If you couldn't find the thread, it's time to brush up on the sections of the manual dedicated to sessions and arrays.

You may have a question. Why are classes needed here? It would be possible to get by with two functions. But let's look further. We may need to create messages with different types (info, error, warning), and determine message recipients.

Please note that at the moment it is not the object itself that is put into the session, but only the message text. OOP allows us to later change the behavior of the send() method without changing the client code that accesses this method (for example, in the future we can write the entire Message object to the session if it has many fields).

Let's imagine that we would do this using functions. We would probably have a message_send($txt) function, and also a message_to_page($txt) function. Now we need to add the ability to have different behavior for different types of messages. Function calls change: message_send($txt, $kind), message_to_page($txt, $kind). You will have to comb through the entire application code in search of such functions, making corrections.

This can be avoided by anticipating the situation in advance by presenting the message as an associative array: $msg[‘txt’], $msg[‘kind’], then there will be only one parameter in function calls. Can you feel how this is trying to become a class?

So, OOP gives you the opportunity to have the luxury of not thinking through everything in advance.

The next class - Inbox - is designed just for this.

class Inbox ( /** * Array of received messages. */ var $messages = array(); /** * In the constructor, we get all received messages * and delete them from the session. */ function Inbox() ( if (is_array($ _SESSION["session_messages"])) ( $messages = $_SESSION["session_messages"]; $co = sizeof($messages); for ($i = 0; $i< $co; $i++) { $this->messages = new Message($messages[$i]); ) ) /* clear the messages array */ $_SESSION["session_messages"] = array(); ) /** * Display the contents of the Inbox on the page. */ function toPage() ( $co = sizeof($this->messages); if ($co > 0) ( echo "Message from the system:
"; ) for ($i = 0; $i< $co; $i++) { $this->messages[$i]->ToPage(); ) ) )

Let's try out our messaging system.

Let's create a very simple example that will respond to a form submission by reporting the number of seconds in the current minute.

send(); /* redirect to yourself */ header("location:"); ) else ( $inbox = new Inbox(); $inbox->toPage(); ) ?>

We hid all the work with arrays and sessions inside classes, and the final code looks simple and beautiful.

Create a directory on your web server, then create these three files in it and try the script out. Please note that there are no problems with the Back and Refresh buttons.

Now imagine that you are creating a complex portal, where, as a rule, there are several blocks on the pages, and each one can contain a separate application.

Here we encounter two difficulties:

* I would like the list of messages to appear in a specific part of the page, and you have already found a good place for this.
The problem is that you need to run the $inbox->toPage() command at exactly the moment that would correspond to the position of the list of messages on the page. If we want to change the position of this list, we will have to go into the code, but it is not good to constantly change the portal frame for this. The best solution would be to make the output of messages in the form of a separate module, which we only know that it needs to be connected to the framework.
That is, free yourself from the strict sequence of launching modules. Indeed, since the result of the Inbox output does not depend on the operation of the system (at this step we already have all the data in the session), then why the extra complexity?
* To maintain the appearance (design) of the message list, you need to take care of the HTML code, which is hardcoded in the toPage() methods of the Message and Inbox classes. Typically, you will have to change the PHP code in order to change the design.

To try to solve the first problem, you can create a buffer that stores the result of the Inbox output.

Perhaps we will still have several similar (to Inbox) things, and we need to create a buffer system. In order not to confuse whose output is whose, we will probably come to naming the buffers. We will store somewhere the sequence in accordance with which the buffers should be output - preferably in an external file to make changes easier.

This attempt at a solution already gives us the idea of ​​using XML as a means of storing intermediate data. And using XSLT styles will help solve the second problem.

I will not dwell on what XML is and what XSLT is. If you're not familiar with these things, zvon.org is a good place to start looking.

The idea is to generate not HTML code, but an XML structure in the toPage() methods. The page document will be created as a string with XML code (it will serve as a “buffer”), and at the last stage of the script we will use an XSL transformation.

First, let's imagine what should be the result of the main part of the code.

minute 57 second: 45

What it is is quite easy to guess - two messages and a form. Please note that the PHP script only needs to prepare such a string - it is very simple. Moreover, the order of the main tags is unimportant - You can put it at the beginning, for example, as it will be convenient for the programmer. How to implement it. You can, without changing anything, use output buffering, output XML instead of HTML code, and at the end simply capture the output into a string. But then we will lose flexibility - for example, sometimes you want to output debugging information directly to the page (using echo). At the same time, PHP developers are working on a DOM module that offers a more advanced way of creating and passing tree documents. If we want to implement the DOM, we will have to redesign the entire application, changing the output of strings to the creation of DOM elements. Therefore, I prefer to store the XML representation of objects within the objects themselves, sequentially assembling a common XML document. It's not that difficult, it just needs a little modification. You will see that this technique is not strictly tied to a specific way of storing XML data, and this will allow you to make the transition to using the DOM with little effort. First of all, notice that each of our objects has a toPage() method. This similarity should make us think about introducing a new common parent class. Let each class that can create pieces of an XML document for a page inherit from a class that will take care of the XML representation of the object. Let's call it Outputable.

class Outputable ( /** * XML container (string). */ var $output = ""; /** * Give the contents of the container and clear the container. * * @return a string with XML data */ function getOutput() ( $ out = $this->output; $this->output = ""; return $out; ) /** * Add a portion to the contents of the container. * * @param string the string to add */ function appendOutput($string) ( $this ->output .= $string . "n"; ) /** * "Abstract" method. */ function toPage() ( ) )

The toPage() method is made empty - in this case it is needed as an indicator of how external “matryoshka” classes should communicate with the inner class. However, we could offer a default implementation here if we noticed that there are many objects that display themselves on the page in the same way.

The Message and Inbox classes will change slightly - they should now both inherit from Outputable, and the toPage() methods will also change
Message.php

class Message extends Outputable ( /** * Message content. */ var $content; /** * Constructor for initializing the message text. * * @param content message content */ function Message($content) ( $this->content = $content; ) /** * Write a message to the session. */ function send() ( $_SESSION["session_messages"] = $this->content; ) /** * Output a message to the page. */ function toPage() ( $this->appendOutput(" ".$this->content.""); } }

class Inbox extends Outputable ( /** * Array of received messages. */ var $messages = array(); /** * In the constructor, we receive all received messages * and remove them from the session. */ function Inbox() ( if (is_array ($_SESSION["session_messages"])) ( $messages = $_SESSION["session_messages"]; $co = sizeof($messages); for ($i = 0; $i< $co; $i++) { $this->messages = new Message($messages[$i]); ) ) /* clear the messages array */ $_SESSION["session_messages"] = array(); ) /** * Display the contents of the Inbox on the page. */ function toPage() ( $co = sizeof($this->messages); $this->appendOutput(" "); for ($i = 0; $i< $co; $i++) { $this->messages[$i]->toPage(); $this->appendOutput($this->messages[$i]->getOutput()); ) $this->appendOutput(""); } }

The output method has changed - now, instead of directly outputting to the page, the external representation is for the time being stored in Outputable, which “sits” in each of the objects. The appendOutput() method serves as a replacement for the echo() construct. To get the output of an object, the getOutput() method is used.

Now let's see what the client part of the code is, which will solve the same problem as before.
index.php

send(); /* current second */ $msg_sec = new Message("second: " . date("s")); $msg_sec->send(); /* redirect to yourself */ header("location:"); exit; ) else ( /* prepare a list of messages in XML form */ $inbox = new Inbox(); $inbox->toPage(); $global_content->appendOutput($inbox->getOutput()); ) $global_content->appendOutput (" "); $xml_string = $global_content->getOutput(); $xh = xslt_create(); $xarg = array(); /* header of the XML document */ $xarg["xml"] = ""."n"; /* body of the XML document */ $xarg["xml"] .= " " . $xml_string . ""; /* XSL template */ $xarg["xsl"] = implode("", file("style.xsl")); /* output the HTML code - the result of the XSL transformation */ echo xslt_process($xh , "arg:xml", "arg:xsl", NULL, $xarg); /* output XML source (debug) */ echo "


" . htmlspecialchars($xml_string) ."
"; ?>

The main innovation is in the $global_content object, the name of which speaks for itself. In this case, it belongs to the Outputable class; in real-life tasks, you would probably create a separate class for the page content.

If you look closely, the content of the script has practically not changed - the same inbox, the same toPage(). Added an instruction that displays the contents of the message list in the page content. For variety, two messages are now generated.

In order to look at the result, all that remains is to prepare the XSL template.
style.xsl

XSLT Example

message

What have we achieved?

First of all, you can more confidently take on complex projects - real independence of modules is ensured. The order in which results are placed on the page is now controlled using an external XSL template and does not depend on the order in which the modules are run.

Any module that generates XML data as a result of its work can be used in a project. By the way, this is one of the advantages over template engines, in which data creation consists of a sequence of calling methods (assign, etc.) of a specific engine, for which there is no common standard.

Another advantage is ease of debugging. If you run the script, you will notice that each page contains debug output - an XML prototype that greatly simplifies debugging applications.

Something else you need to think about is how to create message objects. It is not always convenient to use new directly in client code. But perhaps this is a topic for a separate article.

Finally, a gallop about the prospects:

* pop-up windows for a list of important messages
* "sender pages" and "destination pages" in messages
* logging messages in the database
* button "show history of my actions"
* statistical analysis of user actions within sessions
* "intelligent assistants" in web applications

    To be self-willed, to be self-willed, to be self-willed, to be incompetent. (colloquial). To act arbitrarily, to behave arbitrarily. Ushakov's explanatory dictionary. D.N. Ushakov. 1935 1940 ... Ushakov's Explanatory Dictionary

    BE SELF-WILLING, oh, oh; imperfect (colloquial). Act arbitrarily. Ozhegov's explanatory dictionary. S.I. Ozhegov, N.Yu. Shvedova. 1949 1992 … Ozhegov's Explanatory Dictionary

    Nesov. nepereh. decomposition Do as you please, according to your whim. Ephraim's explanatory dictionary. T. F. Efremova. 2000... Modern explanatory dictionary of the Russian language by Efremova

    Self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, self-willed, ... ... Forms of words

    act without permission- to be deceitful, ay, ay... Russian spelling dictionary

    act without permission- (I), I’m lazing around, I’m having tea, I’m having tea... Spelling dictionary of the Russian language

    Ayu, ay; nsv. Razg. To act as you wish, at your own whim, without asking permission from anyone. S. visiting. S. at work. Do your own thing at home. ◁ Self-will, I; Wed No self-will, please, otherwise I’ll fire you! ... encyclopedic Dictionary

    act without permission- oh, oh; nsv.; decomposition see also self-will To act according to one's own desire, on one's own whim, without asking permission from anyone. Samovo / laziness at a party. Samovo/lazy at work. Do your own thing at home... Dictionary of many expressions