Welcome to the webmvcframework WIKI.
The package webmvcframework,
with the acronym of WebMVC, is a powerful object-oriented PHP framework, suitable as a
web design and development tool.
You can use WebMVC to effectively create small and medium-sized web
projects regarding data-intensive web applications, sites, mobile web apps and web APIs.
WebMVC defines:
WebMvcFramework provides a comprehensive set of features that emphasize the principles of the Model-View-Controller (MVC) architecture, Separation of Concerns (SOC), and Hierarchical Model-View-Controller (HMVC). Here's a summary of the key features:
MVC Architecture:
Subsystem Organization:
HMVC Support:
Technology Unmixing:
Standard Web Technologies:
ORM Code Generation:
Ready-to-Run Components:
Facilities for Rapid Development:
This feature set suggests that WebMVC aims to provide developers with tools and conventions to streamline the development of web applications while adhering to established architectural principles.
The outlined principles and guidelines for developing WebMVC provide a clear insight into the philosophy and goals of the framework. Let's break down each of these principles:
Object-Oriented Programming (OOP):
Avoid Mixing of Programming Languages:
Decomposition:
Component-Based Development:
Naming Convention Over Configuration:
Internationalization Support:
Tools-Aided Framework:
These principles collectively aim to create a framework that not only adheres to sound software engineering practices but also provides developers with a toolset and conventions that simplify and enhance the development of web applications.
By putting all these guidelines and principles of WebMVC in order:
we could imagine using the acronym "CAN DO IT" to indicate the criteria by which a WebMVC application could be designed and developed.
Follow this wiki to learn and to start using the framework!. Let's start with the Setup of WebMVC
This section provides you with basic information for download, setup and configure WebMVC framework.
In order to develop using WebMVC framework you need:
The technical skills you need for developing with WebMVC are:
To install the framework:
sql/mrp.sql to install database sample tables. See the comments inside sql/mrp.sql
to see default users and passwords
config/application.config.php according to your MySQL database and Apache Web Server
configuration
`php
/**
/**
/**
/**
/**
/**
/**
.......
/**
`Finally, make sure you set it properly Apache configuration for enabling mod_rewrite. Look here for details
In the next section, we show you how to configure some advanced option. Alternatively, you can start understanding how WebMVC works.
To follow this tutorial, you will need:
One Debian 10 server with Apache installed
First we need to activate mod_rewrite. It’s already installed, but it’s disabled on a default Apache installation. Use the a2enmod command to enable the module:
sudo a2enmod rewrite
This will activate the module or alert you that the module is already enabled. To put these changes into effect, restart Apache:
sudo systemctl restart apache2
mod_rewrite is now fully enabled.
Before you start using mod_rewrite you’ll need to set up and secure a few more settings.
By default, Apache prohibits using rewrite (with is configured by the framework into .htaccess file) so first, you need to allow changes to the site configuration. Open the default Apache configuration file using nano or your favorite text editor:
sudo nano /etc/apache2/sites-available/000-default.conf
Inside that file, you will find a
/etc/apache2/sites-available/000-default.conf
<VirtualHost *:80>
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
. . .
</VirtualHost>
Save and close the file. If you used nano, do so by pressing CTRL+X, Y, then ENTER.
Note: Do the same
changes for SSL sites.
Then, check your configuration:
sudo apache2ctl configtest
If there are no errors, restart Apache to put your changes into effect:
sudo systemctl restart apache2
You can configure WebMVC to use customized options such as setting the directories for storing your controllers, models, views, and template, configure security options and much more.
In this section, we will clarify these details to permit you to understand any configuration option. However, before starting, you need to know that, in most cases, you do not need to customize the execution environment of your application, the configuration we shown you on the previous page will be sufficient without the need of doing something else. In fact, all the other WebMVC configuration options can be used with their default values.
// TODO
This section provides you with a high-level overview of Model, View, and Controller of WebMVC and how it works to generate web pages. After reading this introduction, you should understand how the different parts of a WebMVC application are physically and logically organized and how they work together. You should also understand how the architecture of a WebMVC application differs from a standard PHP application.
Building a WebMVC application requires you to put your custom code into four special
sub-folders of the server application root folder: models,
views, templates, and controllers. As you might guess
from the folder names, these folders physically organize the classes for implementing models, views, and
controllers. In addition to structuring the physical organization of files, these folders also represent
the logical organization of Namespaces in which each class will be encapsulated.
About
the templates folder, the only thing you must know is that it will contain the HTML code that will be
used by WebMVC PHP classes to generate the dynamic page of your application. The figure below shows the
tree structure for folders:

When you build a traditional PHP application, there is a one-to-one correspondence between a URL and a
PHP page. If you make an HTTP request like http://server/home.php from the server, then
there had better be a page on disk named home.php. If the home.php file does
not exist, you get an ugly 404 - Page Not Found error.
When building a WebMVC application, in contrast, there is no correspondence between the URL that you type into your browser's address bar and the files that you find in your application. In a WebMVC application, a URL corresponds to a controller action instead of a page on disk.
In a traditional PHP application, browser requests are mapped into pages. In a WebMVC application, in contrast, browser requests are mapped to controller actions. A PHP application is content-centric. A WebMVC application, in contrast, is application logic centric.
In WebMVC any browser request gets mapped to a controller action through a feature called Loading and Dispatching. This feature is built on architectural design named "Convention over Configuration" to automatically handle incoming HTTP requests and routes them to the corresponding controller actions. We will give you later more technical details about this feature in Controller Page,
A Controller is responsible for controlling the way that a user interacts with a WebMVC application. A
controller contains the flow control logic for an application. A controller determines what response to
send back to a user when a user makes a browser request.
Technically speaking a controller is just a
concrete class of the abstract framework\Controller class. When you write a controller
class it must be saved under the controllers folder of your web application to allow its
instantiation.
The View has the responsibility to organize and show data in graphical structures.
The development of
a View in the web environment, unlike what happened for desktop applications, involves the use of
different programming languages: some server-side, like PHP, and other client-side, like HTML, CSS, and
JavaScript. In WebMVC these differences are used respectively by involving two distinct entities rather
than just one as was expected by the MVC pattern, originally designed for desktop applications. These
entities are the framework\View concrete class of the framework, and a common static HTML
file, the Template that will contain the GUI design. Custom views and templates must
respectively reside into views and templates folders. Separating HTML
design contained into a template from the class View offers considerable advantages on several sides. We
will discuss this in detail later.
The Model handles the state of the application. The state is what your application is about. In WebMVC
model is provided by the framework\Model concrete class that has the responsibility for
data management of MySql. You can use an instance of this class or extend it with a
custom class and save it under models folder.
The framework also provides you with a
tool for automatically generating all the Model classes needed to manage all tables of a given MySQL
schema.
Now you know how WebMVC, as a result of an HTTP request, loads and runs a Controller, connected in turn with the View, Template, and Model. The following figure shows you how the framework handles incoming HTTP requests and processes data and operations.

Let's summarize the key points in the flow
Incoming HTTP Request:
Using Dispatcher for Recognition of the Controller call:
Importing and using Controller:
Controller Loading and Instantiation:
The Loader imports the Controller class and its dependencies.
The Dispatcher instantiates the appropriate Controller.
Possibility of Hierarchical MVC:
Model Execution:
View Execution:
Controller Output to Dispatcher:
Dispatcher HTTP Response:
This flow illustrates a typical request-response cycle in the WebMVC framework, where the Dispatcher plays a central role in managing the flow of control, and the Model, View, and Controller collaborate to handle different aspects of the request.
In summary, the WebMVC framework uses a Dispatcher to handle incoming HTTP requests. It recognizes the need for Controller execution, loads the appropriate Controller class, and manages the flow of control between the Model, View, and Controller to generate a response, which is then sent back to the client. This process follows the principles of the Model-View-Controller architecture, with additional support for hierarchical MVC and other features provided by the WebMVC framework.
WebMVC requires that you must mandatorily use PascalCase and camelCase notation for naming, respectively, classes and methods. Furthermore is strictly recommended (but optional) to use a unique name for all MVC parts. For example, if you are designing the home page of your site, you can use the name "Home" for all classes such as the Controller, View, Model, and the name 'home' for the Template, You must also use the name 'Home' for many other files, such as language translation files, which we will show you later. See the following figure:

From a conceptual point of view, this means that you can specify a unique name that identifies the MVC triad cooperation. In this example, we call it Home and it identifies a WebMVC assembly that will be generated at runtime for the aggregating of the MVC triad and the template.
Summarizing, a WebMVC assembly identifies an entity generated at runtime that will provide a primary service (typically a web page) and we can identify by a name. Then we can use this name for physically naming the MVC triad and template that cooperate together for producing the service. The name of a WebMVC assembly will match the Controller name of the triad and will be also used by the framework for providing to you an endpoint you will use for consuming the service.
Although we can use the same name for the different MVC classes triad, the unique identification of a single class name still will be possible because WebMVC uses the PHP namespaces for encapsulating each class; this convention allows avoiding naming conflicts and the proliferation of names in complex projects. We will provide more details about using namespaces when they will be used for managing subsystems for decomposing the system.
Generally, a WebMVC assembly, that inherits its name from Controller (alias root Controller), can furthermore aggregate together many more parts, rather than only its related Controller, Model View, and Template. In fact, it can assemble, into a hierarchical structure, many more parts like nested MVC triad and/or Components. All those nested elements may be also considered as child MVC assemblies. We will give you more technical details later about the hierarchy of MVC assemblies when introducing Content Decomposition and Components.
By looking at the figure above, in which we used a WebMVC Assembly name 'Home', see the
positioning of the Home.php classes for the Controller, View, Model in the directory
hierarchy of WebMVC. Also, see how we have been using the name 'home' for the template
home.html.tpl by putting it under the 'templates' folder. By convention,
we used the "_snake_case notation_" (by specifying the name using lowercase)
for naming those files, like template ones, that doesn't contain any classes.
Don't forget that, at the occurrence of composite words in the WebMVC assembly name, snake_case
notation uses an underscore for separating words, eg. 'hello_world.html.tpl' for naming a
Template related to a WebMVC assembly having the name HelloWorld. The file extension ".html.tpl"
is mandatory when naming a Template.
Finally, we can use the endpoint http:/server/home
for running the controller controllers\Home, or better for consuming the service provided
by the Home WebMVC assembly. The name of the callable endpoint will be automatically
provided to you by the framework. It will be represented in snake_notation and it will match exactly the
Assembly name.
Note that the convention we discussed so far, of using a single name for all the main parts of MVC
assembly, is not mandatory. If you prefer you can also decide to name classes and templates by using the
traditional suffixes, eg. HomeController.php, HomeModel.php, HomeView.php
and home_template.html.tpl
We exposed the basic concepts you need to understand before using WebMVC framework for developing an application. They are:
So you simply:
After the explanation of the main architecture of WebMVC, and by understanding its basic structure we are now ready to start coding its first entity: the Controller.
You are going to learn how fast is to start coding with the WebMVC framework.
We have already
discussed the role of the Controller in the MVC design pattern here.
As follow of that, for designing and implementing your first application you only need a basic knowledge
of OOP programming for writing special classes: the Controllers. In fact, by writing a Controller, also
equipped with some public methods, WebMVC will enable you to instantiate and execute it's logic,
simply by typing special HTTP requests from your browser.
Coding and running your first controller is extremely simple!
Just write and save the following file
HelloWorld.php into the controllers folder:
<?php
namespace controllers;
use framework\Controller;
class HelloWorld extends Controller
{
public function sayHello()
{
echo "Hello World";
}
}
The figure below shows you the path for HelloWorld.php. Note that you must use the PascalCase notation for naming a controller.
Here's a breakdown of the code:
Namespace:
controllers namespace. Namespaces help
organize classes and avoid naming conflicts.
Class Declaration:
HelloWorld and extends the Controller class
provided by the WebMVC framework.
Method (sayHello):
sayHello. This method will be executed when
the corresponding action is triggered.
Action Logic:
sayHello method is simple: it echoes the string "Hello
World."
To use this controller, you typically follow the URL structure that corresponds to the MVC pattern. For
example, if your application is hosted at http://example.com, accessing http://example.com/HelloWorld/sayHello
would trigger the sayHello method of the HelloWorld controller.
Make sure that the file is saved in the correct location, and the namespace corresponds to the folder structure. The WebMVC framework likely has conventions for organizing controllers and other components.

At this point, the only thing you have to understand is how to instantiate the HelloWorld
Controller and execute its sayHello method. Just open your favorite web browser and type
the following URL address:
http://localhost/hello_world/say_hello (Click to run)
You should see:
Hello World
Congratulations, you have just developed and executed your first application using the WebMVC framework!
Remember that this is a basic example, and in a real-world application, your controllers would handle more complex logic, interact with models, and generate views to render dynamic content.
WebMVC requires you to code a custom Controller for implementing application logic. In general, a
Controller has the responsibility to handle the logic and control flow of a software application. To do
this you must create a PHP Class that extends the framework\Controller and save it under
the controllers directory. That is what we did by providing HelloWorld
controller. Later we ran it by requesting it from browser URL, that's mean we typed its name and its
sayHellomethod by using a snake_case notation. This notation is very
intuitive because it mirrors the PascalCase or camelCase notation that must be mandatory used
when naming classes or methods. It simply consists of typing the HTTP request by specifying
both the Controller and Method names you want to run, using lowercase and by separating names with a
slash. Snake_case notation also requires an underscore for separating an eventual occurrence of
composite names for the controller or for methods. In fact, we used:
hello_world -> for specifying HelloWorld Controller that must mandatory named by using the PascalCase notation
say_hello -> for specifying its sayHello method that must be mandatory named by using the camelCase notation
then we typed both controller and method names by separating them with a "/" (we assumed localhost is the application root):
http://localhost/hello_world/say_hello
That's it all.
Therefore, you don't need to configure the execution of a particular Controller, but you just use the URL notation proposed by WebMVC. This simplicity derives from the convention over configuration approach that the framework uses for object instantiation and method invocation in order to avoid tedious operations of configuration for running the controllers. The convention over configuration mechanism used by WebMVC is simple: as we just said before, you must mandatorily use the PascalCase and camelCase notation when naming, respectively, classes and methods.
As you can see in the example, for creating a Controller you must write a common PHP Class that uses and
extends the abstract framework\Controller class. Then you must and save it into the
directory controllers. By adding public methods to controllers\Home class, you are able to
implement some application logic that can be executed by an HTTP request.
The only skill you need right now is about the OOP programming. For this purpose, the
next example will show you other concepts regarding the interaction between WebMVC and OOP programming.
Specifically, they are about parameters and visibility of Controller
methods.
Look and run the code below in which to the previous example we add:
sayHelloMessage($message)cantSayHello():<?php
namespace controllers;
use framework\Controller;
class HelloWorld extends Controller
{
public function sayHello()
{
echo "Hello world";
}
public function sayHelloMessage($message)
{
echo "Hello $message";
}
protected function cantSayHello()
{
echo "This method cannot be called from Url";
}
}
Now type the following address:
http://localhost/hello_world/say_hello_message/Mark (Click to run)
The output will be
Hello Mark
Also type:
http://localhost/hello_world/say_hello_message/John (Click to run)
The output now will be:
Hello John
As you can note we requested the execution of the method sayHelloMessage and for specifying
a value Mark (or John) for its single parameter $message we
simply typed its value into the URL. We also used a slash for separating the requested method name
say_hello_message and the value for its parameter $message. This is the
WebMVC convention for passing one, and also multiples, values to a method parameters
through the browser URL. In other words, you must simply specify the values, corresponding to the
parameters, into URL and separate them with slashes. But, take care of passing the exact numbers of
values that a method requires as input parameters otherwise, an exception will be thrown. You further
note that the requested method was defined as public. The reason is that only public methods can
be executed.
In fact, if you try to type:
http://localhost/hello_world/say_hello_message/Mark/John
or alsohttp://localhost/hello_world/cant_say_hello
in both cases, you will obtain an exception. The first exception is because we passed wrong numbers of
values, Mark and John, to the single parameter $message designed
into the method sayHelloMessage while the second one regards the access denied that occur
any time we try to call from the URL a protected method, like cantSayHello.
This page exposes to you how simple is to start coding with WebMVC in accordance with the OOP programming. Just design and write your application in terms of concrete Controller classes and public methods. Then WebMVC let you execute them as common HTTP requests. Technically speaking, it means that every valid HTTP request performed by a user will match the execution of an action managed by a controller. The figure below illustrates this behavior:

