Yii2 - Update Complex Form - yii2

I created a Complex Form using two Model Classes:
Courses
CourseStructure
public function actionCreate()
{
$model = new Course();
$request = Yii::$app->request;
if ($model->load(Yii::$app->request->post()) && Yii::$app->request->isAjax) {
//The course was created successfully, so we can use its data to make course structure
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if ($model->load(Yii::$app->request->post())) {
$model->attributes = $_POST['Course'];
$model->course_start_date = date('Y-m-d', strtotime($_POST['Course']['course_start_date']));
$model->created_at = new \yii\db\Expression('NOW()');
}
$model->save(false);
if($model->save(false))
//The course was created successfully, so we can use its data to make course structure
{
// check if topic format
if($model->course_format == Course::TYPE_TOPIC)
{
for( $i = 1; $i <= $model->course_format_no; $i++ )
{
$structure = new CourseStructure();
$structure->course_id = $model->course_id;
$structure->structure_name = $model->course_format . $i;
$structure->structure_id = $i;
// fill in other course structure data here
$structure->save();
}
}
}
else
return $this->render('create', ['model' => $model,]);
} else {
return $this->render('create', [
'model' => $model,
]);
}
}
From CourseControllers, if course_format = TYPE_TOPIC, then based on the course_format_no selected,
some rows are added in course_structure table (CourseStructure). For instance, if course_format_no = 3, it creates three additional rows in course_structure table.
if($model->course_format == Course::TYPE_TOPIC)
{
for( $i = 1; $i <= $model->course_format_no; $i++ )
{
$structure = new CourseStructure();
$structure->course_id = $model->course_id;
$structure->structure_name = $model->course_format . $i;
$structure->structure_id = $i;
// fill in other course structure data here
$structure->save();
}
}
It works fine in CourseCreate Action in CourseController.
Now how do I do it for the CourseUpdate Action, so that if that either reduce the number of rows or increase it in course_structure table based on the course_format_no added in the update.
course_structure
This is what I have:
public function actionUpdate($id)
{
$model = $this->findModel($id);
$old_model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && Yii::$app->request->isAjax) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if ($model->load(Yii::$app->request->post())) {
$model->attributes = $_POST['Course'];
$model->course_start_date = Yii::$app->dateformatter->getDateFormat($_POST['Course']['course_start_date']);
$model->updated_by = Yii::$app->getid->getId();
$model->updated_at = new \yii\db\Expression('NOW()');
if($model->save(false))
return $this->redirect(['view', 'id' => $model->course_id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
CourseStructure model
class CourseStructure extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'course_structure';
}
public function rules()
{
return [
[['course_id', 'structure_id', 'summary_format', 'created_by', 'updated_by'], 'integer'],
[['structure_summary'], 'string'],
[['created_at', 'updated_at'], 'safe'],
[['structure_name'], 'string', 'max' => 200],
];
}
public function attributeLabels()
{
return [
'course_structure_id' => 'Course Structure ID',
'course_id' => 'Course ID',
'structure_id' => 'Structure ID',
'structure_name' => 'Structure Name',
'structure_summary' => 'Structure Summary',
'summary_format' => 'Summary Format',
'created_at' => 'Created At',
'created_by' => 'Created By',
'updated_at' => 'Updated At',
'updated_by' => 'Updated By',
];
}
public function getCourses()
{
return $this->hasOne(Course::className(), ['course_id' => 'course_id']);
}
public static function getAllCourseStructure()
{
$dataTmp = self::find()->orderBy('structure_name')->all();
$result = yii\helpers\ArrayHelper::map($dataTmp, 'course_structure_id', 'structure_name');
return $result;
}
}
Courses model
class Course extends \yii\db\ActiveRecord
{
const TYPE_WEEKLY= 'Weekly';
const TYPE_TOPIC='Topic';
public $coursefile;
public static function tableName()
{
return 'course';
}
public function rules()
{
return [
[['course_category_id', 'course_format_no', 'show_grade', 'created_by', 'updated_by'], 'integer'],
[['course_code', 'course_name', 'course_format', 'course_format_no'], 'required', 'message' => ''],
[['course_summary'], 'string'],
[['course_start_date', 'created_at', 'updated_at', 'course_file_path'], 'safe'],
[['course_code'], 'string', 'max' => 100],
[['course_name'], 'string', 'max' => 255],
[['course_num', 'course_format'], 'string', 'max' => 20],
[['course_code'], 'unique'],
[['coursefile'], 'safe'],
[['course_name', 'course_category_id'], 'unique', 'targetAttribute' => ['course_name', 'course_category_id'], 'message' => Yii::t('app', 'The combination of Course Name and Course Category has already been taken.')],
[['coursefile'], 'file', 'extensions' => 'jpg, jpeg, gif, png, pdf, txt, jpeg, xls, xlsx, doc, docx', 'maxFiles' => 4],
[['coursefile'], 'file', 'maxSize'=>'10000000'],
[['course_file_path', 'course_file_name'], 'string', 'max' => 255],
];
}
public function attributeLabels()
{
return [
'course_id' => 'Course ID',
'course_category_id' => 'Course Category',
'course_code' => 'Course Short Name',
'course_name' => 'Course Full Name',
'course_num' => 'Course ID Number',
'course_summary' => 'Course Summary',
'course_start_date' => 'Course Start Date',
'course_format' => 'Course Format',
'course_format_no' => 'No.of Sections',
'course_file_path' => Yii::t('app', 'Pathname'), //'Course File',
'course_file_name' => Yii::t('app', 'Filename'),
'show_grade' => 'Show Grade',
'created_at' => 'Created At',
'created_by' => 'Created By',
'updated_at' => 'Updated At',
'updated_by' => 'Updated By',
];
}
public function getCourseCategory()
{
return $this->hasOne(CourseCategories::className(), ['course_category_id' => 'course_category_id']);
}
public static function getAllCourse()
{
$dataTmp = self::find()->orderBy('course_name')->all();
$result = yii\helpers\ArrayHelper::map($dataTmp, 'course_id', 'course_name');
return $result;
}
public static function getCourseFormat()
{
return[
Yii::t('app', self::TYPE_TOPIC) => Yii::t('app', 'Topic'),
Yii::t('app', self::TYPE_WEEKLY) => Yii::t('app', 'Weekly'),
];
}
}
How do I write the code to update CourseStructure in the ActionUpdate.

Related

Yii2 - Dropdownlist OnChange to Display Other Model Attribute

I have these Model Classes
Model:Subject
public function attributeLabels()
{
return [
'subject_id' =>Yii::t('app', 'ID'),
'subject_title' => Yii::t('app', 'Subject Title'),
];
}
Model:Grouping
public function attributeLabels()
{
return [
'grouping_id' => Yii::t('app', 'Grouping ID'),
'grouping_name' => Yii::t('app', 'Grouping Name'),
];
}
Model:SubjectGrouping
public function attributeLabels()
{
return [
'subject_grouping_id' => 'Subject Grouping ID',
'subject_grouping_grouping_id' => 'Subject Grouping Grouping ID',
'subject_grouping_subject_id' => 'Subject Grouping Subject ID',
];
}
Model:Exam
public function attributeLabels()
{
return [
'exam_id' =>Yii::t('app', 'ID'),
'exam_name' => Yii::t('app', 'Exam Name'),
'exam_group_id' => Yii::t('app', 'Exam Group'),
];
}
Model:SubjectGrouping has Foreign Keys from Model: Grouping (subject_grouping_grouping_id) and Model:Subject (subject_grouping_subject_id)
In Model:Exam, exam_group_id relates to subject_grouping_grouping_id in Model:SubjectGrouping.
Controller
public function actionCreate()
{
$model = new Exam();
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
if ($model->load(Yii::$app->request->post())) {
$model->attributes = $_POST['Exam'];
$model->save();
return $this->redirect(['index']);
} else {
return $this->render(
'create', [
'model' => $model
]
);
}
}
View
<div class="col-xs-12 col-sm-4 col-lg-4">
<?=$form->field($model, 'exam_name')->textInput(['maxlength' => 50, 'placeholder' => 'Enter Exam Name'])?>
</div>
<div class="col-xs-12 col-sm-4 col-lg-4">
<?=$form->field($model, 'exam_group_id')->widget(
Select2::classname(), [
'data' => ArrayHelper::map(app\models\Grouping::find()->all(), 'grouping_id', 'grouping_name'),
'language' => 'en',
'options' => ['placeholder' => '--- Select Grouping ---'],
'pluginOptions' => [
'allowClear' => true
]
]
);
?>
</div>
From the diagram, how do I achieve these?
when Dropdownlist for exam_group_id is onChange the list of subjects with respect to grouping is displayed using the relationship between Model: SubjectGrouping and Model: Subject.
Others fields such as exam_name (textInput) and exam_group_id (Dropdownlist) should be save into the Model: Exam. But the subject list should not be saved. It is only for display purpose.
How do I achieve these?
I am using kartik\widgets\Select2 for the dropdownlist
I have done similar code by Kartik extension for state and country data.
here is the code for that.
<?php
//in view use this
use kartik\widgets\DateTimePicker; // or kartik\select2\Select2
use kartik\widgets\DepDrop;
use kartik\widgets\Select2;
?>
<?php
echo
$form->field($model, 'country_id')->widget(
Select2::className(),
[
'data' => \yii\helpers\ArrayHelper::map(common\models\Country::find()->all(), 'id', 'name'),
'options' => [
'id' => 'country_id',
'prompt' => Yii::t('aspns', 'Select')
]
]
);
?>
<?php
echo
$form->field($model, 'state_id')->widget(
DepDrop::classname(),
[
'data' => !empty($model->state_id) ? \yii\helpers\ArrayHelper::map(common\models\State::find()->where(['country_id' => $model->country_id])->all(), 'id', 'name') : [],
'options' => ['id' => 'state_id', 'placeholder' => Yii::t('aspns', 'Select')],
'pluginOptions' => [
'depends' => ['country_id'],
'url' => Url::to(['//country/get-states'])
]
]
)->label(Yii::t('aspns', 'State'));
?>
// In Controller section you need to do this
public function actionGetStates() {
$out = [];
if (isset($_POST['depdrop_parents'])) {
$parents = $_POST['depdrop_parents'];
if ($parents != null) {
$country_id = (int)$parents[0];
$out = State::find()->where(['country_id'=>$country_id])->select(['id', 'name'=>'name'])->asArray()->all();
return Json::encode(['output'=>$out, 'selected'=>'']);
}
}
return Json::encode(['output'=>'', 'selected'=>'']);
}
Change the code according to your requirement.
Thanks

Yii2 Sorting and filtering from a linked table through a table

Good day everyone. I'm trying to add a filter for the associated phone_digital field but I get the following error
Structure -
1 table - ClientClient - first_name, patronymic, last_name, age.
2 table - ClientPhone - client_id, phone_digital.
ClientClient (model)
class ClientClient extends \yii\db\ActiveRecord
{
public static function tableName(){
return 'client_client';
}
public function rules(){
return [
[['age'], 'integer'],
[['first_name', 'patronymic', 'last_name'], 'string', 'max' => 255],
];
}
public function attributeLabels(){
return [
'id' => 'ID',
'first_name' => 'First Name',
'patronymic' => 'Patronymic',
'last_name' => 'Last Name',
'age' => 'Age',
'phone_digital' => 'Phone Digital',
];
}
public function getclientPhone(){
return $this->hasOne(clientPhone::class, ['client_id' => 'id']);
}
public function getPhone(){
return $this->hasOne(clientPhone::class, ['phone_digital' => 'id']);
}
public function getDigital(){
return $this->hasOne(ClientPhone::className(), ['id' => 'phone_digital']);
}
public function getPhoneDigital(){
return $this->phone->phone_digital;
}
}
ClientSearch (model)
class ClientSearch extends Clientclient
{
public $phonedigital;
public function rules(){
return [
[['id', 'age'], 'integer'],
[['first_name', 'phonedigital', 'patronymic', 'last_name'], 'safe'],
];
}
public function scenarios(){
// bypass scenarios() implementation in the parent class
return Model::scenarios();
}
public function search($params){
$query = Clientclient::find()->orderBy('phone_digital');
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->joinWith(['phonedigital' => function($query) { $query->from(['phonedigital' => 'ClientPhone']); }]);
$dataProvider->sort->attributes['phone'] = [
'asc' => ['phonedigital.phone_digital' => SORT_ASC],
'desc' => ['phonedigital.phone_digital' => SORT_DESC],
];
$query->andFilterWhere([
'id' => $this->id,
'age' => $this->age,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'patronymic', $this->patronymic])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'phonedigital.phone_digital', $this->getAttribute('phonedigital')]);
return $dataProvider;
}
}
What do I need to do to make this work?
I guess you should put your orderBy after your join
check the commented lines:
public function search($params){
// do not put the join of a related table at the beginning because it's not related yet
$query = Clientclient::find();
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
$query->joinWith(['phonedigital' => function($query) { $query->from(['phonedigital' => 'ClientPhone']); }]);
// orderBy only after call the relacion
$query->orderBy('phonedigital.phone_digital');
$dataProvider->sort->attributes['phone'] = [
'asc' => ['phonedigital.phone_digital' => SORT_ASC],
'desc' => ['phonedigital.phone_digital' => SORT_DESC],
];
$query->andFilterWhere([
'id' => $this->id,
'age' => $this->age,
]);
$query->andFilterWhere(['like', 'first_name', $this->first_name])
->andFilterWhere(['like', 'patronymic', $this->patronymic])
->andFilterWhere(['like', 'last_name', $this->last_name])
->andFilterWhere(['like', 'phonedigital.phone_digital', $this->getAttribute('phonedigital')]);
return $dataProvider;
}
I hope it helps you, and sorry about my ingles

