Jet MVC
As you know, MVC is related to routing. In the context of our world, the world of online applications, it means how to convert an HTTP request into a specific action.
And of course routing is in Jet MVC as well. Of course, it's a bit more complex, but in real life it's a very powerful and useful system, reflecting what we do and need today and every day, which at the same time provides a great deal of freedom and flexibility.
The point is not just to convert some specific URL to some controller ( i.e. some specific class, for example). No, Jet takes it more broadly and calling some method of some class is just a piece of the puzzle, one part of the whole chain. And this principle needs to be explained properly.
Jet does have a router, but that's just an auxiliary tool.
The primary concepts are base (MVC_Base) and page (MVC_Page). Let's explain these terms.
What is a Base (Base)
As the name suggests, it's a base of some sort. In fact, it's the point from which everything is based. Let's get right down to business. As an example, let's take the sample application that Jet is distributed with - there's an example of everything mentioned here.
Let's say you're doing some kind of corporate portal, or an e-shop, or actually anything else - it doesn't matter what specifically. What would such an application consist of? It will definitely have:
- Administrative interface
- Single portal, e-shop, .... just what is the essence and what will be seen by a wide audience on the Internet (or intranet).
- Some REST API server might be included in the system. This is not a rule, but the bigger the project, the more likely it is.
- A large project (especially e.g. an e-shop) will also have some service operations. Imports, exports, recalculations and calculations ... All sorts of ...
All of these make up one project. It's a single unit that ultimately does its job.
But each part of the project is different. The administration will work differently than, say, an e-shop. For example, the login of company employees to the administration will be completely separate from the login of end customers. Similarly, client logins via the REST API will be completely different. The spectrum of API localizations may be completely different than the localization of what customers see. The functionality of these parts of the project will be completely different, the navigation (and its very principle) will be completely different ... They are actually different worlds in one project. Different philosophies, different approaches and completely different outputs, even completely different users.
And that's exactly what Jet is designed to do - it's designed specifically for such projects.
So the first thing a Jet router has to do is determine what it's all about? Is it the administration URL? Or is it the URL of the e-shop? Or something else entirely? It's absolutely basic.
Of course, base is not just a concept unto itself - it's not an abstract thing. It's an existing entity, or let's say object. You can take a closer look at a base here. But let's list first what all a base includes:
- A base has a textual identifier (in practice, e.g. "admin", "rest", "web", "shop") that you can use to retrieve and work with an instance of it.
- Information about what URL the base has (e.g. the administration URL, the REST API URL, the root URL of the site, etc.). A base can have N root URLs, but one of them is always the default.
- Information about what locales (Locales) the base has. Each base can have its own set of locales. Thus, you can have the administration UI in only one language, but the e-shop in three localizations.
- Information about what URLs each locale has. So the Czech version of the e-shop will have a different URL and the Slovak version will have a different URL.
- And a lot of other (actually very important) meta information. For example, whether the base requires https, whether the base is non-public and "behind a password" (e.g. administration), but also the default meta tags for the HTML header.
- The individual bases and localizations can be easily activated / deactivated ...
- A final (but crucial) piece of information: each base has its own initializer. You will learn more below.
Thus, the very first thing the router does is to determine which base the HTTP request (i.e., the given URL) belongs to, and further holds an instance of that base - a real entity.
The next step is to call the base initializer.
Base Initializer
You will learn later here where and how to set the initializer, but for now the important information is what is the purpose of the initializer.
Back from practice: For example, the authentication and authorization in the administration will be completely different than the customer login in the e-shop. It will work with a different class representing the user and so on (but of course with the same container and authorization system facade - but let's not get ahead of ourselves - we'll talk about that later). Or, for example, the logging of operations will be completely different (or again, the same on the outside, but there will be a different backend). Simply put, you need to ensure (and configure) different basic behavior of the application and the whole system depending on what part of the project it is.
An initializer just configures the whole system to be ready to work with a given base. The initializer is part of the application space. It's a matter entirely under your control and it's up to you what the initializer will do.
At this point, we already have the base defined (we know what part of the project it will be), we have called the base initializer and we have configured the system.
What else? Next, the router starts to figure out what page (Page) the request is going to.
What is a page (Page)
Let's take what you're reading as an example:
https://www.php-jet.net/doc/mvc/plne-vyuziti-mvc-v-php-jet
This is a page. It's been that way since the beginning of time since the web existed. But let's break it down further (and recapitulate the concept of a base as part of that).
The URL can be broken down into these parts:
- https://www.php-jet.net/
This is the URL of base. More specifically, the base site and its default locale cs_CZ. - doc/
This is the URL of the documentation page. That is, the entity page with the appropriate parameters. - mvc/full-use-mvc-in-php-jet
This is the URL of a specific article within the documentation. But we'll get to that later - for now, let's call it the unedited part of the URL. It is no longer a page URL in the sense of an entity page within Jet MVC.
So the router already knows at this point that you are looking at a PHP Jet site (intended for you), that you are reading the default locale of cs_CZ, and that you are looking at the documentation page.
We've already got the base instance set up, now it's time to create and hold an instance of another entity - page.
The page is an even more complex entity than the base. Again, I will give at least a brief overview of what this entity includes:
- A page always belongs to a specific base.
- A page has a text identifier - ID (e.g. "doc", "download", "contacts", etc.), which is unique within the given base.
- A page has its URL. This is very important. It means that you won't "hardcode" links to pages in the application into the HTML code, but use those URLs generated by the page entity (and when the page URL changes, the links change automatically).
- The page also has a whole bunch of meta information. Whether it's the internal page title, various subtitles (for HTML, for menus, for navigation, ...), the ability to make the page non-public and require a login, even assign an icon and priority. It is also impossible not to mention meta tags, it is even possible to define HTTP headers and also internal parameters.
- The pages are of course organized in a tree structure.
- The page has content!
So there must be something to display on the page. And for that "something" to be displayed, you need to specify what and how it should be done ...
Let's stop with the fact that the page has content.
Page content
There are several ways a page can define its content, and each is suitable for a different purpose. We'll take it from the simplest to the most complex (but most typical)
Fully static page - static content
This is the most primitive option. Part of the page definition is HTML code (or plain text, just any data and information) and this is sent as a response back to the visitor/user. Done, no more controller calls are made.
But what good is this? Let's take a real life example.
Years ago we implemented a website for one of the big/major mobile operators. This website very often contains various standalone micro sites - so-called landing pages for various marketing actions. Those pages had to be linked to from various places on the site from content managed by the CMS. Of course, the pages themselves were designed and coded (actually, it still is, if I know correctly) by other agencies in charge of the kapanas. They simply supplied us with static content to deploy. And such a situation is very easy to solve in Jet.
And it doesn't have to be just this situation. If you have a unique fully static site then why any programming? For example, you can easily render a static page in Jet Studio. Plus, it's technically the fastest option - in terms of implementation, but also in terms of site performance.
Callback
This is a slightly different situation. If you need a class (or a method of a class) to handle the page, you can define which class and which method it will be. So the page rendering ends up calling that class of yours and its static method, and the rest is up to you.
But even in this case, the page is fully in the structure of the site, you can reference it, put it in the navigation, and so on.
This way is also good for various low-level things - for example, server-side parts of various web services and so on.
Set of contents
... or one could write a set of contents. This is the main (and at least by me in practice the most commonly used) way.
I didn't use the plural ("contents") by accident.
Let's take another look at the website. Like this one you're reading right now - at its core, this site is very primitive. But even on this primitive page you can see a few elements. At the very top is the search input. Then some main menus, then breadcrumb navigation, then navigation within the documentation, and last but not least this documentation text.
A normal page is actually always made up of some components, and each of those components is at a certain position within some layout.
And that's why a page, if we work in this mode, has not one content, but N contents.
The principle is simple: You simply specify that you want to send this and that action of this and that module to this and that position within the layout of the page.
Each module then takes care of its own - the part of the page that belongs to it. So, for example, the Web.Search module (more precisely, its Main controller and the header_search action - we'll talk about all that later) takes care of displaying the search box, the Doc.Browser module takes care of displaying the article, and so on.
Unprocessed part of URL
I still owe an explanation of this term. A little recap: we have a base, we have a localization, we have a page, and we are left with a chunk of the URL that doesn't belong to any page. For this page you're reading right now, it's mvc/full-use-mvc-in-php-jet. And, as you've probably guessed right away, it's the URL of this article from the documentation.
Of course, the router can't know what it is - what that piece of URL means. The last thing the router got to and recognized is the page. So if the router detects that the URL still continues, it requests the page to resolve the situation (resolv).
The page will do the following: If it has a defined content set, it will successively ask all controllers of all associated modules to resolve the situation. If none of the controllers recognizes this URL residue, the router will arrange to redirect to the last recognized URL (or a 404 can be sent, but redirecting to the last recognized URL is the default behavior).
In our particular example (which is for the page you are looking at), the Web module recognizes this particular piece of the URL.Doc.Browser and immediately detects what article it is and prepares everything to display the article and display the navigation. The Router is informed that this part of the URL has been processed as well, so it's a known URL and everything is fine. So it can do everything it needs to do: call all the actions of all the controllers of the respective modules and build the resulting page.
What about a REST API?
I've been trying to figure out how to display this page, for example. But how to make for example a REST API? Actually, it's even easier:
- You create the appropriate base with the appropriate URL (and set that as non-public - ideally).
- You handle authentication and authorization.
- You can create individual pages as individual nodes (e.g. https://api.mujweb/billing/ , http://api.mujweb/orders/) REST APIs and define modules to be responsible for these API nodes.
- Specially, however, the module controller will be tailored for REST APIs, but we'll talk about that elsewhere.
- This is all from an MVC point of view ... For example, you don't have to deal with such a layout in the context of the API.
Let's summarize ...
In reality, routing is simple:
Detect Base > Detect Locale > Detect Page > Check-in Page (one of several options)
It is important to understand the meaning of the entities base and page. These entities are the basic model of what you're looking at and what the web actually always is - whether it's an administration, an e-commerce site, or an API, it's still a site.
It's important to know, though, that it's these entities (not hard-coded URLs somewhere in the HTML code) that are used for navigation (i.e., creating a URL within a project and using it anywhere - e.g., in menus and the like).When you're creating a new page, you're really creating a new page and its definition as a true non-abstract entity, something that exists in the form of a directory and a definition file - you'll see that below. You can create the page manually, or you can conveniently click through Jet Studio.
You don't write any "routes" anywhere, you don't create a new class for the page. Nothing like that. In fact, it's closer to the old days when you simply created a doc.php file. It's just more sophisticated and powerful, and necessary for large projects. But it's still inherently simple and natural for web and online applications, straightforward and above all unrestrictive and free.