i have a problem with Kartik Select2. When I want save multiple data in my controller, nothing is saved. And I remove foreach in controller, Yii return me error with information about $university_id IS NULL.
User Form
<?= $form->field($user_university, 'university_id')->widget(Select2::classname(),[
'name' => 'university_id[]',
'data' => ArrayHelper::map(
\app\models\University::find()->asArray()->all(),
'id',
function ($university) {
return $university['name'];
}
),
'size' => Select2::MEDIUM,
'options' => ['placeholder' => 'Select a state ...', 'multiple' => true],
'pluginOptions' => [
'allowClear' => true
],
]); ?>
User Controller
$user = new User();
$user->scenario = User::SCENARIO_CREATE;
$auth_assignment = new AuthAssignment();
$user_company = new UserCompany();
$user_university = new UserUniversity();
$user_status = UserStatus::find()
->select('id')
->where(['name' => UserStatus::NON_AUTHORIZED_USER])
->one();
if ($user->load(Yii::$app->request->post()) && $auth_assignment->load(Yii::$app->request->post())) {
$user->auth_key = Yii::$app->getSecurity()->generateRandomString();
$user->password_hash = Yii::$app->getSecurity()->generatePasswordHash($user->password);
$user->password_reset_token = Yii::$app->getSecurity()->generateRandomString();
$user->status_id = $user_status->id;
$user->created_at = date('Y-m-d H:i:s');
$user->updated_at = date('Y-m-d H:i:s');
if ($user->save()) {
$auth_assignment->user_id = $user->id;
$auth_assignment->created_at = date('Y-m-d H:i:s');
$universities = $user_university->university_id;
foreach((array) $universities as $university)
{
$newUserUniversity = new UserUniversity();
$newUserUniversity->user_id = $user->id;
$newUserUniversity->university_id = $university;
$newUserUniversity->created_at = date('Y-m-d H:i:s');
$newUserUniversity->save(false);
}...
User University Model Rule
public function rules()
{
return [
[['user_id', 'university_id', 'created_at'], 'required'],
[['user_id', 'university_id','confirm'], 'integer'],
[['created_at','university_id'], 'safe'],
[['university_id'], 'exist', 'skipOnError' => true, 'targetClass' => University::className(), 'targetAttribute' => ['university_id' => 'id']],
[['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
];
}
Looking at your code i can't see where you are loading the data from the post request into the $user_university before you start looping on the university_id. You need to call $user_university->load(Yii::$app->request->post()), look the following piece of code from your script
if ($user->save()) {
$auth_assignment->user_id = $user->id;
$auth_assignment->created_at = date('Y-m-d H:i:s');
// this below line will give you an empty string rather than
// the selected ids of the `university` that you selected
// in the multi-dropdown
$universities = $user_university->university_id;
and the very next line is the foreach((array) $universities as $university) in which you are trying to save which won't run even once, as there isnt any array loaded in the $unversities. So you can add a call before you get the array from the attribute, dont know if your requirements are to return the user with an error if the data is not loaded for the $user_university otherwise you need to add it to the main check
if ($user->load(Yii::$app->request->post()) && $auth_assignment->load(Yii::$app->request->post()) &&
$user->university->load(Yii::$app->request->post())) {
So your code should look like below
$user = new User();
$user->scenario = User::SCENARIO_CREATE;
$auth_assignment = new AuthAssignment();
$user_company = new UserCompany();
$user_university = new UserUniversity();
$user_status = UserStatus::find()
->select('id')
->where(['name' => UserStatus::NON_AUTHORIZED_USER])
->one();
//validate all models
$allModelsValid=$user->load(Yii::$app->request->post()) && $auth_assignment->load(Yii::$app->request->post()) && $user_university->load(Yii::$app->request->post());
if ($allModelsValid) {
$user->auth_key = Yii::$app->getSecurity()->generateRandomString();
$user->password_hash = Yii::$app->getSecurity()->generatePasswordHash($user->password);
$user->password_reset_token = Yii::$app->getSecurity()->generateRandomString();
$user->status_id = $user_status->id;
$user->created_at = date('Y-m-d H:i:s');
$user->updated_at = date('Y-m-d H:i:s');
if ($user->save()) {
$auth_assignment->user_id = $user->id;
$auth_assignment->created_at = date('Y-m-d H:i:s');
$universities = $user_university->university_id;
foreach((array) $universities as $university)
{
$newUserUniversity = new UserUniversity();
$newUserUniversity->user_id = $user->id;
$newUserUniversity->university_id = $university;
$newUserUniversity->created_at = date('Y-m-d H:i:s');
$newUserUniversity->save(false);
}...
Also apart from above i dont find a reason to use the name as university_id[] for the dropdown rather than university_id
There are multiple ways of Usage of select2 now currently you are using Usage with ActiveForm and model see below multiple ways.
use kartik\select2\Select2
// Usage with ActiveForm and model
echo $form->field($model, 'state_1')->widget(Select2::classname(), [
'data' => $data,
'options' => ['placeholder' => 'Select a state ...'],
'pluginOptions' => [
'allowClear' => true
],
]);
// With a model and without ActiveForm
echo Select2::widget([
'model' => $model,
'attribute' => 'state_2',
'data' => $data,
'options' => ['placeholder' => 'Select a state ...'],
'pluginOptions' => [
'allowClear' => true
],
]);
// Without model and implementing a multiple select
echo '<label class="control-label">Provinces</label>';
echo Select2::widget([
'name' => 'state_10',
'data' => $data,
'options' => [
'placeholder' => 'Select provinces ...',
'multiple' => true
],
]);
// A disabled select2 list input
echo '<label class="control-label">State</label>';
echo Select2::widget([
'name' => 'state_11',
'data' => $data,
'disabled' => true
]);
I guess your problem is in :
'data' => ArrayHelper::map(
\app\models\University::find()->asArray()->all(),
'id',
function ($university) {
return $university['name'];
}
),
Please check data attribute .. check you are passing correct array or not.
Related
How do I get random values from another table? In my employee php I have 3 records, so there is 3 id values. In my ticket.php once I create a ticket it will automatically get the id value from the employee table but it is not randomise how do I do it?
Mine is currently getting the same value from employee whenever I create a ticket.
In the ticketcontroller.php
public function actionCreate()
{
$model = new Ticket();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
$model->time_start = date('y-m-d h:i:s');
$model->status = ('On Going');
$model->employee_respond_id = array_rand('id');
return $this->render('create', [
'model' => $model,
]);
}
}
In the _form.php
<?= $form->field($model, 'employee_respond_id')->dropDownlist(
ArrayHelper::map(Employee::find()->all(), 'id', 'id'),
[
'readOnly' => true,
'style' => 'width:200px'
]
); ?>
Try this way:
public function actionCreate()
{
$model = new Ticket();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
$employeeIDs = ArrayHelper::map(Employee::find()->all(), 'id', 'id'),
$model->time_start = date('y-m-d h:i:s');
$model->status = ('On Going');
$model->employee_respond_id = array_rand($employeeIDs);
return $this->render('create', [
'model' => $model,
'employeeIDs' => $employeeIDs
]);
}
}
_form.php
<?= $form->field($model, 'employee_respond_id')->dropDownlist(
$employeeIDs,
[
'readOnly' => true,
'style' => 'width:200px'
]
); ?>
Better use employee name as label and id as value in dropdown, still it will work for random function.
So i'm currently figuring out how to add users. Adding an email record then using the Auto-incremented Emails id to assign to email_id in Users table with that id being a dependent.
I'm doing it all from the users controller
public function add()
{
if ($this->request->is('post')) {//specify we are getting PostData
$data = [
//'id' => '111',
'address' => $this->request->data['Emails']['address'],
'created' => Time::now(),
'last_modified' => Time::now(),
'last_contacted' => Time::now() ];
$emails = TableRegistry::get('Emails');
$email = $emails->newEntity($data, [ 'associated' => ['Users']]);
$save = $emails->save($email, ['associated' => 'Users']);
$email_id = $save->id;
$users = TableRegistry::get('Users');
$user = $users->newEntity($this->request->getData(), ['associated' => ['Emails.id']]);
$user->dob = date('Y-m-d', strtotime($user->dob));
$user->email['id'] = $email_id;
$user->is_admin = 'n';
$user->last_login = Time::now();
$user->created = Time::now();
$user->last_modified = Time::now();
if ($emails->save($email, ['associated' => 'Users'])) {
if($users->save($user, ['associated' => 'Emails'])) {
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('User could not be saved. Please, try again.'));
}
}else {
$this->Flash->error(__('Email save failure, please try again.'));
}
}
$emails = $this->Users->Emails->find('list', ['limit' => 200]);
$this->set(compact('user', 'emails'));
$this->set('_serialize', ['user']);
}
which takes data in from the form:
` Form->create( ) ?>
<?php
echo $this->Form->control('Emails.address', ['required' => true, 'label' => 'Email']);
echo $this->Form->control('Users.password', ['required' => true, 'label' => 'Password']);
echo $this->Form->label('Gender');
echo $this->Form->radio('Users.gender',['m'=>'Male', 'f' => 'Female'] , [ 'required' => true]);
echo $this->Form->control('Users.family_name', [ 'required' => true, 'label' => 'Given Name']);
echo $this->Form->control('Users.given_name', [ 'required' => true, 'label' => 'Family Name']);
echo $this->Form->control('Users.dob', [ //birth date between 1900 and current year
'data-format'=>'d m Y',
'class' => 'dateinput',
'required' => true,
'data-default-date'=> '03-30-1993',
'maxYear' => date('Y') - 17,
]);
echo $this->Form->control('Users.phone', [ 'required' => true]);
?>
</fieldset>
<?= $this->Form->button(__('Submit'), ['class'=>'text-right']) ?>
<?= $this->Form->end() ?>`
SO my problem is that i can create email addresses and make them save - great.
EMails and Users are a hasOne. defined in emails table
`$this->hasOne('Users', [
'foreignKey' => 'emails_id', 'bindingKey' => 'id', ])
->setDependent(true)
->setName('Emails');
`
I just cant seem to take the users input and add that into the table. Errors include:
Cannot marshal data for "Emails" association. It is not associated with "Users" which happens when i only put the hasone in the UsersTable. Same if I only have it in EmailsTable. Dp it when the other model contains the fk
ERROR 1452: Cannot add or update a child row: a foreign key constraint fails which happens when both have hasOne in it and i make the email first. It still says theres no fk relation
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(),
]);
}
}
I use select2 ajax loading. I get the code from this link: http://demos.krajee.com/widget-details/select2. When I enter words into field, it display all data/value, but it can't automatic select data/value according to words that I enter into field. So, my select2 always select the first data/value and display all value. What's the problem? These are the codes:
_form.php
$url = Url::to(['/paket/jsonlist']);
$cityDesc = empty($model->no_induk) ? '' : Penerima::findOne($model->no_induk)->nama;
echo $form->field($model, 'no_induk')->widget(Select2::classname(), [
'initValueText' => $cityDesc, // set the initial display text
'options' => ['placeholder' => 'Search for a city ...'],
'pluginOptions' => [
'allowClear' => true,
'minimumInputLength' => 1,
'language' => [
'errorLoading' => new JsExpression("function () { return 'Waiting for results...'; }"),
],
'ajax' => [
'url' => $url,
'dataType' => 'json',
'data' => new JsExpression('function(params) { return {q:params.term}; }')
],
'escapeMarkup' => new JsExpression('function (markup) { return markup; }'),
'templateResult' => new JsExpression('function(no_induk) { return no_induk.text; }'),
'templateSelection' => new JsExpression('function (no_induk) { return no_induk.id; }'),
],
]);
my controller:
public function actionJsonlist($q = NULL, $id = NULL)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$out = ['results' => ['id' => '', 'text' => '']];
if(!is_null($q))
{
$query = new \yii\db\Query;
$mainQuery = $query->select('no_induk AS id, nama AS text')
->from('penerima')
->limit(20);
$command = $mainQuery->createCommand();
$data = $command->queryAll();
$out['results'] = array_values($data);
}
elseif ($id > NULL)
{
$out['results'] = ['id' => $id, 'text' => \frontend\models\Penerima::find($id)->nama];
}
return $out;
}
Could be you use the attribute name and not the vars
echo $form->field($model, 'no_induk')->widget(Select2::classname(), [
'initValueText' =>'cityDesc', // set the initial display text
or
echo $form->field($model, 'no_induk')->widget(Select2::classname(), [
'initValueText' =>$model->cityDesc, // set the initial display text
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');