Working with view models

The view-generating part of the APF is heavily based on the HMVC pattern. In contrast to MVC it is
more flexible and allows to build complex applications without the need to strongly connect all parts of the
application or to bring workarounds for decoupling in place (e.g. view helpers). Due to the nature of
HMVC the application is split into any number of separate parts representing a particular functionality of
the application. Separation of concerns is thus easy to achieve and brings several benefits for re-usability
and testing aspects.

To bind all parts of the application together the APF used the inversion of control principle expressed by
the APF DOM model and implemented by the Page controller. Besides, the URL or the session are also used to
allow information exchange and/or storage between parts of the application.

In HMVC-based applications there is not just one model but each MVC unit could have it's
own data representation matching the functional requirements. It is not necessarily required to define one model per
unit and several units could even share a model in case they are responsible for handling certain parts of the
application that deal with the same data structure.

In personalized HMVC-based application there is often a strong need to share essential information such as
the current user. For this reason, you may define an application model that will be used by various
parts and contains vital information of the application's state - such as the user.

In order to still encapsulate data structures within dedicated HMVC entities it is recommended to use
view models. View models represent data structures (a.k.a. DTO) and/or behaviour (a.k.a.
domain object) of single MVC units. Besides their data and/or behavioural encapsulation they can
be used as a container to generate the view representation of a dedicated MVC element.

Using HMVC in combination with view models not only allows to encapsulate data but also to easily
test controllers based on the view model's content rather than based on the HTML output that is generated.
This chapter describes the usage of the view model concept within HMVC in depth to enable you
writing clean and reusable applications.

In order to fully capture the components that are used within this chapter it is recommended to read the following
chapter before:

The following chapters will describe usage of the view model concept by two different scenarios:

Filling a template with data from an application entity.

Displaying repetitive data via a template and with the iterator.

As mentioned above view models are any PHP class that encapsulates data from your application in any kind -
e.g. a user's address or a web page teaser. Models solely containing data are often referred to as DTOs.
Models that contain business logic are considered domain objects.

In general, view models are objects that are directly used within an HMVC unit to generate HTML output. It
may be handy to directly use objects returned by an O/R mapper as view models since they already represent the data
that is processed by a particular part of an application.

Besides the strong data tying using view models has a positive impact on the size of the controller implementation
as view logic can be encapsulated nicely.

Please note that models represented by arrays or array access implementations are prone to errors during access and
break IDE and static code analysis support. For this reason, the APF does explicitly not recommend
to use arrays or array access implementations for any kind of models.

An instance of this class may be returned by an O/R mapper or may be created within the controller manually. To keep
things simple the following code assumes that method getAddress() returns an instance.

This has several disadvantages: the controller code gets fat and contains a lot of view-centric logic (e.g. displaying
data) and separation between real view logic and just displaying data according to the MVC pattern gets
lost.

For this reason, it is recommended to implement the controller in a more view model-based style as we
already have a model Address that represents the data to display. For this reason, we could simplify the
controller as follows:

In case no model is available you may nevertheless use or change to the view model concept as it also
applies to arrays. Admittedly, arrays are no real data encapsulation and prone to errors during access but could be
an appropriate tool to enhance your application. Using arrays you could still keep your controller simple:

The same approach can be used to display close-to-static content such as web page teasers with partly dynamic data
(e.g. a formatted date). Assuming that your data is coming from any kind of CMS implementation and method
getContent() returns an associative array with identifiers referring to editorial form fields and their
respective CMS content. In such kind of situations you can still apply the view model concept by wrapping
the data into a view model with getters for each field.

The following code box contains a view model implementation that both covers CMS data as well as the dynamic parts
(formatted date):

Displaying lists is quite similar to displaying simple entities. The view model concept can be
applied the same way and reduces the lines of code of your controller.

The following chapters show how to display a list of users along with some key information. To keep things easy,
loading the user list is delegated to the UmgtManager shipped with the APF. As a view model class
UmgtUser is used that is also delivered with the APF.

As mentioned in chapter 2 you can basically use any PHP class as your view
model and even arrays could be a less favorable solution. In case we are using an existing business component such as
the UmgtManager that delivers it's own set of domain objects we are already half way done.

Within this chapter, a simple <html:template />-Tag should be used to display the user list. This
certainly implies more logic to be put into the controller, however the view logic can be encapsulated very well to
still be able to guarantee excellent testability.

Based on the UmgtManager-API displaying a list of users can be implemented as follows:

Without a doubt, this approach introduces some more view logic into the controller compared to the implementation in
chapter 2.1. However there is an elegant solution to
remove the logic again by using a view component that takes care of iterating over the list and displaying the
entries: the iterator tag. For details, please have
a look at the next chapter.

In case an existing model does not contain all required functionality to display the desired information there are
two options: generate content within the controller or extend the model. To separate view and controller logic it is
recommended to extend the model.

Assuming that UmgtUser does not provide an option to display an obfuscated e-mail address you could easily
extend the class as follows:

Please note that using __call() is just used to keep this example clear. The APF team does explicitly
not recommend to use magic methods as this will prevent any sort of auto complete, highlighting, and
documentation within your IDE!

The controller then needs to be slightly adapted to display the obfuscated e-mail address:

The iterator tag is a view component based on the APF
DOM tree concept represented by a tag that provides an API to inject the list to display. It takes responsibility for
templating and displaying content including static surrounding content (e.g. start and end of a list). This component
is ideal to be used with the view model concept as it allows you to keep your controller clean and small.

In order to display the list of users from chapter 2.2.1 the templates
needs some adaption:

In case the HtmlIteratorTag is not sufficient to display a list of data within your application you can
easily create a custom tag that displays your data based on the
<html:template /> tag. Details on tag
implementation can be taken from chapter Implementation of tags.

Assuming that the user's address is optional during registration it might make sense to not display the address
block in case no data is available. To easily create the desired output the template could be structured as follows:

The <user:list /> tag consists of an inner HTML part that takes static HTML and the outer
<html:template /> tag representing one user entry. Ths inner <html:template /> tag
represents the user's address. In case the user has address data available the content of the inner
<html:template /> is injected in tho the ${user-address} place holder.

The following code box containing the implementation of the <user:list /> tag. Please note that the
software design of the tag can be adapted in any kind matching your requirements.