Controller (Jet\MVC_Controller class)
Now it's time to look at the controllers. Controllers are no longer an entity within Jet. It's nothing like a base and a page. Controllers are classes in your application space, and they can be standalone classes or they can be part of application modules (which I recommend).
These classes - controllers are tightly bound to Jet MVC. In order to resolve this dependency, each of your controllers must implement the abstract class Jet\MVC_Controller, but in real practice they are more likely to inherit from the classes Jet\MVC_Controller_Default, Jet\MVC_Controller_REST and possibly others that you create yourself. We'll get to that later. But the absolute foundation is just the Jet\MVC_Controller abstract class. This is the basic link between the Jet ecosystem and your application (your modules and classes). The other classes mentioned, especially Jet\MVC_Controller_REST, already address specific use cases - for example, creating a REST server. So let's go back to the Jet\MVC_Controller base class.
As you already know, the controller instance and its call will be provided by the content of the page. This means that you don't have to worry about how controller instances are created, but it is important to be familiar with the controllers themselves.
You will be working with controller properties on a regular basis - the properties mentioned are not just for internal purposes, but are intended for use in the application space. It is therefore crucial to become familiar with them.
|protected MVC_Page_Content_Interface $content||The controller has an instance of content page that initiated and called it. That is, the content to which the controller belongs and thus can access all the information of the content parameters starting with the base information and ending with the base information as needed.
This property is always set and available.
|protected ?Application_Module $module = null||If the controller is used within a system of application modules, it holds an instance of the main class of the module. As you already know, controllers can be used without modules. Therefore, this feature is not mandated.|
|protected MVC_View $view||This is very important. It's an instance of view (i.e. an instance of the Jet\MVC_View class).
This is what your controller will use to generate the resulting output.
This property is mandatory. But the controller creates the view instance itself in the initializeDefaultView() method. Thus, the initialization of the view is completely under your control.
The contorter does not need to use the view (see below). However, much more often the view is used. That's why the property is mandated.
|Constructor ... As you can see, it has a single but essential parameter - page content, which the controller belongs.|
|This method creates an instance of the default view of your controller.
WARNING! Here's the catch. The default implementation relies on the controller being part of one of your modules. If you decide to create controllers outside of modules, you absolutely must overload this method and make your own implementation. Why? Because the directory where the view tabs are located is determined by the directory of the corresponding module. And when the controller is isolated (not part of the application module), there is simply no method to determine the path of the directory containing the view scripts.
Otherwise, of course, it is possible to overload the method at any time, even when working with modules, and do the view initialization your own way.
|Returns the content instance to which the controller belongs.|
|If the controller is part of a module, it is also possible to access an instance of the module's main class.|
|We have already encountered the resolve() method on pages. So this method is directly related to the page method and it is the method that is actually called by the page during the resolve process.
It is very important. If your controller somehow handles e.g. URLs or GET parameters (and decides what to do based on that), you need to implement this method and handle the necessary logic in it.
The default implementation tries to see if your controller makes its microrouter (an instance of the Jet\MVC_Coutroller_Router class) available and use it to resolve the situation. But that's a separate topic.
Now the important thing is that this is the place where you can, for example, catch the URL of the product detail on the e-shop you are developing, or here you can decide whether the user wants to add a new article in the administration or delete an old one. You do not perform that operation here yet. No, that's not what this method is for. It's just a decision point for what happens next and a preparation point for the operation.
Why the preparations for the operation? Because, for example, there's nothing to prevent you from already pulling and holding as a property of your controller an instance of the article (for example) that you'll be displaying based on the URL, and directly setting the context to the cache and telling the router that that part of the URL is valid.
So, once again, this method is a decision point and preparation. And it is entirely within your control. It is to be implemented by you in your controller - the way you need it.
And beware! The method can return both bool,and string. Why?
|This method is already performing (calling) a specific operation. That is, it calls specific controller methods representing the action based on the corresponding content.
A controller action is a method with the _Action extension, it returns nothing (return value void) and has no parameters.
If you ever need to change this behavior for some reason (e.g. change the signature of action methods), just override this method.
|This is the usual and most common, but certainly not the only possible, outcome of the controller's activities.
It is about generating the output and passing it to the content of the page. Instead of explaining it in a complicated way, let's show the default implementation of this method:
Of course, this is not the only thing your controller can do. It's a typical situation for generating HTML (or text or whatever) output, but there's nothing to prevent the controller from doing, for example, this:
And it is not mandatory to generate the eventual output exactly like this. You can read the output from somewhere, e.g. from an .html file and pass it directly to the page:
So this method is no sacred cow. But in absolutely classic and most common situations, it will do exactly what you need. It will generate the output using view and return it back to the page content (and Jet MVC will take care of building the page, which will include the output of that controller).
Again, there's nothing stopping you from overloading the method.
|Let's explain everything straight away with an example: We have an application module for administration, which will be used to manage articles. It will add, edit, delete, display the list of articles ...
Such a module will almost constantly use the resolve method to evaluate what it actually wants based on the unprocessed part of the URL or GET parameters. In practice, this is actually repetitive code, the same logic over and over again, and it's a real pain to do the same thing 20 times.
That's why Jet has what I call a microrouter and it's just to make routing and resolving easier within your controller. You need to look at this topic separately.
Anyway, if your controller is going to use this microrouter, you need to create an instance of it in this method and initialize the microrouter. Then you don't have to deal with the resolve method anymore. As mentioned, the default implementation of the resolv method tests whether the microrouter is available - this is the default expected behavior.
Of course, there are situations when microrouter is not a suitable solution and it is better to overload the resolv method.
Both solutions are well represented in the sample application - so you can take a look there as well.
|abstract public handleNotAuthorized(
|There are situations where it is necessary to respond to an unauthorized/unauthorized operation. The following method is used to deal with such a situation.
It is abstract within the Jet\MVC_Controller class.
But for example, Jet\MVC_Controller_Default already implements it and makes the main Jet MVC router aware of the situation.
On the other hand, the Jet\MVC_Controller_REST class immediately responds by sending an adequate response to the client (http header + JSON error message).
Your controller can handle unauthorized operations as you need.
In the text, I have already mentioned several times the Jet\MVC_Controller_Default and Jet\MVC_Controller_REST classes.
These are the prebuilt parent (and therefore still abstract) classes for your controllers. Of these, Jet\MVC_Controller_Default only addresses one single thing, but Jet\MVC_Controller_REST, designed for creating REST APIs, is already more comprehensive.
Note: You may use these classes, but you don't have to. You can make your own parent classes in your application space, and your controllers can inherit from your own classes. There is no dogma here except that the main parent must be the Jet\MVC_Controller class