View - Jet\MVC_View
After getting familiar with how Jet MVC works and you know how the request goes through the system we are finally at the view. I'll preface right away that Jet has no templating system. You can read why this is the case here.
The view topic is covered under the "Full MVC usage in PHP Jet" chapter, but the view as such - that is, the Jet\MVC_View class is usable completely on its own (without the base, page, router and all that) as we will show in a moment. But now to the heart of the matter.
In the context of view, we will introduce the term view script. A view script is a PHP script, but it is clearly distinguished from other scripts:
- It always has a *.phtml file extension
- I stick to the rule that its name is always lower case and the words are separated by a hyphen, e.g.: edit-form.phtml
This is not a technical necessity, but I stick to it so that it is clear at a glance that this is a view script. - View scripts are in dedicated directories, which are named "view" as a rule. You can find them in bases, in application modules, and also in microapplication directories (_installer, _profiler, Jet Studio). Naming the directory this way is a good habit.
But again, it's not a technical necessity. An example of a different directory name for view scripts might be mail templates. These templates are also view scripts, but their directory is simply called email-templates. - It is a good practice to use alternative - extended PHP syntax in the view. That is, not if($somethoning) {}, but if($somethoning): endif;It may be a matter of habit, but parentheses in this kind of code really aren't the clearest ... But again, there's nothing that tells you to do it this way. It's a recommendation - well-intentioned advice.
Now let's see how view is used in practice.
Initialization and data transfer
Separate use view
First, we'll show how to use the view completely on its own - that is, without the other elements of MVC in Jet. If you're going to build modular applications with bases and pages, you'll hardly use this method, or you'll use it minimally (for really specific things). But it's also a legitimate way (so you need to know it) and it's also a better way to explain how view works.
Let's take a look at a sample standalone view usage:
use Jet\Factory_MVC;
use JetApplication\Content_Article;
$article = Content_Article::get( $id );
$view = Factory_MVC::getViewInstance(('/some/directory/');
$view->setVar('article', $article);
$view->setVar('int_param', 2011);
$view->setVar('float_param', 3.14);
$view->setVar('string_param', '<script>alert(\'Hello!\');</script>');
echo $view->render('view-script-name');
Please note:
- The Jet\MVC_View class instance is not created directly in the example, but via the factory. The Jet\MVC_View instance can also be created directly, but using factories is recommended. Using the factory in this case is strongly recommended, but not required.
- The only parameter of the Jet\MVC_View class constructor (or the Factory_MVC::getViewInstance method) is the full path to the directory where the view scripts are located.
- It is possible (or should we say necessary) to pass data to the view. This is done uniformly by the setVar method.
- The output is generated simply by the render method and the output is returned as a return value (i.e. it is not sent immediately to the application output). The render method has a single parameter and that is the name of the view script. Warning! The name of the view script without the file extension, that is, without .phtml and also without the full path. That is, if the full path of the view script is /some/directory/view-script-name.phtml, then only view-script-name is the name of the view script and thus the given parameter.
And that's all there is to initializing and calling the view script. It's primitive like that. View has no helpers, postprocessors, etc. To be more precise, Jet had such things too, but I gradually removed it as ambiguous and indirect, unnecessarily complicated, generating possible unexpected situations and thus ultimately counterproductive. This simplicity simply worked better for me.
Using view within the controller
Now let's see how view is used in controllers and thus also in application modules. The principle is still the same. There are only these differences:
- You do not need to create a view instance. The controller already has it.
- The output from the view must be passed back to the content of the page. This is because the goal is to place the generated output/content in the appropriate place in the layout.
- There is a connection between the controller and the view. The controller holds the view instance and the view holds the controller instance.
To illustrate, consider one controller action. And let's take something real, the code from the sample application that Jet is distributed with. From the Content.Articles.Browser module, the Main controller, we take the detail action, whose purpose is to display the detail of the article (when you "click" on it).
public function detail_Action(): void
{
$article = $this->article;
// Navigation_Breadcrumb::addURL( $article->getTitle() );
$this->view->setVar( 'article', $article );
$this->output( 'detail' );
}
It is noticeable that:
- Instance view is already available as a property of the controller.
- For output the view->render method is not used, but the output controller method. This method, like the render method, has only one parameter, the name of the view script. The view method calls the script. However, it also takes care of passing the output back to the page in order to put it in the correct place in the layout.
Note: If you need to call a view from a completely different directory (e.g. from some universal view, not from the module, etc.) to generate a partial part of the output in the module, you can use the method of creating an instance of the Jet\MVC_View class (or using the factory). So, for example, a module's view script can easily call another view script that is part of the base. In fact, this is done for example when generating forms and UI. Just because you already have one view available (in the controller) doesn't mean you can't prepare and use another view and include the output from one view in the output of another view. There are no restrictions here.
View skript
We already know how to initialize the view and pass data and parameters to the script and call the view script - i.e. generate the output. Now let's see what such a view script looks like:
<?php
use Jet\MVC_View;
use JetApplication\Content_Article;
/**
* @var MVC_View $this
* @var Content_Article $article
*/
$article = $this->getRaw( 'article' );
?>
Int: <?=$this->getInt('int_param');?><br>
Float: <?=$this->getFloat('float_param');?><br>
Bool: <?=$this->getBool('bool_param') ? 'yes' : 'no';?><br>
Escaped string: <?=$this->getString('string_param');?><br>
<br>
<?php if($article): ?>
<div>
<?= Tr::_( 'Date:' ); ?>
<?= Locale::dateAndTime( $article->getDateTime() ); ?>
</div>
<?php endif; ?>
And again, let's pick out a few things:
- In the view script itself, the view instance (i.e. the Jet\MVC_View class to which we passed the data) is present as $this. Thus, what you have set in the controller is available in this instance and you can / should "reach" for the data using the corresponding methods.
- You do not access the passed parameters (data) directly, but through getters that must respect the expected type of the parameter. For example, if you want a string, its value is directly "passed" through htmlspecialchars. If you want int, you always get int and so on.
- You can call whatever you need, there is no limit. So do you need a translator? You call it: Tr::_(). Do you need to format the date? No problem ... You just call directly and simply what you need.
- ... but I'm sure no one here will think to deal with application logic, input capture and SQL magic. Yes, it can be done. But it's wrong. Of course, why ban everyone from using a lighter to start a fire and keep warm, just because someone is able to use a lighter to set a house on fire ... It's your responsibility to make sure that the view is only what it should be, and I have no doubt that every professional has that responsibility.
For completeness please see the list of methods that Jet\MVC_View class has. There you will surely find some more useful details.
Methods of class Jet\MVC_View
Method | Meaning of |
---|---|
public __construct( string $scripts_dir ) |
The only constructor parameter is the absolute path to the directory containing the view scripts that the instance will work with. |
public setController( MVC_Controller $controller ) : void |
If the view instance is created by the controller, it will insert its instance into it using this method. |
public getController( ): MVC_Controller|null |
If the view instance is created by a controller, this method returns an instance of the corresponding controller. |
public setVar( string $key, mixed $val ): void |
Sets the parameter that will be passed to the view script. |
public unsetVar( string $key ): void |
Cancels the passed parameter. |
public getInt( string $key, int $default_value = 0 ): int |
Always returns the parameter value as int. Or the default value if the parameter is not specified. |
public getFloat( string $key, float $default_value = 0.0 ): float |
Always returns the parameter value as float. Or the default value if the parameter is not specified. |
public getBool( string $key, bool $default_value = false ): bool |
Always returns the parameter value as bool. Or the default value if the parameter is not specified. |
public getString( string $key, string $default_value = '' ): string |
Returns the parameter value as a string, but always encodes it using Data_Text::htmlSpecialChars. Or the default value if the parameter is not specified.. |
public getRaw( string $key, mixed $default_value = null ): mixed |
Returns the value of the parameter without intervention - exactly as the parameter was set by the controller. When to use it:
|
public varExists( string $key ): bool |
Checks if the parameter is defined. |
public getScriptsDir( ): string |
Returns the absolute path to the directory containing the view scripts. |
public setScriptsDir( string $scripts_dir ): string |
Sets the absolute path to the directory containing the view scripts. |
public getScriptName( ): string |
Returns the name of the view script to be (or currently being) rendered. |
public setScriptName( string $script_name ): string |
Sets the name of the view script to be rendered. |
public getScriptPath( ): string |
Returns the complete absolute path to the view script file. |