I have a Create Payslip page and I want to pass a dynamic model since this page/view requires more than one earning items.
My actionCreateNew in my controller:
$session = Yii::$app->session;
$model = new Payslip();
$model->user_id = $id;
$model1 = new EarningDetails();
$model2 = new DeductionDetails();
$items = PayrollItems::find()->where(['store_id' => $id])->andwhere(['active' => 1])->andwhere(['payroll_type' => 'Earnings'])->all();
$count = count($items);
for($i = 1; $i <= $count; $i++){
$earning[$i] = new EarningDetails();
$earning[$i]->earning_item_id = $items[$i];
}
and here's my return statement in the same action controller:
return $this->render('create', [
'model' => $model,
'model1' => $model1,
'model2' => $model2,
'items' => $items,
]);
and in my view:
<?php
$earnings = PayrollItems::find()->where(['store_id' => $session['store_id']])->orwhere(['store_id' => null])->where(['payroll_type' => 'Earnings'])->all();
//$earningslistData = ArrayHelper::map($earnings,'payroll_items_id', 'payroll_name');
$earningslistData = ArrayHelper::map($earnings,'payroll_items_id',function($items, $defaultValue) {
return $items->payroll_name;
});
for($i = 1; $i <= $count; $i++) {
echo $form->field($earning[$i], 'earning_item_id')->widget(Select2::classname(), [
'data' => $earningslistData,
'options' => ['placeholder' => 'Select an Earning ', 'id' => 'earning_item'],
'pluginOptions' => [
'allowClear' => true
],
]);
}
?>
Problem is, how do I return a dynamic model? So I could use it in my view. In my return statement above, there's no $earning since it's a dynamic model and I don't know to return it.
If you have any other implementation about dynamic models, please pleas let me know.
You're halfway there.
First off, there is no Dynamic Model in your snippet, just an array of models. A Dynamic Model is an actual thing in Yii.
Now, if you want the $earning array you created in the controller to be available in the view, just add an entry to the array in the call to render():
return $this->render('create', [
'model' => $model,
'model1' => $model1,
'model2' => $model2,
'items' => $items,
'earning' => $earning,
]);
You may also want to move the definition of $earningslistData to the controller and pass it to the view in the same manner.
Related
I'm implementing a dynamic navbar in Yii2 which displays a dropdown menu picking items from the database. Now, the problem is that when I call the function in which I fill the array, the system crash with the error:
"Invalid argument supplied for foreach()"
since it doesn't find the variable with the array of items. I don't know which controller should pass the arguments to the main view, I just need an array of all items in a data model (i.e. Course).
I've tried out with this but still doesn't work.
/* #var $courses \app\models\Course[] */
layouts/main
function items($courses)
{
$items = [];
foreach ($courses as $course) {
array_push($items, ['label' => $course->title, 'url' =>
Url::to(['course', 'id' => $course->id])]);
}
return $items;
}
$menuItems = [
// other items ...
'label' => 'Courses', 'items' => items($courses)
];
echo Nav::widget([
'options' => ['class' => 'uk-navbar-item'],
'encodeLabels' => false,
'items' => $menuItems
]);
How can I pass the $courses variable to the layouts/main view? Thanks everyone in advance.
You should extract this code into widget:
class MainMenu extends Widget {
public function run() {
echo Nav::widget([
'options' => ['class' => 'uk-navbar-item'],
'encodeLabels' => false,
'items' => $this->getItems(),
]);
}
protected function getItems() {
return [
// other items ...
['label' => 'Courses', 'items' => $this->getCoursesItems()],
];
}
protected function getCoursesItems() {
$items = [];
foreach (Course::find()->all() as $course) {
$items[] = [
'label' => $course->title,
'url' => Url::to(['/course', 'id' => $course->id]),
];
}
return $items;
}
}
Then in your layout you're just calling:
<?= MainMenu::widget() ?>
In this way you can keep your controller and view clean.
My array
$data = [
'subcategoryName' => 'asd',
'fromdate' => $fromdate,
'todate' => $todate,
'amount' => $finalamount,
];
Array data provider
$provider = new ArrayDataProvider([
'allModels' => $data,
'pagination' => [
'pageSize' => 10,
],
'sort' => [
'attributes' => ['subcategoryName'],
],
]);
// get the rows in the currently requested page
$rows = $provider->getModels();
return $rows;
Now I want to display this data on my grid view but I am getting this error Call to a member function getCount() on array
Please tell me that how can I display my array on yii2 grid view
You should'nt return here result of function getModels(). I assume u pass this to GridView, but u have to pass ArrayDataProvider.
Change this:
$rows = $provider->getModels();
return $rows;
To this:
return $provider;
I am trying to implement the 2amigos SelectizeDropDownList widget in a form to add new values to a table directly within the dropdown.
I am using the model Book and the Model Author so basically want to be able to add a new author in the book form.
This is the book controller at the update function:
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['index']);
} else {
return $this->render('update', [
'model' => $model,
'categories' => BookCategory::find()->active()->all(),
'publishers' => Publisher::find()->all(),
'copirights' => Copiright::find()->all(),
'authors' => Author::find()->all(),
]);
}
}
This is the form:
<?=
$form->field($model, 'author_id')->widget(SelectizeDropDownList::className(), [
// calls an action that returns a JSON object with matched
// tags
'loadUrl' => ['author/list'],
'value' => $authors,
'items' => \yii\helpers\ArrayHelper::map(\common\models\author::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
'options' => [
'class' => 'form-control',
'id' => 'id'
],
'clientOptions' => [
'valueField' => 'id',
'labelField' => 'name',
'searchField' => ['name'],
'autosearch' => ['on'],
'create' => true,
'maxItems' => 1,
],
])
?>
And this is the function author controller:
public function actionList($query) {
$models = Author::findAllByName($query);
$items = [];
foreach ($models as $model) {
$items[] = ['id' => $model->id, 'name' => $model->name];
}
Yii::$app->response->format = \Yii::$app->response->format = 'json';
return $items;
}
The form works fine to load, filter, search and add new items.
But it is not inserting the new typed attribute in the author table.
Do I need to add something in the book controller?
How can I check if it is a new value or a change of an existing author?
Thanks a lot
I made it work with the following code, not sure the most elegant because i am checking the if the author_id is a number or a string.
In my case the author won't be a number anyway.
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post())) {
$x = Yii::$app->request->post('Book');
$new_author = $x['author_id'];
if (!is_numeric($new_author)) {
$author = new Author();
$author->name = $new_author;
$author->save();
$model->author_id = $author->id;
}
if ($model->save()) {
return $this->redirect(['index']);
}
} else {
return $this->render('update', [
'model' => $model,
'categories' => BookCategory::find()->active()->all(),
'publishers' => Publisher::find()->all(),
'copirights' => Copiright::find()->all(),
'authors' => Author::find()->all(),
]);
}
}
while i am fetching this records then getting this error how to solve it ?
public function actionIndex()
{
$query = Site::model();
$pagination = new CPagination([
'defaultPageSize' => 5,
'totalCount' => $query->count(),
]);
$countries = $query->orderBy('name')
->offset($pagination->offset)
->limit($pagination->limit)
->all();
return $this->render('view', [
'countries' => $countries,
'pagination' => $pagination,
]);
}
you should distinguish between yii1 and yii2.from your codes,you used yii1 and yii2 together.
Please look the picture below.
As you can see total is 215340 in the summary column. What I want is that in the next page it should start summing those numbers on this number.
Here is a code.
GridView::widget([
'dataProvider' => $dataProvider,
// 'filterModel' => $searchModel,
'columns' => [
[
'class' => 'kartik\grid\SerialColumn'],
// 'id',
[
'attribute' => 'customer_id',
'value' => function ($data) {
return $data->customerDetail->account_no;
}
],
[
'attribute' => 'naration',
'pageSummary' => 'Total',
],
[
'attribute' => 'transaction_type',
'label' => 'Deposits',
'pageSummary' => true,
'pageSummaryOptions' => ['id' => 'total_sum'],
'value' => function ($data) {
if($data->transaction_type==10)
return $data->amount;
else
return 0;
}
],
[
'attribute' => 'transaction_type',
'label' => 'Withdrawals',
'pageSummary' => true,
'value' => function ($data) {
if($data->transaction_type==11)
return $data->amount;
else
return 0;
}
],
[
'class' => 'backend\components\TotalColumn',
'label' => 'Balance',
'attribute' =>'amount',
],
],
// This line displays sum of the columns.
'showPageSummary' => true,
]);
?>
I was thinking about sending this page's sum to the next page using $_GET but the problem is when user going to previous pages i.e. from page 3 to 2. Do you any widget or something for this problem?
My idea is using mysql to select sum of all records in the current column and add this value with the total value of the previous page, I need to know offset and limit of the current page for this query, I can get those values from data provider, to achieve this I have to override the function \yii\grid\Column::renderFooterCellContent().
Extend \yii\grid\DataColumn class
namespace frontend\components;
use yii\helpers\ArrayHelper;
class DataColumn extends \yii\grid\DataColumn
{
protected function renderFooterCellContent()
{
if ($this->footer instanceof \Closure) {
return call_user_func($this->footer, ArrayHelper::getValue($this, 'grid.dataProvider.pagination'));
} else {
return parent::renderFooterCellContent();
}
}
}
Your view file
use frontend\models\Client;
use yii\db\Expression;
use yii\db\Query;
use yii\grid\GridView;
use yii\data\Pagination;
use frontend\components\DataColumn;
echo GridView::widget([
'dataProvider' => $dataProvider,
'dataColumnClass' => DataColumn::className(),
'showFooter' => true,
'columns' => [
//['class' => 'yii\grid\SerialColumn'],
'id',
[
'attribute' => 'num_users',
'footer' => function ($pagination) {
if ($pagination instanceof Pagination) {
$offset = $pagination->offset;
$limit = $pagination->limit;
$cquery = (new Query())
->select(['sub_users' => new Expression('SUM(num_users)')])
->from([
'cpage' => (new Query())
->select('num_users')
->offset($offset)
->limit($limit)
->from(Client::tableName())
]);
//negative offset is illegal
if ($offset > 0) {
$pquery = (new Query())
->select(['sub_users' => new Expression('SUM(num_users)')])
->from([
'ppage' => (new Query())
->select('num_users')
->offset(0)
->limit($offset)
->from(Client::tableName())
]);
$cquery->union($pquery, true);
}
return (new Query())->from(['subt' => $cquery])->sum('sub_users');
}
}
],
]
]);
Raw SQL query
SELECT SUM(sub_sum_users) FROM (
SELECT SUM(num_users) as sub_sum_users FROM (
SELECT num_users FROM `clients` LIMIT 20 OFFSET 120
) cpage
UNION ALL
SELECT SUM(num_users) as sub_sum_users FROM (
SELECT num_users FROM `clients` LIMIT 20 OFFSET 100
) ppage
) sublt
Note:
You could consider to use ActiveRecord, my girdview has a lot of join queries so it's very heavy for me
$offset = $pagination->offset;
$limit = $pagination->limit;
$cquery = Client::find()
->select(['sub_users' => new Expression('SUM(num_users)')])
->from([
'cpage' => Client::find()->select('num_users')->offset($offset)->limit($limit)
]);
//negative offset is illegal
if ($offset > 0) {
$pquery = $cquery = Client::find()
->select(['sub_users' => new Expression('SUM(num_users)')])
->from([
'ppage' => Client::find()->select('num_users')->offset(0)->limit($offset)
]);
$cquery->union($pquery, true);
}
return (new Query())->from(['subt' => $cquery])->sum('sub_users');