In the next page, we expose how you can handle HTTP GET/POST requests.
In the previous page, we saw how to pass values using methods and parameters of a controller. However, the Hypertext Transfer Protocol (HTTP) is designed to enable communications between clients and servers. HTTP works as a request-response protocol between a client and server. A web browser may be the client, and an application on a computer that hosts a website may be the server.
Example: A client (browser) submits an HTTP request to the server; then the server returns a response to the client. The response contains status information about the request and may also contain the requested content.
Two commonly used methods for a request-response between a client and server are GET and POST.
Both GET and POST methods are able to send to the server a query string containing name/value pairs that must be processed by a resource (that is a controller) residing on the server.
Note that the query string (name/value pairs) is sent in the URL of a GET request:
http:/localhost/hello_world.php?name=Mark&skill=Developer
Usually, HTTP GET requests are sent through the browser URL bar or by HTML links.
Note that the query string (name/value pairs) is sent in the HTTP message body of a POST request:
POST /hello_world.php HTTP/1.1
Host: localhost
name=Mark&skill=Developer
Usually, HTTP POST requests are submitted by using HTML forms.
PHP provides:
Inside a Controller, you can use both of these arrays for handling HTTP GET and/or POST requests.
In
the following example, we added the method sayWhatYouGet to HelloWorld for
showing you how using $_GET for handling HTTP GET requests:
<?php
namespace controllers;
use framework\Controller;
class HelloWorld extends Controller
{
public function sayHello()
{
echo "Hello world";
}
public function sayHelloMessage($message)
{
echo "Hello $message";
}
/**
* A simple method for showing of $_GET processing
*/
public function sayWhatYouGet()
{
echo "You get the following requests:<br>";
foreach($_GET as $get_variable => $value) {
echo "$get_variable = $value <br>";
}
}
protected function cantSayHello()
{
echo "This method cannot be called from Url";
}
}
Now, to execute the sayWhatYouGetmethod in conjunction with an HTTP GET request containing
some data, type:
http://localhost/hello_world/say_what_you_get?name=Mark&skill=Developer
You will get the following results:
You get the following requests:
name = Mark
skill =
Developer
Handling HTTP POST by using $_POST array can be done in a similar way: you need to replace it instead of
$_GET in the code above. Then, to execute the sayWhatYouGetmethod in conjunction with an
HTTP POST you can use a tool like Linux CURL (for emulating a POST request of HTML form) and type:
curl --data "name=Mark&skill=Developer" -H "Content-Type: application/x-www-form-urlencoded" -X POST http://localhost/hello_world/say_what_you_get
Note: instead of using S_GET or $_POST in the code above you can also use the $_REQUEST, the PHP associative array that by default contains the contents of $_GET, $_POST (and also $_COOKIE).
Be careful when using the values contained in $ _GET and $ _POST because they come from external users
and may contain malicious data. You always must sanitize data from $_GET and $_POST before using it.
Sanitize
your data depending on what it's being used for and, by using different functionalities provided by
PHP:
If you are inserting data into the database then use mysql_real_escape_string() for
quoting strings and typecasting for numbers would be the way to go (or ideally use "prepared
statements"). Regarding database, WebMVC provides the autogeneration of special ORM classes
equipped with sanitizing functionalities.
If you plan on outputting the data onto the webpage then we would recommend something like the
PHP htmlspecialchars(). WebMVC provides a special function, setVar, that
automatically includes this capability.
About sending emails or HTML forms, the following should suffice:filter_var($_POST['variable'],
FILTER_SANITIZE_CONSTANT)
In this case, WebMVC provides the Record
Component that automatically includes this functionality.
All this does is basically "strip tags" and "encode" the special characters.
We
just said that WebMVC provides some functionalities for automatically sanitize data in the proper way.
We will discuss later these arguments when we will show you the View, ORM and the Record component.
Furthermore, there is no correct way to do blanket sanitation. What sanitation method you need depends on what is done to the data. Sanitize the data directly before it is used.
You learned how using HTTP GET and POST to passing values to the Controller. Depending on your needs, you are able to use both HTTP GET/POST request and HTTP request of a method/parameters of a Controller for handling some values to be processed.
In the next page, we expose some advantages deriving from the conjunction of OOP and WebMVC
In OOP we build classes following the principle of the single responsibility
that states that every module or class should have responsibility over a single part of the
functionality provided by the software and that responsibility should be entirely encapsulated by the
class.
In this section, you will learn how to use the OOP inheritance and method overriding to
handle, generalize, reuse and extend a controller responsibility. Although all the following examples
are focused on the Controller, all of the concepts inherent the OOP can also be applied to the
development of the View and Model classes of WebMVC (which we will discuss later).
In the previous
example, we used the OOP inheritance to take the advantages of extending the "abstract
responsibilities" of framework\Controller class to "custom and
specialized responsibilities" of the concrete controllers\HelloWorld class.
Now
we will give you another example regarding another OOP feature: method overriding, but
before you must know that:
Technically speaking, the main responsibility of a WebMVC Controller is to implement some application logic and to expose it through an interface to be called like a common HTTP request. Controller application logic has the main role to establish automatic cooperation among two external classes: View and Model we will discuss later but, right now, you must take into consideration an important aspect of WebMVC architecture: anytime you invoke from HTTP a controller execution, its default, and automatic behavior is to connect a View and a Model. Then WebMVC will show you the GUI design provided by the connected View.
To see in action this behavior, first reconsidering the previous controllers\HelloWord:
<?php
namespace controllers;
use framework\Controller;
class HelloWorld extends Controller
{
public function sayHello()
{
echo "Hello World";
}
}
But now, instead of typing http://localhost/hello_world/say_hello, like we made in the
previous example, just invoking HelloWord without requesting any method execution. Type:
http://localhost/hello_world
By now we are requesting the execution of the HelloWorld standard behavior, supplied by its __construct(),
and we will obtain an exception:
framework\exceptions\NotInitializedViewException
Are you surprised? That happens because, by typing http://localhost/hello_world, we invoke
the controller\HelloWord standard behavior inherited from its parent: the __construct()
method which is defined and built into the abstract framework\Controller class.
The
parent __construct(), implements the following behavior: it uses a generic and null View
when it does not have any reference to a custom instance of it. It does the same for the Model. But,
when WebMVC tries to show the View it throws an exception because the design of a generic null View, by
default, is not initialized. In the example, we have an uninitialized design because we are just echoing
a message rather than printing an HTML GUI design.
Fortunately, by using the OOP method overriding we can build an extended version, we call it controllers\EchoController,
of framework\Controller that will implement an "overridden" behavior with the
purpose of avoiding the exception when we don't want use any GUI design.
Take a look at the
following class:
<?php
namespace controllers;
use framework\Controller;
class EchoController extends Controller
{
/**
* @override framework\Controller __construct()
*/
public function __construct()
{
parent::__construct();
$this->hookViewInitialization();
}
/**
* A custom hook to initialize the design managed by the View.
* @note: We use replaceTpl to initialize design to a space when it is Null
*/
protected function hookViewInitialization()
{
$this->view->replaceTpl(" ");
}
}
In this version, we override the standard parent behavior by building (and automatically calling) a hook
to the View initialization, because we haven't the need of using a GUI design. You must don't
take care, right now, of hookViewInitialization implementation. Simply you must consider
that by calling it we are always able to initialize the View avoiding the exception.
So with the
availability of controllers\EchoController, in witch a GUI design is always initialized, we
can now refactor the previous controllers\HelloWorld in this way:
<?php
namespace controllers;
use controllers\EchoController;
class HelloWorld extends EchoController
{
public function sayHello()
{
echo "Hello World";
}
}
Now by making the request http://localhost/hello_world no exception will be thrown.
Finally,
if you want to automatically show the echo message by using the previous request, override the
__construct in this way:
<?php
namespace controllers;
use controllers\EchoController;
class HelloWorld extends EchoController
{
/**
* @override controllers\EchoController __construct()
*/
public function __construct()
{
parent::__construct();
echo "Hello World";
}
/**
* Note:
* We don't need of sayHello() now because
* we put an echo message in the constructor
*/
}
In this section, you learned how to apply OOP for extending and overriding a controller behavior. You
also learned how you can use the __construct to automatically execute some code when
instantiating a controller
In the next section, we will speak about interesting feature regarding automatic code execution of a controller: the autorun method.
We learned how, by using the __construct method of the controller, we can implement some
actions to be automatically executed. However, having in some circumstances the goal of managing complex
web pages, we could involve mixing, when writing the code for the constructor, of some generics actions
together with more specialized ones. The autorun method gives you the ability to separate,
outside the controller constructor, the coding of those specialized actions that must be automatically
executed. As result of this separation, you will obtain a smart reuse of a controller any times you will
need to extend it to a more specialized behavior.
First, consider the following and simple extension of the previous
controllers\EchoController, we call it controllers\WebPageProductsList and we
use it for simulating the behavior that must be executed automatically inside a web page having the
responsibility of showing a list of products for a hypothetical e-commerce application.
<?php
namespace controllers;
use controllers\EchoController;
class WebPageProductsList extends EchoController
{
/*
* @override controllers\EchoController __construct()
*/
public function __construct()
{
echo "Building page navigation bar <br>";
echo "Building page status bar <br>";
echo "Building page credits information <br>";
echo "Building products list <br>";
parent::__construct();
}
}
We are simulating a page having a specialized responsibility to show a section containing products list.
The page also shows many sections that should be shared across the different pages of the e-commerce
application. These sections are the site navigation bar, the status bar, and credit information.
Finally, we emulated the output of the page that shows the products list just by printing one message
respectively for each section.
Now suppose we need a new web page, we call it controllers\WebPageProductDetail,
that must show the same generics section regarding navigation, credits information and status bar but it
must show a product detail rather than the products list.
We can code controllers\WebPageProductDetail
in this way:
<?php
namespace controllers;
use controllers\EchoController;
class WebPageProductDetail extends EchoController
{
/*
* @override controllers\EchoController __construct()
*/
public function __construct()
{
echo "Building page navigation bar <br>";
echo "Building page status bar <br>";
echo "Building page credits information <br>";
echo "Building product detail<br>";
parent::__construct();
}
}
Now try to type the following HTTP requests to show the results:
http://localhost/web_page_products_list
andhttp://localhost/web_page_product_detail
You will get the following results:
Building page navigation bar
Building page status bar
Building
page credits information
Building products list
and
Building page navigation bar
Building page status bar
Building
page credits information
Building product detail
Although these implementations are both correct, it is certainly not the most efficient way to write
their code. In fact, all the two classes contain parts of repeated code but necessary to carry out the
(shared) generic actions for computing the navigation bar, the credits information, and the status
bar.
By using autorun, in conjunction with OOP extension, you can code better versions of previous
controllers. See the code below:
<?php
namespace controllers;
use controllers\EchoController;
class WebPageProductsList extends EchoController
{
/*
* @override controllers\EchoController __construct()
*/
public function __construct()
{
echo "Building page navigation bar <br>";
echo "Building page status bar <br>";
echo "Building page credits information <br>";
parent::__construct();
}
/**
* @override framework\Controller autorun()
*/
protected function autorun($parameters = null)
{
echo "Building products list <br>";
}
}
<?php
namespace controllers;
use controllers\WebPageProductsList;
class WebPageProductDetail extends WebPageProductsList
{
/**
* @override controllers\WebPageProductsList autorun()
*/
protected function autorun($parameters = null)
{
echo "Building product detail <br>";
}
}
In this version, we coded a parent plus a child controller. Then we shared the generic actions built
inside the parent constructor leaving to the autorun method the responsibility for implementing,
respectively, the different and specialized behavior of each controller.
So by running these two
controllers, you will get the same result as above because what will happen will be:
controllers\WebPageProductsList
controllers\WebPageProductDetail
Finally, you understand the Controller and some advantages of using OOP and of the method autorun. With
this premise, now we want to show you how you can build HelloWorld in a more efficient way.
First of all, we customizing the generic behavior of the abstract framework\Controller by
writing a reusable abstract Controller we can use any time having the need of printing out a simple text
message. We call it controllers\EchoWebPage;
<?php
namespace controllers;
use framework\Controller;
abstract class EchoWebPage extends Controller
{
/**
* @override framework\Controller __construct().
*/
public function __construct()
{
parent::__construct();
$this->view->replaceTpl(" ");
}
}
Now, by having an abstract Controller that implements an "echo behavior" without throwing any exceptions and, also, having a Hook (provided by autorun) to a logic that can be automatically executed, we can write the final and well engineered release of HelloWorld:
<?php
namespace controllers;
class HelloWorld extends EchoWebPage
{
/**
* @override autorun()
*/
protected function autorun($parameters = null)
{
echo "Hello World";
}
}
Note that in the above controllers\HelloWorld we are extending and concretizing the abstract
controllers\EchoWebPage also by omitting the initial instruction 'use
controllers\EchoWebPage'. That's because both controllers\HelloWorld and contollers\EchoWebPage
are encapsulated in the same controllers namespace (we will discuss its details later).
By typing
http://localhost/hello_world
You (still) will obtain
Hello World
By using the controller autorun you have the ability to automatically execute some custom
code, even located outside its constructor. Then, you can potentially extend a controller just by
writing or overriding the autorun code for extending a parent behavior that must be executed
automatically without the need to override the constructor.
In others terms, you can think about
autorunlike an event that is generated after a controller object creation. So you can hook this event in any child controller, to extend the main responsibility of a parent one without the need to override the constructor.
From Wikipedia
In computer programming, the term hooking covers a range of techniques used to alter or augment the behavior of software components by intercepting function calls or messages or events passed between software components. Code that handles such intercepted function calls, events or messages is called a hook.
Until now we have focused on the WebMVC Controller. To clearly showing its basic features, we have introduced extended versions of it, called EchoController and EchoWebPage, that we built with different design principles. We designed both of them as sub-classes to modify the Controller basic behavior, that is, the interaction with the View and Model. Starting from now we will introduce the use of the View, an essential WebMVC class we need for generating web pages rather than simple text messages.
We are now introducing the concrete class frameworks\View.php which is the WebMVC entity
that provides you all the necessary methods to interact with the HTML pages. You will learn to use it as
an object instance or, when occurring the need to produce complex and dynamic web pages, by extending it
with custom classes designed for your needs.
In MVC Design pattern the View layer has the prior responsibility to manage and show data in graphical structures like HTML page. With WebMVC, this responsibility is managed by a View that operates together with a Template file containing the HTML static design. To use a View you must:
So, when you having the need to show an HTML page rather than a simple message (like we made with the EchoController) you must create a template file containing the HTML. Later you also need to manage the template by creating an object of the concrete class "frameworks\View.php". You also need to build a controller in a way to enabling the execution of the view object previously introduced to produce the output. This because the controller is the only MVC entity that you are able to instantiate and run (by typing an HTTP request).
Pratically:
Create the template templates\home.html.tpl containing the HTML of the web page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Site home page</title>
</head>
<body>
<p>Welcome to the site Home Page</p>
</body>
</html>
Then create the Hello controller controllers\Home.php as follow (pay attention to the
comments):
namespace controllers;
use framework\Controller;
use framework\View;
class Home extends Controller
{
/**
* Home constructor.
* @override framework\Controller __construct()
*/
public function __construct()
{
/**
* A reference to the file: templates/home.html.tpl
* @note Do not to specify the file extension ".html.tpl".
*/
$tplName = "home";
/**
* Set the view with a new object of type framework\View.
* @note: We create the View object by using the template reference.
*/
$this->view = new View($tplName);
/**
* To starting up the standard WebMVC behavior of acting
* cooperation between Controller and the View just
* invoke the parent constructor by passing the current view
*/
parent::__construct($this->view);
}
}
The following figure shows the WebMVC directory tree with files location:

Finally, run the controller by typing the following address into your web browser:
http://localhost/home
You should see the page:

We create an HTML static content into a file and save it in the directory templates. The file
must have a .tpl extension in order to be accepted by WebMVC. Note that the template file must be
written only by using client-side technologies like HTML, JavaScript or CSS
programming languages. This is a constraint specially designed in WebMVC to avoid mixing between
server-side, like PHP, and client-side technologies within a single source code file.
Then, in order
to manage and render out the static HTML design of templates\home.html.tpl, WebMVC let you
use the concrete framework\View class by creating an object of this type. By convention, we specified
the template name in lowercase (see naming
convention specifications we previously discussed).
Finally, as shown in the code, you can automatically use the view object inside controllers\Home.php
by overriding the __construct of the abstract framework\Controller. This practice gives you
the ability to automatically produce the output simply by instantiating form HTTP the controller without
the need of invoking any of its methods.
The purpose of this section is to give you another example regarding the advantages deriving from using
OOP and autorun. Supposing we want to have a "Bootstrap" mobile version of the previous page.
We can do this job simply by extending the controllers\Home.php by creating controllers\HomeBootstrap.php
in which we quickly hook the autorun by loading a different GUI template appositely
designed for mobile devices.
See the code below:
namespace controllers;
use controllers\Home;
class HomeBootstrap extends Home
{
/**
* @override autorun($parameters = null)
*/
protected function autorun($parameters = null)
{
/**
* Replaces the GUI template of the parent with a Bootstrap
* mobile template coded into templates/home.bootstrap.html.tpl
* We used loadCustomTemplate method provided by framework\View
*/
$this->view->loadCustomTemplate("templates/home.bootstrap");
}
}
Now we use Bootstrap for the mobile template of GUI. Note that it is ineffective on the server-side code developed so far thanks to the features of WebMVC that isolate client-side technologies in external template files
<!DOCTYPE html>
<html>
<head>
<title>Site Home Page</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css"
rel="stylesheet" media="screen"
>
</head>
<body>
<div class="jumbotron text-center">
<h1>Welcome to the site Home Page</h1>
</div>
<!-- Bootstrap and jQuery core JS -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>
Now run by typing:
http://localhost/home_bootstrap
You should see the bootstrap mobile version of the homepage

This example shows you how WebMVC, by separating GUI Design, View and Controller and by managing their
cooperation realizes an efficient implementation of the "Separation of Concern". We will
discuss here in depth about this benefit. Right now
consider only the advantage deriving from avoid to mix programming languages into a single source code
when you need to show the static content of a web page rather than simple string
messages.
We also focused on how OOP and even more the controller autorun behavior give you effective
ways to specialize your code.
The figure below shows the View usage

In the next example, we expose how to manage dynamic content. For dynamic content, we define a content inside a web page that is evaluated and generated at runtime, rather than static content we can design at development time inside a template. For this purpose, we can adopt a better practice to using and instantiating the View.
Consider the common situation where you have to manage and show data dynamically on the web pages. You just learned that showing output is the main role of the View. This is still valid also when data to show are dynamical. For this purpose, in this paragraph, we expose a solution for handling dynamic web page by a using static Template, View, and Controller
Look again at the following templates\home.html.tpl, we shown it on the previous
page. You can note we have placed the static placeholder {UserName}. Now supposing we want to assign
to it a value, eg. 'Mark' but the assignment must be dynamically provided at run-time.
<!DOCTYPE html>
<html>
<head>
<title>Site home page</title>
</head>
<body>
<p>Welcome to the site Home Page</p>
<br />
<p>Welcome {UserName}</p>
</body>
</html>
To do this job we procede by creating the following View class we call views\Home.php, which
extends framework\View:
<?php
namespace views;
use framework\View;
/**
* Class views\Home
* Handles the treatment of the placeholder designed
* into templates\home.html.tpl and provides the dynamic page.
*/
class Home extends View
{
/* Contructor.
* Override framework\View __construct() to
* use templates\home.html.tpl as design
*/
public function __construct($tplName = null)
{
$tplName = "home";
parent::__construct($tplName);
}
/* Custom method designed to manage the dynamic content
* of the placeholder {UserName}.
*
* @param string $name The value to assign to {UserName}
*/
public function setUserName($name)
{
// setVar is a method inherited from framework\View
$this->setVar("UserName",$name);
}
}
We are using the method setVar() provided by framework\View to replace a value to
placeholder {UserName}.
Note that, unlike the instance of the abstract framework\View we used to show the static
content in the previous
example, we are now creating a custom class, views\Home.php, that extends framework\View.
The reasons we make so are:
framework\View.
Generally, a custom View should be appositely written anytime you need the treatment of the dynamism of Placeholders and Blocks coded into a Template.
The framework\View provides only abstract behaviors like: showing a static design,
replacing a value to a placeholder, and repeating n times the content of a block. It does not know
anything about a custom logic necessary for providing a dynamic web page. We need to build a custom
View and one or more methods for this purpose, in which we can use all the (abstract)
functionalities provided by its parent framework\View. Note that it's what we have
done with setUserName($name). You can see we used setVar() that is
provided by the parent framework\View.
By implementing a custom View, we are respecting the SOC
principle. Note that the custom views\Home view we used is the only entity enabled to
manage the specialized behavior we expected to obtain from the placeholders or blocks of the custom
templates\home.html.tpl template. If we had chosen to use, inside the Controller, an
instance of framework\View rather than wrote views\Home for handling the
placeholder, probably we had coupled altogether different responsibilities and concerns inside the
Controller.
Then, we modify the controller controllers\Home.php as follow to enable it to
communicate with views\Home.php (pay attention to the comments):
namespace controllers;
use framework\Controller;
use views\Home as HomeView;
/**
* Class controllers\Home
* Handles home HTTP request.
* Provides home web page
*/
class Home extends Controller
{
/**
* Home constructor.
* @override framework\Controller __construct()
*/
public function __construct()
{
/**
* A reference to the file: templates/home.html.tpl
* @note Do not to specify the file extension ".html.tpl".
*/
$tplName = "home";
/**
* Set the view with a new object of type views\Home.
* @note: We create the views\Home object by using the
* template reference.
*/
$this->view = new HomeView($tplName);
/**
* To starting up the standard WebMVC behavior of acting
* cooperation between Controller and the View just
* invoke the parent constructor by passing the current view
*/
parent::__construct($this->view);
/**
* By default, the controller behavior will be
* that to greet a Guest
*/
$this->view->setUserName("Guest");
}
/**
* Handles home/set_user_name/(value) HTTP request.
* Provides greeting to the given value.
*
* @param string $user The value to be greet
* @use views\Home->setUserName($name)
*/
public function userToGreet($user) {
$this->view->setUserName($user);
$this->render();
}
}
The following figure shows the WebMVC directory tree with files location:

Note we used 'Home' name for naming Controller, View, and 'home' for Template. We talked about this on the naming convention page page.
Finally, run the controller by typing the following address into your web browser:
http://localhost/home/user_to_greet/Mark
You should see the page:

You can also run the controller without calling its userToGreet() method. Type:
http://localhost/home/
Now, you should see:

Although this example is very simple, there are still many feasible considerations to do:
setVar() exactly does ?The method setVar($placeholder, $value) provided by framework\View find a given placeholder
in the active template and replace it with a given value.
Bear in mind that:
setVar() method after the view has been initialized in the controller.
framework\View source code:
/**
* Replaces all occurrences of the given placeholder with a given value.
* If the placeholder is contained into a (previously opened) block
* the replacement is made against the opened block.
*
* You can also specify if the given placeholder is enclosed in braces,
* if you need to purify the given value against XSS and CHARSET for the given value
*
* @param string $placeholder The placeholder to find
* @param string $value The value for replacing to founded placeholder
* @param bool|true $useBraces If true (default) the placeholder name contain braces {}
* @param bool $xssPurify If true (default=false) purify the value against XSS
* @param string $charset Charset string for the give value. Default (UTF8) is the CHARSET
* constant value defined into config\application.config.php
*
* @throws VariableNotFoundException. If variable/placeholder was not found
* @throws NotInitializedViewException If template was not loaded
*/
public function setVar($placeholder, $value, $useBraces=true, $xssPurify=false, $charset = CHARSET)
render()?Although you can invoke the render() method from the Controller, in action this is a service
implemented by the View for showing the GUI to the screen.
When you are writing a public method of a
Controller, you need to manually invoke method render() anytime you want to output the GUI
to the screen. Differently, you will not need to invoke it when you are writing a Controller
constructor. The reason is that WebMVC, by default, when you are invoking a Controller without calling
any of its methods, automatically executes render() for you. See the previous controller\Home
source and you will find that we invoke render() inside userToGreet() but
never in __construct();
In this section, we speak about the need of creating a View with the purpose of handling the placeholders and of generating dynamic content.
In the next page, we will introduce the dynamic Blocks handling for generating dynamic pages containing repeated sections
We can extend the idea of dynamic substitution of a placeholder with some value to the case where we have to handle a block of content and we need to perform some actions on it. For this purpose, WebMVC uses the concept of Block.
A Block is nothing more than a piece of code (typically HTML but it can be also Javascript or CSS inside the HTML) delimited by two comments for marking its beginning and ending limit. The content inside a block is usually subject to an action in order to generate a dynamic page in the browser. The block management is a useful feature of WebMVC for computing dynamic actions like:
Supposing we want to show a list of users rather than a single one like we previously done in the controllers\Home.
On the section about Dynamic
Content, we introduced and coded the following templates\users_manager.html.tpl, by
using a block named Users suitable for this purpose.
<!DOCTYPE html>
<html>
<head>
<title>Users list</title>
</head>
<body>
<h1>Users list</h1>
<table>
<thead>
<tr>
<th>User</th>
<th>Email</th>
<tr>
</thead>
<tbody>
<!-- BEGIN Users -->
<tr>
<td>{UserName}</td>
<td>{UserEmail}</td>
</tr>
<!-- END Users -->
</tbody>
</table>
</body>
</html>
As you can guess from the HTML code, the expected dynamic behavior of the web page will be to show a table containing some users. For each user, it will show the username and email.
This means that the HTML contained in the Users block can be considered as a Template pattern that must be dynamical repeated N times, and valued each time with different values representing a user.
In the HTML code, two comments have been added, and they together wrap the block of code that will be
dynamically replaced many times in the HTML file. These comments mark the BEGIN and the END of a block
of name Users. This means that WebMVC will be able to recognize the block.
Now, we can write the code of views\UsersManager and controllers\UsersManager
in order to show a table of users.
First, we code views\UsersManager and save it as views\UsersManager.php
<?php
namespace views;
use framework\View;
class UsersManager extends View
{
/**
* @override framework\View __construct()
*/
public function __construct($tplName = null)
{
if (empty($tplName)) {
$tplName = "/users_manager";
}
parent::__construct($tplName);
}
/**
* Shows the given $user in the block Users
* of tempalates\users_manager.html.tpl
*
* @param array $users Array of users in the format
* array(array('Username'=>,'UserEmai'=>''))
*/
public function setUsersBlock($users)
{
$this->openBlock("Users");
foreach ($users as $user) {
$this->setVar("UserName", $user["UserName"]);
$this->setVar("UserEmail", $user["UserEmail"]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
}
In the view we have created a method setUsersBlock that uses the block Users
and processes it with all the elements contained in the given $users array; specifically,
we:
Invoking the openBlockmethod inherited from framework\View. This
method, behind the scenes, do:
Usersdynamic_contenttemplate_patternsetVar method to be restricted to the
content of template_pattern.
Then, we start a PHP foreach loop on $users. For each element of
$users:
setVar method by valorizing placeholders {UserName}
and {UserEmail} with the values referenced
by the array keys UserName and UserEmail of the current element,
$user, of $usersparseCurrentBlock() which, behind the scenes do:
template_pattern, which now contain data
rather than placeholders, to the content of dynamic_content. Note that,
on each iteration, parseCurrentBlock() will add one user to
dynamic_content. On the ending of forech,dynamic_content` will contain
all users.
template_pattern for using it, once again, on the
next iteration.
foreach evaluates if exist the next element in $users:
foreach backs to _i_ for processing the next
element. This means that placeholders
contained in the (just regenerated) template_pattern are, once again,
ready to be valorized, but now with
the values of the next element of $usersforeach loop exitFinally, by calling the setBlock method, we stop the processing on the opened block
and, behind the scenes, method replaces the text originally enclosed in the block Users
with the text contained into its internal variable dynamic_content
Now we code the controllers\UsersManagerand save it as
controllers\UsersManager.php
<?php
namespace controllers;
use framework\Controller;
use views\UsersManager as UsersManagerView;
class UsersManager extends Controller
{
/**
* @override framework\Controller __construct()
*/
public function __construct()
{
$this->view = new UsersManagerView();
parent::__construct($this->view);
$users = $this->getUsersData();
$this->view->setUsersBlock($users);
}
/**
* Provides users data
*
* @return array Array of users in the
* format array(array('Username'=>,'UserEmai'=>''))
*/
private function getUsersData()
{
$users = array(
array('UserName' => 'Mark', 'UserEmail' => 'mark@email.com'),
array('UserName' => 'Elen', 'UserEmail' => 'elen@email.com'),
array('UserName' => 'John', 'UserEmail' => 'john@email.com')
);
return $users;
}
}
Now you can run the controller:
http://localhost/users_manager
...and you will get the users table (see the page summary below)
In this section, we show how handling the content repetition and valorization of a block. What we have done is:
$users = array(
array('UserName'=>'Mark', 'UserEmail'=>'mark@email.com'),
array('UserName'=>'Elen', 'UserEmail'=>'elen@email.com'),
array('UserName'=>'John', 'UserEmail'=>'john@email.com')
);
templates\users_manager.html,tpl, containing a block and
two placeholders:
| User | |
|---|---|
| <!-- BEGIN Users --> | |
| {UserName} | {UserEmail} |
| <!-- END Users --> | |
views\UsersManager for handling the templatecontrollers\UsersManager for handling the view, users as well
as the HTTP requestshttp//localhost/users_manager, we dynamically produced out:
| User | |
|---|---|
| Mark | mark@email.com |
| Elen | elen@email.com |
| John | john@email.com |
In the next page, we show you how hiding and replacing the content inside a block.
In the previous page, you learned how to dynamically generate content by repeating and valorizing many times a static content of a block. Another interesting feature you can do with a block is the capability to hide or to replace its content.
By supposing that:
templates\users_manager.html.tpl,
statically defined using a block named Users.
For this purpose, we add a new block called ContenUsers in the template. See the template
code below:
<!DOCTYPE html>
<html>
<head>
<title>Users list</title>
</head>
<body>
<h1>Users list</h1>
<!-- BEGIN ContenUsers -->
<table>
<thead>
<tr>
<th>User</th>
<th>Email</th>
<tr>
</thead>
<tbody>
<!-- BEGIN Users -->
<tr>
<td>{UserName}</td>
<td>{UserEmail}</td>
</tr>
<!-- END Users -->
</tbody>
</table>
<!-- END ContenUsers -->
</body>
</html>
The view views\UsersManager will remain the same of the previous example
<?php
namespace views;
use framework\View;
class UsersManager extends View
{
/**
* @override framework\View __construct()
*/
public function __construct($tplName = null)
{
if (empty($tplName)) {
$tplName = "/users_manager";
}
parent::__construct($tplName);
}
/**
* Shows the given $user in the block Users
* of tempalates\users_manager.html.tpl
*
* @param array $users Array of users in the format
* array(array('Username'=>,'UserEmai'=>''))
*/
public function setUsersBlock($users)
{
$this->openBlock("Users");
foreach ($users as $user) {
$this->setVar("UserName", $user["UserName"]);
$this->setVar("UserEmail", $user["UserEmail"]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
}
Now we need to update the controllers\UsersManager by adding two methods:
hideUsers and disallowUsers. See the code:
<?php
namespace controllers;
use framework\Controller;
use views\UsersManager as UsersManagerView;
class UsersManager extends Controller
{
/**
* @override framework\Controller __construct()
*/
public function __construct()
{
$this->view = new UsersManagerView();
parent::__construct($this->view);
$users = $this->getUsersData();
$this->view->setUsersBlock($users);
}
/**
* Provides users data
*
* @return array Array of users in the
* format array(array('Username'=>,'UserEmai'=>''))
*/
private function getUsersData()
{
$users = array(
array('UserName' => 'Mark', 'UserEmail' => 'mark@email.com'),
array('UserName' => 'Elen', 'UserEmail' => 'elen@email.com'),
array('UserName' => 'John', 'UserEmail' => 'john@email.com')
);
return $users;
}
/**
* Hides users list
*/
public function hideUsers()
{
$this->hide("ContenUsers");
$this->render();
}
/**
* Disallows users list
*/
public function disallowUsers()
{
$this->view->openBlock("ContenUsers");
$this->view->setBlock("Sorry, you are not allowed to access users' list");
$this->render();
}
}
Now you can run the controller in three different ways:
1) By running http://localhost/users_manager you will get the following users list:
| User | |
|---|---|
| Mark | mark@email.com |
| Elen | elen@email.com |
| John | john@email.com |
http://localhost/users_manager/hide_users you will get the following output:
3) By running http://localhost/users_manager/disallow_users you will get the following
output:
In this page, you learned how to use the hide($blockName) method for hiding the content
inside a block. You also learned another capability of the setBlock() method. In fact by
calling setBlock($text) and by passing it a text message you can replace the content of an
opened block with the given message.
In the next page, we speak about nesting blocks
There are two general purposes of using the nesting of blocks:
We start by showing you the following templates\nested_blocks.html.tpl
<!DOCTYPE html>
<html>
<head>
<title>Users list</title>
</head>
<body>
<h1>Users list</h1>
{CurrentAction}
<table border="1">
<thead>
<tr>
<th>User</th>
<th>Email</th>
<th>Actions</th>
<tr>
</thead>
<tbody>
<!-- BEGIN Users -->
<tr>
<td>{UserName}</td>
<td>{UserEmail}</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="{GLOBAL:SITEURL}/nested_blocks/do_action/{ActionName}/{UserEmail}">{ActionCaption}</a> </li>
<!-- END UserActions -->
</ul>
</td>
</tr>
<!-- END Users -->
</tbody>
</table>
</body>
</html>
As you can guess from the code above the purpose of this template is to representing the static structure of a table of users and to show, for each user, a set of links for performing some actions, e.g. send email, edit or delete the user data. Note that each user will share the same names of action links. Only links parameters will be different among differnt users.
To achieve this goal, we nested the block UserActions inside the main block
Users we used to show users list. Then we designed inside UserActions the
static representation of an unnumbered list of actions links. Also note that, like we have done for the
user data, we coded only the static representation of one action link by representing a call to doAction()
method of controller\NestedBlocks controller and by passing it two parameters: the action
name and the user email, their respectively designed by using {ActionName} and {UserEmail}
placeholders.
Pay also attention that:
{GLOBAL:SITEURL} for getting the root URL of links that will be
generated at runtime
The following picture shows you the output of the static design in which we highlighted with green the Users block and its inner block UserActions with red:
Figure 1
For dynamically producing the output we also code the following views\NestedBlocks. Pay
attention to comments for understanding the purpose of its methods:
<?php
namespace views;
use framework\View;
class NestedBlocks extends View
{
/**
* @override framework\View __construct()
*/
public function __construct($tplName = null)
{
if (empty($tplName)) {
$tplName = "/nested_blocks";
}
parent::__construct($tplName);
}
/**
* Shows the given $user in the block Users
* of tempalates\nested_blocks.html.tpl
*
* @param array $users Array of users in the format:
* array( array('Username'=>'','UserEmail'=>'') )
*/
public function setUsersBlock($users)
{
$this->openBlock("Users");
foreach ($users as $user) {
$this->setVar("UserName", $user["UserName"]);
$this->setVar("UserEmail", $user["UserEmail"]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
/**
* Shows the given $actions in the block UserActions
* of tempalates\nested_blocks.html.tpl
*
* @param array $actions Array of actions in the format:
* array( array('ActionName'=>'','ActionCaption'=>'') )
*/
public function setUserActionsBlock($actions)
{
$this->openBlock("UserActions");
foreach ($actions as $action) {
$this->setVar("ActionName", $action["ActionName"]);
$this->setVar("ActionCaption", $action["ActionCaption"]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
}
Finally, we code the controllers\NestedBlocks for providing the users' data, handling
links actions, and for interacting with the previous view views\NestedBlocks:
<?php
namespace controllers;
use framework\Controller;
use views\NestedBlocks as NestedBlockView;
class NestedBlocks extends Controller
{
/**
* @override framework\Controller __construct()
*/
public function __construct()
{
$this->view = new NestedBlockView();
parent::__construct($this->view);
$actions = $this->getUserActions();
$this->view->setUserActionsBlock($actions);
$users = $this->getUsersData();
$this->view->setUsersBlock($users);
}
/**
* Set the default behaviour when no actions is performed
*/
protected function autorun($parameters = null)
{
$this->view->setVar("CurrentAction","Please, perform an action on user");
}
/**
* Provides users data.
*
* @return array Array of users in the
* format array( array('Username'=>'','UserEmai'=>'') )
*/
private function getUsersData()
{
$users = array(
array('UserName' => 'Mark', 'UserEmail' => 'mark@email.com'),
array('UserName' => 'Elen', 'UserEmail' => 'elen@email.com'),
array('UserName' => 'John', 'UserEmail' => 'john@email.com')
);
return $users;
}
/**
* Provides users actions.
*
* @return array Array of actions in the format:
* array( array('ActionName'=>'','ActionCaption'=>'') )
*/
private function getUserActions()
{
$userActions = array(
array("ActionName" => "email" ,"ActionCaption" => "Send email"),
array("ActionName" => "edit" ,"ActionCaption" => "Edit information"),
array("ActionName" => "erase","ActionCaption" => "Delete user")
);
return $userActions;
}
/**
* Performs the given action on a given user.
*
* @param string $actionName The action to performs
* @param string $userEmail The user email on which to perform the action
*/
public function doAction($actionName,$userEmail)
{
$currentAction = "Current action: $actionName on user $userEmail";
$this->view->setVar("CurrentAction",$currentAction);
$this->render();
}
}
By running http://localost/nested_blocks you will obtain:
Figure 2
The following picture shows the result after clicking email link of the user Elen:
Figure 3
The following code shows you the HTML dynamically generated after running http://localost/nested_blocks
of Figure 2. You can notice how the two blocks, Usersand UsersActions, were
dynamically valued with the data provided by the two arrays $userActions, and
$user of the controller controllers\NestedBlocks.
<!DOCTYPE html>
<html>
<head>
<title>Users list</title>
</head>
<body>
<h1>Users list</h1>
<h3>Please, perform an action on user</h3>
<table border="1">
<thead>
<tr>
<th>User</th>
<th>Email</th>
<th>Actions</th>
<tr>
</thead>
<tbody>
<!-- BEGIN Users -->
<tr>
<td>Mark</td>
<td>mark@email.com</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/email/mark@email.com">Send email</a> </li>
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/edit/mark@email.com">Edit information</a> </li>
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/erase/mark@email.com">Delete user</a> </li>
<!-- END UserActions -->
</ul>
</td>
</tr>
<tr>
<td>Elen</td>
<td>elen@email.com</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/email/elen@email.com">Send email</a> </li>
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/edit/elen@email.com">Edit information</a> </li>
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/erase/elen@email.com">Delete user</a> </li>
<!-- END UserActions -->
</ul>
</td>
</tr>
<tr>
<td>John</td>
<td>john@email.com</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/email/john@email.com">Send email</a> </li>
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/edit/john@email.com">Edit information</a> </li>
<li><a href="http:/localhost/mvccourse/nested_blocks/do_action/erase/john@email.com">Delete user</a> </li>
<!-- END UserActions -->
</ul>
</td>
</tr>
<!-- END Users -->
</tbody>
</table>
</body>
</html>
In this page, we showed how to code the nesting of blocks for producing a set of multiple values relating to parent data. The examples we showed assumed to share the same set of values but with different parents.
In the next page, we will show you a similar example but with the need of producing a set of custom values related to each parent data.
In this page, we are going to expose a little variation of the previous example. We now consider the need of showing a set of custom values that must be assigned to each user we previously have shown.
Now supposing the need of adding a new column to the previous table containing distinct roles for each user. So we need to rearrange the template templates\nested_blocks.htpl.tpl in the following way:
<!DOCTYPE html>
<html>
<head>
<title>Users list</title>
</head>
<body>
<h1>Users list</h1>
<h3>{CurrentAction}</h3>
<table border="1">
<thead>
<tr>
<th>User</th>
<th>Email</th>
<th>Actions</th>
<th>Roles</th>
<tr>
</thead>
<tbody>
<!-- BEGIN Users -->
<tr>
<td>{UserName}</td>
<td>{UserEmail}</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="{GLOBAL:SITEURL}/nested_blocks/do_action/{ActionName}/{UserEmail}">{ActionCaption}</a> </li>
<!-- END UserActions -->
</ul>
</td>
<td>
<ul>
<!-- BEGIN {UserEmail}Roles -->
<li>{UserRoleName}</li>
<!-- END {UserEmail}Roles -->
</ul>
</td>
</tr>
<!-- END Users -->
</tbody>
</table>
</body>
</html>
In the table header, we simply added a new column containing the caption Role. In the body, we
also added a new column but containing a new block. We assigned the name {UserEmail}Roles
to this block with the purpose of dynamically generate many distinct block name, in the format 'UserEmailRoles',
for how many users will be shown in the table.
You can better understand this result by running http://localhost/nested_blocks. You will
obtain:

Now, if you will give a look inside the source code below, regarding the HTML that was dynamically
generated, you will find these blocks named `mark@email.comRoles,elen@email.comRoles, andjohn@email.comRoles`:
<!DOCTYPE html>
<html>
<head>
<title>Users list</title>
</head>
<body>
<h1>Users list</h1>
<h3>Please, perform an action on user</h3>
<table border="1">
<thead>
<tr>
<th>User</th>
<th>Email</th>
<th>Actions</th>
<th>Roles</th>
<tr>
</thead>
<tbody>
<!-- BEGIN Users -->
<tr>
<td>Mark</td>
<td>mark@email.com</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/email/mark@email.com">Send email</a> </li>
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/edit/mark@email.com">Edit information</a> </li>
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/erase/mark@email.com">Delete user</a> </li>
<!-- END UserActions -->
</ul>
</td>
<td>
<ul>
<!-- BEGIN mark@email.comRoles -->
<li>{UserRoleName}</li>
<!-- END mark@email.comRoles -->
</ul>
</td>
</tr>
<tr>
<td>Elen</td>
<td>elen@email.com</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/email/elen@email.com">Send email</a> </li>
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/edit/elen@email.com">Edit information</a> </li>
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/erase/elen@email.com">Delete user</a> </li>
<!-- END UserActions -->
</ul>
</td>
<td>
<ul>
<!-- BEGIN elen@email.comRoles -->
<li>{UserRoleName}</li>
<!-- END elen@email.comRoles -->
</ul>
</td>
</tr>
<tr>
<td>John</td>
<td>john@email.com</td>
<td>
<ul>
<!-- BEGIN UserActions -->
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/email/john@email.com">Send email</a> </li>
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/edit/john@email.com">Edit information</a> </li>
<li><a href="https://server.local/mvccourse/nested_blocks/do_action/erase/john@email.com">Delete user</a> </li>
<!-- END UserActions -->
</ul>
</td>
<td>
<ul>
<!-- BEGIN john@email.comRoles -->
<li>{UserRoleName}</li>
<!-- END john@email.comRoles -->
</ul>
</td>
</tr>
<!-- END Users -->
</tbody>
</table>
</body>
</html>
Now, by having distinct blocks regarding each user's roles, for dynamically assigning him the
corresponding set of values, we need to rearrange the views\NetsedBlocks by adding the
method setUsersRoles($usersRoles). See the code below and also pay attention to its
comments:
<?php
namespace views;
use framework\View;
class NestedBlocks extends View
{
/**
* @override framework\View __construct()
*/
public function __construct($tplName = null)
{
if (empty($tplName)) {
$tplName = "/nested_blocks";
}
parent::__construct($tplName);
}
/**
* Shows the given $user in the block Users
* of tempalates\nested_blocks.html.tpl
*
* @param array $users Array of users in the format:
* array( array('Username'=>'','UserEmail'=>'') )
*/
public function setUsersBlock($users)
{
$this->openBlock("Users");
foreach ($users as $user) {
$this->setVar("UserName", $user["UserName"]);
$this->setVar("UserEmail", $user["UserEmail"]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
/**
* Shows the given $actions in the block UserActions
* of tempalates\nested_blocks.html.tpl
*
* @param array $actions Array of actions in the format:
* array( array('ActionName'=>'','ActionCaption'=>'') )
*/
public function setUserActionsBlock($actions)
{
$this->openBlock("UserActions");
foreach ($actions as $action) {
$this->setVar("ActionName", $action["ActionName"]);
$this->setVar("ActionCaption", $action["ActionCaption"]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
/**
* Shows the given $usersRoles in the block {UserEmail}Roles
* of tempalates\nested_blocks.html.tpl
*
* @param array $usersRoles Array of users roles in the format:
* array ( array("UserEmail"=>'',"UserRoles"=> array(r1,r2...,rn)))
*/
public function setUsersRoles($usersRoles)
{
foreach ($usersRoles as $userRoles ) {
$email = $userRoles["UserEmail"];
$roles = $userRoles["UserRoles"];
$this->openBlock("$email"."Roles");
foreach ($roles as $roleName) {
$this->setVar("UserRoleName", $roleName);
$this->parseCurrentBlock();
}
$this->setBlock();
}
}
}
Finally we udate the controllers\NestedBlocks for providing users' roles data and for
handling the View
<?php
namespace controllers;
use framework\Controller;
use views\NestedBlocks as NestedBlockView;
class NestedBlocks extends Controller
{
/**
* @override framework\Controller __construct()
*/
public function __construct()
{
$this->view = new NestedBlockView();
parent::__construct($this->view);
$actions = $this->getUserActions();
$this->view->setUserActionsBlock($actions);
$users = $this->getUsersData();
$this->view->setUsersBlock($users);
$usersRoles = $this->getUsersRoles();
$this->view->setUsersRoles($usersRoles);
}
/**
* Set the default behaviour when no actions is performed
*/
protected function autorun($parameters = null)
{
$this->view->setVar("CurrentAction","Please, perform an action on user");
}
/**
* Provides users data.
*
* @return array Array of users in the
* format array( array('Username'=>'','UserEmai'=>'') )
*/
private function getUsersData()
{
$users = array(
array('UserName' => 'Mark', 'UserEmail' => 'mark@email.com'),
array('UserName' => 'Elen', 'UserEmail' => 'elen@email.com'),
array('UserName' => 'John', 'UserEmail' => 'john@email.com')
);
return $users;
}
/**
* Provides users actions.
*
* @return array Array of actions in the format:
* array( array('ActionName'=>'','ActionCaption'=>'') )
*/
private function getUserActions()
{
$userActions = array(
array("ActionName" => "email" ,"ActionCaption" => "Send email"),
array("ActionName" => "edit" ,"ActionCaption" => "Edit information"),
array("ActionName" => "erase","ActionCaption" => "Delete user")
);
return $userActions;
}
/**
* Provides users roles.
*
* @return array Array of users roles in the format:
* array ( array("UserEmail"=>'',"UserRoles"=>array(r1,r2...,rn)))
*/
private function getUsersRoles()
{
$usersRoles = array(
array( "UserEmail" => "mark@email.com",
"UserRoles" => array("admin","webmaster","moderator")
),
array( "UserEmail" => "elen@email.com",
"UserRoles" => array("editor","webmaster","user")
),
array( "UserEmail" => "john@email.com",
"UserRoles" => array("user","editor")
)
);
return $usersRoles;
}
/**
* Performs the given action on a given user.
*
* @param string $actionName The action to performs
* @param string $userEmail The user email on which to perform the action
*/
public function doAction($actionName,$userEmail)
{
$currentAction = "Current action: $actionName on user $userEmail";
$this->view->setVar("CurrentAction",$currentAction);
$this->render();
}
}
Now by running http://localhost/nested_blocks you will see the following result:

Keep in mind that when you nesting of blocks you have to manage the correct sequence on how to produce
the repetitions of the data in order to obtain the desired output. In this example, in fact, when coding
the controller __construct, we first generated the data relating to the actions
common to each user. Then we produced the list of users, also producing distinct
blocks for each user's specific roles. Finally, we have enhanced the roles for each
distinct block in the format UserEmailRole. If you try to change this sequence, the result could not be
correct.
In this page, we discussed another dynamic behavior you can obtain when using the nesting of blocks. Although we used the nesting of blocks, or even blocks in general, to produce simple HTML list, you must take in consideration that you can apply them on different GUI components like, for example, options' list, radio buttons, check boxes, divs and so on.
In the next page, we starting to introduce another important entity of MVC design pattern: the Model
In an MVC software architecture, a Model is a component that has the responsibility for data management. In other words, the model maintains a repository of data and provides the methods for data recording and retrieval. It is worthwhile to observe that the decomposition into the three components of an MVC architecture reflects the approach of divide et impera in which the controller assumes the role of coordinator that assigns the tasks of data management and data presentation to the model and view components respectively.
In WebMVC, the instantiation of a model is similar to that of a controller or a view; in fact, it is
sufficient to extend the framework\Model class. As an example, we can further discuss the
problem of showing a list of people in a browser. In the previous
page, the list of users, actions, and roles were taken from the controller; while this could be
convenient when the problem to solve is of small dimension (we could do without the model), it is more
frequent the case where the data are managed by the model. So we can build a news class, models\NestedBlocks,
in this way:
namespace models;
use framework\Model;
class NestedBlocks extends Model
{
/**
* Provides users data.
*
* @return array Array of users in the format:
* array( array('Username'=>'','UserEmai'=>''))
*/
public function getUsersData()
{
$users = array(
array('UserName' => 'Mark', 'UserEmail' => 'mark@email.com'),
array('UserName' => 'Elen', 'UserEmail' => 'elen@email.com'),
array('UserName' => 'John', 'UserEmail' => 'john@email.com')
);
return $users;
}
/**
* Provides users actions.
*
* @return array Array of actions in the format:
* array( array('ActionName'=>'','ActionCaption'=>'') )
*/
public function getUserActions()
{
$userActions = array(
array("ActionName" => "email" ,"ActionCaption" => "Send email"),
array("ActionName" => "edit" ,"ActionCaption" => "Edit information"),
array("ActionName" => "erase","ActionCaption" => "Delete user")
);
return $userActions;
}
/**
* Provides users' roles.
*
* @return array Array of users roles in the format:
* array ( array("UserEmail"=>'',"UserRoles"=>array(r1,r2...,rn)))
*/
public function getUsersRoles()
{
$usersRoles = array(
array("UserEmail" => "mark@email.com",
"UserRoles" => array("admin","webmaster","moderator")
),
array("UserEmail" => "elen@email.com",
"UserRoles" => array("moderator","editor","user")
),
array("UserEmail" => "john@email.com",
"UserRoles" => array("user","editor")
)
);
return $usersRoles;
}
}
By using the new class models\NestedBlocks, in which we coded methods for providing all the
necessary data, we can now refactor the controllers\NestedBlocks by:
models\NestedBlocksgetUsersData(), getUserActions(), and
getUsersRoles() because they are now provided by models\NestedBlocks as
public services.
See the code below for the new version of controllers\NestedBlocks :
<?php
namespace controllers;
use framework\Controller;
use views\NestedBlocks as NestedBlockView;
use models\NestedBlocks as NestedBlockModel;
class NestedBlocks extends Controller
{
/**
* @override framework\Controller __construct()
*/
public function __construct()
{
$this->view = new NestedBlockView();
$this->model = new NestedBlockModel();
parent::__construct($this->view,$this->model);
$actions = $this->model->getUserActions();
$this->view->setUserActionsBlock($actions);
$users = $this->model->getUsersData();
$this->view->setUsersBlock($users);
$usersRoles = $this->model->getUsersRoles();
$this->view->setUsersRoles($usersRoles);
}
/**
* Set the default behaviour when no actions is performed
*/
protected function autorun($parameters = null)
{
$this->view->setVar("CurrentAction","Please, perform an action on user");
}
/**
* Performs the given action on a given user.
*
* @param string $actionName The action to performs
* @param string $userEmail The user email on which to perform the action
*/
public function doAction($actionName,$userEmail)
{
$currentAction = "Current action: $actionName on user $userEmail";
$this->view->setVar("CurrentAction",$currentAction);
$this->render();
}
}
We don't need to update the previuos
views\NestedBlokcs and templates\nested_blocks.html.tpl because they are
already decoupled from control and data logic.
The figure below shows the files structure of model,
view, template, and controller:

So we can run again controllers\NestedBlocks by typing
http://localhost/nested_blocks to obtain the same result of the previous page:

By using Model, the Controller must now take into account the coordination of View and Model following these steps:
$this->view and $this->model to the corresponding
class instances passing them to the constructor of the framework\Controller class
Summary the controller, retrieve the data from the model; then, calling the view, it arranges the presentation. Note that the code of view and the corresponding template are unchanged.
By introducing the Model you can now better understand the WebMVC architecture that separates an application into four layers: Model, View, Template, and Controller.
Model: Model represents the shape of the data and business logic. It maintains
the data of the application. Model objects retrieve and store model state in some data structures
like a database, array and so on.
Model is a data and business logic.
View: View handles the user interface. View display data using Model and
Template to the user and also enables them to submit an update on data. These requests will be later
interceped and managed by the controller.
View is a User Interface logic to provide data
dynamically.
Template: Templates provides the static GUI design. A template is used by the
View to generate dynamic web pages also by consuming data provided by the Model.
Template is the
User Interface design.
Controller: Controller handles the user request. Typically, a user interacts
with View, which in-tern raises appropriate URL request, this request will be handled by a
controller. The controller renders the appropriate view with the model data as a response.
Controller
is a request handler and a coordinator for Model and View.
The following figure summarizes the interaction between Model, View, Template, and Controller.

Having in mind the role of a Model and how to use it in the MVC architecture, we can now introduce the data structures most used by WebMVC Model: MySQL database
WebMVC framework\Model extends PHP \mysqli class for a native interaction with
MySQL. In this page, we will show you the basic steps for creating and connecting to a MySQL database as
well as for the data retrieving.
We can modify the previous example and retrieve the array of users and roles from a database. Before we do so, it must be taken into account that:
framework\Model extends the PHP \mysqli class to interact with
MySQL database
framework\Model also provides you with a custom $sql attribute, the
methods updateResultSet(), and getResultSet() for:
Model->$sql is a class attribute designed to store any valid SQL statement,
e.g a SELECT query, INSERT, UPDATE, DELETE, and more.
Model->updateResultSet() you can execute the SQL statement you
previously stored in the attribute Model->$sqlWith Model->getResultSet() you are able to access the result of the
executed SQL statement by means of Model->updateResultSet().
The result can be one of the following:
for successful SELECT, SHOW, DESCRIBE or EXPLAIN statements (which returning data
rows) it returns a PHP \mysqli_result object. The object will contain
some data rows you can fetch by using some specialized methods it provides, or
better it inherits from parent mysqli class. These methods are (see the
\mysqli_result full documentation here):
mixed fetch_all()
mixed fetch_array()
array fetch_assoc()
object fetch_field()
array fetch_fields()
object fetch_object()
mixed fetch_row()
for other successful SQL statements (which do not return any data rows) it returns TRUE.
\mysqli class, eg. mysqli:query(), mysqli:real_escape_string,
etc. (see the mysqli full documentation here).
config\application.config.php. Specifically, you must
modify the constants DBHOST, DBUSER, DBPASSWORD,
DBNAME, and DBPORT according to your MySQL setting.config\application.config.php regarding MySQL
configuration:
/**
* Defines the constants for MySQL database connection parameters.
*/
/**
* MySQL Host
*/
define("DBHOST","TOUR_DB_HOST");
/**
* MySQL User
*/
define("DBUSER","YOUR_USER");
/**
* MySQL Password
*/
define("DBPASSWORD","YOUR_PASSWORD");
/**
* MySQL Database
*/
define("DBNAME","YOUR_DB_NAME");
/**
* MySQL Port
*/
define('DBPORT', '3306');
In this example, we modify the models\NestedBlocks for enable it to retrieve data from some
database tables.
We assume:
$users shown in the previous example$usersRoles shown in the example beforeThe following figure shows the database schema and tables' relationships:

Note that, when we design the database, we use the snake_case notation (lowercase and _under_scores_), rather the camelCase or PascalCase, for naming convention of tables and fields. This convention is widely adopted for MySQL design. Furthermore, by adopting this convention, WebMVC will provide you with an ORM engine to handle database tables with some specialized classes. We will discuss it later in this page.
To build the required DB schema and data you can use the following mvc_wiki_db.sql MySQL
script:
-- MySQL Script for mvc_wiki database
-- Temporary disabling DB constraints checking
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Create the schema for a simple database named mvc_wiki
-- -----------------------------------------------------
CREATE DATABASE IF NOT EXISTS `mvc_wiki` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `mvc_wiki`;
-- -----------------------------------------------------
-- Create table `user`
-- Stores users information
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `user` (
`user_id` INT NOT NULL AUTO_INCREMENT,
`user_name` VARCHAR(45) NULL,
`user_email` VARCHAR(100) NULL,
PRIMARY KEY (`user_id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Create table `application_role`
-- Stores all available application roles
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `application_role` (
`role_id` INT NOT NULL AUTO_INCREMENT,
`role_name` VARCHAR(45) NULL,
PRIMARY KEY (`role_id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Create table `users_roles`
-- Stores users roles
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `users_roles` (
`user_id` INT NOT NULL,
`role_id` INT NOT NULL,
PRIMARY KEY (`user_id`, `role_id`),
INDEX `fk_user_has_application_role_application_role1_idx` (`role_id` ASC),
INDEX `fk_user_has_application_role_user_idx` (`user_id` ASC),
CONSTRAINT `fk_user_has_application_role`
FOREIGN KEY (`user_id`)
REFERENCES `user` (`user_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_application_role_assigned_to_user`
FOREIGN KEY (`role_id`)
REFERENCES `application_role` (`role_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- Restoring DB constraints checking
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
-- -----------------------------------------------------
-- Sample data for table `user`
-- -----------------------------------------------------
START TRANSACTION;
INSERT INTO `user` (`user_id`, `user_name`, `user_email`) VALUES (1, 'Mark', 'mark@email.com');
INSERT INTO `user` (`user_id`, `user_name`, `user_email`) VALUES (2, 'Elen', 'elen@email.com');
INSERT INTO `user` (`user_id`, `user_name`, `user_email`) VALUES (3, 'John', 'john@email.com');
COMMIT;
-- -----------------------------------------------------
-- Sample data data for table `application_role`
-- -----------------------------------------------------
START TRANSACTION;
INSERT INTO `application_role` (`role_id`, `role_name`) VALUES (5, 'admin');
INSERT INTO `application_role` (`role_id`, `role_name`) VALUES (4, 'webmaster');
INSERT INTO `application_role` (`role_id`, `role_name`) VALUES (3, 'moderator');
INSERT INTO `application_role` (`role_id`, `role_name`) VALUES (2, 'editor');
INSERT INTO `application_role` (`role_id`, `role_name`) VALUES (1, 'user');
COMMIT;
-- -----------------------------------------------------
-- Sample data for table `users_roles`
-- -----------------------------------------------------
START TRANSACTION;
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (1, 5);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (1, 4);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (1, 3);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (2, 3);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (2, 2);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (2, 1);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (3, 2);
INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (3, 1);
COMMIT;
To create the schema on your MySQL database open a command line prompt and type (be sure the mysql excutable file is in your PATH):
mysql -uYOUR_USER -pYOUR_PASSWORD < mvc_wiki_db.sql
Finally, we can modify the models\NestedBlocks by updating getUsersData() and
getUsersRoles() with database access PHP instructions for retrieving information. Pay
attention that we need to returns data retrieved from the DB by using arrays also having the same
formats required by the views\NestedBlocks. For example, the format of
$usersRoles array must be the following:

See the code below for the new version models\NestedBlocks by paying attention to comments:
<?php
namespace models;
use framework\Model;
class NestedBlocks extends Model
{
/**
* Retrieves users from db
*
* @return array|false Array of users in the format:
* array( array('Username'=>'','UserEmai'=>'') )
* Returns false when no data found
*/
public function getUsersData()
{
// Notice:
// - We use PHP HereDoc to specify the SQL string
$this->sql = <<<SQL
SELECT
user_name as UserName,
user_email as UserEmail
FROM
user;
SQL;
// Run the SQL statement and store the result
$this->updateResultSet();
// getResultSet() returns a mysqli_result already with the format
// array( array('Username'=>'','UserEmai'=>'') )
return $this->getResultSet();
}
/**
* Provides users actions.
*
* @return array Array of actions in the format:
* array( array('ActionName'=>'','ActionCaption'=>'') )
*/
public function getUserActions()
{
$userActions = array(
array("ActionName" => "email" ,"ActionCaption" => "Send email"),
array("ActionName" => "edit" ,"ActionCaption" => "Edit information"),
array("ActionName" => "erase","ActionCaption" => "Delete user")
);
return $userActions;
}
/**
* Retrieves users' roles from db.
*
* @return array|false Array of users roles in the format:
* array(array("UserEmail"=>'',"UserRoles"=>array(r1,r2...,rn)))
* Returns false when no data found
*/
public function getUsersRoles()
{
// Notice:
// - We use PHP HereDoc to specify the SQL string
//
// - The SQL below joins tables user and application_role for retrieving
// the values for email and role name of each id stored into the
// users_roles table.
$this->sql = <<<SQL
SELECT
user.user_id,
user.user_email,
application_role.role_name
FROM
user
JOIN users_roles ON ((user.user_id = users_roles.user_id))
JOIN application_role ON ((users_roles.role_id = application_role.role_id))
ORDER BY
application_role.role_id DESC
SQL;
// Run the SQL statement and store the result
$this->updateResultSet();
// Gets the results into a variable for processing
$mySqlResults = $this->getResultSet();
// Initializing an empty array for storing users roles
$usersRoles= array();
if ($mySqlResults) {
while ($row = $mySqlResults->fetch_array()) {
$userId=$row["user_id"];
$userEmail=$row["user_email"];
$userRoleName=$row["role_name"];
// Adds email to $usersRoles array
$usersRoles[$userId]["UserEmail"]=$userEmail;
// Adds role to $usersRoles array
$usersRoles[$userId]["UserRoles"][] = $userRoleName;
}
}
return !empty($usersRoles)? $usersRoles : false;
}
}
So we can run once again controllers\Nested Blocks by typing http://localhost/nested_blocks
to obtain the same result we shown on the previous page, but now by having data
provided by MySQL:

Note that we don't need any updates on the Controller, View, and Template. This is the main purpose of MVC design, that is to separate the computational tasks in different layers also avoiding that, making a change on a layer, involves the need to update the others.
By understanding how to interacting with MySQL we are now potentially ready to build a web application. We finally, described all the steps needed to design and run a MVC instance which provide a dynamic web page. They are:
Pay also attention to the flow of operations when you run an MVC Instance with WebMVC:
Note that, in the flow above, we intentionally omitted to describe Loader and Dispatcher actions because they are automatically executed by WebMVC
The following figure gives a graphical representation of these points:

In the next page, we show you how to INSERT, UPDATE, and DELETE data from a database by using the WEB MVC ORM Engine.
Object-relational mapping (ORM) is a mechanism that makes it possible to address, access and manipulate
objects without having to consider how those objects relate to their database tables.
WebMVC provides
you with a useful tool for the Object Relation Mapping of MySQL.
This tool generates automatically Model classes for any tables of a given database schema.
To generate Model classes to map database tables you need to:
1) Use lowercase with the underscore, which is the widely used MySQL naming notation (formerly named as snake case notation), on your database tables and field names.
2) Configure your database schema by modifying
util\mysqlreflection\mysqlreflection.config.php file and, assigning appropriate values to
DBHOST, DBNAME, DBUSER, DBPASSWORD, and DBPORT PHP constants, according to your MySQL settings.
3) Then, launch the tool by typing:
http/localhost/util/app_create_beans.php
Note that, the GUI of the utility uses Bootstrap and jQuery from CDN. So you also need an internet
connection alive before running it.
4) Once the utility is started, click the "Generate classes" button.
The following figure shows you the startup screen of the utility:

After running the generation of classes you can close the utility. You will find all the generated
classes under models\beans folder.
Notice that:
You can find a class for each table of your MySQL schema.
Each auto-generated class name is prefixed with "Bean" followed by the table name in a PascalCase format. E.g, for the table name users_roles you will find a class named BeanUsersRoles.
Each auto-generated class extends framework\Model.php, so you can relate it to a
Controller
Each auto-generated Model, widely known as a Database Bean, provides you with the following:
A constructor for managing a fetched data row from a table or for adding a new one on it
Management for both single or composite Primary Keys
Automatic mapping of the different date formats which may occur between the web application and database
It defines a set of attributes corresponding to the table fields
Setter and Getter methods for each attribute
Setter methods automatically sanitize data against SQL injection
OOP methods for simplifying the DML operations of SELECT, INSERT, UPDATE, and DELETE.
A facility for quickly updating a previously fetched row
Useful methods to obtain table DDL and the last executed SQL statement
Error handling of SQL statements
It uses camelCase and PascalCase naming convention on class, attributes, and methods that were generated to map table and fields
PHPDOC on table, fields, class, attributes, and usage of methods
Notice that ORM doesn't relieve you from a good DB design. This means you must design a good relational database schema, before using the ORM engine provided by WebMVC.
You can use autogenerated database bean classes as a Model or in conjunction with it when coding your MVC applications. On the next page, we explain a a fully functioning DB application and consuming, Model, View ad an autogenerate database bean class.
The purpose of this example is to provide a simple but fully functioning customer management application, and also for exposing all basic concepts of WebMC Framework we discussed right now:
First of all, we need to define the system requirements, they are the following:
CRM User must be
able:
We organized the System Design under the following sections:
First of all, we need to define the Database Design to store and manage customers. In
our system it is very simple, it consists of the single table customer coded below:
--
-- Table `customer`
--
CREATE TABLE `customer` (
`customer_id` int(11) NOT NULL,
`name` varchar(45) NOT NULL,
`email` varchar(100) NOT NULL,
`nationality` varchar(4) DEFAULT NULL,
`assurance` int(1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- PK for table `customer`
--
ALTER TABLE `customer`
ADD PRIMARY KEY (`customer_id`);
--
-- Unique index for email field
--
ALTER TABLE `customer` ADD UNIQUE(`email`);
--
-- AUTO_INCREMENT for table `customer`
--
ALTER TABLE `customer`
MODIFY `customer_id` int(11) NOT NULL AUTO_INCREMENT;
COMMIT;
As you can see in the SQL code above, the customer table stores the name, email,
nationality, and assurance level (listed in system requirements). It also defines an incremental primary
key, required by DB normalization
regarding no duplicate tuples, and a Unique index for the email field (a Non-Functional Requirement).
Note that, when building a database, you should always be compliant with DB design principles.
Due to the simplicity of the system, we made a rapid "System Analysis" for establishing its GUI Design capable of covering all previous system requirements. So, we decided to provide two user scenarios, or better two web pages, for the purpose.

The left side showing the GUI for browsing customers with the ability to select a customer record for editing, or sending a mail easily. There is also a function to add a new record. The right side showing the GUI for a customer record. The same GUI can be used for implementing two different operative mode can be done on a customer record. The first, in the upper left, is regarding the editing mode where the user can show and update data, or delete a customer record previously selected. The second, in the bottom right, is regarding the inserting mode when the user needs to add a new customer to DB.
Under a UML point of view, the right side may be considered as a single Use Case, the customer record, that can be extended with two different features: one regarding inserting, other for editing data.
In conclusion, the GUI Design may be defined with the following two GUI templates:
The first template, on the left, is used for implementing the browsing, the second, on the right, for the customer's record. In the last one, both the insert and editing functions are implemented as extensions on a common section showing form fields. Furthermore, all templates are built with a responsive design (look, for example, at the navigation bar) provided by Bootstrap, a wonderful HTML/CSS/JS web framework for designing amazing Web GUI. You may also note like some UI elements, in both templates, are designed to be shown when some circumstances occurred. For example, the red message "no customer" will be shown only when no customers are stored in the DB. Furthermore, the red section "Errors" or buttons regarding form submission will be respectively processed depending, on the occurrence of a DB error or by analyzing if the record is in inserting or editing mode.
Finally, we provide the Application Design for organizing system development. We define the following two Web MVC Assemblies for implementing the application :
CustomersManager for browsing customersCustomerRecord for customer data manipulation.The implementation details of both assemblies will be exposed in the section below
The following sections contain the template and MVC source code of the CustomersManager
assembly.
file templates\customers_manager.html.tpl
<!DOCTYPE html>
<html>
<head>
<title>Customers Manager</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"
media="screen">
<!-- Fonts Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">CRM Simple</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="#">Home</a></li>
<li class="active"><a href="{GLOBAL:SITEURL}/customers_manager">Customers</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col col-12">
<h1>Customers Manager</h1>
<hr>
<div class="table-responsive-lg">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">Actions</th>
<th scope="col">Customer name</th>
<th scope="col">Email</th>
</tr>
</thead>
<tbody>
<!-- BEGIN CustomersList -->
<tr>
<th scope="row">
<a class="btn btn-info" href="customer_record/open/{CustomerID}">
<i class="fa fa-edit"></i> Edit</a>
<a class="btn btn-warning" href="mailto:{CustomerEmail}">
<i class="fa fa-address-card-o"></i> Email</a>
</th>
<td>{CustomerName}</td>
<td>{CustomerEmail}</td>
</tr>
<!-- END CustomersList -->
</tbody>
<tfoot>
<!-- BEGIN NoCustomers -->
<tr>
<td colspan="3" class="text-danger text-center">
No customer
</td>
</tr>
<!-- END NoCustomers -->
<tr>
<td colspan="3">
<a class="btn btn-primary" href="customer_record"><i class="fa fa-plus"></i> Add a new customer</a>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>
file controllers\CustomersManager.php
namespace controllers;
use framework\Controller;
use framework\Model;
use framework\View;
use models\CustomersManager as CustomersManagerModel;
use views\CustomersManager as CustomersManagerView;
class CustomersManager extends Controller
{
protected $view;
protected $model;
/**
* Object constructor.
*
* @param View $view
* @param Model $mode
*/
public function __construct(View $view=null, Model $model=null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}
/**
* Autorun method. Put your code here for running it after object creation.
* @param mixed|null $parameters Parameters to manage
*
*/
protected function autorun($parameters = null)
{
$customers = $this->model->getCustomers();
$this->view->setCustomersBlock($customers);
}
/**
* Inizialize the View by loading static design of /customers_manager.html.tpl
* managed by views\CustomersManager class
*
*/
public function getView()
{
$view = new CustomersManagerView("/customers_manager");
return $view;
}
/**
* Inizialize the Model by loading models\CustomersManager class
*
*/
public function getModel()
{
$model = new CustomersManagerModel();
return $model;
}
}
The controller just initializes View and Model. Then retrieve customers' data (from Model) to be processed by the View.
file models\CustomersManager.php
namespace models;
use framework\Model;
class CustomersManager extends Model
{
/**
* Object constructor.
*
*/
public function __construct()
{
parent::__construct();
}
/**
* Autorun method. Put your code here for running it after object creation.
* @param mixed|array|null $parameters Additional parameters to manage
*
*/
protected function autorun($parameters = null)
{
}
public function getCustomers()
{
// Notice: we use PHP HereDoc to specify SQL string
$this->sql = <<<SQL
SELECT
customer_id as CustomerID,
name as CustomerName,
email as CustomerEmail
FROM
customer
ORDER BY
name;
SQL;
$this->updateResultSet();
// The mysqli result set already has the format:
// array( array('CustomerID'=>'','CustomerName'=>'','CustomerEmail'=>''),)
return $this->getResultSet();
}
}
The Model just implements the necessary SQL statement for retrieving customers from MySQL database.
file views\CustomersManager.php
namespace views;
use framework\View;
class CustomersManager extends View
{
/**
* Object constructor.
*
* @param string|null $tplName The html template containing the static design.
*/
public function __construct($tplName = null)
{
if (empty($tplName))
$tplName = "/customers_manager";
parent::__construct($tplName);
}
/**
* Render CustomersList Block
*
* @param \mysqli_result $customers
* @throws \framework\exceptions\BlockNotFoundException
* @throws \framework\exceptions\NotInitializedViewException
* @throws \framework\exceptions\VariableNotFoundException
*/
public function setCustomersBlock(\mysqli_result $customers)
{
if ($customers->num_rows > 0) {
$this->hide("NoCustomers");
$this->openBlock("CustomersList");
while ($customer = $customers->fetch_object()) {
$this->setVar("CustomerID", $customer->CustomerID);
$this->setVar("CustomerName", $customer->CustomerName);
$this->setVar("CustomerEmail", $customer->CustomerEmail);
$this->parseCurrentBlock();
}
$this->setBlock();
} else {
$this->hide("CustomersList");
}
}
}
The View renders the customer list by processing
the template Block CustomersList. If no data are retrieved from Model it shows an
information text. To perform this action it uses the block
hiding feature
In the next section, we show you the codes about record management for editing or inserting customers.
The main news is regarding the Model and the auto-generated DataBase Bean class, from the MySQL customer
table, we obtained through the ORM engine we previously discussed
The
database Bean code is shown below
file models\beans\BeanCustomer.php
/**
* Class BeanCustomer
* Bean class for object oriented management of the MySQL table customer
*
* Comment of the managed table customer: Not specified.
*
* Responsibility:
*
* - provides instance constructor for both managing of a fetched table or for a new row
* - provides destructor to automatically close database connection
* - defines a set of attributes corresponding to the table fields
* - provides setter and getter methods for each attribute
* - provides OO methods for simplify DML select, insert, update and delete operations.
* - provides a facility for quickly updating a previously fetched row
* - provides useful methods to obtain table DDL and the last executed SQL statement
* - provides error handling of SQL statement
* - uses Camel/Pascal case naming convention for Attributes/Class used for mapping of Fields/Table
* - provides useful PHPDOC information about the table, fields, class, attributes and methods.
*
* @extends MySqlRecord
* @implements Bean
* @filesource BeanCustomer.php
* @category MySql Database Bean Class
* @package models/bean
* @author Rosario Carvello <rosario.carvello@gmail.com>
* @version GIT:v1.0.0
* @note This is an auto generated PHP class builded with MVCMySqlReflection, a small code generation engine extracted from the author's personal MVC Framework.
* @copyright (c) 2016 Rosario Carvello <rosario.carvello@gmail.com> - All rights reserved. See License.txt file
* @license BSD
* @license https://opensource.org/licenses/BSD-3-Clause This software is distributed under BSD Public License.
*/
namespace models\beans;
use framework\MySqlRecord;
use framework\Bean;
class BeanCustomer extends MySqlRecord implements Bean
{
/**
* A control attribute for the update operation.
* @note An instance fetched from db is allowed to run the update operation.
* A new instance (not fetched from db) is allowed only to run the insert operation but,
* after running insertion, the instance is automatically allowed to run update operation.
* @var bool
*/
private $allowUpdate = false;
/**
* Class attribute for mapping the primary key customer_id of table customer
*
* Comment for field customer_id: Not specified<br>
* @var int $customerId
*/
private $customerId;
/**
* A class attribute for evaluating if the table has an autoincrement primary key
* @var bool $isPkAutoIncrement
*/
private $isPkAutoIncrement = true;
/**
* Class attribute for mapping table field name
*
* Comment for field name: Not specified.<br>
* Field information:
* - Data type: varchar(45)
* - Null : NO
* - DB Index:
* - Default:
* - Extra:
* @var string $name
*/
private $name;
/**
* Class attribute for mapping table field email
*
* Comment for field email: Not specified.<br>
* Field information:
* - Data type: varchar(100)
* - Null : NO
* - DB Index:
* - Default:
* - Extra:
* @var string $email
*/
private $email;
/**
* Class attribute for mapping table field nationality
*
* Comment for field nationality: Not specified.<br>
* Field information:
* - Data type: varchar(4)
* - Null : YES
* - DB Index:
* - Default:
* - Extra:
* @var string $nationality
*/
private $nationality;
/**
* Class attribute for mapping table field assurance
*
* Comment for field assurance: Not specified.<br>
* Field information:
* - Data type: int(1)
* - Null : YES
* - DB Index:
* - Default:
* - Extra:
* @var int $assurance
*/
private $assurance;
/**
* Class attribute for storing the SQL DDL of table customer
* @var string base64 encoded $ddl
*/
private $ddl = "Q1JFQVRFIFRBQkxFIGBjdXN0b21lcmAgKAogIGBjdXN0b21lcl9pZGAgaW50KDExKSBOT1QgTlVMTCBBVVRPX0lOQ1JFTUVOVCwKICBgbmFtZWAgdmFyY2hhcig0NSkgTk9UIE5VTEwsCiAgYGVtYWlsYCB2YXJjaGFyKDEwMCkgTk9UIE5VTEwsCiAgYG5hdGlvbmFsaXR5YCB2YXJjaGFyKDQpIERFRkFVTFQgTlVMTCwKICBgYXNzdXJhbmNlYCBpbnQoMSkgREVGQVVMVCBOVUxMLAogIFBSSU1BUlkgS0VZIChgY3VzdG9tZXJfaWRgKQopIEVOR0lORT1Jbm5vREIgREVGQVVMVCBDSEFSU0VUPXV0Zjg=";
/**
* setCustomerId Sets the class attribute customerId with a given value
*
* The attribute customerId maps the field customer_id defined as int(11).<br>
* Comment for field customer_id: Not specified.<br>
* @param int $customerId
* @category Modifier
*/
public function setCustomerId($customerId)
{
// $this->customerId = (int)$customerId;
$this->customerId = (int) $this->real_escape_string($customerId);
}
/**
* setName Sets the class attribute name with a given value
*
* The attribute name maps the field name defined as varchar(45).<br>
* Comment for field name: Not specified.<br>
* @param string $name
* @category Modifier
*/
public function setName($name)
{
// $this->name = (string)$name;
$this->name = (string) $this->real_escape_string($name);
}
/**
* setEmail Sets the class attribute email with a given value
*
* The attribute email maps the field email defined as varchar(100).<br>
* Comment for field email: Not specified.<br>
* @param string $email
* @category Modifier
*/
public function setEmail($email)
{
// $this->email = (string)$email;
$this->email = (string) $this->real_escape_string($email);
}
/**
* setNationality Sets the class attribute nationality with a given value
*
* The attribute nationality maps the field nationality defined as varchar(4).<br>
* Comment for field nationality: Not specified.<br>
* @param string $nationality
* @category Modifier
*/
public function setNationality($nationality)
{
// $this->nationality = (string)$nationality;
$this->nationality = (string) $this->real_escape_string($nationality);
}
/**
* setAssurance Sets the class attribute assurance with a given value
*
* The attribute assurance maps the field assurance defined as int(1).<br>
* Comment for field assurance: Not specified.<br>
* @param int $assurance
* @category Modifier
*/
public function setAssurance($assurance)
{
// $this->assurance = (int)$assurance;
$this->assurance = (int) $this->real_escape_string($assurance);
}
/**
* getCustomerId gets the class attribute customerId value
*
* The attribute customerId maps the field customer_id defined as int(11).<br>
* Comment for field customer_id: Not specified.
* @return int $customerId
* @category Accessor of $customerId
*/
public function getCustomerId()
{
return $this->customerId;
}
/**
* getName gets the class attribute name value
*
* The attribute name maps the field name defined as varchar(45).<br>
* Comment for field name: Not specified.
* @return string $name
* @category Accessor of $name
*/
public function getName()
{
return $this->name;
}
/**
* getEmail gets the class attribute email value
*
* The attribute email maps the field email defined as varchar(100).<br>
* Comment for field email: Not specified.
* @return string $email
* @category Accessor of $email
*/
public function getEmail()
{
return $this->email;
}
/**
* getNationality gets the class attribute nationality value
*
* The attribute nationality maps the field nationality defined as varchar(4).<br>
* Comment for field nationality: Not specified.
* @return string $nationality
* @category Accessor of $nationality
*/
public function getNationality()
{
return $this->nationality;
}
/**
* getAssurance gets the class attribute assurance value
*
* The attribute assurance maps the field assurance defined as int(1).<br>
* Comment for field assurance: Not specified.
* @return int $assurance
* @category Accessor of $assurance
*/
public function getAssurance()
{
return $this->assurance;
}
/**
* Gets DDL SQL code of the table customer
* @return string
* @category Accessor
*/
public function getDdl()
{
return base64_decode($this->ddl);
}
/**
* Gets the name of the managed table
* @return string
* @category Accessor
*/
public function getTableName()
{
return "customer";
}
/**
* The BeanCustomer constructor
*
* It creates and initializes an object in two way:
* - with null (not fetched) data if none $customerId is given.
* - with a fetched data row from the table customer having customer_id=$customerId
* @param int $customerId. If omitted an empty (not fetched) instance is created.
* @return BeanCustomer Object
*/
public function __construct($customerId = null)
{
// $this->connect(DBHOST,DBUSER,DBPASSWORD,DBNAME,DBPORT);
parent::__construct();
if (!empty($customerId)) {
$this->select($customerId);
}
}
/**
* The implicit destructor
*/
public function __destruct()
{
$this->close();
}
/**
* Explicit destructor. It calls the implicit destructor automatically.
*/
public function close()
{
// unset($this);
}
/**
* Fetchs a table row of customer into the object.
*
* Fetched table fields values are assigned to class attributes and they can be managed by using
* the accessors/modifiers methods of the class.
* @param int $customerId the primary key customer_id value of table customer which identifies the row to select.
* @return int affected selected row
* @category DML
*/
public function select($customerId)
{
$sql = "SELECT * FROM customer WHERE customer_id={$this->parseValue($customerId,'int')}";
$this->resetLastSqlError();
$result = $this->query($sql);
$this->resultSet=$result;
$this->lastSql = $sql;
if ($result){
$rowObject = $result->fetch_object();
@$this->customerId = (integer)$rowObject->customer_id;
@$this->name = $this->replaceAposBackSlash($rowObject->name);
@$this->email = $this->replaceAposBackSlash($rowObject->email);
@$this->nationality = $this->replaceAposBackSlash($rowObject->nationality);
@$this->assurance = (integer)$rowObject->assurance;
$this->allowUpdate = true;
} else {
$this->lastSqlError = $this->sqlstate . " - ". $this->error;
}
return $this->affected_rows;
}
/**
* Deletes a specific row from the table customer
* @param int $customerId the primary key customer_id value of table customer which identifies the row to delete.
* @return int affected deleted row
* @category DML
*/
public function delete($customerId)
{
$sql = "DELETE FROM customer WHERE customer_id={$this->parseValue($customerId,'int')}";
$this->resetLastSqlError();
$result = $this->query($sql);
$this->lastSql = $sql;
if (!$result) {
$this->lastSqlError = $this->sqlstate . " - ". $this->error;
}
return $this->affected_rows;
}
/**
* Insert the current object into a new table row of customer
*
* All class attributes values defined for mapping all table fields are automatically used during inserting
* @return mixed MySQL insert result
* @category DML
*/
public function insert()
{
if ($this->isPkAutoIncrement) {
$this->customerId = "";
}
// $constants = get_defined_constants();
$sql = <<< SQL
INSERT INTO customer
(name,email,nationality,assurance)
VALUES(
{$this->parseValue($this->name,'notNumber')},
{$this->parseValue($this->email,'notNumber')},
{$this->parseValue($this->nationality,'notNumber')},
{$this->parseValue($this->assurance)})
SQL;
$this->resetLastSqlError();
$result = $this->query($sql);
$this->lastSql = $sql;
if (!$result) {
$this->lastSqlError = $this->sqlstate . " - ". $this->error;
} else {
$this->allowUpdate = true;
if ($this->isPkAutoIncrement) {
$this->customerId = $this->insert_id;
}
}
return $result;
}
/**
* Updates a specific row from the table customer with the values of the current object.
*
* All class attribute values defined for mapping all table fields are automatically used during updating of selected row.<br>
* Null values are used for all attributes not previously setted.
* @param int $customerId the primary key customer_id value of table customer which identifies the row to update.
* @return mixed MySQL update result
* @category DML
*/
public function update($customerId)
{
// $constants = get_defined_constants();
if ($this->allowUpdate) {
$sql = <<< SQL
UPDATE
customer
SET
name={$this->parseValue($this->name,'notNumber')},
email={$this->parseValue($this->email,'notNumber')},
nationality={$this->parseValue($this->nationality,'notNumber')},
assurance={$this->parseValue($this->assurance)}
WHERE
customer_id={$this->parseValue($customerId,'int')}
SQL;
$this->resetLastSqlError();
$result = $this->query($sql);
if (!$result) {
$this->lastSqlError = $this->sqlstate . " - ". $this->error;
} else {
$this->select($customerId);
$this->lastSql = $sql;
return $result;
}
} else {
return false;
}
}
/**
* Facility for updating a row of customer previously loaded.
*
* All class attribute values defined for mapping all table fields are automatically used during updating.
* @category DML Helper
* @return mixed MySQLi update result
*/
public function updateCurrent()
{
if ($this->customerId != "") {
return $this->update($this->customerId);
} else {
return false;
}
}
}
?>
As you can note, the class provides you with all the necessary methods for customer table management. It
also extends the framework\MySqlRecord,and implements the framework\Bean
interface, which are both frameworks facilities for interacting with MySQL, as well as, for classifying
a Database Bean as a Model type could be consumed by an MVC Assembly.
For these reasons, as you can
easily note in the following code regarding the models\CostomerRecord.php, we designed it,
simply by extending the previously showed database Bean, and so we are able to interact with the table
customer (managed by its parent Database Bean)
file models\CustomerRecord.php
namespace models;
use models\beans\BeanCustomer;
class CustomerRecord extends BeanCustomer
{
/**
* Get the list of allowed nationalities for a customer.
*
* @return array Array of nationalities
*/
public function getCustomerNationalitiesList(){
return array (
array ("it","Italian"),
array( "out","Guest")
);
}
/**
* Get the list of allowed assurances level for a customer.
*
* @return array Array of assurances level
*/
public function getCustomerAssurancesList(){
return array (
array ("1","Low"),
array( "2","Middle"),
array( "3","High"),
);
}
}
As you can note, in the code above, we don't have any methods regarding data management like, for example, inserting or updating records. We just defined two methods providing customer nationalities and assurances levels we need when classifying a customer.
The template code is shown below
file templates\customer_record.html.tpl
<!DOCTYPE html>
<html>
<head>
<title>Customer Record</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"
media="screen">
<!-- Fonts Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">CRM Simple</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="#">Home</a></li>
<li class="active"><a href="{GLOBAL:SITEURL}/customers_manager">Customers</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<h1>Customer Record</h1>
{Operation}
<hr>
<form class="form-horizontal" method="post">
<!-- BEGIN DBError -->
<div class="alert alert-danger" role="alert">
{Errors}
</div>
<!-- END DBError -->
<div class="form-group">
<label for="name" class="control-label col-xs-4">Name</label>
<div class="col-xs-8">
<div class="input-group">
<div class="input-group-addon">
<i class="fa fa-user-md"></i>
</div>
<input id="name" name="name" placeholder="Customer name" type="text" required="required"
class="form-control" value="{name}">
</div>
</div>
</div>
<div class="form-group">
<label for="email" class="control-label col-xs-4">Email</label>
<div class="col-xs-8">
<div class="input-group">
<div class="input-group-addon">
<i class="fa fa-address-card-o"></i>
</div>
<input id="email" name="email" placeholder="Customer email" type="email" required="required"
class="form-control" value="{email}">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-4">Nationality</label>
<div class="col-xs-8">
<!-- BEGIN NationalitiesCheckboxes -->
<label class="checkbox-inline">
<input type="radio" name="nationality" value="{nationality}" {is_checked}>
{nationality_text}
</label>
<!-- END NationalitiesCheckboxes -->
</div>
</div>
<div class="form-group">
<label for="assurance" class="control-label col-xs-4">Customer assurance</label>
<div class="col-xs-8">
<select id="assurance" name="assurance" required="required" class="select form-control">
<!-- BEGIN AssuranceOptions -->
<option value="{assurance}" {is_selected}>{assurance_text}</option>
<!-- END AssuranceOptions -->
</select>
</div>
</div>
<div class="form-group row">
<div class="col-xs-offset-4 col-xs-8">
<input type="hidden" name="customer_id" value="{customer_id}">
<!-- BEGIN AddMode -->
<input name="operation_insert" type="submit" class="btn btn-primary" value="Add customer">
<!-- END AddMode -->
<!-- BEGIN EditMode -->
<input name="operation_update" type="submit" class="btn btn-primary" value="Update">
<input name="operation_delete" id="delete" type="submit" class="btn btn-danger" value="Delete customer">
<!-- END EditMode -->
<a href="{GLOBAL:SITEURL}/customers_manager" class="btn btn-info">Close or Cancel</a>
</div>
</div>
</form>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script>
function confirmDelete(){
return confirm("Delete current customer ?");
}
$(document).ready(function() {
$("#delete").click(function () {
return confirmDelete();
});
});
</script>
</body>
</html>
The template designs different blocks we need for managing DB error, nationalities list and of assurances levels, as well as, the buttons manging inserting or editing actions will be submitted by the HTML form. Finally, it also contains the necessary Javascript and Jquery code for handling confirmation message when deleting a record.
Finally, we show the code for controllers\CustomerRecord.php
namespace controllers;
use framework\Controller;
use framework\Model;
use framework\View;
use models\CustomerRecord as CustomerRecordModel;
use views\CustomerRecord as CustomerRecordView;
class CustomerRecord extends Controller
{
protected $view;
protected $model;
/**
* CustomerRecord constructor.
*
* @param View|null $view
* @param Model|null $model
* @throws \framework\exceptions\TemplateNotFoundException
*/
public function __construct(View $view = null, Model $model = null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view, $this->model);
}
/**
* Autorun method. Put your code here for running it after
* object creation.
*
* @param mixed|null $parameters Parameters to manage
*/
protected function autorun($parameters = null)
{
$this->handleFormActionsSubmission();
$this->view->initFormFields($this->model);
}
/**
* Manage open action of a customer record
*
* @param int $customerID The customer id you need to select
* @throws \framework\exceptions\NotInitializedViewException
*/
public function open($customerID)
{
$currentRecord = $this->model->select($customerID);
if (!$currentRecord)
$this->closeAndRedirect();
$this->autorun();
$this->render();
}
/**
* Manage form actions submission.
*
*/
private function handleFormActionsSubmission()
{
if (isset($_POST["operation_update"])) {
$this->handlePostFields();
$this->model->updateCurrent();
}
if (isset($_POST["operation_delete"])) {
$this->model->delete($_POST["customer_id"]);
$this->closeAndRedirect();
}
if (isset($_POST["operation_insert"])) {
$this->handlePostFields();
$this->model->insert();
$this->closeAndRedirect();
}
}
/**
* Handle post fields and setting the corresponding
* model values.
*
*/
private function handlePostFields()
{
$this->model->setName(@$_POST["name"]);
$this->model->setEmail(@$_POST["email"]);
$this->model->setNationality(@$_POST["nationality"]);
$this->model->setAssurance(@$_POST["assurance"]);
}
/**
* Closing and redirecting if no SQL error occurred
*
*/
private function closeAndRedirect()
{
if (!$this->model->isSqlError()) {
header("location:" . SITEURL . "/customers_manager");
}
}
/**
* Init View by loading static design of /customer_record.html.tpl
* managed by views\CustomerRecord class
*
*/
public function getView()
{
$view = new CustomerRecordView("/customer_record");
return $view;
}
/**
* Init Model by loading models\CustomerRecord class
*
*/
public function getModel()
{
$model = new CustomerRecordModel();
return $model;
}
}
The controller, depending on form submission, is able to perform the right action on the database by
using the Model, which is the customer database bean. It interacts with the View below by passing it the
model (look at autorun method). Also, note the default behavior for the controller is to
show the record in Inserting Mode. For handling record update it provides the open method.
Thi method just selects the given customer record and performs a redirection if the customer is not
found in the table, then it executes the autorun method.
file 'views\CustomerRecord.php'
namespace views;
use framework\View;
class CustomerRecord extends View
{
/**
* Object constructor.
*
* @param string|null $tplName The html template containing the static design.
*/
public function __construct($tplName = null)
{
if (empty($tplName))
$tplName = "/customer_record";
parent::__construct($tplName);
}
public function initFormFields(\models\CustomerRecord $model){
$name = isset($_POST["name"]) ? $_POST["name"] : $model->getName();
$email = isset($_POST["email"]) ? $_POST["email"] : $model->getEmail();
$nationality = isset($_POST["nationality"]) ? $_POST["nationality"] : $model->getNationality();
$assurance = isset($_POST["assurance"]) ? $_POST["assurance"] : $model->getAssurance();
$customer_id = isset($_POST["customer_id"]) ? $_POST["customer_id"] : $model->getCustomerId();
$this->setVar("name", $name);
$this->setVar("email", $email);
$this->initCustomerNationalities($model->getCustomerNationalitiesList(),$nationality);
$this->initCustomerAssurances($model->getCustomerAssurancesList(),$assurance);
$this->setVar("customer_id", $customer_id);
if (empty($model->getCustomerId())) {
$this->setVar("Operation", "New Customer");
$this->hide("EditMode");
} else {
$this->setVar("Operation", "Edit Customer");
$this->hide("AddMode");
}
if (!$model->isSqlError()){
$this->hide("DBError");
} else {
$this->setVar("Errors", $model->lastSqlError());
}
}
private function initCustomerNationalities($nationalities,$checkedItem = ""){
$this->openBlock("NationalitiesCheckboxes");
foreach ($nationalities as $nationality) {
$this->setVar("nationality", $nationality[0]);
if ($checkedItem == $nationality[0]) {
$this->setVar("is_checked", "checked");
} else {
$this->setVar("is_checked", "");
}
$this->setVar("nationality_text", $nationality[1]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
private function initCustomerAssurances($assurances, $selectedIdem = ""){
$this->openBlock("AssuranceOptions");
foreach ($assurances as $assurance) {
$this->setVar("assurance", $assurance[0]);
if ($selectedIdem == $assurance[0]) {
$this->setVar("is_selected", "selected");
} else {
$this->setVar("is_selected", "");
}
$this->setVar("assurance_text", $assurance[1]);
$this->parseCurrentBlock();
}
$this->setBlock();
}
}
The View initializes the GUI elements depending on the Model (and by its status) it receives. Look at the
initFormFields method. So behaviors of all GUI elements are depending on inserting or
updating mode, which is strictly related to the database bean status. The status can be expressed with
the following roles:
The example we just discussed is a simple demonstration for the basic features of the Web MVC framework and its ORM engine for easily building of database applications. In the next pages of the current wiki, we expose you how to improve this basic example with advanced functionalities like:
In this section, you will learn about the key design principles and guidelines for software architecture.
Many
of these principles have addressed the development of the framework determining those characteristics of
decomposition that will be illustrated in the following pages. Moreover, the topics covered are useful
to have a general understanding of the architecture that software application should have.
If you are
already familiar with this concepts you can skip
reading of this page.
In this section, you will learn about the key design principles and guidelines for software architecture. Software architecture is often described as the organization or structure of a system, where the system represents a collection of components that accomplish a specific function or set of functions. In other words, architecture is focused on organizing components to support specific functionality. This organization of functionality is often referred to as grouping components into “areas of concern.” Th figure below illustrates common application architecture with components grouped by different areas of concern.

In addition to the grouping of components, other areas of concern focus on the interaction between the components and how different components work together. The guidelines in this page examine different areas of concern that you should consider when designing the architecture of your application.
When getting started with your design, keep in mind the key principles that will help you to create an architecture that adheres to proven principles, minimizes costs and maintenance requirements, and promotes usability and extendibility. The key principles are:
Separation of concerns. Divide your application into distinct features with as little overlap in functionality as possible. The important factor is minimization of interaction points to achieve high cohesion and low coupling. However, separating functionality at the wrong boundaries can result in high coupling and complexity between features even though the contained functionality within a feature does not significantly overlap.
Single Responsibility principle. Each component or module should be responsible for only a specific feature or functionality, or aggregation of cohesive functionality.
Principle of Least Knowledge (also known as the Law of Demeter or LoD). A component or object should not know about internal details of other components or objects.
Don’t repeat yourself (DRY). You should only need to specify intent in one place. For example, in terms of application design, specific functionality should be implemented in only one component; the functionality should not be duplicated in any other component.
Minimize upfront design. Only design what is necessary. In some cases, you may require upfront comprehensive design and testing if the cost of development or a failure in the design is very high. In other cases, especially for agile development, you can avoid big design upfront (BDUF). If your application requirements are unclear, or if there is a possibility of the design evolving over time, avoid making a large design effort prematurely. This principle is sometimes known as YAGNI ("You ain’t gonna need it").
When designing an application or system, the goal of a software architect is to minimize the complexity by separating the design into different areas of concern. For example, the user interface (UI), business processing, and data access all represent different areas of concern. Within each area, the components you design should focus on that specific area and should not mix code from other areas of concern. For example, UI processing components should not include code that directly accesses a data source, but instead should use either business components or data access components to retrieve data.
However, you must also make a cost/value determination on the investment you make for an application. In some cases, you may need to simplify the structure to allow, for example, UI data binding to a result set. In general, try to consider the functional boundaries from a business viewpoint as well. The following high level guidelines will help you to consider the wide range of factors that can affect the ease of designing, implementing, deploying, testing, and maintaining your application.
Keep design patterns consistent within each layer. Within a logical layer, where possible, the design of components should be consistent for a particular operation. For example, if you choose to use the Table Data Gateway pattern to create an object that acts as a gateway to tables or views in a database, you should not include another pattern such as Repository, which uses a different paradigm for accessing data and initializing business entities. However, you may need to use different patterns for tasks in a layer that have a large variation in requirements, such as an application that contains business transaction and reporting functionality.
Do not duplicate functionality within an application. There should be only one component providing a specific functionality—this functionality should not be duplicated in any other component. This makes your components cohesive and makes it easier to optimize the components if a specific feature or functionality changes. Duplication of functionality within an application can make it difficult to implement changes, decrease clarity, and introduce potential inconsistencies.
Prefer composition to inheritance. Wherever possible, use composition over inheritance when reusing functionality because inheritance increases the dependency between parent and child classes, thereby limiting the reuse of child classes. This also reduces the inheritance hierarchies, which can become very difficult to deal with.
Establish a coding style and naming convention for development. Check to see if the organization has established a coding style and naming standards. If not, you should establish common standards. This provides a consistent model that makes it easier for team members to review code they did not write, which leads to better maintainability.
Maintain system quality using automated QA techniques during development. Use unit testing and other automated Quality Analysis techniques, such as dependency analysis and static code analysis, during development. Define clear behavioral and performance metrics for components and sub-systems, and use automated QA tools during the build process to ensure that local design or implementation decisions do not adversely affect the overall system quality.
Consider the operation of your application. Determine what metrics and operational data are required by the IT infrastructure to ensure the efficient deployment and operation of your application. Designing your application’s components and sub-systems with a clear understanding of their individual operational requirements will significantly ease overall deployment and operation. Use automated QA tools during development to ensure that the correct operational data is provided by your application’s components and sub-systems.
Separate the areas of concern. Break your application into distinct features that overlap in functionality as little as possible. The main benefit of this approach is that a feature or functionality can be optimized independently of other features or functionality. In addition, if one feature fails, it will not cause other features to fail as well, and they can run independently of one another. This approach also helps to make the application easier to understand and design, and facilitates management of complex interdependent systems.
Be explicit about how layers communicate with each other. Allowing every layer in an application to communicate with or have dependencies upon all of the other layers will result in a solution that is more challenging to understand and manage. Make explicit decisions about the dependencies between layers and the data flow between them.
Use abstraction to implement loose coupling between layers. This can be accomplished by defining interface components such as a façade with well-known inputs and outputs that translate requests into a format understood by components within the layer. In addition, you can also use Interface types or abstract base classes to define a common interface or shared abstraction (dependency inversion) that must be implemented by interface components.
Do not mix different types of components in the same logical layer. Start by identifying different areas of concern, and then group components associated with each area of concern into logical layers. For example, the UI layer should not contain business processing components, but instead should contain components used to handle user input and process user requests.
Keep the data format consistent within a layer or component. Mixing data formats will make the application more difficult to implement, extend, and maintain. Every time you need to convert data from one format to another, you are required to implement translation code to perform the operation and incur a processing overhead.
A component or an object should not rely on internal details of other components or objects. Each component or object should call a method of another object or component, and that method should have information about how to process the request and, if appropriate, how to route it to appropriate subcomponents or other components. This helps to create an application that is more maintainable and adaptable.
Do not overload the functionality of a component. For example, a UI processing component should not contain data access code or attempt to provide additional functionality. Overloaded components often have many functions and properties providing business functionality mixed with crosscutting functionality such as logging and exception handling. The result is a design that is very error prone and difficult to maintain. Applying the single responsibility and separation of concerns principles will help you to avoid this.
Understand how components will communicate with each other. This requires an understanding of the deployment scenarios your application must support. You must determine if all components will run within the same process, or if communication across physical or process boundaries must be supported—perhaps by implementing message-based interfaces.
Keep crosscutting code abstracted from the application business logic as far as possible. Crosscutting code refers to code related to security, communications, or operational management such as logging and instrumentation. Mixing the code that implements these functions with the business logic can lead to a design that is difficult to extend and maintain. Changes to the crosscutting code require touching all of the business logic code that is mixed with the crosscutting code. Consider using frameworks and techniques (such as aspect oriented programming) that can help to manage crosscutting concerns.
Define a clear contract for components. Components, modules, and functions should define a contract or interface specification that describes their usage and behavior clearly. The contract should describe how other components can access the internal functionality of the component, module, or function; and the behavior of that functionality in terms of pre-conditions, post-conditions, side effects, exceptions, performance characteristics, and other factors.
This guide describes the major decisions that you must make, and which help to ensure that you consider all of the important factors as you begin and then iteratively develop your architecture design. The major decisions, briefly described in the following sections, are:
Choosing the appropriate application type is the key part of the process of designing an application. Your choice is governed by your specific requirements and infrastructure limitations. Many applications must support multiple types of client, and may make use of more than one of the basic archetypes. This guide covers the following basic application types:
In addition, it provides information and guidelines for some more specialist application types. These include the following:
Your application may be deployed in a variety of environments, each with its own specific set of constraints such as physical separation of components across different servers, a limitation on networking protocols, firewall and router configurations, and more. Several common deployment patterns exist, which describe the benefits and considerations for a range of distributed and non-distributed scenarios. You must balance the requirements of the application with the appropriate patterns that the hardware can support, and the constraints that the environment exerts on your deployment options. These factors will influence your architecture design.
When choosing technologies for your application, the key factors to consider are the type of application you are developing and your preferred options for application deployment topology and architectural styles. Your choice of technologies will also be governed by organization policies, infrastructure limitations, resource skills, and so on. You must compare the capabilities of the technologies you choose against your application requirements, taking into account all of these factors before making decisions.
Quality attributes, such as security, performance, and usability, can be used to focus your thinking on the critical problems that your design should solve. Depending on your requirements, you might need to consider every quality attribute covered in this section, or you might only need to consider a subset. For example, every application design must consider security and performance, but not every design needs to consider interoperability or scalability. Understand your requirements and deployment scenarios first so that you know which quality attributes are important for your design. Keep in mind that quality attributes may conflict; for example, security often requires a tradeoff against performance or usability.
When designing to accommodate quality attributes, consider the following guidelines:
Questions you should ask when considering quality attributes include:
Crosscutting concerns represent key areas of your design that are not related to a specific layer in your application. For example, you should consider implementing centralized or common solutions for the following:
The following list describes some of the key crosscutting concerns that you must consider when architecting your applications:
After introducing the basic principles of the Systems' Architectures, we can now describe the key features of WebMVC framework that allow you to apply different levels of decomposition to a software application. These are:
The following table reassumes these concepts and gives you a smart report for consulting the features provided by the framework and also show you their applicability scope. We will discuss them in dept in the next pages:
| System decomposition levels provided by WebMVC Framework with their applicability scope | |
| level | scope |
| OOP |
Logic, computational ad reusable parts that cooperates for producing a goal. Typically are basic
entities of a system
designed with SOLID principles:
|
| SUBSYSTEMS | Composing a system looking at its business roles. Typically, subsystems are physical directories collecting classes. Subsystems are mapped into logical namespaces/packages |
| BUSINESS OBJECTS | Whereas a program may implement classes, which typically end in objects managing or executing behaviors, a business object usually does nothing itself but holds a set of instance variables or properties, also known as attributes, and associations with other business objects, weaving a map of objects representing the business relationships. For example, a "Manager" would be a business object where its attributes can be "Name", "Second name", "Age", "Area", "Country" and it could hold an 1-n association with its employees (a collection of Employee instances). WebMVC let you to automatically generate Business ObjectS from MySQL tables . |
| MVC | Decomposing system scenarios (typically web pages) looking at computer concerns. For example data functions, graphic presentation, flow control and so on. Futhermore with WebMVC, the usage of different types of programming languages is broken down amongst the Model, View, Template, and Controller in order to avoid mixing them within a single code file. |
| HMVC | Decomposing system scenarios looking at the widgetization and reuse of their content |
| LOCALIZATION | Decomposing system scenarios looking at their different language translations |
| CBD | Building system recurring aspects by assembling reusable components |
| ACL and SECURITY | Decomposing system scenarios looking at their different access levels and security |
One of the purposes of WebMVC is to provide tools that allow software developers to take advantage of sound principles when they design and implement complex web applications. An important principle of software engineering is system decomposition that can be used to split out a software system into smaller interacting parts, called subsystems, in order to dominate the system complexity.
In WebMVC, the decomposition of a software can be pursued considering several perspectives. We have
already seen how the splitting into model, view, and controller can be done. MVC is a canonical
architectural pattern that can be applied in a great variety of software applications, and in a certain
sense, we can say that the MVC decomposition pattern can be used for many application domains regardless
of their structure.
Another decomposition perspective concerns how to split a software with respect
to an application domain. Consider, for example, a software system that has the purpose to manage some
fundamental functions of an enterprise such as manufacturingand crm(customers
relationship management); we call it minierp. After the system design phase made by the
software engineer, the subsystems structure can be represented in WebMVC by means of two
fundamental concepts strictly related to each other. They are:
a hierarchy of directories, by which, we can organize the different source code files used to compose the software application
namespaces, groups of related software entities, e.g. classes or interfaces, that each has a unique name or identifier and also a scope in which it was defined
In the broadest definition namespaces are a way of encapsulating items. This can be seen as an abstract concept in many places. For example, in any operating system directories serve to group related files, and act as a namespace for the files within them. As a concrete example, the file foo.txt can exist in both directory /home/greg and in /home/other, but two copies of foo.txt cannot co-exist in the same directory. In addition, to access the foo.txt file outside of the /home/greg directory, we must prepend the directory name to the file name using the directory separator to get /home/greg/foo.txt. This same principle extends to namespaces in the programming world
For each subsystem, WebMVC uses both directories and namespaces:
WebMVC directories and namespaces must mandatory have
For example, if we decide to implement the subsystem manufacturing for the
minierp application we previously introduced, we must define:
controllers\manufacturing - the directory path where to store classes
for the manufacturing subsystem;
controllers\manufacuring - the namespace that we must use when coding
each class of the manufacturing subsystem.
An excerpt of directory structure for the minierp web application is shown in figure 6.1.
We
must mandatory use two decomposition levels for defining the directories structure:
Figure 6.1. An excerpt of the static system decomposition of minierp.

In the minierp software, the initial application domain decomposition is made by the subsystems
crm, and manufacturing; the latter comprises the class Inventory.
Note that the directory controllersis the root directory from which all application
controllers for the defined subsystems can be invoked. This is because in WebMVC the directory
controllers is the entry point to access application software functionalities. You can also note the
replica of application domain directories structure (we did at controllers folder level) within models
directory, views, and templates.
In the Controller page, we have learned how to invoke a controller from the URL according to the format:
http://site/controller
http://site/controller/method/param1/param2/.../paramn
where the automatic conversion from the URL to the class name works, for example, as follows:
http://localhost/hello_world/say_hello_message/Mark => controllers\UserManager->sayHelloMessage('Mark')
We extend this convention in order to call a controller class located within a subsystem using formats like:
http://site/subsystem/controller/method/param1/param2/.../paramn
http://site/subsystem/.../subsystem/controller/method/param1/param2/.../paramn.
An example taken from the minierp web application concerns the presentation of the inventory records
list whose code is located within the subsystem manufacturing/Inventory. It is a
simplified version of a software application that aims at the inventory management of a manufacturing
industry. The inventory table is taken from the database named minierp and is made of the following
attributes:
code -> the record keydescription -> the description of the good maintained in the inventorystock -> quantity in stockThe task to retrieve the inventory records is in charge of the Inventory model:
namespace models\manufacturing;
use framework\Model;
class Inventory extends Model
{
public function getInventory()
{
$this->sql = "SELECT * FROM inventory";
$this->updateResultSet();
return $this->getResultSet();
}
}
Next, the Inventory view class receives the records retrieved by the model and proceeds with
the substitution of the template placeholders contained in /manufacturing/inventory with
the values taken from the records. The Inventory view takes advantage of the concept of block.
namespace views\manufacturing;
use framework\View;
class Inventory extends View
{
public function __construct($tplName = null)
{
if (empty($tplName))
$tplName = "/manufacturing/inventory";
parent::__construct($tplName);
}
public function setInventoryBlock(\mysqli_result $resultset){
$this->openBlock("Parts");
while ($part = $resultset->fetch_object()) {
$this->setVar("code",$part->code);
$this->setVar("description",$part->description);
$this->setVar("stock",$part->stock);
$this->parseCurrentBlock();
}
$this->setBlock();
}
}
The file inventory.html.tpl simply arranges the output in the form of a table. The block
named Parts states how the record retrieved by the inventory table will be rendered in
output one row at a time by the Inventory view.
`html template
<!DOCTYPE html>
| code | description | stock |
|---|---|---|
| {code} | {description} | {stock} |
Finally, the code of the `Inventory controller` coordinates, as usual, the work made by the model and the view. We remark that the function `showInventory()` has to be public; it first invokes the method `getInventory()` from the model, then it passes the result set to the method `setInventoryBlock()` of the view that arranges for the placeholder substitutions with the values contained in the retrieved records.
```php
namespace controllers\manufacturing;
use framework\Controller;
use framework\Model;
use framework\View;
use models\manufacturing\Inventory as InventoryModel;
use views\manufacturing\Inventory as InventoryView;
class Inventory extends Controller
{
public function __construct(View $view=null, Model $model=null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}
public function showInventory() {
$inventoryResultSet = $this->model->getInventory();
$this->view->setInventoryBlock($inventoryResultSet);
$this->render();
}
public function getView()
{
$view = new InventoryView("/manufacturing/inventory");
return $view;
}
public function getModel()
{
$model = new InventoryModel();
return $model;
}
}Assuming that in the table inventory there are data of components necessary to build a digital mouse, we can get the output typing:
http://localhost/minierp/manufacturing/inventory/show_inventory

Subsystems allow splitting software with respect to an application domain. After the system design phase made by the software engineer, the subsystems structure can be represented in WebMVC by means of two fundamental concepts strictly related to each other. They are:
In the next section, you will learn how WebMVC let you apply another pattern for decomposing the content of an application
Into WebMVC package you will find different examples of source code located under the examples
subfolder.
They give you a demonstration of the main WebMVC functionalities, as well as, how to organize software into
subsystems. Subsystems of the provided examples are organized as follow:
examples - which is the main subsystemabout - it contains a simple demonstration of coding a source code information helpercms - this subsystem contains general examples about how showing contents by using WebMVC
db - this subsystem contains some DB related examplesBelow is the directory/files structure:
.
Rember that, due to the MVC design pattern, you will
find a replica of examples folders/files structure also under models, views
and, templates folders.
You can run a demo from here
As we just described in the previous page a subsystem, in WebMVC, is identified at two levels:
examples/cms
identify the subsystem cms which is contained into the main subsystem examples;
examples/cms and must be equal to its pathname. Namespaces
are used in source code for structuring and organizing naming conflicts.
So, for each subsystem, WebMVC uses a directory for physically storing of all its classes and uses a namespace to refer each class when it needs to be instantiated and executed; directories and namespaces must have identical names that are conventionally written in lowercase.
In conclusion, you need to take in mind that there are two decomposition levels when writing code with WebMVC:
- First is the MVC decomposition (directories: controllers, models, views and templates)
- Second is provided by the application subsystems, that is a folders/files structure you need to replicate within the controllers, models, views, as well as, for the templates directory.
Also, remember that the directory controllers are the root directory from which all application controllers for the defined subsystems can be invoked. This is because in WebMVC the directory controllers are the entry point to access application software functionalities.
Inside all levels live WebMVC assemblies. An assembly is represented by a logical name you need to choose to identify the aggregation of the classes for Model, View, and, Controller and also for the HTML. Then when you coding classes for Model, View, and, Controller and also for the HTML you can use the same logical name for storing these files.
You just learned how WebMVC let you decompose an application using subsystems. However, this is not the unique way
for organizing software design in an efficient way.
For introducing a new approach for decomposing a system, we
consider the previous
example, when we showed you the web page for browsing products of an e-commerce application. We discovered
how it can dispose of different sections of content (such as navigation bar, status bar, and credits information)
could be shared with other pages, such as product detail page, cart and so on.
So, in addition of applying a
decomposition by subsystems, we use for logically organize our e-commerce application (we can design subsystems such
as the store, orders, users and so on), we can also design the content of a web page by composing it using different
and small sections. Also, we could reuse each of these sections when they are shared across different pages.
While subsystems provide an efficient way to apply separation of logical application roles, we can use a feature of
WebMVC, named HMVC (Hierarchical MVC), to decompose the application from the point of view of its
"Content".
By assuming that the content of a web page, in WebMVC, is obtained as a result of
the execution of Controller, we can state:
A content of a generic web page that can be designed by using nested and smaller sections of content can be generated by running nested controllers where each controller is responsible to produce one section of the page content.
HMCV is a built-in feature of WebMVC framework that allows you for nesting Controllers in a very simple way for producing nested contents inside a web page. The standard assembly of Model, View (with Template), and Controller will become layered into a "hierarchy of parent-child MVC layers". The image below illustrates how this works:

Each assembly functions independently from one another. An assembly can request access to another WebMVC assembly via their controllers. Both of these points allow the application to be distributed over multiple locations if needed. In addition, the layering of WebMVC assembly allows for a more in-depth and robust application development. This leads to several advantages:
These advantages will allow you to get M.O.R.E out of your application with less headaches.
Let's start the e-commerce application design now!
First of all, we simplify it by assuming we need to develop
just the products list, the product detail page and by sharing among them a simple navigation bar.
Now, take a
look at the following UML diagram we made for representing controller classes relationships:

Note that, just for simplifying, we are only considering controller classes. Models and Views will have a similar
design.
The diagram defines:
framework (obtained from WebMVC)
and e-commerce (we will use it for encapsulating all e-commerce classes). Also, you must remember
that subsystems must be logically encapsulated by using namespaces (in the figure the names preceding colon)
e-commerce subsystem, we design two child subsystems: store and common
respectively used for encapsulating the store classes and the common classes we need to reuse across the
e-commerce application.
store namespace we put ProductsListand ProductDetail controllers
for managing their respective pages
commonnamespace we put NavigationBarcontroller for managing the content needed
for painting a navigation bar
ProductsList contains a NavigationBar. Look at the composition relationship
into the UML diagram.
ProductDetails also contains the previous NavigationBarProductsList, ProductDetail and NavigationBar are controllers
extending the base class Controller provided by WebMC
The file system structure for representing subsystems and classes for controllers is shown in the following figure:

Note that you can imagine having moreover subsystems: users, salesand so on.
As shown in
the figure below, Models, Views, and Templates will have a mirror structure:

You already knew that the Templates folder will contain the HTML files for GUI.
In the following section, we code controllers, and templates by omitting views and models because they are not relevant for this purpose. Let's start by coding first the ProductsList and NavigationBar writing the following files
controllers\ecommerce\store\ProductsList.phpcontrollers\ecommerce\common\NavigationBar.phptemplates\ecommerce\store\products_list.html.tpltemplates\ecommerce\common\navigation_bar.html.tplThe ProductsList controller:
/**
* Class ProductsList
*
*/
namespace controllers\ecommerce\store;
use framework\Controller;
use framework\Model;
use framework\View;
use controllers\ecommerce\common\NavigationBar as NavigationBar;
class ProductsList extends Controller
{
protected $view;
protected $model;
/**
* Object constructor.
*
* @param View $view
* @param Model $mode
*/
public function __construct(View $view=null, Model $model=null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}
/**
* Autorun method is automatically executed after object creation.
* We do the nesting of the navigation bar.
*
* @param mixed|null $parameters Parameters to manage
*
*/
protected function autorun($parameters = null)
{
$navigation = new NavigationBar();
$this->bindController($navigation);
}
/**
* Get the View by using an instance of concrete framework\View class.
* The instance will use the template containing the GUI design stored into
* ecommerce/store/products_list.html.tpl
*/
public function getView()
{
$view = new View("/ecommerce/store/products_list");
return $view;
}
/**
* Get the Model by using an instance of concrete framework\Model class.
*/
public function getModel()
{
$model = new Model();
return $model;
}
}
Pay attention to the folowing lines inside the `autorun() method:
$navigation = new NavigationBar();
$this->bindController($navigation); With this two lines of code, we first create an instance
of NavigationBar (remember we designed the NavigationBar as a child of the root controller
ProducstList). Secondly, we put the instance inside the ProductsList controller simply by
binding it into the GUI of the caller controller (ProductsList). The bind method also
requires a special placeholder that must be present into the GUI template of ProducstList and the
placeholder must be also named equal to the child controller. Look at the following
protucts_list.html.tpl template we designed for ProductsList. You will find the
placeholder we just described named {Controller:ecommerce\common\NavigationBar}:
<!DOCTYPE html>
<html>
<head>
<title>eCommerce Demo - Products list</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
{Controller:ecommerce\common\NavigationBar}
<h1>This is the products list demo page</h1>
<hr>
<table id="" class="table table-hover">
<thead>
<tr>
<th>Product name</th>
<th>Description</th>
<th class="text-right">Price</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td>Mouse</td>
<td>High quality mouse</td>
<td class="text-right">30,45</td>
<td><a href="#">Show detail</a></td>
</tr>
<tr>
<td>Printer</td>
<td>Laserjet 20 pages/mm</td>
<td class="text-right">90,00</td>
<td><a href="#">Show detail</a></td>
</tr>
<tr>
<td>Monitor</t></td>
<td>LCD 23''</td>
<td class="text-right">150,00</td>
<td><a href="#">Show detail</a></td>
</tr>
</tbody>
</table>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>The following figure is the static
output produced by the GUI template in which you will see the placeholder we designed for nesting the NavigationBar
into ProductsList

So to make the example up and running we need also to code the NavigationBar (child) controller:
/**
* Class NavigationBar
*
*/
namespace controllers\ecommerce\common;
use framework\Controller;
use framework\Model;
use framework\View;
class NavigationBar extends Controller
{
protected $view;
protected $model;
/**
* Object constructor.
*
* @param View $view
* @param Model $mode
*/
public function __construct(View $view=null, Model $model=null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}
/**
* Autorun method. Put your code here for running it after object creation.
* @param mixed|null $parameters Parameters to manage
*
*/
protected function autorun($parameters = null)
{
}
/**
* Get the View by using an instance of concrete framework\View class.
* The instance will use the template containing the GUI design stored into
* ecommerce/common/navigation_bar.html.tpl
*/
public function getView()
{
$view = new View("/ecommerce/common/navigation_bar");
return $view;
}
/**
* Get the Model by using an instance of concrete framework\Model class.
*/
public function getModel()
{
$model = new Model();
return $model;
}
}and its GUI template navigation_bar.html.tpl
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">eCommerce Demo</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="">Catalog</a></li>
<li><a href="#">Contact us</a></li>
<li><a href="#">Cart</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">User Profile <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Language settings</li>
<li><a href="?locale=en">English</a></li>
<li><a href="?locale=it-it">Italian</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">User settings</li>
<li><a href="#">Payments</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>The GUI template simply draws:

Finally the following figure shows you the result running https://server/ecommerce/store/products_list
and producing HMVC:

Now, just for concluding the e-commerce example we designed in the previous UML diagram, we show you the necessary
code for implementing the product detail page. Like the previous ProductsList,
ProductDetail will use HMVC for nesting of (the previous and shared) NavigationBar.
The code for ProductDetail controller:
/**
* Class ProductDetail
*
*/
namespace controllers\ecommerce\store;
use framework\Controller;
use framework\Model;
use framework\View;
use controllers\ecommerce\common\NavigationBar as NavigationBar;
class ProductDetail extends Controller
{
protected $view;
protected $model;
/**
* Object constructor.
*
* @param View $view
* @param Model $mode
*/
public function __construct(View $view=null, Model $model=null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}
/**
* Autorun method is automatically executed after object creation.
* We do the nesting of the navigation bar.
*
* @param mixed|null $parameters Parameters to manage
*
*/
protected function autorun($parameters = null)
{
$navigation = new NavigationBar();
$this->bindController($navigation);
}
/**
* Get the View by using an instance of concrete framework\View class.
* The instance will use the template containing the GUI design stored into
* ecommerce/store/products_list.html.tpl
*/
public function getView()
{
$view = new View("/ecommerce/store/product_detail");
return $view;
}
/**
* Get the Model by using an instance of concrete framework\Model class.
*/
public function getModel()
{
$model = new Model();
return $model;
}
}
A very simple GUI template (product_detail.html.tpl) for the product detail ...
<!DOCTYPE html>
<html>
<head>
<title>eCommerce Demo - Product detail</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container">
{Controller:ecommerce\common\NavigationBar}
<h1>This is the product detail demo page</h1>
<hr>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>Running https://server/ecommerce/store/product_detail
you will produce:

The largest practical benefit of using an HMVC architecture is the widgetization of content structures. An example might be comments, ratings, Twitter or blog RSS feed displays, or the display of shopping cart contents across pages of an e-commerce website. It is essentially a piece of content that needs to be displayed across multiple pages, and possibly even in different places, depending on the context of the main HTTP request.
Traditional MVC frameworks generally don't provide a direct answer for these types of content structures, so people generally end up duplicating and switching layouts, using custom helpers, creating their own widget structures or library files, or pulling in unrelated data from the main requested Controller to push through to the View and render in a partial. None of these are particularly good options, because the responsibility of rendering a particular piece of content or loading required data ends up leaking into multiple areas and getting duplicated in the places it is used.
The HMVC feature of WebMVC has the ability to dispatch sub-requests to a Controller to handle these kinds of responsibilities. In this regard, HMVC is really just a natural byproduct of striving for increased code modularity, re-usability, and maintaining a better separation of concerns. This is the selling point of HMVC provided by the framework.
In the next section, you will learn how to create a multi-language application.
Definitions about internationalization and localization are:
Internationalization
1) Commerce: The growing tendency of corporations to operate across national boundaries. 2) Marketing and Computing: An approach to designing products and services that are easily adaptable to different cultures and languages.
Localization
The practice of adjusting a product's functional properties and characteristics to accommodate the language, cultural, political, and legal differences of a foreign market or country.
Like other frameworks, WebMVC provides support to write software applications aiming at reaching a larger audience by means of internationalization and localization. Definition 2) of internationalization is interpreted in WebMVC how the capability to build, with little effort, the GUI of software in different natural languages. This capability allows the presentation of your application to people of different nations or with specific visualization requirements.
The term localization is the counterpart of internationalization. Having a product or service that is ready for the international market, with the term localization we refer to the process that adapts a product or service to meet the needs of a language, culture, or desired population’s “look-and-feel”. From one side, we can say that the internationalization focuses on the structure of your application because it builds several static contents ready to serve people of different nations or cultures. On the other side, the localization process places a user within a context that is near, familiar, and easy to use. It can be regarded as a dynamic aspect that restricts the wide context of a multilinguistic application to the smaller context suitable for the user. It is trivially to observe that the most important part of a localization process is the translation of a word or a text from one language to another, but localization is a bit more. For example, a message could be written in a completely different manner when we write it for a nation rather than another one, even if the message conveys the same semantics.
These aspects are considered by WebMVC by means of a standard way to build multilanguage applications.
In the following figure, we show an example of WebMVC
Assembly, named Localization, that manages a GUI capable to shift the language from a page
written in English to a page written in Italian. The showed example is taken from examples we provide with the
framework and it is located under examples/cms/localization path of controllers, models,
views, and templates directories.
So, by assuming your server is localhost and your project root is webmvcframwork, by
running https://localhost/webmvcframework/examples/cms/localization?locale=en the output will be
showned in English:

By running https://localhost/webmvcframework/examples/cms/localization?locale=it-t the output will be
showned in Italian:

Note we used a URL parameter locale with a given value en or it-it to apply
respectively English or Italian translation of the content.
By running https://localhost/webmvcframework/examples/cms/localization, without locale
parameter, the output will be showned in the default browser language:
WebMVC manages the technicalities of internationalization/localization providing the folder locales
where resource files containing the presentation content can be placed in different subfolders, one for each natural
language. Again, the folder locales have to reflect the structure of system decomposition that we made for our
project examples/cms/controllers.
The following image shows the files structure for controllers,
models, views, templates, and locales

As you can see, insides the folders locales (the blue box) you need to reflect the same system decomposition assigned
to the controllers folder (the red box, as well as models, views, and templates).
In
the blu box, the directories en and it-it contain the resource files for the translation
of the content shown in GUI. In particular, for the welcome page managed by the controller https://localhost/webmvcframework/examples/cms/localization,
the following files:
locales/en/application.txt and locales/it-it/application.txt
contain a list of the resource identifiers that will be used to respectively translate, in English or Italian, and that could also be shared among all controllers of your application
whereas the following files:
locales/en/controllers/Localization.txt and locales/it-it/controllers/Localization.txt
contain a list of the resource identifiers that will be used to respectively translate, in English or Italian, the
page content managed by the controller controllers/examples/cms/Localization.php.
By now, to show you as the resource identifiers are organized and managed by WebMVC for applying translations, in the
following sections, we illustrate the content of all .txt files and of the template file.
Note: we just consider
the resource files regarding English because for Italian, as well as for more other languages you need, logic,
structure, and principles are the same.
The code for HTM template file: template/examples/cms/localization.html.tpl is:
<!DOCTYPE html>
<html>
<head>
<title>Localization example</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" media="screen">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js"></script>
<![endif]-->
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">{RES:ProjectName}</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="">Home</a></li>
<li><a href="#about">{RES:Contacts}</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{RES:Setting} <span class="caret"></span></a>
<ul class="dropdown-menu">
<li class="dropdown-header">{RES:LanguageSettings}</li>
<li><a href="?locale=en">{RES:English}</a></li>
<li><a href="?locale=it-it">{RES:Italian}</a></li>
<li role="separator" class="divider"></li>
<li class="dropdown-header">{RES:GuiSettings}</li>
<li><a href="">{RES:LookAndFeel}</a></li>
</ul>
</li>
<li><a href="..">{RES:Exit}</a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<h1>{RES:Welcome}</h1>
<p>{BodyMessage}</p>
<p>{RES:InfoMessage}</p>
</div>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
</html>In the above template we used a new
type of placeholders defined by the format {RES:PlaceHolderName}.
In the above HTML code they are:
{RES:ProjectName}
{RES:Contacts}
{RES:Setting}
{RES:LanguageSettings}
{RES:English}
{RES:Italian}
{RES:GuiSettings}
{RES:LookAndFeel}
{RES:Exit}
{BodyMessage}
{RES:InfoMessage}
and
{RES:Welcome}Values for this type of placeholders is automatically computed by the framework by using the following criteria:
locale or by the browser
default languageSo, when we running https://localhost/webmvcframework/examples/cms/localization?locale=en WebMVC
framework automatically selects the resource file:
locales/en/controllers/examples/cms/Localization.txt, which contains:
#Comment:Translations for controller Localization
ProjectName=MRP Management System
Contacts=Contact us
Setting=Settings
LanguageSettings=Language settings
English=English
Italian=Italian
GuiSettings=GUI settings
LookAndFeel=Look and Feel
Exit=Exit (TOC)
InfoMessage=Click Settings->Language settings to change language. Traslations are placed into "locales" folder.
as well as the file locales/en/applicaton.txt, which contains:
Welcome=WelcomeAs you can note, these resource files selected contain the values for RES type placeholders of the template.
For example, the resource identifier InfoMessage is linked to the value ”Message from the
localization file: Click Settings->Language settings to change language” that will replace the placeholder
{RES:InfoMessage} appearing in the template
Just a bit more of information about the resource file: you can store in the file application.txt
differents values that you can be shared among many different controllers or use a specific resource file for a
given controller like we made when using Localization.txt for the controller controllers\example\cms\Localizatio.php.
Finally, we show you View and Model source code for Localization example
file models\examples\cms\Localization.php
<?php
namespace models\examples\cms;
use framework\Model;
class Localization extends Model
{
private $pageBodies;
public function __construct()
{
// Simulate a multi language database
$bodiesDb = array(
"it-it" => "Questo è il contenuto della pagina per la lingua italiana.",
"en" => "This is the page objectContent for english language",
);
$this->pageBodies = $bodiesDb;
}
/**
*
* Gets page body
* @param string $locale string identifying LCID
* @return string
*/
public function getBody($locale)
{
if (isset($_REQUEST[LOCALE_REQUEST_PARAMETER])) {
$locale = $_REQUEST[LOCALE_REQUEST_PARAMETER];
}
return $this->pageBodies[$locale];
}
}file views\examples\cms\Localization.php
<?php
namespace views\examples\cms;
use framework\View;
class Localization extends View
{
/**
* Object constructor.
*
* @param string|null $tplName The html template containing the static design.
*/
public function __construct($tplName = null)
{
if (empty($tplName))
$tplName = "/examples/cms/localization";
parent::__construct($tplName);
}
/**
* Sets value for BodyMessage placeholder
*
* @param mixed $value
*/
public function setVarBodyMessage($value)
{
$this->setVar("BodyMessage",$value);
}
}The architecture of WebMVC is designed by following the Separation of Concerns (SOC) design principle. In the next section, we discuss the advantages deriving from SOC as well as by focusing on all possible organizational benefits due to the technologies separation provided by the framework.
In general, SOC is a design principle for separating a computer program into distinct sections, such that each section addresses a separate concern. A concern is a set of information that affects the code of a computer program. A concern can be as general as the details of the hardware the code is being optimized for or as specific as the name of a class to instantiate. MVC, which is a SOC implementation, is a software architectural pattern for user interfaces that divides an application into three interconnected parts. This is done to separate internal representations of information (Model) from the ways information is managed (Controller) and then presented (View) to, and accepted from, the user.
The value of separation of concerns is simplifying development and maintenance of computer programs. When concerns are well-separated, individual sections can be reused, as well as developed and updated independently. Of special value is the ability to later improve or modify one section of code without having to know the details of other sections, and without having to make corresponding changes to those sections.
In general, organizational benefits usually derive from a better organization of work through specialization and coordination. Specialization concerns the division of a work into smaller parts and their assignment to specialized workers. This is a standard practice in modern software development methodologies where the work can proceed in parallel in relatively little increments assigned to software developers and testing activities can be pursued as soon as possible. However, the specialization that comes from the division of work also requires coordination because what has been broken by specialization (subsystem decomposition) has to be reconducted to unity by coordination (system integration).
The advantages deriving from the division of work are possible when we decide to use the MVC architectural pattern provided by WebMVC. Furthermore, the technologies used in each MVC layer are homogeneous (e.g. HTML and Javascript for the Template, PHP for the View and Controller, and PHP with SQL for the Model part). The code reflects the separation of the professional skills necessary to deal with the various aspects of development as shown in the following table. The code is easier to design, implement, verify and maintain, and you can use pre-existing code where appropriate (e.g. by using a pre-built website template). The same information can be presented in several ways (e.g. textual/graphics) and on different devices. Note that the Controller assumes the role of coordinator of View and Model and this easy the system integration activity necessary to build a software system perceived as a unity.
Table Separation of skills and technologies for the development of Web MVC applications.

With WebMVC, the usage of different types of programming languages is broken down amongst the Model, View, Template, and Controller in order to avoid mixing them within a single code file.

In the next sections we speak about an important feature of WebMVC that emphasizes the separation of concerns: Component Based Development
Components-based development (CBD), is a branch of software engineering that emphasizes the separation of concerns with respect to the wide-ranging functionality available throughout a given software system. It is a reuse-based approach to defining, implementing and composing loosely coupled independent components into systems. This practice aims to bring about an equally wide-ranging degree of benefits in both the short-term and the long-term for the software itself and for organizations that sponsor such software. (from wikipedia)
In Sommerville), you can find a discussion about the benefits of component-based software engineering. The following definition of software component is due to Szyperski:
“A software component is a Unit of composition with contractually-specified interfaces and explicit context dependencies only. A software component can be deployed independently and is subject to composition by third parties.”
A widely used definition is due to UML:
“A modular part of a system, that encapsulates its content and whose manifestation is replaceable within its environment. A component defines its behavior in terms of provided and required interfaces".
A component may be replaced by another if and only if their provided and required interfaces are identical. This idea is the underpinning for the plug-and-play capability of component-based systems and promotes software reuse.
For recurring problems occurring during the implementation of data-intensive applications, WebMVC provides software components that can be reused to easy software development. Framework’s components, in fact, realize common Aspects that can occur, in a similar way, into different web applications. Many of these aspects are regarding the database, for example, data listing, data listing with sorting, data listing with filtering, data listing with pagination, record management with common table’s operations regarding select, insert, delete and update operations. The framework offers a set of pre-built components for implementing the necessary server logic for these common database management aspects.
You must keep in mind that, unlike a canonical component that implements a reusable behavior, a component designed for the web must possibly also consider the graphic layout that it will have to expose on the GUI. For this reason, WebMCV components are equipped with specific functions to manage this need, and there are two major advantages for using them:
The first is because each WebMVC component is designed like an MVC Assembly. In fact, it assembles a Controller, Model, View, and a Template. So a developer can easily customize its GUI just by updating its Template according to the needs of the application. The component internal logic will remain fully reusable without the need for any source code modifications.
Because components are designed like MVC assemblies, developers can also use and aggregate many of them into
one parent controller for the purpose of building a complex application page regarding database management. In
the provided examples you will find a typical DB application implemented here (controllers\examples\db\PartListManager)
that uses different components assembled into one root Controller.
Now you learned about the roles and goals of the components, in the this section you will find a detailed description for all WebMVC components
Role-based decomposition is a model for designing security and concurrency in
object-oriented software development environments. In the software development process, the target software system
consists of a large number of components closely related with one another. This results in potential operation
conflicts in security, as well as, cooperative works among the project members. This problem can be much reduced by
decomposing the target software system into the relatively independent assemblies where each one incorporates a
role-based decomposition model to separate operation conflicts frequently occurring during collaboration. So, a
basic WebMVC assembly is also designed for managing role-based access control.
We will' discuss the
implementations for Security and Role-based in the next sections.
WebMVC provides different levels of application security.
Click the following links for details of each one:
WebMVC uses a security model known as RBAC, "Role Based Access Control".
RBAC
establishes that:
a) Every user must be authenticated, identified, and assigned to an application role (i.e. admin, user, power user,
and so on).
b) Afterward, a user, after logging in, can access only web pages that were designed to have
restricted access only to their role.
c) Roles can (or not) restrict user access to web pages. They can also
restrict database record operations, like INSERT, UPDATE, or DELETE.
WebMVC, lets you implement a),b) and, c) by providing you services for:
1) Defining the database tables in which to store: users, credentials, roles (access_level), and assignment of a role to users 2) Implementing a login mechanism for authenticating and identifying users. 3) Implementing a mechanism to establish that the access for execution of given MVC assemblies is allowed only to an authenticated user and/or who has the appropriate role. 4) Limiting database record operations depending on user role
You can use the sql\rbac.sql script to automatically create these tables. The generated tables will also
contain sample data for users and roles.
In the example, data access_level = 100 is for Administrators while 60 is for Managers.
User credentials will be given by its email and password and password will be optionally stored by using md5 or
password_hash one-way encryption algorithm. In sample data, all md5 passwords are equal to "password".
The
figure below shows you the tables diagram:

While tables are used to store the RBAC information regarding users and roles, the framework\User class
provides you with all methods and helpers for handling user status every time you need and from everywhere (inside
of a controller, model, or view).
Specifically, the framework/User.php class will use tables and data for implementing the following
methods that you can/must use during the development of your MVC classes for managing user authentication, login,
logout, and so on (read comments):
First of all "getter" methods:
<?php
/**
* Gets user ID. The id is the primary key
*
* @return int
*/
public function getId()
/**
* Gets user email. Used for credential
*
* @return string
*/
public function getEmail()
/**
* Gets user password. Used for credential
*
* @return string (Optionally encrypted by md5 algo)
*/
public function getPassword()
/**
* Gets user role
*
* @return int The number identifying the user role
*/
public function getRole()
Here are some useful methods to manage user login and logout:
<?php
/**
* Login user
*
* @param string $mail User email
* @param string $password User password
*
* @return bool True if login ok, else false
*/
public function login($email, $password)
/**
* Logout user
*
* @return bool
*/
public function logout()
/**
* Checks if a user is successfully logged in
*
* @return bool True if logged in, else false
*/
public function isLogged()
/**
* Checks if a user is logged in. If false it redirects to a custom link used for showing
* the login form and requiring authentication. If true it redirects to a custom link.
*
* @param null|string $redirect
* The Controller URL for redirecting when the user is not logged in.
* If null it automatically redirects to the default login page.
* @param null|string $returnLink
* The return link is to be used for redirecting if the user is successfully logged in.
* If null it (still) will be the default login page
* @param null|string $LoginWarningMessage
* A custom warning message to show in the login form after
* unsuccessful login
* If null it will be the default message
*
*/
public function checkForLogin($redirect=null, $returnLink=null, $LoginWarningMessage=null)
/**
* Auto-login by using Cookies
*
* @uses ChiperService
* It uses the ChiperService class to decrypt Cookie
*/
public function autoLoginFromCookies()
If you prefer to define and use your custom tables for storing and managing users and roles you must
instruct WebMVC how to find tables for getting information. In this case, it will be necessary to modify the file
config/security.config.php (please read comments)
<?php
/**
* security.config.php
*
* Main application security configuration parameters.
* You can change those values according to your security
* MySQL environment or Chiper preferences
*/
/**
* Defines the constants for MySQL database User table.
* Class User uses this information.
*/
/**
* Constant for the User MySQL Table
*/
define("USER_TABLE", "user");
/**
* Defines a constant for INT Primary Key field of the User MySQL Table
*/
define("USER_ID","id_user");
/**
* Defines a constant for the UNIQUE email field of the User MySQL Table
* Email is used as the credential
*/
define("USER_EMAIL","email");
/**
* Defines a constant for the password field of the User MySQL Table
* Password is used as the credential
*/
define("USER_PASSWORD"," password");
/**
* Defines a constant for the role field of the User MySQL Table
* User role defines access levels criteria managed by RBAC Engine
*/
define('USER_ROLE', 'id_access_level');
/**
* Defines a constant for Administrator role id
*
*/
define('ADMIN_ROLE_ID', 100);
/**
* Defines a constant for the enable field of the User MySQL Table
* User enable field can temporarily disable users.
* Leave blank the value for USER_ENABLED if you don't want to manage the enabling/disabling of users.
* Note: User enable database field value must be 1 or -1
*/
define('USER_ENABLED', 'enabled');
You can protect access and execution of a Controller by using RBAC features. To do this the abstract Controller class of WebMVC provides you with the following methods:
/**
* Restricts on RBAC. User role must have a role contained into RBACL.
*
* @param string $redirect The Controller URL path to redirecting when access is denied.
* If null it redirects to the default login page.
* @param null|string $returnLink The return link after logging in with the default login page
* @param null|string $LoginWarningMessage A custom warning message to show
* @return User
*/
protected function restrictToRBAC($redirect = null, $returnLink = null, $LoginWarningMessage = null)
/**
* Restricts access only to authenticated users
*
* @param string $redirect The Controller URL path to redirecting when the user is not logged in.
* If null it redirects to the default login page.
* @param null|string $returnLink The return link after logging in with the default login page
* @param null|string $LoginWarningMessage A custom warning message to show
* @return User
*/
protected function restrictToAuthentication($redirect = null, $returnLink = null, $LoginWarningMessage = null)
/**
* Grants a user role for access
*
* @param int $role number
*/
protected function grantRole($role)
{
$role = (int)$role;
$this->roleBasedACL[] = $role;
}
So you can restrict access and execution of a Controller only to authenticated users or to users having a specific role.
In controller\examples\cms\InnerBlocks you can find an example of how to implement RBAC. The following
code section illustrates how the access
restriction can be implemented into the __construct class constructor.
/**
* Object constructor.
*
* @param View $view
* @param Model $mode
*/
public function __construct(View $view=null, Model $model=null)
{
$this->grantRole(100); // Administrator
$this->grantRole(60); // Manager (see access_level table)
$this->restrictToRBAC(null,"examples/cms/inner_blocks");
// Alternatively, you can limit access to only the authenticated user, regardless of role
// $this->restrictToAuthentication(null,"examples/cms/inner_blocks");
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}It means that just by writing the first three lines of code you restricted the execution only to
Administrator (role 100) and Manager (60).
So if you try to access to:
http://localhost/examples/cms/inner_blocks
the response will be:
login Controller/Page to specify
your credentials
controller\examples\cms\InnerBlocks (defined with the first
two lines of code into the constructor)
controller\examples\cms\InnerBlocks,
otherwise you will be redirected to the login page and a login warning message will be shown (the message text
is an optional parameter of restrictToRBAC and restrictToAuthentication)
Finally, If you just want to restrict access to authenticated users, regardless of role/access_level assigned to each
user, you can use restrictToAuthentication method in a similar way described before.
To evaluate the user role you can simply use the "getRole" method of "framework\User" and thus determine the correct database operation that you need to implement and that is required by your application. Below is an example of code that you can, arbitrarily, put into a Model (as well as Controller or View) to illustrate how to implement a DB operation depending on the role of the current user logged in
// ...some code before
$user = new framework\User();
$userRole = $user->getRole();
if ($userRole == 100) {
// custom code to allow add or update a record
}
// custom code to read a recordThe components provided by the framework are instances of the abstract class
framework\components\Component, in turn, an instance of the abstract class
framework\Controller; therefore, a component is a full-fledged controller.
In the next page, we
start by showing the first and simple webMVC Component: the DataRepeater
The simpler component made available by WebMVC is framework\components\DataRepeater to easy the
displaying of data coming from a given source. Two possible scenarios where the DataRepeater can be conveniently
used are when:
must be provided in the output according to a given visualization structure.
In the example above example, implemented by coding the SimpleDataRepeater assembly, we show how an
instance of framework\components\DataRepeater will provide data repetition from different data sources,
array and DB, and how you can use it.
First of all the code for templates\simple_data_repeater.html.tpl where a Block Parts is designed to
renders data.
<!DOCTYPE html>
<html>
<head>
<title>DataRepeater component</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" media="screen">
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js"></script>
</head>
<body>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
</body>
<div class="container-fluid">
<h2>Part list example using the DataRepeater component</h2>
<div class="row">
<div class="col-md-12">
<table class="table table-hover">
<thead>
<tr>
<th>Part code</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<!-- BEGIN Parts -->
<tr>
<td>{part_code}</td>
<td>{description}</td>
</tr>
<!-- END Parts -->
</tbody>
</table>
</div>
</div>
</div>
</html>Here is the simple views\SimpleDataRepetaer.php
<?php
namespace views;
use framework\View;
class SimpleDataRepeater extends View
{
/**
* Object constructor.
*
* @param string|null $tplName The html template containing the static design.
*/
public function __construct($tplName = null)
{
if (empty($tplName))
$tplName = "/simple_data_repeater";
parent::__construct($tplName);
}
}Below we show the models\SimpleDataRepetaer.php in which we coded two methods getPartsFromArray()
and getPartsFromDB() (read code comments) providing respectively data from array and DB. You will find
the DDL of the table part here (lines from 171 to 198)
<?php
namespace models;
use framework\Model;
class SimpleDataRepeater extends Model
{
public function getPartsFromArray()
{
$users = array(
array('part_code' => '1', 'description' => 'description 1'),
array('part_code' => '2', 'description' => 'description 2'),
array('part_code' => '3', 'description' => 'description 3'),
);
return $users;
}
/**
* Provides parts from table part
*
* @return \mysqli_result
* @note resultset must be in a proper keys and number of columns
* required by the Block which is used by the Datarepeater
* component.
*/
public function getPartsFromDB()
{
$this->sql = "SELECT part_code,description FROM part";
$this->updateResultSet();
}
}Finally the code for controllers\SimpleDataRepeater
<?php
namespace controllers;
use framework\components\DataRepeater;
use framework\Controller;
use framework\Model;
use framework\View;
use models\SimpleDataRepeater as SimpleDataRepeaterModel;
use views\SimpleDataRepeater as SimpleDataRepeaterView;
class SimpleDataRepeater extends Controller
{
protected $view;
protected $model;
/**
* SimpleDataRepeater constructor.
*
* @param View|null $view
* @param Model|null $model
* @throws \framework\exceptions\TemplateNotFoundException
*/
public function __construct(View $view=null, Model $model=null)
{
$this->view = empty($view) ? $this->getView() : $view;
$this->model = empty($model) ? $this->getModel() : $model;
parent::__construct($this->view,$this->model);
}
/**
* Autorun method. Put your code here for running it after object creation.
* @param mixed|null $parameters Parameters to manage
*
*/
protected function autorun($parameters = null)
{
$this->useArray();
// $this->useDB();
// $this->manualSetupArray();
// $this->manualSetupDB();
}
/**
* DataReapeter smart initialization and usage with array values
*
* @throws \ReflectionException
* @throws \framework\exceptions\NotInitializedViewException
* @throws \framework\exceptions\TemplateNotFoundException
* @throws \framework\exceptions\VariableNotFoundException
*/
public function useArray(){
$parts = $this->model->getPartsFromArray();
$repeater = new DataRepeater($this->view,null,"Parts",$parts);
$this->bindComponent($repeater);
}
/**
* DataReapeter smart initialization and usage with DB values
*
* @throws \ReflectionException
* @throws \framework\exceptions\NotInitializedViewException
* @throws \framework\exceptions\TemplateNotFoundException
* @throws \framework\exceptions\VariableNotFoundException
*/
public function useDB() {
$this->model->getPartsFromDB();
$repeater = new DataRepeater($this->view,$this->model,"Parts",null);
$this->bindComponent($repeater);
}
/**
* DataReapeter manual initialization and usage with array values
*/
public function manualSetupArray(){
$parts = $this->model->getPartsFromArray();
$repeater = new DataRepeater();
$repeater->setView($this->view);
$repeater->setContentToBlock("Parts");
$repeater->setValuesFromArray($parts);
$repeater->render();
}
/**
* DataReapeter manual initialization and usage with DB values
*/
public function manualSetupDB(){
$this->model->getPartsFromDB();
$repeater = new DataRepeater();
$repeater->setView($this->view);
$repeater->setModel($this->model);
$repeater->setContentToBlock("Parts");
$repeater->setValuesFromModel();
$repeater->render();
}
/**
* Initialize the View by loading the static design of /simple_data_repeater.html.tpl
* managed by views\SimpleDataRepeater class
*
*/
public function getView()
{
$view = new SimpleDataRepeaterView("/simple_data_repeater");
return $view;
}
/**
* Initialize the Model by loading models\SimpleDataRepeater class
*
*/
public function getModel()
{
$model = new SimpleDataRepeaterModel();
return $model;
}
}In the above code, you will find the following methods. Each one uses different (optionally) parameters to instantiate the DataRepeater component:
new DataRepeater( [View] , [Model] , [Template Block], [Array] )
useArray(): It automatically renders array data into the Block labeled Parts.
new DataRepeater($this->view,null,"Parts",$parts)
useDB(): It automatically renders model data into the Block labeled Parts.
new DataRepeater($this->view,$this->model,"Parts",null)
manualSetupArray(): It manually renders array data into the Block labeled Parts by manually
setting the DataRepeater Instance.
manualSetupDB(): It manually renders model data into the Block labeled Parts by manually setting
the DataRepeater Instance.
Please read the code comments and implementations for technical details regarding the methods above.
Let only one of them be uncommented inside the autorun method for showing its output when running
SimpleDataRepeater.
