View Models
The concept of a view model in SiteAdmin is derived from Microsoft's .NET framework. Though in comparison, SA's implementation is varied. Their purpose is to prevent excessive code bloat in application controllers. As mentioned in the controller documentation, a controller method should only contain logic for receiving and responding to requests. Business logic, such as querying/constructing data or performing calculations should be handled elsewhere. A ViewModel is that elsewhere.
View models reside inside of specific modules.
{application root}/siteadmin/modules/{vendor}/{module}/ViewModels/
All view models must implement the
\sa\application\IViewModel
interface.Method | Returns | Description |
__construct(array $data) | n/a | The $data parameter will contain any data initially passed from the parent view. |
getXssSanitationExcludes() | array | Constructs and a returns an array of keys, where each key corresponds to the name of a public property in the view model. Any fields in the returned list of keys will not be sanitized for XSS content. |
<?php
use sa\application\IViewModel;
class ShippingOptionsListViewModel implements IViewModel {
public $defaultOptions;
public $heading;
private $shippingOptions;
public function __construct(array $data) {
$this->defaultOptions = $data['default_options'];
$this->heading = $data['shipping_heading'];
$this->shippingOptions = null;
}
public function getShippingOptions() {
if ($this->shippingOptions != null) {
return $this->shippingOptions;
}
$options = array();
// <get shipping options>
return $options;
}
public function getXssSanitationExcludes() {
return array('defaultOptions', 'heading');
}
}
When binding a view model to a subview, its public properties will made available in the subview's global scope. For example, the view model's properties
defaultOptions
and heading
may be accessed in the subview as so,{module}/views/_shipping_options_list.php
<h1><?= $heading ?></h1>
<?php
foreach($defaultOptions as $option) {
// do something
}
?>
A view model's public properties are generally reserved for constants or default values. It is not recommended to populate these values by performing business logic in the constructor. For business logic, use the view model's helper methods instead.
Notice both public properties are included in the
getXssSanitzationExcludes()
method. Any public properties will be excluded from XSS sanitizing step.As you might expect, the view model's private properties will not be exposed to the view. In addition, private methods are not affected by the
getXssSanitizationExcludes()
method!.In the previous example, the
getShippingOptions
method is exposed as a helper method. This is where complex business operations are performed, such as fetching data from a repository or constructing data structures.There are two ways you can use your view models in an application. The general rule of thumb is to use the subviews method with controllers which respond with HTML templates. Use the direct controller method for controllers which respond with JSON, XML, or any other non-template response.
For controller methods that respond with HTML content, it is best practice to create a parent view, then populate it with subviews which are bound to view models.
To encourage this practice, it is not possible to directly bind a view model to a parent view.
Binding view model to subview
parent_view.php
<?= $self->subViewWithModel('_shipping_options_list', 'ShippingOptionsListViewMo
del', $data) ?>
Parameter | Type | Description |
$view | string | The name of the sub view to render. |
$viewModel | string | The view model to bind to the view. |
$data | array | The parent view's data. |
<a name="accessing-in-subview"></a>
Accessing view model in subview
Once a view model has been bound to a subview, a
$viewmodel
variable becomes available in the subview's context. This variable holds the view model's instance. It is used to access helper methods within the view model._shipping_options_list.php
<h1><?= $heading ?></h1>
<ul>
<?php
foreach($viewmodel->getShippingOptions as $option) {
// render option
}
?>
</ul>
Some controller methods respond with JSON or XML rather than a HTML template. These types of responses don't have views, so binding a view model to a subview is not possible. Instead, the view models should be used directly.
Last modified 4yr ago