Yii2 MultilingualBehavior throws getPrimaryKey error

I want to save multilingual record in my table but some error occurs - Call to a member function getPrimaryKey() on string. I am using multilingual behavior
and it is not for first time. Made two tables system_information and system_informationLang. This is my model:
<?php
namespace app\models;
use backend\models\CActiveRecord;
use Yii;
use omgdef\multilingual\MultilingualBehavior;
use omgdef\multilingual\MultilingualQuery;
/**
* This is the model class for table "system_information".
*
* #property int $id
* #property int $city_id
*
* #property SystemInformationlang[] $systemInformationlangs
*/
class SystemInformation extends CActiveRecord
{
public static function find()
{
return new MultilingualQuery(get_called_class());
}
public function behaviors()
{
$allLanguages = [];
foreach (Yii::$app->params['languages'] as $title => $language) {
$allLanguages[$title] = $language;
}
return [
'ml' => [
'class' => MultilingualBehavior::className(),
'languages' => $allLanguages,
//'languageField' => 'language',
//'localizedPrefix' => '',
//'requireTranslations' => false',
//'dynamicLangClass' => true',
//'langClassName' => PostLang::className(), // or namespace/for/a/class/PostLang
'defaultLanguage' => Yii::$app->params['languageDefault'],
'langForeignKey' => 'system_id',
'tableName' => "{{%system_informationlang}}",
'attributes' => [
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
]
],
];
}
/**
* #inheritdoc
*/
public static function tableName()
{
return 'system_information';
}
/**
* #inheritdoc
*/
public function rules()
{
$string_255_lang = $this->multilingualFields([
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
]);
$string_255 = [
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
];
$require = ['name', 'phone', 'email', 'owner', 'address'];
$email_lang = $this->multilingualFields(['email']);
$email = ['email'];
return [
[$require, 'required'],
[$string_255, 'string', 'max' => 255],
[$string_255_lang, 'string', 'max' => 255],
[['city_id'], 'integer'],
[$email_lang, 'email'],
['email', 'email'],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => Yii::t('app', 'ID'),
'city_id' => Yii::t('app', 'City ID'),
];
}
}
This is custom function for language fields creating :
protected function multilingualFields($fields){
$output = [];
foreach ($fields as $field){
foreach (Yii::$app->params['languages'] as $language) {
if(Yii::$app->params['languageDefault'] != $language){
$output[] = "{$field}_{$language}";
}
}
}
return $output;
}
And finally my controller:
public function actionCreate()
{
$model = new SystemInformation();
if ($model->load(Yii::$app->request->post())) {
$model->multilingualLoad($model, [
'name',
'email',
'phone',
'address',
'facebook',
'instagram',
'google',
'linkin',
'fax',
'owner',
'latitude',
'longitude'
]);
var_dump($model->save());
var_dump($model->getErrors());die;
if($model->save()){
return $this->redirect(['view', 'id' => $model->id]);
}else{
Yii::$app->session->setFlash('error', Yii::t('app', 'Something went wrong. Please, try again later!'));
return $this->render('create', [
'model' => $model,
]);
}
}
return $this->render('create', [
'model' => $model,
]);
}
multilingualLoad is also a custom function for filling the lingual fields:
public function multilingualLoad($model, $props = []){
$model_name = explode('\\', get_class($model));
$model_name = end($model_name);
foreach (Yii::$app->params['languages'] as $language){
if(Yii::$app->params['languageDefault'] != $language){
foreach ($props as $property){
$prop_lang = "{$property}_{$language}";
$model->$prop_lang = Yii::$app->request->post($model_name)["{$property}_{$language}"];
}
}
}
}
I got a picture of the Yii2 error. I guess it is searching for the lang table but somehow $owner gets value of a string.
Thank you in advance!

