= Yii 2 Examples = == Controls in Views == === Carousel === [ // the item contains only the image '', // equivalent to the above ['content' => ''], // the item contains both the image and the caption [ 'content' => '', //'caption' => 'Learn More...', 'caption' => '

This is title

This is the caption text

', 'options' => [...], ], ], 'showIndicators' => true, //'controls' => ['‹', '›'], 'controls' => [ '', '' ], ]); >
=== DatePicker === * run in your project dir: $ php composer.phar global require "fxp/composer-asset-plugin:~1.1.1" $ php composer.phar require --prefer-dist yiisoft/yii2-jui "*" * update composer: ''$ composer update'' * In your view file use ''use yii\jui\DatePicker;''. use yii\jui\DatePicker; ... publish_up = ($model->isNewRecord ? date('Y-m-d', strtotime(date('Y-m-d'))) : substr($model->publish_up, 0, 10) ); ?> $model, 'attribute' => 'publish_up', 'language' => 'ru', 'clientOptions' => [ 'dateFormat' => 'yyyy-mm-dd', ], 'options'=> ['class'=>'form-control'], ]) ?> field($model, 'publish')->widget(DatePicker::classname(), [ 'language' => 'en', 'clientOptions' => [ 'defaultDate' => '01-01-2014', 'dateFormat' => 'MM-dd-yyyy' ], 'options'=> ['class'=>'form-control'], // Bootstrap theme ]) ?> Example: ship_date = ($model->isNewRecord ? date('Y-m-d', strtotime(date('Y-m-d')." +3 Days")) : substr($model->ship_date, 0, 10) ); ?> field($model,'ship_date', [ 'template' => '{label}
{input}
' ])->widget(\yii\jui\DatePicker::className(), [ 'dateFormat' => 'php:Y-m-d', // 'php:Y-m-d' is the only supported format 'value' => ($model->isNewRecord ? date("Y-m-d") : $model->date), 'clientOptions' => [ // Options for JQuery UI widget 'defaultDate' => '+7', //'2010-01-01', 'currentText' => 'Today', //'dateFormat' => 'php:Y-m-d', // 'php:Y-m-d' is the only supported format 'language' => 'US', 'country' => 'US', 'showAnim' => 'fold', 'yearRange' => 'c-20:c+0', 'changeMonth'=> true, 'changeYear' => true, 'autoSize' => true, 'showButtonPanel' => true, //'showOn' => "button", //'buttonImage'=> "images/calendar.gif", //'htmlOptions'=>[ // 'style'=>'width:80px;', // 'font-weight'=>'x-small', ], 'options' => [ // Options for HTML attributes 'class' => 'form-control', // Bootstrap theme ], ]) ?>
See also: [[#maskedinput|MaskedInput]] * [[http://www.yiiframework.com/doc-2.0/yii-jui-datepicker.html|DatePicker]] === DropDownList === A dropdownlist (or listbox) can be populated in several ways. ==== Method 1: Inline array ==== // View: [app]/views/order/_form.php ... field($model, 'color')->dropDownList( ['red'=>'Red', 'blue'=>'Blue', 'green'=>'Green'], ['prompt'=>'--Select One--'] // options ) ?> ==== Method 2: Model attribute ==== // View: [app]/views/order/_form.php ... field($model, 'color')->dropDownList( $colors, ['prompt'=>'--Select One--'] // options ) ?> Where $colors is defined in the model: //... class Product extends \yii\db\ActiveRecord { //... public function getColors() { return array('red'=>'Red', 'blue'=>'Blue', 'green'=>'Green'); } } ==== Method 3: Data from another table (Lookup Table)==== // View: [app]/views/order/_form.php use yii\helpers\ArrayHelper; use app\models\Customer; ...
... field($model, 'customer_id')->label('Customer')->dropDownList( ArrayHelper::map(Customer::find()->all(), 'id', 'fullname'), // Or: ArrayHelper::map($model->customers, 'id', 'fullname'), // but requires to add the following function to the current model: // public function getCustomers() // { // return Customer::find()->all(); // } ['prompt'=>'--Select One--'] // options ) ?> ...
Where ''fullname'' is a table field. If it is a virtual attribute, it needs to be defined in the model: ... class Customer extends \yii\db\ActiveRecord { ... // Virtual attributes public function getFullName() { return $this->first_name . " " . $this->last_name; } } NOTE: If using ActiveForm, then the value of the model field will be used as the selected value. However, if not using ActiveForm and generating dropdown list with Html helper, then the dropDownList() function accepts parameter ''selection'' as well, which allows the value to default as selected. See more in the [[http://www.yiiframework.com/doc-2.0/yii-helpers-basehtml.html#dropDownList()-detail|documentation]]. Example: public function actionCreate() { $model = new Content(); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { // set default values if (empty($model->show_hits)) $model->show_hits = 0; if (empty($model->show_rating)) $model->show_rating = 0; if (empty($model->featured)) $model->featured = 0; if (empty($model->ordering)) $model->ordering = 0; if (empty($model->created_by)) $model->created_by = Yii::$app->user->id; return $this->render('create', [ 'model' => $model, ]); } } Alternatively, define ''default'' rules in your model: public function rules() { return [ ... [['created_at', 'modified_at'], 'safe'], [['created_at', 'modified_at'], 'default', 'value' => function(){ return date('Y-m-d'); }], ]; } === ListView === In view ''search'', add widget ''ListView'': ... $dataProvider, 'itemView' => '_listitem', ]) ?> Add new partial view ''_listitem'' to define how each item in list will display:

id) ?>

name) ?>
Alternatively, you can use an inline ''itemView'': $dataProvider, 'options' => [ 'tag' => 'div', 'class' => 'list-wrapper', 'id' => 'list-wrapper', ], 'layout' => "{pager}\n{items}\n{summary}", 'itemView' => function ($model, $key, $index, $widget) { return $this->render('_list_item',['model' => $model]); // Alternatively, just do some echo... //return "{$model->title} posted by {$model->author}"; }, ]); ?> In controller, the action should have a ''searchModel'' and ''dataProvider'' defined: public function actionSearch() { $searchModel = new CustomerSearch(); if (empty(Yii::$app->request->queryParams)) { $dataProvider = new \yii\data\ArrayDataProvider(); } else { $dataProvider = $searchModel->search(Yii::$app->request->queryParams); } $dataProvider->pagination->pageSize = 0; // Set to no page return $this->render('search', [ 'searchModel' => $searchModel, 'dataProvider' => $dataProvider, ]); } See more: [[http://www.codevoila.com/post/4/yii2-listview-example|Yii2 ListView Example]] === DetailView === $model, 'template' => '{label}{value}', // row template 'attributes' => [ // using default values 'title', // title attribute (in plain text) // using formatters: // (see http://www.yiiframework.com/doc-2.0/yii-i18n-formatter.html) 'description:html', // description attribute in HTML 'description:ntext', // description attribute in HTML text [ // or alternatively 'attribute' => 'description', 'label' => 'Main Description', 'format' => 'html', 'value' => '
'.description.'
', ], intro_image:image, [ 'attribute' => 'intro_image', 'label' => 'Intro Image', 'format' => 'image', 'value' => (!empty($model->intro_image) ? Yii::$app->urlManager->createUrl('').'media/'.$model->intro_image : ''), ], [ 'attribute' => 'intro_image', 'label' => 'Intro Image', // Add image size limit 'format' => 'raw', 'value' => '' ], // dates [ 'attribute' => 'publish_date', 'label' => 'Publish Date', 'format' => ['date', 'php:Y-m-d'], 'value' => publish_date, ], 'publish_date:date', // requires 'yii\i18n\Formatter' 'defaultTimeZone' to be set in config.php 'publish_date:datetime', // requires 'yii\i18n\Formatter' 'defaultTimeZone' to be set in config.php 'ship_cost:currency', // formatted to default currency [ // ship_cost formatted as proforma currency 'attribute' => 'ship_cost', 'format' => ['raw'], 'value' => call_user_func(function($data) { // formatted to specific currency //return Yii::$app->formatter->asCurrency($data->ship_cost, $data->currency); // or formatted to USD or EUR currency return Yii::$app->formatter->asCurrency($data->ship_cost, 'EUR'); }, $model), ], // using custom label/values, // including values in other related models [ // the owner name of the model 'label' => 'Owner', 'value' => $model->owner->name, ], // using boolean logic for values [ 'label' => 'Status', 'value' => ($model->status > 0 ? 'Published' : 'Unpublished') ], // using Bootstrap html elements [ 'label' => 'Status', 'format' => 'html', 'value' => ($model->status > 0 ? 'Active' : 'Inactive') ], [ 'attribute' => 'is_available ', 'format' => 'html', 'value' => ($model->is_available > 0 ? '' : '') ], [ // Call custom function for value 'label' => 'Quantity', 'attribute' => 'quantity', 'format' => ['raw'], 'value' => call_user_func(function ($data) { return ($data->quantity >= 0 ? $data->quantity : -1); }, $model), ], [ 'attribute' => 'created_by', 'label' => 'Created by', 'value' => ($model->createdByUser !== null ? $model->createdByUser->username : 'N/A'), ], [ 'attribute' => 'updated_by', 'label' => 'Updated by', 'value' => User::findUsername($model->updated_by), ], 'created_at', ], ]);
* [[http://www.yiiframework.com/doc-2.0/guide-output-formatting.html|Field Formatting Options]] The ''created_by'' field would require this extra code in the model: use app\models\User; ... public function getCreatedByUser() { // NOTE: Use only one of these: // 'basic' application return User::findIdentity($this->created_by); // 'advanced' application return $this->hasOne(User::className(), ['id' => 'created_by']); } public static function findUsername($id) { //return isset(self::$users[$id]) ? new static(self::$users[$id]['username']) : null; $usr = isset(self::$users[$id]) ? new static(self::$users[$id]) : null; if ($usr !== null) { return $usr->username; } else { return 'N/A'; } } === GridView (with links) === $dataProvider, 'filterModel' => $searchModel, 'tableOptions' => ['class' => 'table table-striped table-bordered table-hover'], 'columns' => [ // record number column ['class' => 'yii\grid\SerialColumn'], // Record with checkbox column // Users may click on the checkboxes to select rows of the grid. // The selected rows may be obtained by calling the following JavaScript code: // // // keys is an array consisting of the keys associated with the selected rows // var keys = $('#grid').yiiGridView('getSelectedRows'); // ['class' => 'yii\grid\CheckboxColumn'], 'id', [ 'attribute' => 'id', 'label' => 'Ref ID', 'format' => ['raw'], 'value' => function($model) { return str_pad($model->id, 8, "0", STR_PAD_LEFT); } ], 'first_name', //'last_name', [ // Use 'last_name' as link to view record 'attribute' => 'last_name', 'format' => ['raw'], 'value' => function($data) { // Alternative 1 //return Html::a( // Html::encode($data['last_name']), // 'index.php?r=customer/view&id='.$data['id'] //); // Alternative 2 // Must include: use yii\helpers\Url; return Html::a( Html::encode($data['last_name']), Url::toRoute(['view', 'id' => $data['id']], ['data-pjax' => '0' /* disable pjax */]) ); }, ], 'company_name', [ // field with custom label 'attribute' => 'company_name', 'label' => 'Company', 'value' => 'company_name', ], //'address', 'city', 'state_prov', 'postal_code', // 'country', // 'email:email', // 'phone', // 'fax', // 'account_number', // 'ip_address', // 'notes:ntext', [ // field with truncated content 'attribute' => 'description', 'label' => 'Description', 'format' => 'ntext', 'value' => function($data) { return yii\helpers\StringHelper::truncateWords($data['description'], 50); } ], [ // column with 220px (or 20%) specified width 'attribute' => 'connector', 'value' => 'connector', 'headerOptions' => ['style' => 'width: 20%;'], 'contentOptions' => ['style' => 'width: 220px;'], //'contentOptions' => ['style' => 'width: 220px; white-space: normal;'], //'contentOptions' => ['style' => 'width: 220px; white-space: nowrap;'], ], [ // link to related table 'vendor' and get field 'company_name' 'attribute' => 'Vendor Info', 'format' => ['raw'], 'value' => function($model) { return $model->vendor->company_name; }, ], [ // use dropdown listbox for column filter 'attribute' => 'featured', 'label' => 'Featured', 'format' => ['raw'], 'value' => function($data) { return ($data['featured'] > 0 ? 'Yes' : 'No'); }, 'filter' => [0 => 'No', 1 => 'Yes'] ], [ // use dropdown listbox for column filter 'attribute' => 'status', 'label' => 'Status', 'format' => ['raw'], 'value' => function($data) { return ($data['status'] > 0 ? 'Active' : 'Disabled'); }, 'filter' => [1 => 'Active', 0 => 'Disabled'] ], [ // use dropdown listbox for column filter, using data from array 'attribute'=>'resolution_type', 'format' => ['raw'], 'value' => function($model) { return $model->resolution_type; }, 'filter' => ['Call Back' => 'Call Back', 'Pending' => 'Pending', 'Solved' => 'Solved', 'Unsolved' => 'Unsolved'] ], [ // use dropdown listbox for column filter, using data from lookup table 'attribute'=>'category_id', 'format' => ['raw'], 'value' => function($model) { return $model->category->title; }, 'filter' => \yii\helpers\ArrayHelper::map(ContentCategory::find()->all(), 'id', 'title'), // Or querying same product table: //'filter' => \yii\helpers\ArrayHelper::map(app\models\Product::find()->distinct()->all(), 'category_id', 'category_id'), ], [ // use dropdown listbox for column filter, using data from model 'attribute'=>'product_code', 'format' => ['raw'], 'value' => function($model) { return $model->product_code; }, //'filter' => ArrayHelper::map(Product::getProductCodes, 'id', 'product_code'), 'filter' => Product::getProductCodes(), ], [ // Column with footer (must enable 'showFooter' and 'footerRowOptions' GridView options) 'attribute' => 'quantity', 'format' => 'raw', 'value' => function($model, $key, $index, $widget) use ($total) { $total += $model->quantity; return $model->quantity; }, 'footer' => getPageTotal($dataProvider->models, 'quantity'), ], [ // Column with footer showing totals (must enable 'showFooter'), // and formatted as currency, equivalent to 'total_price:currency' 'attribute' => 'total_price', 'label' => 'Total Price', 'value' => function ($modelItem, $key, $index, $widget) { return Yii::$app->formatter->asCurrency($modelItem->total_price, 'USD'); }, 'footer' => Yii::$app->formatter->asCurrency($model->sub_total_cost, 'USD'), ], // Search by Date (on a DateTime field), Alternative 1 'created_at:date', // Add to the search model query app/models/ProductSearch.php //public function search($params) //{ // //... // $query->andFilterWhere(['like', ...); // // if (isset($this->created_at) && !empty($this->created_at)){ // $query->andFilterWhere(['like', "created_at", "{$this->created_at}"]); // } //} // Search by Date (on a DateTime field), Alternative 2 //'created_at:datetime', [ 'attribute' => 'created_at', 'filter' => app\models\Product::getCreatedDateList(), ], // Add the following to the Product model: //public static function getCreatedDateList() //{ // $dates = (new yii\db\Query())-> // select('DISTINCT DATE(`created_at`) as dates')-> // from('{{%product}}')->column(); // return array_combine($dates, $dates); //} // // Add the following to the ProductSearch model: //public function search($params) //{ // //... // // $query->andFilterWhere([ // 'id' => $this->id, // //'created_at' => $this->created_at, // 'DATE(`created_at`)' => $this->created_at, // //... // ]); // // //... //} // Search by Year (on a DateTime field) //'created_at:datetime', [ 'attribute' => 'created_at', 'filter' => app\models\Product::getCreatedYearList(), ], // Add the following to the Product model: //public static function getCreatedYearList() //{ // $years = (new yii\db\Query())-> // select('DISTINCT YEAR(`created_at`) as years')-> // from('{{%product}}')->column(); // return array_combine($years, $years); //} // // Add the following to the ProductSearch model: //public function search($params) //{ // //... // // $query->andFilterWhere([ // 'id' => $this->id, // //'created_at' => $this->created_at, // 'YEAR(`created_at`)' => $this->created_at, // //... // ]); // // //... //} // 'created_at', // 'modified_at', // 'created_by', [ // Custom Created_By 'attribute' => 'created_by', 'label' => 'Created By', 'value' => function($model) { return User::findUsername($model->created_by); }, 'filter'=> User::getUsernames(), ], // 'status', // 'user_id', ['class' => 'yii\grid\ActionColumn'], // default actions [ // custom actions 'class' => 'yii\grid\ActionColumn', 'template' => '{view} {update} {clone} {download}', /* '{view} {update} {delete}' */ 'buttons' => [ 'view' => function ($url, $model, $key) { return Html::a('', yii\helpers\Url::toRoute([ 'carousel-view', 'id' => $model['id'] ])); // view record }, 'update'=> function ($url, $model, $key) { return Html::a('', yii\helpers\Url::toRoute([ 'carousel-update', 'id' => $model['id'] ])); // update record }, 'delete'=> function ($url, $model, $key) { return Html::a('', ['delete', 'id' => $model['id']], [ 'data' => [ 'confirm' => Yii::t('app', 'Are you sure you want to delete this item?'), 'method' => 'post', ], ]); // delete record }, // custom action Clone 'clone' => function ($url, $model, $key) { return Html::a('', yii\helpers\Url::toRoute(['clone', 'id' => $model['id']]) // clone record ); }, // custom action Download 'download' => function ($url, $model) { return Html::a('', ['another-controller/another-action', 'id' => $model->id], [ 'title' => 'Download', 'data-pjax' => '0', ] ); }, ], ], ], //'summary' => '', // uncomment this line to remove table summary 'showFooter' => true, 'footerRowOptions'=>['style'=>'font-weight:bold'], ]); ?> class Product extends \yii\db\ActiveRecord { ... public static function getProductCodes() { return [ 'prod_Big' => 'Big', 'prod_Medium' => 'Medium', 'prod_Small' => 'Small', ]; } } class User extends \yii\base\Object implements \yii\web\IdentityInterface { //... /** * Find username for specified userid. * * @id integer $id of user to search. * @return string Username if found, 'N/A' if not found. */ public static function findUsername($id) { $usr = isset(self::$users[$id]) ? new static(self::$users[$id]) : null; if (count($usr) > 0) { return $usr->username; } else { return 'N/A'; } } /** * get list of all usernames, to be used in dropdown. * @return array usernames. */ public static function getUsernames() { return \yii\helpers\ArrayHelper::map(User::$users, 'id', 'username'); } } ==== Gridview with Searchable Columns ==== To make a column searchable in the ''GridView::widget()'', you must add the field to the query in ''app/models/[MyModel]Search.php''. Eg: To search vendor by: * ''brand'' * ''postal_code'' Edit ''app/models/VendorSearch.php'': use app\models\Vendor; // add model reference to current model use app\models\Manufacturer; // add model reference to related model class VendorSearch extends Vendor { // Add the public attributes that will be used to store the custom data to be searched // NOTE: Only required for fields not in current table, // Eg: fields in related table such as 'manufacturer.name' using alias 'brand' public $brand; // Add searchable fields to the 'safe' array in rules // Eg: 'brand', and 'postal_code' public function rules() { return [ [['id', 'status', 'created_by', 'updated_by'], 'integer'], // Add all searchable field here [['name', 'description', 'type', 'address', 'city', 'state_prov', 'postal_code', 'country', 'image', 'contact', 'brand', 'created_at', 'updated_at'], 'safe'], ]; } ... public function search($params) { // Perform a JOIN with related table $query = Vendor::find()->joinWith('manufacturer'); // make sure to set no order here!! ... $query->andFilterWhere([ 'id' => $this->id, 'status' => $this->status, 'created_by' => $this->created_by, 'created_at' => $this->created_at, 'updated_by' => $this->updated_by, 'updated_at' => $this->updated_at, ]); // Set all searchable fields (make sure they are available at the top (under rules[]) $query->andFilterWhere(['like', 'name', $this->name]) ->andFilterWhere(['like', 'description', $this->description]) ->andFilterWhere(['like', 'type', $this->type]) ->andFilterWhere(['like', 'address', $this->address]) ->andFilterWhere(['like', 'city', $this->city]) // simple lookup using 'postal_code' ->andFilterWhere(['like', 'postal_code', $this->postal_code]) ->andFilterWhere(['like', 'state_prov', $this->state_prov]) ->andFilterWhere(['like', 'country', $this->country]) ->andFilterWhere(['like', 'image', $this->image]) ->andFilterWhere(['like', 'contact', $this->contact]) // complex lookup of 'brand' on another table (field 'manufacturer.name') ->andFilterWhere(['like', 'LOWER(manufacturer.name)', strtolower($this->brand)]); return $dataProvider; } } ==== Gridview with Sortable Columns ==== To make the column headers sortable, set the sort attributes in the method ''search()''. Edit ''app/models/ProductSearch.php'': ... class ProductSearch extends Product { // Add the public attributes that will be used to store the custom data to be searched // NOTE: Only required for fields not in current table, // Eg: fields in related table such as 'company.name_short' using alias 'brand' public $brand; // Add searchable fields to the 'safe' array in rules // Eg: 'brand' public function rules() { return [... // Add all searchable field here [[... 'brand'], 'safe'], ]; } ... public function search($params) { $query = Product::find()->joinWith('company'); // Make sure to set no order here!! // Use 'defaultOrder' in setSort() instead. $dataProvider = new ActiveDataProvider([ 'query' => $query, 'sort'=> ['defaultOrder' => ['code'=>SORT_ASC, 'name'=>SORT_ASC]] ]); /** * Setup your sorting attributes * Note: This is setup before the $this->load($params) statement below */ $dataProvider->setSort([ 'attributes' => [ 'id', 'name', 'code', 'model_number', 'upc', 'brand' => [ 'label' => 'Brand', 'asc' => ['company.name_short' => SORT_ASC], 'desc' => ['company.name_short' => SORT_DESC], 'default' => SORT_ASC ], 'description', ], 'defaultOrder' => ['code'=>SORT_ASC, 'name'=>SORT_ASC] ]); if (!($this->load($params) && $this->validate())) { return $dataProvider; } ... return $dataProvider; } } GridView: ... $dataProvider, 'filterModel' => $searchModel, 'columns' => [ ['class' => 'yii\grid\SerialColumn'], 'id', 'name', 'code', 'model_number', //'company_id', [ // link to related table 'company' and get field 'name_short' 'label' => 'Brand', 'attribute' => 'brand', 'format' => ['raw'], 'value' => 'company.name_short', 'filter' => ArrayHelper::map(Company::find()->all(), 'name_short', 'name_short'), ], ['class' => 'yii\grid\ActionColumn'], ], ]); ?> === Button / Link === Create an action in the controller: ... class SiteController extends Controller { public function actionPrivacy() { return $this->render('privacy'); } ... } Create link in view: 'btnPrivacyPolicy', 'class' => 'btn btn-default btn-sm', ]); // Method 2: Link styled as button echo \yii\helpers\Html::a('Privacy Policy', ['site/privacy']); // Method 3: Link styled as button $url = urldecode(\yii\helpers\Url::toRoute(['site/privacy'])); echo \yii\helpers\Html::a('Privacy Policy', $url); // Method 4: Link styled as button echo \yii\helpers\Url::to(['site/privacy']); ?> Create an image link: request->BaseUrl . '/images/logo.png', ['class' => 'img-responsive', 'alt' => 'Logo', 'title' => 'Company Logo' ]); echo Html::a($logo, ['site/index'], ['class' =>'class-name']); ?> Link with icon and text: ' . ' Admin Dashboard', ['site/admin-dashboard']) ?> Link with icon and as a button: ' . ' Admin Dashboard', ['site/admin-dashboard'], ['class'=>'btn btn-default']) ?> Link as button with popup for warning: 'btn btn-success', 'data-confirm' => "It might take a while to generate certificates. Do you want to proceed?", 'data-method' => "post", 'data-pjax' => '0' ] ) ?> Link as a button with tooltip: registerJs($script, \yii\web\View::POS_END); ?> 'btn btn-success', 'data-toggle' => "tooltip", 'data-placement' => "bottom", 'title' => "Modify settings for Certificate Title, Body, and Signature" ] ) ?> Link with POST data: 'btn btn-default', //'data-method' => 'post', //'data-pjax' => 0, //'data-params' => "{'serial_range': ".Yii::$app->request->post('serial_range').",'more_data': '123'}", 'data' => [ 'method' => 'post', 'pjax' => 0, 'params' => [ 'serial_range' => Yii::$app->request->post('serial_range'), 'more_data' => '123', ], ] ] ) ?> === Button Dropdown ===
$model->customer_id], ['class' => 'btn btn-success']) ?>
' . Yii::t('app', 'Generate') . ' ', '#', [ 'class' => 'btn btn-primary dropdown-toggle', 'data-toggle' => "dropdown", 'role' => "button", 'aria-haspopup' => "true", 'aria-expanded' => "false" ]) ?>
=== MaskedInput === field($model, 'publish_date')->widget(\yii\widgets\MaskedInput::className(), [ 'mask' => '99/99/9999', ]); ?> === NavBar (Dropdown Menu) === Edit file ''[app]/views/layouts/main.php'' to modify default menu: 'Acme Inc.', 'brandUrl' => Yii::$app->homeUrl, 'options' => [ 'class' => 'navbar-inverse navbar-fixed-top', ], //'submenuOptions' => ['target' => '_blank'], // to go blank tab for each menu item ]); $menuitems = [ ['label' => ' Home', 'url' => ['/site/index']], // icon requires 'encodeLabels' => false ['label' => 'About', 'url' => ['/site/about']], ['label' => 'News', 'url' => ['/content/index', 'category' => 'latest']], ['label' => 'Contact', 'url' => ['/site/contact']], // For external URLs, use raw string, i.e. no [] in url ['label' => 'External Site', 'url' => 'http://www.yiiframework.com'], ['label' => 'Workshop', 'url' => ['/site/workshop'], 'items' => [ ['label' => 'Equipment', 'url' => ['/site/workshop', '#'=>'equip']], ['label' => 'Techniques', 'url' => ['/site/workshop', '#'=>'tech']], '', // divider '', // divider with header ['label' => 'References', 'url' => ['/site/workshop', '#'=>'ref']], ['label' => 'Register (new tab)', 'url' => ['/site/workshop', '#'=>'ref'], 'linkOptions' => ['target' => '_blank']], // open url in new tab ]], ]; // Special permissions for Admin user (requires 'use app\models\User') if (isset(Yii::$app->user->identity) && (Yii::$app->user->identity->role == User::ROLE_ADMIN)) { $menuItems[] = ['label' => 'Admin', 'url' => '', 'items' => [ ( YII_ENV_DEV ? ['label' => 'Code Generator (Gii)', 'Gii', 'url' => ['/gii']] : '' ), ['label' => 'Web Analytics', 'url' => '/webanalytics'], ['label' => 'Database', 'url' => '/support/phpmyadmin'], '', // divider ['label' => 'Users', 'url' => ['user/index']], ]]; } if (Yii::$app->user->isGuest) { $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']]; $menuItems[] = ['label' => 'Login', 'url' => ['/site/login']]; } else { $menuItems[] = [ 'label' => 'Logout (' . Yii::$app->user->identity->username . ')', 'url' => ['/site/logout'], 'linkOptions' => ['data-method' => 'post'] ]; } echo Nav::widget([ 'options' => ['class' => 'navbar-nav navbar-right'], 'encodeLabels' => false, // to allow icons in labels 'items' => $menuitems, ]); NavBar::end(); ?> Process the action parameters. Eg: the ''content/index'' action with parameter ''category'': public function actionIndex($category='N/A') { $categoryAlias = $category; // to retrieve all *active* customers and order them by their ID: $query = Content::find() ->joinWith('category') ->where(['status' => Content::STATUS_ACTIVE]) ->where(['content_category.alias' => $categoryAlias]) //->orderBy('id') ->orderBy(['created_at' => SORT_DESC]) ->all(); return $this->render('index', [ 'models' => $query, ]); } Alternatively, process the action parameters as GET request parameters. Eg: the ''content/index'' action: public function actionIndex() { if (Yii::$app->request->isGet) { $categoryAlias = Yii::$app->request->get('category'); // GET params } else if (Yii::$app->request->isPost) { $categoryAlias = Yii::$app->request->post('category'); // POST params } else { $categoryAlias = 'N/A'; } echo var_dump(Yii::$app->request->method); // data-method echo var_dump(Yii::$app->request->get()); // GET params echo var_dump(Yii::$app->request->post()); // POST params // to retrieve all *active* customers and order them by their ID: $query = Content::find() ->joinWith('category') ->where(['status' => Content::STATUS_ACTIVE]) ->where(['content_category.alias' => $categoryAlias]) //->orderBy('id') ->orderBy(['created_at' => SORT_DESC]) ->all(); return $this->render('index', [ 'models' => $query, ]); } === Tabs (Bootstrap) === Create a view with tabs to divide content. For example, when presenting data in tabs "Content" and "Options": use yii\bootstrap\Tabs;
field($model, 'title')->textInput(['maxlength' => 255]); ?>
'; $tabContent .= $form->field($model, 'intro_text')... $tabContent .= '
'; // Side column $tabContent .= '

'; $tabContent .= $form->field($model, 'category_id')... $tabContent .= '
'; //-------------------- // TAB: Publishing //-------------------- $tabOptions = '

'; $tabOptions .= $form->field($model, 'publish_up')... $tabOptions .= '
'; ?> [ [ 'label' => 'Content', 'content' => $tabContent, 'active' => true ], [ 'label' => 'Options', 'content' => $tabOptions, ], ], ]); ?>
isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
=== TextArea with Tinymce Editor === * Download component from: [[http://www.yiiframework.com/extension/tinymce-for-yii2/]] * Install: * Run: ''C:\> composer.phar require "letyii/yii2-tinymce" "dev-master"'' * Or: Add to ''require'' section in ''app/componser.json'': ''"letyii/yii2-tinymce": "dev-master"'' * Add widget to your view. Basic example: field($model, 'introtext')->widget(letyii\tinymce\Tinymce::className(), [ 'options' => [ 'id' => 'testid', ], 'configs' => [ // Read more: http://www.tinymce.com/wiki.php/Configuration 'plugins' => 'code image link media lists advlist table hr textcolor textpattern help', 'toolbar'=> 'undo redo | styleselect | removeformat bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image code help', 'height' => 300, ], ]); ?> Here is one with more options: field($model, 'introtext')->widget(letyii\tinymce\Tinymce::className(), [ 'options' => [ 'id' => 'testid', ], 'configs' => [ // Read more: http://www.tinymce.com/wiki.php/Configuration // full plugin list: http://www.tinymce.com/wiki.php/Plugins //'plugins' => 'advlist anchor autolink autoresize autosave bbcode charmap code // colorpicker compat3x contextmenu directionality emoticons example // example_dependency fullpage fullscreen hr image insertdatetime layer // legacyoutput link lists importcss media nonbreaking noneditable // pagebreak paste preview print save searchreplace spellchecker // tabfocus table template textcolor textpattern visualblocks visualchars wordcount', 'plugins' => 'code image link media table template hr spellchecker', 'templates' => [ ['title' => 'Template 1', 'description' => 'Basic Template', 'content' => 'Basic Template'], ['title' => 'Template 2', 'description' => 'Dev Template', 'url' => 'development.html'] ], 'link_list' => [ [ 'title' => 'My page 1', 'value' => 'http://www.tinymce.com', ], [ 'title' => 'My page 2', 'value' => 'http://www.tinymce.com', ], ], 'browser_spellcheck' => true, 'toolbar'=> 'undo redo | styleselect | removeformat bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image code help', //'menubar'=> 'tools table view insert edit format', // set menu order 'menu' => [ // this is the complete default configuration 'file' => ['title' => 'File', 'items' => 'newdocument'], 'edit' => ['title' => 'Edit' , 'items' => 'undo redo | cut copy paste pastetext | selectall'], 'insert' => ['title' => 'Insert', 'items' => 'link media | template hr'], 'view' => ['title' => 'View' , 'items' => 'visualaid'], 'format' => ['title' => 'Format', 'items' => 'bold italic underline strikethrough superscript subscript | formats | removeformat'], 'table' => ['title' => 'Table' , 'items' => 'inserttable tableprops deletetable | cell row column'], 'tools' => ['title' => 'Tools' , 'items' => 'spellchecker code'], ], 'height' => 300 ], ]); ?> === Form Fields === // Plain text field field($model, 'subject') ?> // Plain text field with placeholder and hint field($model, 'subject') ->textInput(['placeholder' => 'YYYY-MM-DD']) ->hint('A simple hint') ?> // TextArea field field($model, 'body')->textArea(['rows' => 6]) ?> // Field as textInput, with restrictions field($model, 'first_name')->textInput(['maxlength' => 255]) ?> // Field as textInput Date field($model, 'date')->textInput(['value' => Yii::$app->formatter->asDate('now', 'php:Y-m-d')]) ?> field($model, 'resolution_date')->textInput(['type'=>'date', 'placeholder' => 'Date input']) ?> field($model, 'due_date')->Input('date') ?> // Field with Label field($model, 'customer_id')->label('Customer') ?> // Field with Hidden Label field($model, 'sample_text')->textArea()->label(false) ?> // Field with Checkbox field($model, 'delivered')->checkBox() ?> field($model, 'is_valid')->checkBox(['label' => 'Is Valid?']) ?> // Field with dropDownList, or listBox field($model, 'printed')->dropDownList(['Yes'=>'Yes', 'No'=>'No']) ?> field($model, 'delivered')->dropDownList( ['Yes', 'No'], ['prompt'=>'--Select One--'] // options ) ?> field($model, 'power_response')->dropDownList( yii\helpers\ArrayHelper::merge( [$model->power_response], // current value \app\modules\requisition\models\CustomOrder::$power_response_types ), ['prompt'=>'--Select One--'] // options ) ?> field($model, 'status')->listBox( ['1'=>'Enabled', '0'=>'Disabled'] ) ?> // Field with radio buttons field($model, 'isUseful')->label('Is is useful?')->radioList([ 'Yes', 'No' ]) ?> // Field with check list field($model, 'productColors') ->label('What colors do you like? (choose all that apply)') ->checkBoxList([ 'Red', 'Green', 'Blue' ]) ?> // Field with checkboxlist field($model, 'help_methods')->label('I can help in the following ways (choose all that apply)') ->checkBoxList([ 'Help teach a class for 1-2 hours', 'Help with a fundraising event', 'Help cook for the day', ], [ 'onclick' => "$(this).val( $('input:checkbox:checked').val()); ", // if you use required as a validation rule, you will need this for the time being until a fix is in place by yii2 'item' => function($index, $label, $name, $checked, $value) { //return ""; //return "
"; return " {$label}
"; } ]) ?>
See: [[http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html|Yii ActiveField]] === Hidden Input === // Conditional hidden field display if this is a new record isNewRecord ? Html::activeHiddenInput($model, 'ip_address', ['value' => Yii::$app->request->userIP]) : $form->field($model, 'ip_address')->textInput( ['readonly' => Yii::$app->user->getId() != '100'] // is Admin? ) ) ?> // Conditional hidden field selection if this is a new record isNewRecord ? Html::activeHiddenInput($model, 'created', ['value' => Yii::$app->formatter->asDate('now', 'php:Y-m-d')]) : Html::activeHiddenInput($model, 'modified', ['value' => Yii::$app->formatter->asDate('now', 'php:Y-m-d')]) ) ?> See more Field options: [[http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html|Yii Widgets: ActiveField]] === Inline Controls ===
Style
field($model, 'style_left')->label('')->dropDownList( [ 'IIC'=>'IIC', 'CIC'=>'CIC', 'Canal'=>'Canal', 'Mini Canal'=>'Mini Canal', 'Half Shell'=>'Half Shell', 'Full Shell'=>'Full Shell', ], ['prompt'=>'--Select One--'] // options ) ?>
field($model, 'style_right')->label('')->dropDownList( [ 'IIC'=>'IIC', 'CIC'=>'CIC', 'Canal'=>'Canal', 'Mini Canal'=>'Mini Canal', 'Half Shell'=>'Half Shell', 'Full Shell'=>'Full Shell', ], ['prompt'=>'--Select One--'] // options ) ?>
=== Modal Window === * See: [[systems:yii2:Modal Window]] == Events == Some events that can be handled in a model are: afterFind(), beforeValidate(), afterValidate(), beforeSave(), afterSave(), beforeDelete(), afterDelete(). For example: /** * @return success */ public function beforeValidate() { if (parent::beforeValidate()) { // Do some work before validation. // Eg: Populate field with automatic values (set default values). $this->LastEdited = new \yii\db\Expression('NOW()'); return true; // validated } return false; // not validated } /** * @return success */ public function beforeSave($insert) { if (parent::beforeSave($insert)) { // Do some work before saving. // Eg: Populate field with automatic values. if (empty($this->cost)) { $this->cost = 0; } if (empty($this->warranty_included)) { $this->warranty_included = 0; } return true; // validated } return false; // not validated } See Also: * [[http://www.sitepoint.com/yii-2-0-activerecord-explained/| Yii 2.0 ActiveRecord Explained]] == Field Validation == * [[http://www.yiiframework.com/doc-2.0/guide-input-validation.html|Input Validation]] * [[http://www.yiiframework.com/doc-2.0/guide-tutorial-core-validators.html|Core Validators]] * Get validation errors: [[http://www.yiiframework.com/doc-2.0/yii-base-model.html#getErrors()-detail|$model->getErrors()]] Output errors on a controller: echo "Errors: ".print_r($model->getErrors(), true)."\n"; Output errors on a view: Method 1 session->setFlash('error', print_r($model->getErrors(), true) ) ?> Method 2 'errors']) ?> == Flash Messages == Set flash message in Controller using: $count = 25; Yii::$app->session->setFlash('success', "Saved {$count} items successfully."); return $this->redirect(['view', 'id' => $model->id]); ... Display flash message in View using:
session->hasFlash('success')): ?> session->hasFlash('error')): ?>
...
In the view template ''[app]/views/layouts/main.php'', you can simply add ''Alert::widget()'' to have flash messages display there: use frontend\widgets\Alert; // for advanced app use app\widgets\Alert; // for basic app (alternative 1) use yii\bootstrap\Alert; // for basic app (alternative 2) ...
isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], ]) ?>
== Common Behaviors == Some tables require to provide timestamps and users who created or updated a record. With some built-in behaviors we can add the functionality without much code. For each model requiring it, add the following behaviors: use yii\behaviors\BlameableBehavior; use yii\behaviors\TimestampBehavior; use yii\db\Expression; /** * @inheritdoc */ public function behaviors() { date_default_timezone_set( (!empty(Yii::$app->params['timezone']) ? Yii::$app->params['timezone'] : 'America/New_York') ); return [ [ 'class' => TimestampBehavior::className(), 'createdAtAttribute' => 'created_at', // OR 'create_time', to override default field name 'updatedAtAttribute' => 'updated_at', // OR 'update_time', to override default field name 'value' => new \yii\db\Expression('NOW()'), // for PHP/SQL datetime field //'value' => time(), // for epoch time (unix) field ], [ 'class' => BlameableBehavior::className(), 'createdByAttribute' => 'created_by', // OR 'author_id', to override default field name 'updatedByAttribute' => 'updated_by', // OR 'updater_id', to override default field name ], ]; } See more: * [[http://www.yiiframework.com/doc-2.0/yii-behaviors-timestampbehavior.html| TimeStampBehavior]] * [[http://www.yiiframework.com/doc-2.0/yii-behaviors-blameablebehavior.html| BlameableBehavior]] == Authorization == === User Access Based on Behavior Rules === Add ''access'' settings in the ''behavior()'' function in the required controller: use yii\filters\AccessControl; //... class MyController extends Controller { //... public function behaviors() { return [ 'access' => [ 'class' => AccessControl::className(), 'only' => ['index', 'create', 'view', 'update', 'delete'], // comment this if all pages require auth 'rules' => [ //[ // Guest users // 'allow' => true, // 'actions' => ['index', 'view'], // 'roles' => ['?'], // ? = Guest user //], [ // Authenticated users 'actions' => ['index', 'view'], 'allow' => true, 'roles' => ['@'], // @ = Authenticated users ], [ // Admin users 'actions' => ['index', 'create', 'view', 'update', 'delete'], 'allow' => true, 'matchCallback' => function ($rule, $action) { //return (!Yii::$app->user->isGuest && Yii::$app->user->identity->isAdmin()); return (isset(Yii::$app->user->identity) && (Yii::$app->user->identity->role === 'admin')); } ], ], ], //... ]; } } See: * [[http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#access-control-filter|Yii 2.0 Doc: Access Control Filter]] === User Access Based on Permissions === Allowing access to certain sections based on user roles: if (Yii::$app->user->isGuest) { // show or do something for guest (not authenticated) users only } When giving access to only admin: use app\models\User; // Get user roles (requires authManager to be configured) if (in_array(User::ROLE_ADMIN, Yii::$app->authManager->getRolesByUser(Yii::$app->user->getId()))) { // Do something } // access only to admin user if (Yii::$app->user->getId() == User::USER_ADMIN) { // show or do something for admin user only } // access only to admin user if (isset(Yii::$app->user->identity) && ((Yii::$app->user->identity->username == 'admin')) { // show or do something for admin user only } // access only to admin users (based on role) if (isset(Yii::$app->user->identity) && (Yii::$app->user->identity->role == User::ROLE_ADMIN)) { // show or do something for users with admin role only } Note: * ''Yii::$app->user->identity'' has all the authenticated user details (id, username, role, etc.), but ''identity'' attribute is not available when not logged in. * To use ''getRolesByUser()'', you need to have ''authManager'' configured first. See [[http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#role-based-access-control-rbac|Security using RBAC]]. Define admin role in ''app\models\User.php'' ... class User extends ActiveRecord implements IdentityInterface { // Roles const ROLE_ADMIN = 1; // Super user const ROLE_MANAGER = 2; // Create/update content, edit user profiles const ROLE_EDITOR = 3; // Create/update content const ROLE_AUTHOR = 4; // Create content, update own content only const ROLE_USER = 10; // Basic site use. Same as ROLE_REGISTERED const ROLE_REGISTERED = 10; // Basic site use. Same as ROLE_USER ... } === Access Based on Roles (RBAC) === See [[systems:yii2:Role Based Access Control (RBAC)]] === References === See also: * [[http://www.yiiframework.com/doc-2.0/yii-filters-accesscontrol.html|Yii Access Control Filters]] * [[http://www.yiiframework.com/doc-2.0/yii-filters-accessrule.html|Yii Filters Access Rule]] * [[http://www.yiiframework.com/doc-2.0/guide-security-authorization.html|Security Authorization]] * [[http://www.yiiframework.com/doc-2.0/yii-web-user.html|Yii Web User]] == System Variables == === URL and Path Variables: Root or Base Path === ^ Variable ^ Value ^ Description ^ | ''homeUrl ?>'' | ''http://example.com/myapp/web/'' | | | ''request->baseUrl ?>'' | ''http://example.com/myapp/web'' | | | ''str_replace('/frontend/web/', "", str_replace('/backend/web/', "", Yii::$app->homeUrl))'' | ''/myapp/web'' | Equivalent to ''Yii::$app->request->baseUrl'' without host. | | ''basePath ?>'' | ''C:\wamp\www\myapp\basic'' (or ''C:\wamp\www\myapp\advanced\backend''). | Eg: ''Yii::$app->basePath . DS . 'migrations' . DS . 'data' . DS . 'customer-data.rpt';'', where ''define('DS', DIRECTORY_SEPARATOR);'' | | '''' | ''C:/wamp/www/myapp/basic'' (or ''C:/wamp/www/myapp/advanced/backend''). | For other predefined aliases, see [[http://www.yiiframework.com/doc-2.0/guide-concept-aliases.html|Yii 2: Predefined Aliases]] and also [[http://www.yiiframework.com/wiki/667/yii-2-list-of-path-aliases-available-with-default-basic-and-advanced-app/|Available Path Aliases]]. | | ''params['frontendUrl'] ?>'' | Whatever string was stored. | Basically, add a global variable ''$frontendUrl'' to ''basic/config/params.php'' or ''common/config/params.php'', and access it using ''params['frontendUrl'] ?>''. | | ''request->userIP ?>'' | ''192.168.0.x'' | User IP address. | | ''user->id ?>'' | ''100'' | User ID. | | ''user->identity->username ?>'' | ''admin'' | Username. | | ''user->isGuest ?>'' | ''true'' | T if user is guest (not logged in). | | ''$isAdmin = (isset(Yii::$app->user->identity) && (Yii::$app->user->identity->role == User::ROLE_ADMIN))'' | ''true'' | T if use is admin. Requires adding role support to User model. | | ''$isAdmin = (!Yii::$app->user->isGuest && (Yii::$app->user->identity->role == self::ROLE_ADMIN))'' | ''true'' | T if use is admin. Requires adding role support to User model. | ^ Target ^ Variable ^ Description ^ | controller name | ''Yii::$app->controller->id'' | | | controller name | ''Yii::$app->getController()->getId()'' | | | controller name | ''$this->id'' | where ''$this'' refers to current controller | | action name | ''$this->action->id'' | where ''$this'' refers to current controller | | action name | ''Yii::$app->controller->action->id'' | | | module name | ''Yii::$app->controller->module->id'' | | | module name | ''$this->module->id'' | | | module object | ''Yii::$app→controller→module'' | | You can create backend and frontend urls using this in the ''[app]/backend/config/main.php'' file: return [ ... 'components' => [ 'urlManager' => [ // here is your normal backend url manager config //'class' => 'yii\web\UrlManager', 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [] ], 'urlManagerFrontend' => [ // here is your frontend URL manager config 'class' => 'yii\web\UrlManager', 'baseUrl' => '../../../frontend/web', 'enablePrettyUrl' => true, 'showScriptName' => false, 'rules' => [] ], ] ]; In the view, use this: echo Yii::$app->urlManager->createUrl(''); // returns ''/backend/web'' echo Yii::$app->urlManagerFrontend->createUrl(''); // returns ''/frontend/web'' echo Yii::$app->urlManagerFrontend->createUrl(['user/activate', 'id' => $model->id]); // returns ''/frontend/web/user/activate?id=71'' echo Yii::$app->urlManagerFrontend->createAbsoluteUrl(['user/activate', 'id' => $model->id]); // returns ''http://localhost:8080:myapp/frontend/web/user/activate?id=71'' === Global Variables === Add global variables to ''basic/config/params.php'' or ''common/config/params.php'': Simple add a key and value pairs: return [ 'adminEmail' => 'admin@example.com', 'supportEmail' => 'support@example.com', 'user.passwordResetTokenExpire' => 3600, 'frontendUrl' => 'http://www.example.com/frontend/web', ]; You can then use that variable anywhere in the system: params['frontendUrl'] ?> === Namespaces === Depending on what application you are using (console, basic, frontend/backend (advanced), etc.), you can end up trying to make reference to a namespace not found in that current application. For example, a migration console script cannot see namespaces defined in the frontend app. To solve this issue, you can add class maps that register the required namespace. Eg: In ''console/migrations/m10000_init.php'' script: // Add namespace for 'Dealers' frontend module, to access 'Dealer' model // which resides in [app]/frontend/modules/dealers/models/Dealer.php Yii::setAlias('@frontend', '@app/../frontend'); Yii::$classMap['app\modules\dealers\models\Dealer'] = '@frontend/modules/dealers/models/Dealer.php'; // Make use of namespace. Eg: $availTables = [ common\models\Payment::tableName(), app\modules\dealers\models\Dealer::tableName(), common\models\Distributor::tableName(), common\models\AccountAging::tableName(), common\models\User::tableName(), ]; To add a custom namespace to the autoloader you need to define an alias for the base directory of the namespace using ''Yii::setAlias()''. For example to load classes in the foo namespace that are located in the ''path/to/foo'' directory you will call ''Yii::setAlias('@foo', 'path/to/foo')''. See more: [[https://www.yiiframework.com/doc/guide/2.0/en/concept-autoloading|Namespace and Autoloading]] === Debug Variables / Logging === Use ''VarDumper'' which is intended to replace the buggy PHP function ''var_dump()'' and ''print_r()''. use yii\helpers\VarDumper; ... // Use one of these VarDumper::dump($item); VarDumper::dumpAsString($item); VarDumper::export($item); // To be more legible: echo '
' . yii\helpers\VarDumper::dumpAsString($item) . '
';
Alternatively, you can log directly to the log file: Yii::trace('Item data: ' . print_r($item, true), __METHOD__); You can also display error content to a view. For example, if a ''save()'' command fails in a controller, we can display the error contents to the view using ''print_r($model->getErrors())'' like this: public function actionUpdate($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request->post())) { if($model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { Yii::$app->session->setFlash('error', "Error during save. Missing field. Error:
" . print_r($model->getErrors(), true) . "
"); return $this->render('update', [ 'model' => $model, ]); } } else { return $this->render('update', [ 'model' => $model, ]); } }
=== YII_DEBUG Variable: Switching Between Development/Production Environments === In development, execute the ''init'' command and select ''dev'' as environment. $php /path/to/yii-application/init Otherwise, in production, execute ''init'' in non-interactive mode. NOTE: Make sure all existing config files are backed up. This includes ''config'' in Basic App, or ''frontend/config'', ''backend/config'', and ''common/config'' directories in Advanced App. $php /path/to/yii-application/init --env=Production --overwrite=All The results might look like this. Note all the files that get overwritten: W:\site>init --env=Production --overwrite=All Yii Application Initialization Tool v1.0 Start initialization ... unchanged console/config/params-local.php unchanged console/config/main-local.php exist common/config/params-local.php ...overwrite? [Yes|No|All|Quit] overwrite common/config/params-local.php overwrite common/config/main-local.php overwrite backend/web/index.php unchanged backend/config/params-local.php overwrite backend/config/main-local.php overwrite yii overwrite frontend/web/index.php unchanged frontend/config/params-local.php overwrite frontend/config/main-local.php generate cookie validation key in backend/config/main-local.php generate cookie validation key in frontend/config/main-local.php chmod 0777 backend/runtime chmod 0777 backend/web/assets chmod 0777 frontend/runtime chmod 0777 frontend/web/assets chmod 0755 yii ... initialization completed. To verify, view file ''[app]/web/index.php'': // The following two lines are active when in dev mode. // Use '[yiiapp]/init --env=Production --overwrite=All' when deployed to production. defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); Alternatively, add this: if ($_SERVER['SERVER_NAME'] == 'localhost' || $_SERVER['SERVER_NAME'] == '127.0.0.1') { defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_ENV') or define('YII_ENV', 'dev'); } else { defined('YII_DEBUG') or define('YII_DEBUG', false); defined('YII_ENV') or define('YII_ENV', 'prod'); } See Also: * [[http://www.yiiframework.com/doc-2.0/guide-concept-configurations.html|Yii2 Configurations]] * [[http://yii2-framework.readthedocs.org/en/stable/guide/tutorial-advanced-app/]] == Controllers == Calling another controller for the current controller: Yii::$app->runAction('main/goods', ['model_id' => $goods->id]); Sometimes trying to save data, it fails due to CSRF checks. This is a workaround: /** * ContentController implements the CRUD actions for Content model. */ class ContentController extends Controller { public $enableCsrfValidation = true; // Set to 'false' if having trouble saving data (create/update, etc.) // ... /** * Updates an existing Content model. * If update is successful, the browser will be redirected to the 'view' page. * @param integer $id * @return mixed */ public function actionUpdate($id) { // set to 'false' to overcome 'Unable to verify your data submission: Bad request (#400)' error. $this->enableCsrfValidation = false; $model = $this->findModel($id); if ($model->load(Yii::$app->request->post()) && $model->save()) { return $this->redirect(['view', 'id' => $model->id]); } else { // set values before rendering if (empty($model->updated_by)) $model->updated_by = Yii::$app->user->id; return $this->render('update', [ 'model' => $model, ]); } $this->enableCsrfValidation = true; // restore CSRF validation } } == Views == === Accessing Data in View === ==== Send Data from Controller (push method) ==== In the controller action, call the ''render()'' method with some data. echo $this->render('report', [ 'foo' => 1, 'bar' => 2, ]); ==== Get Data from Controller (pull method) ==== Sometimes in a view, you need to get data from the controller. Eg: The controller ID is: context->id ?> Some controller data: context; echo 'controller id = ' . $controller->id; echo 'controller data = '. $controller->getData(); ?> === Get Current View Name === Sometimes in a view, you need to get the current view's name. Here is how to do it: view->context->action->id; // For view 'site/index', the view ID = 'index' ?> === Security === To avoid cross-site scripting, encode any text to display:
name) ?>
To display HTML content, filter it to avoid issues:
text) ?>
=== Render a View File from Any View === When wanting to embed and render another view file into the existing view, simply include it in the right place. Eg: For view ''/site/index'', add ''/site/about'': title = 'Index'; $this->params['breadcrumbs'][] = Html::encode($this->title); ?>

title; ?>

...
view->renderFile('@frontend/views/site/about.php'); ?>
See also: * [[http://www.yiiframework.com/doc-2.0/guide-structure-views.html#rendering-in-views|Rendering in Views]] * [[http://www.yiiframework.com/doc-2.0/guide-structure-views.html#rendering-in-other-places|Rendering in Other Places]] === Custom Layout === Add a custom layout in controller function when needed: ... class ContentController extends Controller { ... public function actionIndex() { ... $this->layout = 'new-layout'; } } See also: * [[http://www.yiiframework.com/doc-2.0/guide-structure-views.html#using-layouts|Using Layouts]] === View Without Model === Create a form with fields not attached to a model: View (file ''/app/views/issue/search.php''): use yii\helpers\Html; use yii\widgets\ActiveForm; ...

'account', 'maxlength' => true, 'class' => 'form-control'] ) ?> ...
=== View With Model Not Connected to Database === Add the required fields to the model and use them in the view. Model (file ''/app/models/Issue.php''): //class Issue extends \yii\db\ActiveRecord // for database support class Issue extends \yii\base\Model // for no database support { // Add field public $account_number = ''; ... // Add validation rule public function rules() { return [ [['account_number', ...], 'string', 'max' => 255], ]; } // Add field label public function attributeLabels() { return [ ... 'account_number' => Yii::t('app', 'Account Number'), ]; } ... } View (file ''/app/views/issue/search.php''): use yii\helpers\Html; use yii\widgets\ActiveForm; ...
field($model, 'account_number')->textInput(['maxlength' => true']) ?> ...
== Inline Javascript & AJAX == You can add Javascript functionality anywhere in a view, if necessary: // NOTE: $position can be: // View::POS_READY (the default) // View::POS_HEAD // View::POS_BEGIN // View::POS_END $position = \yii\web\View::POS_END; // Inline block of Javascript $jsBlock = " $('#el').on('click', function(e) { $.ajax({ url: '/path/to/action', data: {id: '', 'other': ''}, success: function(data) { // process data } }); }); "; $this->registerJs($jsBlock, $position); // Alternatively, use Javascript from an external file $this->registerJsFile('http://example.com/lib/external.js', $position); Alternatively, write it so: registerJs($script); ?> Alternatively, to link to a JavaScript file: See more: * [[http://www.yiiframework.com/doc-2.0/yii-web-view.html#registerJsFile()-detail|registerJs()]] * [[http://www.yiiframework.com/doc-2.0/yii-web-view.html#registerJsFile()-detail|registerJsFile()]] * [[http://www.yiiframework.com/doc-2.0/guide-helper-html.html#styles-and-scripts|Styles and Scripts]] === AJAX Example (returning HTML) === Eg: The view ''_form'' for the ''IssueController'' (file ''[app]/views/issue/_form.php''):
field($model, 'account_number')->textInput([ 'maxlength' => true, 'onchange' =>'getCustomerRecord()', 'onmouseover'=>'getCustomerRecord()' ]) ?>

'company_search_results']); ?>

...
registerJs($jsBlock, $position); $jsBlock = " function getCustomerRecord() { $.ajax({ url: '" . Yii::$app->request->baseUrl. '/issue/get-company' . "', data: { account_number: $('#issue-account_number').val(), }, type: 'POST', cache: false, // Code to run if the request succeeds; // the response is passed to the function success: function(data) { // process data console.log('data: [' + data + ']'); $('#company_search_results').html(data); }, // Code to run if the request fails; the raw request and // status codes are passed to the function error: function( xhr, status, errorThrown ) { alert('Sorry, there was a problem! Error: ' + errorThrown + '. Status: ' + status + ' ' + xhr + ' ' ); console.log('Error: ' + errorThrown ); console.log('Status: ' + status ); console.dir( xhr ); }, // Code to run regardless of success or failure complete: function( xhr, status ) { //alert('The request is complete!'); } }); } "; // NOTE: $position can be: // View::POS_READY (the default) // View::POS_HEAD // View::POS_BEGIN // View::POS_END $position = \yii\web\View::POS_END; $this->registerJs($jsBlock, $position); ?>
Eg: The action ''get-company'' in ''IssueController'' (file ''[app]/controllers/IssueController.php''): use Yii; use app\models\Customer; ... class IssueController extends Controller { public function actionGetCompany() { if (Yii::$app->request->isPost) { $account_number = Yii::$app->request->post('account_number'); Yii::info('POST account_number: ' . $account_number, 'actionGetrec'); } if (empty($account_number)) { $modelCust = new Customer(); $account_number = $modelCust->account_number; $company_name = $modelCust->company_name; $arrCustomer = $modelCust->toArray(); Yii::info('Empty account_number: ' . $account_number . 'company_name: ' . $company_name, 'actionGetrec'); } else { $modelCust = Customer::find()->where(['account_number' => $account_number])->one(); $arrCustomer = Customer::find()->where(['account_number' => $account_number])->asArray()->one(); if(!empty($modelCust)) { $company_name = $modelCust->company_name; Yii::info('Found customer: ' . print_r($modelCust, true), 'actionGetrec'); Yii::info('Found account_number: ' . $account_number . 'company_name: ' . $company_name, 'actionGetrec'); } else { Yii::info('Customer not found: ' . $account_number, 'actionGetrec'); } } $model = new Issue(); $data = array(); //if (!empty($arrCustomer['account_number'])) { $data[] = $arrCustomer['account_number']; } if (!empty($arrCustomer['company_name'])) { $data[] = $arrCustomer['company_name']; } if (!empty($arrCustomer['address'])) { $data[] = $arrCustomer['address']; } if (!empty($arrCustomer['city'])) { $data[] = $arrCustomer['city']; } if (!empty($arrCustomer['state_prov'])) { $data[] = $arrCustomer['state_prov']; } if (!empty($arrCustomer['country'])) { $data[] = $arrCustomer['country']; } if (!empty($arrCustomer['phone'])) { $data[] = $arrCustomer['phone']; } if (!empty($arrCustomer['phone'])) { $data[] = $arrCustomer['phone']; } if (!empty($arrCustomer['email'])) { $data[] = $arrCustomer['email']; } if (count($data) > 0) { return ''; } else { return ''; } } //public function actionGetCustomerRecord() //{ // if (Yii::$app->request->isAjax) { // $data = Yii::$app->request->post(); // $account_number= explode(":", $data['account_number']); // $account_number= $account_number[0]; // \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; // return [ // 'account_number' => $account_number, // 'code' => 100, // ]; // } //} ... } == Assets == Place CSS and JS assets in ''[app]/web/'', then add references in ''AppAsset.php'' for main application, or ''MyComponentAsset.php'' for a component or site section with specific asset requirements: // Class name should be AppAsset for the main app assets, // or MyComponentAsset for your specific component assets. class AppAsset extends AssetBundle { public $basePath = '@webroot'; public $baseUrl = '@web'; public $css = [ // Place CSS assets here ... ]; public $js = [ // Place JS assets here ... ]; public $depends = [ 'yii\web\YiiAsset', 'yii\bootstrap\BootstrapAsset', ]; } Using assets in a view: use app\assets\MyComponentAsset; MyComponentAsset::register($this); // $this represents the view object ... See more: [[http://www.yiiframework.com/doc-2.0/guide-structure-assets.html|Guide 2.0: Structure Assets]] == Model Constants == Sometimes we need to use constants when working with models. Eg: Finding all customer with active status (''STATUS_ACTIVE''): // Retrieve all *active* customers and order them by their ID: $customers = Customer::find() ->where(['status' => Customer::STATUS_ACTIVE]) ->orderBy('id') ->all(); We defined them in the model like this: namespace app\models; use Yii; class Customer extends \yii\db\ActiveRecord { // Model constants const STATUS_ACTIVE= 1; const STATUS_INACTIVE= 0; ... } == General Purpose Data in Views == For example, many forms use Country or State as an input field. We can populate these fields with a predetermined dropdown list. Create a basic model where to store the data. Eg: ''app\models\Tool.php'': namespace app\models; use yii\base\Model; // parent for model classes not associated with database tables //use yii\db\ActiveRecord; // parent for model classes that do correspond to database tables /** * This is the model class for table "Tools". * * @property array $countries * @property array $countryNames * @property array $languages * @property array $states */ class Tool extends Model { public static $countries = array( 'af' => 'Afganistan', 'al' => 'Albania', ... ); public static $countryNames= array(...); public static $languages= array(...); public static $states = array( "N/A"=> "Not Applicable", "AL"=> "AL - Alabama", ... "WI"=> "WI - Wisconsin", "WY"=> "WY - Wyoming" ); /** * @inheritdoc */ public function rules() { return [ [['countries', 'countryNames', 'languages', 'states'], 'safe'], ]; } } Add fields to a model that needs it. Eg: For model ''Customer'', we add these functions in ''app\models\Customer.php'': namespace app\models; use Yii; use app\models\Tool; // Our model with static data class Customer extends \yii\db\ActiveRecord { ... public function getStates() { return Tool::$states; } public function getCountries() { return Tool::$countryNames; } } Make use of that data in a view. Eg: For a create customer view, we add these fields in ''ap\views\customer\_form.php'': use yii\helpers\Html; use yii\widgets\ActiveForm; /* @var $this yii\web\View */ /* @var $model app\models\Customer*/ /* @var $form yii\widgets\ActiveForm */ ?>
field($model, 'name')->textInput(['maxlength' => 255]) ?> ... field($model, 'state_prov')->dropDownList( $model->states, [ 'prompt' => '--Select One--' ] ) ?> field($model, 'postal_code')->textInput(['maxlength' => 255]) ?> field($model, 'country')->dropDownList( $model->countries, [ 'prompt' => '--Select One--' ] ) ?> ...
isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
== Virtual Attributes (aka Virtual Fields) == A model might need an additional fields not found in the database table. For example, ''customer'' has ''last_name'' and ''first_name'', but sometimes you need a ''fullname''. Instead of combining last and first names every time, we can use a virtual attributes to create ''fullname''. In your ''customer'' model, add the following: class Customer extends \yii\db\ActiveRecord { public function rules() { return [ [['first_name', 'last_name'], 'string', 'max' => 255], ... [['fullname'], 'safe'] // virtual attributes ]; } public function attributeLabels() { return [ 'id' => Yii::t('app', 'ID'), 'first_name' => Yii::t('app', 'First Name'), 'last_name' => Yii::t('app', 'Last Name'), ... 'fullname' => Yii::t('app', 'Name'), ]; } // Virtual attributes public function getFullName() { return $this->first_name . " " . $this->last_name; } } This new field can be used in a controller: echo $model->fullname; This can be used in a view like any other field: $model, 'attributes' => [ 'id', //'first_name', //'last_name', 'fullname', ], ]) ?> Alternatively, you can simply add a virtual field to MySQL/MariaDB: // Full Account Num: concat(`account_number`, IFNULL(CONCAT('-',`shipto`), '') ) ALTER TABLE customer ADD full_account_num char(60) GENERATED ALWAYS AS concat(`account_number`, IFNULL(CONCAT('-',`shipto`), '') VIRTUAL NOT NULL; // Full Name: concat(`first_name`, IFNULL(`last_name`, '') ) ALTER TABLE customer ADD full_name char(60) GENERATED ALWAYS AS concat(`first_name`, IFNULL(`last_name`, '') ) VIRTUAL NOT NULL; == Using Related Models in a View == Set relations in model. For example, in model ''order'': class Order extends \yii\db\ActiveRecord { public function getCustomer() { // Order has_one Customer via Customer.id -> customer_id return $this->hasOne(Customer::className(), ['id' => 'customer_id']); } ... } Alternatively, join tables in a query to access relational data in a view. We do this query in the controller: //$query = Order::find(); // use this if relations are setup in 'Order' model already $query = Order::find()->joinWith('customer'); // use for dataprovider columns for sorting purposes (eg. 'customer.city') In the view, just make reference to the related model fields. Eg: ''customer.last_name'', ''customer.company_name'': $dataProvider, 'filterModel' => $searchModel, 'columns' => [ ['class' => 'yii\grid\SerialColumn'], [ 'attribute' => 'id', 'format' => ['raw'], 'value' => function($data) { $ordernum = str_pad($data['id'], 6, "0", STR_PAD_LEFT); // link to view record return Html::a(Html::encode($ordernum), Url::toRoute(['view', 'id' => $data['id']])); // link to view record }, 'label' => 'Order ID' ], 'date', //'customer.first_name', //'customer.last_name', 'customer.fullname', 'customer.company_name', // Searchable fields [ 'attribute'=>'city', 'value'=>'customer.city' ], [ 'attribute'=>'state_prov', 'value'=>'customer.state_prov' ], [ 'attribute'=>'country', 'value'=>'customer.country' ], ['class' => 'yii\grid\ActionColumn'], ], ]); ?> When creating the ''index'' view, you would normally have support for search. In the ''OrderSearch'' model, this is how it would look (assuming ''order.customer_id = customer.id''): namespace app\models; use Yii; use yii\base\Model; use yii\data\ActiveDataProvider; use app\models\Order; /** * OrderSearch represents the model behind the search form about `app\models\Order`. */ class OrderSearch extends Order { // Add the public attributes that will be used to store the data to be searched public $company_name; public $city; public $state_prov; public $country; // Add search fields to rules public function rules() { return [ [['id', 'customer_id', 'user_id'], 'integer'], [['date', 'company_name', 'city', 'state_prov', 'country'], 'safe'], ]; } public function search($params) { //$query = Order::find(); $query = Order::find()->joinWith('customer'); $dataProvider = new ActiveDataProvider([ 'query' => $query, ]); // Add search fields to sorting attributes // Note: This is setup before the $this->load($params) statement below $dataProvider->setSort([ 'attributes' => [ 'id', 'name', 'date', 'customer.fullname' => [ 'asc' => ['customer.last_name' => SORT_ASC], 'desc' => ['customer.last_name' => SORT_DESC], 'label' => 'Customer Name' ], 'company_name' => [ 'asc' => ['customer.company_name' => SORT_ASC], 'desc' => ['customer.company_name' => SORT_DESC], 'label' => 'Company' ], 'city' => [ 'asc' => ['customer.city' => SORT_ASC], 'desc' => ['customer.city' => SORT_DESC], 'label' => 'City' ], 'state_prov' => [ 'asc' => ['customer.state_prov' => SORT_ASC], 'desc' => ['customer.state_prov' => SORT_DESC], 'label' => 'State/Province' ] 'country' => [ 'asc' => ['customer.country' => SORT_ASC], 'desc' => ['customer.country' => SORT_DESC], 'label' => 'Country' ] ] ]); if (!($this->load($params) && $this->validate())) { return $dataProvider; } // Add search fields to filter $query->andFilterWhere([ 'id' => $this->id, 'date' => $this->date, 'customer_id' => $this->customer_id, //'customer.company_name' => $this->company_name, //'customer.city' => $this->city, //'customer.state_prov' => $this->state_prov, //'customer.country' => $this->country, 'user_id' => $this->user_id, ]) // Add searchable attributes ->andFilterWhere(['like', 'LOWER(customer.company_name)', strtolower($this->company_name)]) ->andFilterWhere(['like', 'LOWER(customer.city)', strtolower($this->city)]); ->andFilterWhere(['like', 'LOWER(customer.state_prov)', strtolower($this->state_prov)]); ->andFilterWhere(['like', 'LOWER(customer.country)', strtolower($this->country)]); return $dataProvider; } ... } == Creating Extensions == Create extension controller in ''[app]/vendor/acme/myext/myext.php'': namespace acme; use yii\web\Controller; class MyExtController extends Controller { // Action here } Optional Step: Create bootstrap class in component, to attach controller class automatically. Eg. ''[app]/vendor/acme/myext/MyBootstrap.php'': controllerMap['myext'] = '\acme\myext\MyExtController'; } } To register extension manually (when installing and autoloading through ''composer'' is not available), write the following code inside the application configuration (or directly on the file ''[app]/vendor/yiisoft/extensions.php''): $vendorDir = __DIR__ . '/..'; 'extensions' => array_merge( (require __DIR__ . '/../vendor/yiisoft/extensions.php'), [ 'acme\myext' => [ 'name' => 'MyExtension', 'version' => '1.0.0', 'bootstrap' => '\acme\myext\MyBootstrap', 'alias' => ['@acme/myext' => $vendorDir . '/acme/myext'] // path to extension ] ] ) Add extension to application configuration. In ''[app]/config/web.php'', add this to ''components'': ... $config = [ ... 'components' => [ ... 'myext' => [ 'class' => 'acme\myext\MyExt', ], ]; ... To allow automatic registration using ''composer'', we need to create a ''composer.json'' file in the extension directory. Eg: ''[app]/vendor/acme/myext/composer.json'' { "name": "acme/yii2-myext", "version": "1.0.0", "description": "Yii2 MyExtension", "keywords": ["yii2", "myext", "Sample Extension"], "homepage": "https://github.com/acme/yii2-acme", "type": "yii2-extension", "license": "BSD 3-Clause", "authors": [ { "name": "John Doe", "email": "info@example.com", "homepage": "http://www.example.com/" } ], "require": { "yiisoft/yii2": "*" }, "autoload": { "psr-4": { "acme\\myext\\": "" } }, "extra": { "bootstrap": "acme\\Bootstrap" } } Install with ''composer''. Either run from command line: * Linux/Mac: $ php composer.phar require "acme/yii2-myext:*" * Windows: C:\www\Yii2Site\> composer require "acme/yii2-myext:*" Or: * Add this line to the ''require'' section of your ''composer.json'' file:... "require": { ... "acme/yii2-myext": "dev-master" } * Run ''composer install'' to install the specified extensions. See: * [[https://www.packtpub.com/books/content/creating-extension-yii-2|Creating Extension in Yii 2.0]] * [[http://www.yiiframework.com/doc-2.0/guide-structure-extensions.html|Yii 2.0 Guide: Extensions]] == Cache Flushing Guide == When you need to invalidate all the stored cache data, you can call ''yii\caching\Cache::flush()''. You can flush the cache from the console by calling ''yii cache/flush'' as well. * ''yii cache'': lists the available caches in application. * ''yii cache/flush cache1 cache2'': flushes the cache components ''cache1'', ''cache2'' (you can pass multiple component names separated with space). * ''yii cache/flush-all'': flushes all cache components in the application. Info: Console application uses a separate configuration file by default. Ensure, that you have the same caching components in your web and console application configs to reach the proper effect. Source: * [[http://www.yiiframework.com/doc-2.0/guide-caching-data.html#cache-flushing]] == DataProvider == You can override certain default values used in the DataProvider. To filter all records by a customer ID: $searchModelPrice = new \app\models\PriceSearch(); $dataProviderPrice = $searchModelPrice->search(yii\helpers\ArrayHelper::merge( Yii::$app->request->queryParams, ['PriceSearch' => [ 'customer_id' => $id, ]] )); Or override the pagination to be greater than the default 20 rows per page: $searchModelPrice = new \app\models\PriceSearch(); $dataProviderPrice = $searchModelPrice->search(Yii::$app->request->queryParams)); $dataProviderPrice->pagination->defaultPageSize = 1000; $dataProviderPrice->pagination->pageSizeLimit = false; == Copy to Clipboard using Javascript == # Add a reference to the //ClipboardJS// library either by using Yii2 registerJsFile or adding the file to ''assets\AppAsset.php'' # Add javascript to your page that creates an instance of ClipboardJS: $this->registerJs("var clipboard = new ClipboardJS('.btn-clip');", \yii\web\View::POS_END); # Add a button that follows this logic: