Dear,
I’ve tried to create a virtual attribute and validate it, but it only worked with client validation while the server validation didn’t work.
My environment version is:
My code as below:
Project.php (model)
<?php
namespace app\models;
use Yii;
use yii\bootstrap\Html;
use yii\helpers\ArrayHelper;
class Project extends \yii\db\ActiveRecord
{
    private $assignArray = [];
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'description', 'assignments'], 'required'],
            [['assignments', 'created', 'modified'], 'safe'],
            [['name'], 'string', 'max' => 160],
            [['description'], 'string', 'max' => 1000]
        ];
    }
    /**
     * @inheritdoc
     */
    public function afterSave($inserted)
    {
        if (!$inserted) {
            ProjectUser::deleteAll('project_id = :id', array('id'=>$this->id));
        }
        // insert it.
        return array_walk($this->assignArray, function ($val, $key) {
            $assignment = new ProjectUser();
            $assignment->project_id = $this->id;
            $assignment->user_id = $val;
            $assignment->save();
        });
    }
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProjectUsers()
    {
        return $this->hasMany(ProjectUser::className(), ['project_id' => 'id']);
    }
    /**
     * Set value for user assignment
     *
     * @param array $members
     */
    public function setAssignments($value)
    {
        $this->assignArray = (array) $value;
    }
    /**
     * @return ProjectUser[]
     */
    public function getAssignments()
    {
        if ($this->isNewRecord) {
            return $this->assignArray;
        }
        return ArrayHelper::getColumn($this->projectUsers, 'user_id');
    }
}
ProjecUser.php (model)
<?php
namespace app\models;
use Yii;
class ProjectUser extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'project_user';
    }
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['project_id', 'user_id'], 'required'],
            [['project_id', 'user_id'], 'integer'],
            [['created', 'modified'], 'safe']
        ];
    }
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProject()
    {
        return $this->hasOne(Project::className(), ['id' => 'project_id']);
    }
    /**
     * @return \yii\db\ActiveQuery
     */
    public function getUser()
    {
        return $this->hasOne(User::className(), ['id' => 'user_id']);
    }
}
_form.php(view)
<?php
use app\models\User;
use kartik\widgets\Select2;
use kartik\widgets\ActiveForm;
use yii\helpers\Html;
/* @var $this yii\web\View */
/* @var $model app\models\Project */
/* @var $form kartik\widgets\ActiveForm */
?>
<div class="project-form">
    <?php $form = ActiveForm::begin(); ?>
    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>
    <?= $form->field($model, 'description')->textarea(['maxlength' => true, 'rows' => '10']) ?>
    <?= $form->field($model, 'assignments')->widget(Select2::className(), [
        'data' => User::findListAsArrayMap('id', 'username'),
        'options' => [
            'multiple' => true,
            'placeholder' => 'Please select ...',
            'allowClear' => true,
        ]
    ]) ?>
    <div class="form-group">
        <?= Html::submitButton(
            $model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'),
            ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']
        ) ?>
    </div>
    <?php ActiveForm::end(); ?>
</div>
I use with kartik activeform and select2, but it doesn’t matter, because it work very well with normal attribute, or an public class property. I mean only when I use set and get function to make a virtual attribute, it just work with client validation, not server validation (focus on assignments required).
Doesn’t Yii2 support it ?