yii2 user dektrium user_id

Hello guys i'm using yii2 user of dektrium . I would save user_id an account in my table. the User table has 1..N relationship with my table. I am a princiapiante and do not know how to save user id in my table. I tried so but the record in the database is blank.
My model
public static function tableName()
{
return 'viaggio';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['citta_part','citta_arrivo','user_id'], 'required'],
[['data_part','ora_part','data_arrivo','ora_arrivo'],'safe'],
[['posti_disponibili', 'conferma_utenze', 'user_id','posti_max'], 'integer'],
[['prezzo'], 'number'],
[['citta_part', 'via_part', 'citta_arrivo', 'via_arrivo', 'veicolo'], 'string', 'max' => 45],
[['note'], 'string', 'max' => 255],
[['wifi', 'bagno', 'ac_dc','condizioni'],'integer'],
[['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => User::className(), 'targetAttribute' => ['user_id' => 'id']],
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id_viaggio' => Yii::t('app', 'Id Viaggio'),
'citta_part' => Yii::t('app', 'Citta Part'),
'via_part' => Yii::t('app', 'Via Part'),
'ora_part' => Yii::t('app', 'Ora Part'),
'data_part' => Yii::t('app', 'Data Part'),
'posti_disponibili' => Yii::t('app', 'Posti Disponibili'),
'conferma_utenze' => Yii::t('app', 'Conferma Utenze'),
'prezzo' => Yii::t('app', 'Prezzo'),
'note' => Yii::t('app', 'Note'),
'citta_arrivo' => Yii::t('app', 'Citta Arrivo'),
'data_arrivo' => Yii::t('app', 'Data Arrivo'),
'ora_arrivo' => Yii::t('app', 'Ora Arrivo'),
'via_arrivo' => Yii::t('app', 'Via Arrivo'),
'veicolo' => Yii::t('app', 'Veicolo'),
'posti_max' => Yii::t('app', 'Posti Max'),
'wifi' => Yii::t('app', 'Wifi'),
'bagno' => Yii::t('app', 'Bagno'),
'ac_dc' => Yii::t('app', 'Ac Dc'),
'user_id' => Yii::t('app', 'User ID'),
];
}
public function getUser()
{
return $this->hasOne(User::className(), ['id' => 'user_id'])->inverseOf('offris');
}
My Controller
public function actionOffri() {
$model = new Offri;
if($model->load(Yii::$app->request->post()) && $model->validate() && $model->save()) {
$model->$user_id = Yii::$app->user->identity->id;
Yii::$app->session->setFlash('success', 'Hai inserito i dati correttamente');
return $this->render('offri', ['model' => $model]);
} else {
Yii::$app->getSession()->setFlash('error', 'Completa correttamente tutti i campi.');
return $this->render('offri', ['model' => $model]);
}
}
suggestions?
First try move the assignment for user_id before validation otherwise the validation surely fail and the model is not saved
public function actionOffri()
{
$model = new Offri;
$model->$user_id = Yii::$app->user->id;
if($model->load(Yii::$app->request->post())&& $model->validate() && $model->save()) {
Yii::$app->session->setFlash('success', 'Hai inserito i dati correttamente');
return $this->render('offri', ['model' => $model]);
} else {
Yii::$app->getSession()->setFlash('error', 'Completa correttamente tutti i campi.');
return $this->render('offri', ['model' => $model]);
}
}
or if yuo need the username you can use Yii::$app->user->identity->username
I think your code has error:
$model->$user_id = Yii::$app->user->identity->id;
Try replace it by:
$model->user_id = Yii::$app->user->identity->id;

