I am sure that many of you who read this text are familiar with the concept Fluid Interface. And even if you have not heard about him, I am sure that you used it more than once. It is really convenient. So what are we talking about?
<?php class Images { public $width; public $height; public function SetWidth($value) { $this->width = $with; return $this; } public function SetHeight($value) { $this->height = $value; return $this; } } $images = new Images(); $images->SetWidth(100)->SetHeight(100); ?>
Here is a small example. We can, in a row, consistently, perform actions. The same principle underlies the popular jQuery library. What can I say, all modern frameworks abound with similar structures. But what if you use a similar mechanism to build the entire site?
')
entrance
Here I will not make a big digression, I will return back. To continue you need to answer the question why? Well, really, why invent a bicycle if there are standard models and proven architectures. I'm talking about the MVC family of models. What is MVC bad for?
No, he is not bad. But he has his limitations, like everything else in this world. This is a great site building model. It is the site. But when it comes to building, on the basis of a web application, alas, its limitations are felt. Let's take a closer look at the situation. Take for example the standard site. No matter what the topic is. Look at the pictures.

Here is drawn layout site layout. We see a block of news, tabs (there may be just buttons), a block of ads and a block of content. The content contains a table - an index. How to organize a request for this page?
mysite.ru/section=2&task=index
This is a classic, common mechanism. One parameter sends a section, another task. Here is another picture. We look

There is already the content of the site contains a form of editing. Here is a request for this page of the site.
mysite.ru/section=2&task=edit
Everything is good and clear. This is also programmed simply. For example, so
<?php class Site { public function Section($value) { return new MyController(); } } class MyController extends GeneralController { public function Index() { return new Table(); } public function Edit() { return new Form(); } } $site = new Site(); $section = $_GET["section"]; $task = $_GET["task"]; $site->Section($section)->$task(); ?>
The Site class returns the controller for the desired section. The MyController section controller performs the necessary actions.
Tell me, what if you are developing a web application, not a website. The interface of the web application is much more complicated than the one above. Tabs, tables, menus, etc. After all, to each element of the page we need to have access, update it, redraw? What if most content needs to be updated with AJAX? See another picture

Now our site has a tree, a bunch of tabs, a form, several toolbars, etc. The tables that are inserted into the tabs are sorted in all directions. A field Avatar in the form can load and delete a picture without reloading the entire page. So how to organize requests to all these elements?
Let's try to go the same way. Suppose we have the same MVC scheme. Obviously, we will need another parameter that will indicate what specifically to change on the page. Let it be called part. Then requests might look something like this:
mysite.ru?section=2&part=tree&task=expand
mysite.ru?section=2&part=form&task=delete
And how will you turn to the toolbar in the Tree section? Or to the toolbar in the Contents tab? Another parameter to enter? Dead end
Output
And again the picture.

This is a block diagram of the Electronic University Users section. I am sure that it is not necessary to have even a higher education in order to understand its content. Understand that Students are made up of Groups, and groups are already Student elements. Before us is nesting. And now we remember the Fluid interface and make the following assumption. And why would the root object methods not return other objects, but not just their own object? Actually, as soon as we implement this, we can easily expand this scheme into a chain. Go!
<?php class Members { public function Teachers() { return new Teachers(); } public function Students() { return new Students(); } } class Teachers { public function Teacher($number) { return new Teacher($number); } } class Students { public function Group($number) { return new Group($number); } } class Group { public function Student($number) { return new Student($number); } } class Teacher { public function Show() { } } class Student { public function Show() { } } ?>
Now, to show a student, you need to run the following chain of commands
Members::Students()->Group(123)->Student(327)->Show();
Let's repeat the question, the question that brought us to a dead end in the previous paragraph. And how will you turn to the toolbar in the Tree section?
We answer. Like this
Members::Students()->Group(123)->Student(327)->Tree()->Toolbar()->Add();
The class Student itself can have inside itself the same calls on chains to other objects. Simply put, a student class consists of a form, the Form () method, Tree () is a tree and what else is needed. This is like Lego. What we see, then sculpt, compose, design!
Dessert
The above proposed scheme of the Extended Fluid Interface for building web applications is very easily transformed into a chain of inquiries, the chain - to the site address, to the user's position on the site.
In case you write the following in .htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Then all requests to the site will be redirected to index.php. In it, you will remain type links
mysite.ru/control/members/students/group=123/student=321/show
turn into a chain of commands
Application::Control()->Members()->Students()->Group(123)->Student(431)->Show();
You can do it this way.
<?php class Application { public function __construct() { if (!$this->request = $this->Request()) { $this->errors[] = ERROR_PARAM_GET; } } public function Init() { if (!is_object(self::$instance)) { self::$instance = new self(); } return self::$instance; } public function Request() { if (!$uri = explode("/", $_SERVER["REQUEST_URI"])) { return false; } else { foreach ($uri as $item) { if (strpos($item, "=")) { $key = substr($item, 0, strpos($item, "=")); $value = substr($item, strpos($item, "=")+1); } else { $key = $item; $value = null; } if (!empty($item)) { $result[] = array( "key" => $key, "value" => isset($value) ? $value : null ); } } } return $result; } function Run() { if (isset($this->errors)) { foreach ($this->errors as $error) { echo $error; } } else { $root = $this; foreach ($this->request as $element) { if (is_object($root) && method_exists($root, $element["key"])) { $root = $root->{$element["key"]}(@$element["value"]); } else { return $this->Welcome()->Show(); } } } } } Application::Init()->Run(); ?>
PS: Dear colleagues. The above code samples do not contain checks and therefore cannot be used in work projects as they are. They are written solely for clarity.
Links
For the preparation of this material, I used
gomockingbird.com/mockingbird in which I drew a site scheme.