Twig or stick with PHP templates

Hiho,

Im trying to make use of Twig templates, because i thought it should be easier for front-end developers to understand. But im having doubts about the use of Twig and want your opinion if im thinking wrong.

At this moment we use PHP templates instead of Twig. So we tryed switching to Twig, but the code that was necessary to write view templates with widgets or ActiveForms felt like adding an extra complex factor by adding the Twig language. If the template only contains of Twig variables it feels beter but still not noticeable difference.

What makes the use of Twig better in comparison with PHP templates in Yii2?

In my very own opinion, PHP templates are just fine and Twig may complicate things, both for the PHP developer and the frontend integrator.

I’d stick with PHP templates and apply these two rules:

  1. Use PHP short syntax & favorite plain HTML instead of PHP echo '<html>'

For example, instead of doing:

foreach ($foo as $bar) {
    echo '<li>' . $bar . '</li>';
}

do this:

<?php foreach ($foo as $bar): ?>
    <li><?= $bar ?></li>
<?php endforeach ?>
  1. Move complex operations to the top of the file

Instead of doing:

<?= $form->field($model, 'id_membre')->dropDownList(ArrayHelper::map(Dealer::find()->all(), 'id_membre', 'self'), [
   'prompt' => '-',
   'data-ajaxnew' => can('dealer-create') ? Url::to(['dealer/create']) : '',
]) ?>

do this:

<?php

/** @var $this \yii\web\View **/

$dealersForDropDrown = ArrayHelper::map(Dealer::find()->all(), 'id_membre', 'self');
$dealersAjaxNewUrl = can('dealer-create') ? Url::to(['dealer/create']) : '';

?>

....

<?= $form->field($model, 'id_membre')->dropDownList($dealersForDropDrown, [
   'prompt' => '-',
   'data-ajaxnew' => $dealersAjaxNewUrl,
]) ?>

This will make the field way more readable for the designer.

You could come up with more designer-friendly rules like these to ease things a bit more. And the designer would pick up some PHP syntax & knowledge along the way :slight_smile:

4 Likes

Couldn’t agree with you more, stuff like $dealersForDropDrown = ArrayHelper::map(Dealer::find()->all(), 'id_membre', 'self'); i even place in the Controller. The problem is only that the front-end developer does not know which variables are available.

Stuff like \/ this can’t get any easier, right?

<?php
/**
 * Created by PhpStorm.
 * User: Martijn
 * Date: 19/01/2018
 * Time: 11:57
 */
use yii\helpers\Html;
use yii\grid\GridView;
use yii\data\ActiveDataProvider;
use common\models\records\entity\Entity;

/** @var $entity common\models\records\entity\Entity */

$this->beginContent('@common/modules/dashboard/views/layouts/_default.php', [
    'model'=>$entity,
]);
echo GridView::widget([
    'dataProvider'=>new ActiveDataProvider([
        'query'=>$entity->childQuery(),
    ]),
    'columns'=> [
        [
            'class' => 'yii\grid\ActionColumn',
            'template' => '{update}',
            'buttons' => [
                'update' => function ($url, $record)
                {
                    return Html::a('<i class="fa fa-pencil"></i>', [
                        '/dashboard/entity/form/update/',
                        'typeId'=> $record->getType()->id,
                        'id' => $record->id
                    ], [
                        'class'=>'icon-link icon-md icon-default',
                    ]);
                },
            ]
        ],
        [
            'class' => 'yii\grid\DataColumn',
            'attribute' => 'child_type_id',
            'label' => 'Type',
            'value' =>function(Entity $model){
                return $model->getType()->title;
            }
        ],
        [
            'class' => 'yii\grid\DataColumn',
            'attribute' => 'child_id',
            'label' => 'Entiteit',
            'value' =>function( Entity $model){
                return $model->getHeaderValues();
            }
        ],
    ]
]);
$this->endContent();

Let’s take this one:

        [
            'class' => 'yii\grid\DataColumn',
            'attribute' => 'child_type_id',
            'label' => 'Type',
            'value' =>function(Entity $model){
                return $model->getType()->title;
            }
        ],

First off, DataColumn is the default, so you can drop it.

        [
            'attribute' => 'child_type_id',
            'label' => 'Type',
            'value' =>function(Entity $model){
                return $model->getType()->title;
            }
        ],

Then, let’s remove the label entry. Implement attributesLabels() in Entity and have it return ‘Type’ for ‘child_type_id’. Yii will automatically pick it up if you don’t provide a label.

New version:

        [
            'attribute' => 'child_type_id',
            'value' =>function(Entity $model){
                return $model->getType()->title;
            }
        ],

Finally, there’s the magic of __toString():

Supposing that Entity have a getType() relation targeting child_type_id which is a Type.

If you implement __toString() on Type as follow:

public function __toString()
{
   return (string) $this->title;
}

Then you could directly use <?= $model->type ?> and have the title outputted.

So getting back to our GridView column, we would change it like this:

        [
            'attribute' => 'type', // <- we target the relation now, not the _id field
        ],

which can ultimately be written using the string syntax:

  'columns'=> [
        ...,
       'type',
]

Way more readable, ain’t it ? :wink:

1 Like

And for other cases where using __toString() doesn’t really make sense, you can introduce some helpers.

I usually extend GridView & Formatter to add some shorthands for my most common cases:

 'columns' => [
    // Just some syntactic sugar
    GridView::actionColumn('update'),
    // This calls my custom link formatter, inspects the given object 
    // (model in this case) and generate the accurate link
    // (i.e. Html::a($model, ['model/view', id => $model->id])
    // See how I use ^^^^^  __toString() for the link label ? 
    'model:link',
    'dealer:link',
    // another formatter
    'prix:price',
    // renders a nice boolean display using font-awesome 
    // fa-check or fa-close depending on the value
     GridView::boolColumn('actif'),
   ],
3 Likes

Thank you for taking the time, in this case it is more readable. I choose the worst template to display :wink: Anyhow i get the point, there’s not a lot we can do to make code of widgets display better for front-end developers. It’s as clean as it gets, the default widgets.

Definitely stick with plain PHP views. One of reasons I use Yii is that it does not use extra rendering layer, which boosts performance, simplifies learning curve & gives better flexibility. Should anyone wish to use templating engine, he can still integrate his own / or one of supported into his application.