Either or validation for string and file yii2

I have two fields message and file where one is just plain string and file is an image.
I want to create validator which only allows user to send either one of those 2 fields.
I tried when validator but in when the field $model->file is always null so what is other method to do either or validation with file.
Here is my model code
class Message extends \yii\db\ActiveRecord
{
public $file;
/**
* #inheritdoc
*/
public static function tableName()
{
return 'message';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['sender_id', 'receiver_id'], 'integer'],
[['message'], 'string'],
[['file'], 'file', 'extensions'=>'jpg, gif, png,jpeg'],
/*['file', 'required', 'when' => function($model) {
return $model->message == null;
}],
['message', 'required', 'when' => function($model) {
return $this->file->baseName == null;
}]*/
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'sender_id' => 'Sender ID',
'receiver_id' => 'Receiver ID',
'message' => 'Message',
'file' => 'Image (jpg/png)',
'is_delivered' => 'Is Delivered',
'is_notified' => 'Is Notified',
'is_deleted' => 'Is Deleted',
'created_date' => 'Created Date',
'updated_date' => 'Updated Date',
'is_group' => 'Is Group',
];
}
}
Thank you
This may Help you..
Define Your rules as : -
public function rules()
{
return [
//Your Rules ......
['message' ,'string'],
['file' ,'file'],
['message', 'required', 'when' => function($model) {
return $model->file === null;
} ,'whenClient' => 'function (attribute, value) {
return $("#'. Html::getInputId($this ,'file') .'").val() === null;
}'],
['file', 'required', 'when' => function($model) {
return $model->message === null;
} , 'whenClient' => 'function (attribute, value) {
return $("#'. Html::getInputId($this ,'message') .'").val() == "";
}'],
];
}