Custom renderers

With all this, you now probably know the most contrived part of the Yii conventions. Let's now talk about the custom renderers.

Yii uses renderers to process the view file you referenced in the render() method, based on its file extension. If the View component of Yii is unable to find any renderer for the given view file, it treats this view file as a PHP script, and executes the renderPhpFile() method:

    /**
     * @param string $_file_ the view file.
     * @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file.
     * @return string the rendering result
     */
    public function renderPhpFile($_file_, $_params_ = [])
    {
        ob_start();
        ob_implicit_flush(false);
        extract($_params_, EXTR_OVERWRITE);
        require($_file_);
        return ob_get_clean();
    }

As you can see in the preceding code, Yii will just require the file for buffering the output. An important effect of custom renderers is that you can do anything inside your view files, which will be dangerous if you really do anything. You should ideally treat PHP view files as being in some template system's format, only allowing them to paste data passed to them as associative arrays or plain data structures.

Yii 2 does not ship along with any custom renderers. Let's think about how we can utilize this feature for our convenience.

The original design goal of the developers, obviously, was that you'll write the parser for some template system format, and then you'll be able to write view files not as raw PHP, but as these (supposedly, more restricted, and domain-specific) templates. By giving the templates a new format with a distinct extension, you'll force Yii to use your custom parser on them, which will supposedly convert the given template to, say, HTML, which you'll send to the client.

Let's employ a simple solution here, which is using Markdown (http://daringfireball.net/projects/markdown/syntax) to author the static pages. Let's say we want the set of user-level documentation pages, which will be handcrafted by a skilled tech writer. You probably neither want to force him or her to author pages in HTML nor allow him or her to author them in Word to painfully convert it to HTML yourself. Markdown will be a simple middle ground for this task.

Employing a custom renderer to render static Markdown files is pretty simple. We assume that you have the same CRM application we have been building in the previous two chapters.

First, let's declare what we want:

./cept generate:cept acceptance Documentation

Then, in the tests/acceptance/DocumentationCept.php file just generated, use the following code:

$I = new AcceptanceTesterCRMUserSteps($scenario);
$I->wantTo('see whether user documentation is accessible'),

$I->amOnPage('/site/docs'),
$I->see('Documentation', 'h1'),
$I->seeLargeBodyOfText();

The seeLargeBodyOfText() method will be defined in the CRMUserSteps class as follows:

    public function seeLargeBodyOfText()
    {
        $I = $this;
        $text = $I->grabTextFrom('p'), // naive selector
        $I->seeContentIsLong($text);
    }

We basically assert that we do see a documentation page if there's a heading called Documentation and a lengthy body of text below that. It's pretty naïve, of course, but we cannot afford to write an AI code capable of automatically checking whether the given text is indeed a documentation page or not.

We will place the seeContentIsLong() method in the AcceptanceHelper class inside tests/_support/AcceptanceHelper.php:

    public function seeContentIsLong($content, $trigger_length = 100)
    {
        $this->assertGreaterThen($trigger_length, strlen($content));
    }

We have to do this because we don't have assertions in the AcceptanceTester class itself. Don't forget to run ./cept build afterwards, as we have modified the module of AcceptanceTester (yup, AcceptanceHelper is technically a Codeception module).

Now, run the test and watch it fail:

$ ./cept run tests/acceptance/DocumentationCept.php

1) Failed to see whether user documentation is accessible in DocumentationCept.php
Sorry, I couldn't see "Documentation","h1":
Failed asserting that any element by 'h1' on page /site/docs
Elements:
+ <h1> Not Found (#404)
contains text 'Documentation'

Scenario Steps:
2. I see "Documentation","h1"
1. I am on page "/site/docs"

Of course, we don't have the /site/docs route handler yet. Create the SiteController.actionDocs method:

    public function actionDocs()
    {
        return $this->render('docindex.md'),
    }

Note the absence of any Markdown-handling code, which is the whole point of using a custom renderer.

Now, the view file at views/site/docindex.md should look as follows:

# Documentation

Here we'll see some *Markdown* code.
It's easier to write text documents with simple formatting this way.

Imagine the user documentation here, describing:

1. [How to add Customers](/customers/add)
2. [How to find Customer by phone number](/customers/query)
3. [How to manage Services](/services)

The preceding code is a perfectly valid page in the Markdown format.

If you access the /site/docs page now, you'll see that the text is rendered verbatim, because docindex.md is being processed as the PHP script, and as it does not contain the <?php processing instruction, it is parsed as HTML text. Here is the screenshot:

Custom renderers

Finally, let's write the custom renderer itself. As this class is a part of the application infrastructure and has nothing to do with the domain model or the route handling, let's create a separate utilities subdirectory and namespace for it. So, in a utilities/MarkdownRenderer.php file, write the following:

<?php
namespace apputilities;

use yiihelpersMarkdown;
use yiiaseViewRenderer;

class MarkdownRenderer extends ViewRenderer
{
    public function render($view, $file, $params)
    {
        // TODO
    }
}

The apputilities namespace is automatically mapped to the utilities directory under the root of the code base, thanks to the Yii 2 autoloader we require in the index.php entry script.

You may ask, how do we render the Markdown? We can render the Markdown as follows:

    public function render($view, $file, $params)
    {
        return Markdown::process(file_get_contents($file));
    }

Yii 2 includes the whole Markdown processor as one of its dependencies.

Be cautious, though, because just calling the raw file_get_contents() method is pretty unsafe. We rely on $file being safely constructed by the Yii internals here.

Note

The MarkdownRenderer class does not have the proper unit tests because arguably all we did was wrap two built-in and already extensively tested functions into one call. To simplify the discussion, we omitted the proper test-driving MarkdownRenderer. Note, however, that in more complex cases, you must not do this. It is not all the time that you have a parser as simple as the one presented here.

With MarkdownRenderer written, we have to wire it to the application. Add the description of our custom renderer to the components.view.renderers.md section of the config at config/web.php:

    'components' => [
        'view' => [
            'renderers' => [
                'md' => [
                    'class' => 'apputilitiesMarkdownRenderer'
                ]
            ]
        ]
    ]

The index in the renderers array is the filename extension. In our case, it should be md. Our renderer does not have any properties, so to properly reference it in the application configuration, we just need to provide the fully qualified name of its class.

Now run the tests. They will be executed successfully, as shown in the following screenshot:

Custom renderers

At the /site/docs location, you can see the properly formatted HTML page now:

Custom renderers
..................Content has been hidden....................

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