5. System decomposition - notafrancescodavid/webmvcframework GitHub Wiki

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 (client 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;
  • the namespace.

For each subsystem, WebMVC uses a directory to physically store 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.
For example, if we decide to implement the subsystem manufacturing we must define:

  1. controllers\manufacturing - the directory path where to store classes for the manufacturing subsystem;
  2. 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 the figure 6.1. There are now two decomposition levels: the first is the MVC decomposition (directories: controllers, models, and views/templates) and the second is provided by the structure of the application domain. Note that we have a replica of the subsystem application names within the models, views, and controllers directories as well as for the templates directory. 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 controllers is 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.

Figure 6.1. An excerpt of the static system decomposition of minierp.

How to invoke a subsystem controller class

In the quick start section, 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://site/user_manager/get_user/1 => UserManager->getUser(1).

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.

Managing the inventory record

An example taken from the minierp web application concerns the presentation of the inventory record 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 key
  • description -> the description of the good maintained in the inventory
  • stock -> quantity in stock

The 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.

 <!DOCTYPE html>
<html>
<head>
    <title>Inventory</title>
</head>
<body>
    <h1>Inventory</h1>
	<table>
            <thead>
                    <th>code</th>
                    <th>description</th>
                    <th>stock</th>
            </thead>
            <tbody>
                <!-- BEGIN Parts -->
                <tr>
                    <td>{code}</td>
                    <td>{description}</td>
                    <td>{stock}</td>
                </tr>
                <!-- END Parts -->
            </tbody>
        </table> 
</body>
</html>

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.

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

Next section: TO DO

⚠️ **GitHub.com Fallback** ⚠️