yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.24k stars 6.91k forks source link

Template/view code style and conventions #603

Closed resurtm closed 11 years ago

resurtm commented 11 years ago

This issue is about proposing view code style and discussing it.

Proof of necessity

I think view code conventions must be also documented and described for an end users, developers and core developers, just like it is made for the common Yii2 PHP code. Understanding of the problem may come after some real world samples.

Consider developer M wrote the following view code:

<?php
/**
 * @var yii\base\View $this
 * @var yii\widgets\ActiveForm $form
 * @var app\models\Post[] $posts
 * @var app\models\ContactMessage $contactMessage
 */

use yii\helpers\Html;
use yii\widgets\ActiveForm;

$this->title = 'Posts';
?>

<?php foreach($posts as $post): ?>
    <h2><?php echo $post['title']; ?></h2>
    <p><?php echo $post['shortDescription']; ?></p>
<?php endforeach; ?>

<?php $form = ActiveForm::begin(array(
    'options' => array('id' => 'contact-message-form'),
    'fieldConfig' => array('inputOptions' => array('class' => 'common-input')),
)); ?>
    <?php echo $form->field($contactMessage, 'name')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'email')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'subject')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'body')->textArea(array('rows' => 6)); ?>

    <div class="form-actions">
        <?php echo Html::submitButton('Submit', array('class' => 'common-button')); ?>
    </div>
<?php ActiveForm::end(); ?>

Then his colleague N started to discuss and change view code on his own. After his changes view may become to something as follows:

<?php
/**
 * @var yii\base\View $this
 * @var yii\widgets\ActiveForm $form
 * @var app\models\Post[] $posts
 * @var app\models\ContactMessage $contactMessage
 */

use yii\helpers\Html;
use yii\widgets\ActiveForm;

$this->title = 'Posts';
?>

<?php
foreach($posts as $post):
    echo '<h2>'.$post['title'].'</h2>';
    echo '<p>'.$post['shortDescription'].'</p>';
endforeach;
?>

<?php
$form = ActiveForm::begin(array(
    'options' => array('id' => 'contact-form'),
    'fieldConfig' => array('inputOptions' => array('class' => 'common-input')),
));
    echo $form->field($contactMessage, 'name')->textInput();
    echo $form->field($contactMessage, 'email')->textInput();
    echo $form->field($contactMessage, 'subject')->textInput();
    echo $form->field($contactMessage, 'body')->textArea(array('rows' => 6));

    echo '<div class="form-actions">';
        echo Html::submitButton('Submit', array('class' => 'common-button'));
    echo '</div>';
ActiveForm::end();
?>

His main argument on this change: why do we need so much PHP tags? Isn't better to remove them all and code would be much more readable? Abscence of common prescribed view style causes waste of time and pointless debates.

Moreover third developer P could rewrite views above in absolutely different manner:

<?php
$this->title = 'Posts';
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/**
 * @var yii\base\View $this
 * @var yii\widgets\ActiveForm $form
 * @var app\models\Post[] $posts
 * @var app\models\ContactMessage $contactMessage
 */
?>
<?php foreach($posts as $post) { ?>
    <?php echo '<h2>'.$post['title'].'</h2>'; ?>
    <?php echo '<p>'.$post['shortDescription'].'</p>'; ?>
<?php } ?>
<?php $form=ActiveForm::begin(array('options'=>array('id'=>'contact-form'),
    'fieldConfig'=>array('inputOptions'=>array('class'=>'common-input'))));
    echo $form->field($contactMessage,'name')->textInput();
    echo $form->field($contactMessage,'email')->textInput();
    echo $form->field($contactMessage,'subject')->textInput();
    echo $form->field($contactMessage,'body')->textArea(array('rows' => 6));
    echo '<div class="form-actions">'.Html::submitButton('Submit',array('class'=>'common-button')).'</div>';
ActiveForm::end(); ?>

This third variant looks even worse and ugly (from objective POV). I am sure his colleagues M and N shall hate this fashion of template decoration. :-)

In Yii 1.1 everyone is writing views/templates on their own, without any common conventions. Imagine big team of developers where many people can edit single view file. I realize big teams usually have their own internal conventions, but why not to create them at the framework level?

Moreover i think it would be very comfortable for every developer when 100% of created applications would have absolutely identical view decoration style. In this case there won't be need to get used to the style of an existing project, in case you have to move from one project to another.

Proposed view code style

Without comments (raw):

<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;

/**
 * @var yii\base\View $this
 * @var yii\widgets\ActiveForm $form
 * @var app\models\Post[] $posts
 * @var app\models\ContactMessage $contactMessage
 */

