Chapter 13. Final Refactoring

This is the final stage of our development. Now that we have written all the working code, we must make it reusable but most importantly, maintainable. This chapter will help you to reuse code by means of widgets and other components. We will see some practical examples on how to use them. Then, we will deal with documentation, an important aspect of app development that allows everyone to quickly learn how a project is structured and built.

For the documentation, we are going to use the two most important tools provided by the framework in order to build API and guide references, making a real-life example. We will cover the following topics:

  • Creating widgets
    • Example – creating a widget with a carousel
  • Creating components
    • Example – creating a component that creates a backup of the MySQL database and sends an e-mail to the administrator
  • Creating modules
  • Generating the API documentation
    • Example – using API documentation to generate doc of the app

Creating widgets

A widget is a reusable client-side code (containing JavaScript, CSS, and HTML) with minimal logic wrapped in a yiiaseWidget object that we can easily insert and apply in any view.

Building a widget requires you to extend two methods of yiiaseWidget:

  • The init() method initializes the object
  • The run() method executes the object

In order to instance a widget, it is enough to call the static widget() method that accepts just one parameter or better still an array containing values for its public properties.

The following is an example:

    MyWidget::widget(['prop1' => 'value of prop1', …])

This returns a string containing widget output, passing its value value of prop1 for its prop1 public properties.

If we need to insert an extra code in a widget's execution (for example, in the ActiveForm widget), we have a more complex way of instantiating the widget, using the begin() and end() methods.

The first method, begin(), accepts a function parameter with a configuration array to pass to the widget, and it will return the widget object.

When the second method, end(), is called, the code between these two methods will be displayed and simultaneously, the end() method directly echoes the output of the widget run() method:

    $widget = MyWidget::begin(['prop1' => 'value of prop1', …]);

    ..
    .. I can use $widget object here  ..
    ..

     MyWidget::end();

As for any other views, in the run() method, we can refer to a view file, through the render() method, in order to display the widget output.

For example, a widget could be a real-time date/time clock. For this purpose, we will build a clock based on a block containing the date/time string updated by the JavaScript code. We can pass to widget construct time some values concerning for example, the color of the border box.

To make an instance, let's start with the basic template app (but this is obviously also valid for the advanced template app). Create a new folder (if it does not exist) named components in the root of the project at the same level of controllers, models, views, and so on, which will contain all the widgets we want to build.

Then, in this folder, we will create a new file named ClockWidget.php with the complete path basic/components/ClockWidget.php:

<?php

namespace appcomponents;

use yiiaseWidget;

class ClockWidget extends Widget
{

    public function init()
    {
        yiiwebJqueryAsset::register($this->getView());
    }
    
    public function run()
    {
        return $this->render('clock');
    }
    
}

In the init() method, we have also made references to the jQuery asset to request the framework to load the jQuery plugin, since we need it in the view file.

In the run() method, we have rendered the clock view, whose content will be discussed in next rows.

So, create a new folder at basic/components/views and, within it, a new file named clock.php with the following code:

<?php

$this->registerJs( <<< EOT_JS

    function ClockWidget_refresh_datetime()
    {
        var dateTimeString = new Date().toString();
        $('#ClockWidget_realtime_clock').html(dateTimeString);
    }

    setInterval(ClockWidget_refresh_datetime,1000);
    
    ClockWidget_refresh_datetime();
EOT_JS
);

?>

<div style="border:1px solid black;padding:5px;width:200px;text-align:center">
    <span id="ClockWidget_realtime_clock"></span>
</div>

This code simply displays a box with a string containing real-time values of the current date and time, updated every second.

Finally, we can use our widget in any view using this code:

<?= appcomponentsClockWidget::widget(); ?>

Example – creating a widget with a carousel

In this example, we will create a widget that consists of a carousel with some rooms (we can choose which one to display by passing them to the widget with the public property). Again, we will use a basic template application; however, everything is equally applicable to the advanced template apps.

For this example, we will create a new controller to use its view as a widget container.

So, let's create this new controller named TestCarouselController at basic/controller/TestCarouselController.php. From here, we will pass the models property, consisting of a list of maximum three rooms:

<?php

namespace appcontrollers;

use yiiwebController;
use appmodelsRoom;

class TestCarouselController extends Controller
{
    public function actionIndex()
    {
        $models = Room::find()->limit(3)->all();
        
        return $this->render('index', ['models' => $models]);
    }
}

Next, we will create the view at basic/views/test-carousel/index.php with the widget output as follows:

This is a carousel widget with some rooms:
<?= appcomponentsCarouselWidgetCarouselWidget::widget(['models' => $models, 'options' => ['style' => 'border:1px solid black;text-align:center;padding:5px;']]); ?>

This builds the widget filling and its public properties models and options.

Now it is time to create our widget. To isolate the widget from another code as much as possible, we create a specific widget folder at the basic/components folder, under a subfolder named CarouselWidget inside of which we will create the widget file named CarouselWidget.php.

This widget includes a public property, models that contains the room's model that has been passed from the container view. It is necessary to pass these models to the Carousel widget at yiiootstrapCarousel as an array of this kind:

items => [
['content' => '...', 'caption' => '...'],
['content' => '...', 'caption' => '...'],
['content' => '...', 'caption' => '...'],
...
];

In this way, in the init() method, we will create an internal representation of the models according to the Bootstrap Yii2 widget expectation.

Finally, in the run() method, we will output the view now in the views folder at basic/components/CarouselWidget/views. This is the widget content; remember that it is stored in CarouselWidget.php at basic/components/CarouselWidget:

<?php

namespace appcomponentsCarouselWidget;

use yiiaseWidget;

class CarouselWidget extends Widget
{
    public $carouselId = 'carouselWidget_0';
    public $options = [];
    public $models = [];
    
    
    private $carouselItemsContent;

    public function init()
    {
        // It is not necessary because yii bootstrap Carousel widget will load it automatically
        // yiijuiJuiAsset::register($this->getView());
        
        $this->carouselItemsContent = [];
        foreach($this->models as $model)
        {
            $caption = sprintf('<h1>Room #%d</h1>', $model->id);
            $content = sprintf('This is room #%d at floor %d with %0.2f€ price per day', $model->id, $model->floor, $model->price_per_day);
            $itemContent = ['content' => $content, 'caption' => $caption];
            $this->carouselItemsContent[] = $itemContent;
        }
        
    }
    
    public function run()
    {
        return $this->render('carousel', ['carouselItemsContent' => $this->carouselItemsContent]);
    }
    
}

The widget view, called in the run() method, will be stored in the carousel.php file at basic/components/CarouselWidget/views:

<?php $styleOption = isset($this->context->options['style'])?$this->context->options['style']:''; ?>
<div id="<?php echo $this->context->id ?>" style="<?php echo $styleOption ?>">
    <?php
    echo yiiootstrapCarousel::widget([
        'id' => $this->context->carouselId,
        'items' => $carouselItemsContent
        
    ]);
    ?>

</div>

Browsing to http://hostname/basic/web/test-carousel/index, we will see the carousel widget (only text, but we can also insert some images within).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.9.236