Related
I have a user model. When I save the user I want to make sure the username is unique, so I have a rule [['username'], 'unique']. Users belong to offices, which belong to practices, which belong to organizations. Therefore I have the following queries:
class UserQuery extends \yii\db\ActiveQuery
{
public function init()
{
$this->joinWith('office');
parent::init();
}
}
class OfficeQuery extends \yii\db\ActiveQuery
{
public function init()
{
$this->joinWith('practice');
parent::init();
}
}
class PracticeQuery extends \yii\db\ActiveQuery
{
public function init()
{
$this->joinWith('org');
if (!Yii::$app->user->can('Corporate') and isset(Yii::$app->session['practice_id'])) $this->andWhere(['practice.id'=>Yii::$app->session['practice_id']]);
parent::init();
}
}
class OrgQuery extends \yii\db\ActiveQuery
{
public function init()
{
if (!Yii::$app->user->can('Xpress') and isset(Yii::$app->session['org_id'])) $this->andWhere(['org.id'=>Yii::$app->session['org_id']]);
parent::init();
}
}
However, when I try to save a User model, I get an undefined index exception on office_id in ActiveRelationTrait at line 494. I do have an office_id value in the User model.
Any ideas on what is going on?
rules from User model
public function rules()
{
return [
[['gender', 'phone1_type', 'phone2_type','birth_date'], 'string'],
[['gender','phone1_type','phone2_type'],'default'],
[['opt_out_date', 'last_login', 'created_at', 'updated_at'], 'safe'],
[['bounce_count', 'status_id', 'sort', 'image_id', 'type_id', 'office_id', 'practice_id', 'org_id'], 'integer'],
[['lastname', 'firstname', 'auth_key'], 'string', 'max' => 32],
[['nickname', 'middlename', 'phone1', 'phone2'], 'string', 'max' => 16],
[['username', 'password_hash', 'addr1', 'addr2', 'position', 'permission'], 'string', 'max' => 64],
[['prefix'], 'string', 'max' => 8],
[['suffix'], 'string', 'max' => 24],
[['email', 'work', 'work_url'], 'string', 'max' => 255],
[['opt_out_reason', 'work_title'], 'string', 'max' => 128],
[['zipcode'], 'string', 'max' => 10],
[['username'], 'unique'],
[['username','phone1_type','phone2_type'],'default'],
[['email'],'required', 'on'=>'newUser'],
[['org_id', 'practice_id', 'office_id', 'permission', 'email','username', 'position'],'required', 'on'=>'newUser'],
['userImages','safe'],
['tab','string'],
['relationship','integer'],
['responsible','boolean'],
[['zipcode'], 'exist', 'skipOnError' => true, 'targetClass' => \app\models\Zip::className(), 'targetAttribute' => ['zipcode' => 'zipcode']],
[['lastname','firstname'],'required'],
[['responsible','gender','birth_date','zipcode'],'required','on'=>['patient']],
['relationship','required','on'=>['patientParty']],
];
}
and before/after save actions
public function beforeSave($insert)
{
if (parent::beforeSave($insert)) {
foreach(self::$dateFields as $date) if ($this->$date) $this->$date = date('Y-m-d',strtotime($this->$date)); else $this->$date = null;
if (!$this->zipcode) $this->zipcode = null;
if ($this->password) {
$this->password_hash = Yii::$app->security->generatePasswordHash($this->password);
$this->auth_key = Yii::$app->security->generateRandomString();
}
if (!$this->image_id and $this->images) $this->image_id = $this->images[0]->id;
return true;
} else {
return false;
}
}
public function afterSave($insert, $changedAttributes)
{
$auth = Yii::$app->authManager;
$auth->revokeAll($this->id);
$role = $auth->getRole($this->permission);
if ($role) $auth->assign($role,$this->id);
parent::afterSave($insert, $changedAttributes);
}
You can define a property (variable) in a model
public $office_id;
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.
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!
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() == "";
}'],
];
}
While updating image using Yii2 I'm facing a problem with the validation.Its always asking me to upload an image. But I don't want this. Always updating an image is not necessary.
I tried skipOnEmpty but its not working properly it cause effect while uploading a photo, which is also incorrect.
Please help!!
Model
public function rules()
{
return [
[['carid', 'name'], 'required'],
[['carid', 'coverphoto', 'status'], 'integer'],
[['name'], 'string', 'max' => 200],
[['imageFiles'], 'image','extensions' => 'png, jpg, jpeg, gif', 'maxFiles' => 4, 'minWidth' => 100, 'maxWidth' => 800, 'minHeight' => 100, 'maxHeight'=>600,'skipOnEmpty' => true],
];
}
Controller
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->photoid]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
You should to use scenario for update.
Like as,
Add on condition in model's rule for applying scenario .
[['imageFiles'], 'image','extensions' => 'png, jpg, jpeg, gif', 'maxFiles' => 4, 'minWidth' => 100, 'maxWidth' => 800, 'minHeight' => 100, 'maxHeight'=>600,'skipOnEmpty' => true, 'on' => 'update-photo-upload'],
And use that scenario in controller's action.
public function actionUpdate($id)
{
$model = $this->findModel($id);
$model->scenario = 'update-photo-upload';
........
.....
}
try rule as
[
['imageFiles'], 'file',
'extensions' => 'png, jpg, jpeg, gif',
'mimeTypes' => 'image/jpeg, image/png',
'maxFiles' => 4,
'minWidth' => 100,
'maxWidth' => 800,
'minHeight' => 100,
'maxHeight'=>600,
'skipOnEmpty' => true
],
This is working in my case, hope it works for you too.
**Your View Like This**
<?php use yii\widgets\ActiveForm;?>
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
<?= $form->field($model, 'imageFiles')->fileInput() ?>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end() ?>
*** Your Controller Like This******
use Yii;
use yii\web\Controller;
use app\models\UploadForm;
use yii\web\UploadedFile;
class SiteController extends Controller
{
public function actionUpdate()
{
$model = new UploadForm ();
$model->scenario = 'update';
if (Yii::$app->request->isPost) {
$model->imageFiles= UploadedFile::getInstance($model, 'imageFiles');
if ($model->upload()) {
// file is uploaded successfully
return;
}
}
return $this->render('update', ['model' => $model]);
}
}
***** Your ModelLike This ******
use yii\base\Model;
use yii\web\UploadedFile;
class UploadForm extends Model
{
/**
* #var UploadedFile[]
*/
public $imageFiles;
public function rules()
{
return [
[['carid', 'name'], 'required'],
[['carid', 'coverphoto', 'status'], 'integer'],
[['name'], 'string', 'max' => 200],
[['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4,'on'=>'update'],
];
}
public function upload()
{
if ($this->validate()) {
foreach ($this->imageFiles as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
return true;
} else {
return false;
}
}
function scenario()
{
return [
'create' => ['imageFiles ', 'carid','name','coverphoto','status'],
'update' => ['imageFiles ', 'carid','name','coverphoto','status'],
];
}
}