$this->title = 'Posts';
?>

<?php foreach($posts as $post): ?>
    <h2><?php echo Html::encode($post['title']); ?></h2>
    <p><?php echo Html::encode($post['shortDescription']); ?></p>
<?php endforeach; ?>

<?php $form = ActiveForm::begin(array(
    'options' => array('id' => 'contact-message-form'),
    'fieldConfig' => array('inputOptions' => array('class' => 'common-input')),
)); ?>
    <?php echo $form->field($contactMessage, 'name')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'email')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'subject')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'body')->textArea(array('rows' => 6)); ?>

    <div class="form-actions">
        <?php echo Html::submitButton('Submit', array('class' => 'common-button')); ?>
    </div>
<?php ActiveForm::end(); ?>

With comments:

<?php
// Leading PHP tag is a must in every template file. Empty line after leading PHP tag is also required.

// Describe input variables passed by controller here.
/**
 * @var yii\base\View $this
 * @var yii\widgets\ActiveForm $form
 * @var app\models\Post[] $posts
 * @var app\models\ContactMessage $contactMessage
 */
// Empty line below is necessary.

// Namespaced classes declaration.
use yii\helpers\Html;
use yii\widgets\ActiveForm;
// Empty line below is necessary.

// Set context properties, call its setters, do other things.
$this->title = 'Posts';
?>
<!-- Empty line below is necessary, excluding view which uses beginContent/endContent inheritance mechanism. -->

<!-- Every statement should have its own PHP tag. PHP is some kind of a DSL in this case. -->
<?php foreach($posts as $post): ?>
    <!-- Enclosing several PHP statements in one PHP tag is forbidden. -->
    <!-- In other words PHP tags in a views should simulate HTML tags concept. -->
    <!-- Note indentation level here. -->
    <h2><?php echo Html::encode($post['title']); ?></h2>
    <p><?php echo Html::encode($post['shortDescription']); ?></p>
<!-- Only `endforeach;`, `endfor;`, `endif;`, etc. are valid. Using `}` must be considered as code smell. -->
<?php endforeach; ?>
<!-- Space below is needed for logical separation of elements. -->

<!-- Widget declaration may or may not be exploded into multiple LOCs. -->
<?php $form = ActiveForm::begin(array(
    'options' => array('id' => 'contact-message-form'),
    'fieldConfig' => array('inputOptions' => array('class' => 'common-input')),
)); ?>
    <!-- Note indentation level here. -->
    <?php echo $form->field($contactMessage, 'name')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'email')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'subject')->textInput(); ?>
    <?php echo $form->field($contactMessage, 'body')->textArea(array('rows' => 6)); ?>
    <!-- Space below is needed for logical separation of elements. -->

    <div class="form-actions">
        <?php echo Html::submitButton('Submit', array('class' => 'common-button')); ?>
    </div>
<!-- Ending widget call should have individual PHP tag. -->
<?php ActiveForm::end(); ?>
<!-- Trailing newline character is mandatory as well. -->

What do you think about idea itself and proposed view style? For this case i think we can create additional Wiki page.

samdark commented 11 years ago

Idea is definitely good.

  1. Empty lines outside <?php will be actually rendered.
  2. "Every statement should have its own PHP tag" is controversial. Sometimes multiple statements are OK such as
$b = $this->preprocess($a);
$b = empty($b) ? 'default' : $b;
echo Html::encode($b);
bwoester commented 11 years ago

I like standardization as it generally helps understanding unknown code. Also, I like your proposed style. But there are two things that should be kept in mind:

  1. For every rule, there's an exception. Although I generally like to use PHP as you suggested above - that is: like a templating language, you write the html and use PHP to fill certain areas, loop over collections, show some stuff conditionally - there are cases where more complex processing is required. @samdark shows a simple example, I'm sure there are much more complex ones. Ones that might even include conditions and loops. In such cases you write PHP-only blocks, switching context for every statement would be ridiculous. Also, in such blocks I'd never use the alternative control structure syntax. So it basically depends on context.
  2. I don't think it'd be any good to give the impression yii puts any constraints on its users. Yii shouldn't define what coding style a team has to use for one of its projects, if they only want to use yii. Nor should Yii try to do so. Such things are in the responsibility of every single user/ team. As a proposal for extensions though, I think it would be a good idea. But even when looking at extensions: I prefer having good quality extensions that use their own coding style over having extensions that follow some coding style but don't work, are of bad quality, etc. So it really should only be a proposed style, nothing that is enforced. There are more important things than how code is formatted.
samdark commented 11 years ago

https://github.com/yiisoft/yii2/wiki/Yii2-view-code-style