Yii2 MultilingualBehavior throws getPrimaryKey error - yii2

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!

Related

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 - Update Complex Form

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.

yii2 add search widget grid view

**how can i add girdView search to my relation table column ?
i have all girlview search box except my relation table
(developersActivity.developer_point) and ('developersActivity.project_done')
i have thier value but widget search box not apear above them**
my controller
$searchModel = new DeveloperSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
return $this->render('dashboard', [
'dataProvider' => $dataProvider,
'searchModel' => $searchModel
]);
my search model
class DeveloperSearch extends Developers
{
public function rules()
{
return parent::rules();
}
public function scenarios()
{
return Model::scenarios();
}
public function search($param)
{
$query = Developers::find();
$dataProvider = new ActiveDataProvider([
'query' => $query
]);
$this->load($param);
$query->joinWith('developersActivity');
$dataProvider->setSort([
'attributes'=> [
'name',
'developersActivity.developer_point'=>[
'asc'=>['developer_point'=>SORT_ASC],
'desc'=>['developer_point'=>SORT_DESC],
]
]
]);
$query->andFilterWhere([
'developer_id' => $this->developer_id,
]);
$query->andFilterWhere(['like', 'name', $this->name])
->andFilterWhere(['like', 'phone', $this->phone])
->andFilterWhere(['like', 'email', $this->email]);
return $dataProvider;
}
}
the model
class Developers extends ActiveRecord
{
public static function tableName()
{
return 'developers';
}
public function rules()
{
return [
[['name',
'family',
'phone',
'email',
'address',
'brithday',
'age',
'ability',
'role',
'join_date',
], 'required'],
[['developer_id'], 'integer'],
['email','email'],
[['phone'],'integer', 'min' => 10],
[['address'], 'string', 'max' => 100],
[['name'], 'string', 'min' => 3],
];
}
public function getDevelopersActivity(){
return $this->hasOne(DevelopersActivity::className(),['developer_activity_id' => 'developer_id']);
}
}
and developersActivity model class
class DevelopersActivity extends ActiveRecord
{
public function rules()
{
return [
[['developer_activity_id',
'developer_point',
'project_done',
'free_rate',
'address',
'estimate_for_next_project',
'date_project_done',
'number_of_project',
'activity_rate',
], 'safe'],
];
}
}
here is the view
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
'developer_id',
'name',
'email',
'phone',
'email',
'developersActivity.developer_point',
'developersActivity.project_done'
// 'value'=>'developersActivity.point',
//'contentOptions'=>['style'=>'width: 120px;']
],
]);
?>
in your model add a getter for the field (assuming the field is named actvityname)
/* Getter for deleveloer activity name */
public function getDevelopersActivityName() {
return $this->developersActivity->activityname;
}
in your searchModel
add a public var for your related field and declare as safe in rules
/* your calculated attribute */
public $activityName;
/* setup rules */
public function rules() {
return [
/* your other rules */
[['activityName'], 'safe']
];
}
and in the filter you can add the filter for your field
// filter by developer activity
$query->joinWith(['developersActivity' => function ($q) {
$q->where('yor_develeoper_activity_table.your_developer_activity_column LIKE "%' . $this->activityName. '%"');
}]);
return $dataProvider;
in gridview you can refer directly using
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'id',
'fullName',
'activityName',
['class' => 'yii\grid\ActionColumn'],
]
you can take a look ad this tutorial for some suggestions http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/

Unable to save model attribute as null?

Here is my model rules
public function rules() {
return [
[['header_image', 'profil_picture'], 'default', 'value' => null],
[['yahoo_id', 'whats_app_id', 'bbm_id'], 'string', 'max' => 20],
[['bbm_id'], 'match', 'pattern' => '/^[a-zA-Z0-9]+$/', 'message' => 'Alpha numeric only'],
[['header_image_file', 'profil_picture_file'], 'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpeg, jpg, bmp', 'maxSize' => 10240 * 20240 * 2],
[['deskripsi_toko'], 'string', 'max' => 300],
[['agent_id', 'nama_toko', 'tag_line', 'header_image', 'profil_picture', 'yahoo_id', 'whats_app_id', 'bbm_id', 'deskripsi_toko'], 'filter', 'filter' => function($value) {
return BeoHelper::replace_mc($value);
}],
];
}
Here is my controller
$storeSetting->header_image = null;
if($storeSetting->save()){
return $this->redirect(Yii::$app->request->referrer);
}
replace_mc function
public static function replace_mc($str)
{
$new_data = preg_replace('/[^A-Za-z0-9\-\ \.\:\#\+]/', '', $str);
return $new_data;
}
Record save successfully, but header_image is empty string instead of null?
It should set header_image as null, Where I'm doing wrong?
Thanks in advance.
Try with additional condition in replace_mc():
public static function replace_mc($str)
{
return $str === null
? $str
: preg_replace('/[^A-Za-z0-9\-\ \.\:\#\+]/', '', $str);
}

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() == "";
}'],
];
}