`Skip on empty` not working in Yii2 file upload - yii

I have a provision to upload logo for companies in my application. Uploading and saving on creating profile works fine. But on update, logo goes empty if I am not uploading it again!
Here's my update form
<?php $form = ActiveForm::begin([
'options' => ['enctype'=>'multipart/form-data']
]); ?>
.....
<?= $form->field($model, 'logo')->fileInput() ?>
...
My Controller action
if ($model->load($_POST) ) {
$file = \yii\web\UploadedFile::getInstance($model, 'logo');
if($file){
$model->logo=$file; }
if($model->save()){
if($file)
$file->saveAs(\Yii::$app->basePath . '/web/images/'.$file);
}
return $this->redirect(['profile']);
} else {
return $this->renderPartial('update', [
'model' => $model,
]);
}
My Rules:
public function rules()
{
return [
[['logo'], 'image', 'extensions' => 'jpg,png', 'skipOnEmpty' => true],
[['name'], 'required'],
[['name', 'description'], 'string'],
];
}
Any ideas????

skipOnEmpty does not apply here because in the update action the $model->logo attribute will not be empty, it will be a string with the file name.$file is still an array with only keys, but not values if not uploaded again. So checked the $file->size instead of checking !empty($file). Fixed the issue by modifying the controller code as follows!
$model = $this->findModel($id);
$current_image = $model->featured_image;
if ($model->load(Yii::$app->request->post())) {
$image= UploadedFile::getInstance($model, 'featured_image');
if(!empty($image) && $image->size !== 0) {
//print_R($image);die;
$image->saveAs('uploads/' . $image->baseName . '.' .$image->extension);
$model->featured_image = 'uploads/'.$image->baseName.'.'.$image->extension;
}
else
$model->featured_image = $current_image;
$model->save();
return $this->redirect(['update', 'id' => $model->module_id]);
} else {
return $this->render('add', [
'model' => $model,
]);
}

'skipOnEmpty' => !$this->isNewRecord
For update it can be skipped.

Related

default selected in multiselect dropdown in yii

it will not display default selected value in my multi select dropdown list and i am not getting the mistak. is dropdown list accept array for defalt select array list
public function actionCreate()
{
.......
$cust= implode('_',$_POST['supplier'] ['manufacture']);
$model->customer = $cust;
$model->save();
........
}
public function actionUpdate($id)
{
$model = $this->findModel($id);
$model->customer = explode('_',$model->customer);
if ($model->load(Yii::$app->request->post())) {
$cust= implode(',',$_POST['supplier']['manufacturer']);
$model->customer = $cust`enter code here`;
$model->save();
return $this->redirect(['view', 'id' => $model->ID]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
View
<?=
$form->field($model, 'car_manufacturer[]')->dropDownList($model->getcustinfo(), [
'multiple'=>'multiple',
'class'=>'chosen-select input-md required',
]);
?>
Pass the selected value in options:
['options' => $yourvalue => ['Selected'=>'selected']]
You should pass an array in options:
['options' =>
[
$id1 => ['selected' => true]
],
[
$id2 => ['selected' => true]
],
]
You can use foreach loop to make this array.
You should use only attribute name.
<?= $form->field($model, 'car_manufacturer')->dropDownList($model->getcustinfo(), [
'multiple'=>'multiple',
'class'=>'chosen-select input-md required', ])?>

Why i getting an error "Call to a member function formName() on a non-object"

i try to save multilanguaged content
My About model
...
public function rules() {
return [
[['status', 'date_update', 'date_create'], 'integer'],
[['date_update', 'date_create'], 'required'],
];
}
...
public function getContent($lang_id = null) {
$lang_id = ($lang_id === null) ? Lang::getCurrent()->id : $lang_id;
return $this->hasOne(AboutLang::className(), ['post_id' => 'id'])->where('lang_id = :lang_id', [':lang_id' => $lang_id]);
}
My AboutLang model
public function rules()
{
return [
[['post_id', 'lang_id', 'title', 'content'], 'required'],
[['post_id', 'lang_id'], 'integer'],
[['title', 'content'], 'string'],
];
}
My About controller
public function actionCreate()
{
$model = new About();
$aboutLang = new AboutLang();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,'aboutLang'=>$aboutLang]);
}
}
and my view (create form)
...
<?= $form->field($model, 'status')->textInput() ?>
<?= $form->field($aboutLang, 'title')->textInput() ?>
<?= $form->field($aboutLang, 'content')->textInput() ?>
enter code here
And when i put $aboutLang in create form i get an error "Call to a member function formName() on a non-object"
It looks like the views you are using were generated by Gii. In that case, Gii generates a partial view for the form (_form.php) and two views both for create and update actions (create.php and update.php). These two views perform a rendering of the partial view.
The problem you might have is that you are not passing the variable $aboutLang from create.php to _form.php, that must be done in create.php, when you call renderPartial():
$this->renderPartial("_form", array(
"model" => $model,
"aboutLang" => $aboutLang, //Add this line
));
Hope it helps.
Check your $aboutLang type.
It looks like it is null.
if ($aboutLang) {
echo $form->field($aboutLang, 'title')->textInput();
echo $form->field($aboutLang, 'content')->textInput();
}

Upload multiple files yii2

Tell me where I was wrong, everything is tried
my view file:
echo FileInput::widget([
'model' => $model,
'attribute' => 'files[]',
'options' => ['multiple' => true]
]);
Also i added
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>
enctype option to form element
Model:
i add two variables as property:
public $files; // files instance
public $serialize; // set string which store the files
in rules
serialize as string, and files:
[['files'], 'file', 'skipOnEmpty' => true, 'extensions' => 'gif, jpg, png, pdf, doc, docx', 'maxFiles' => 10],
and controller action:
public function actionUpdate($id)
{
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post())) {
$oldFiles = $model->serialize;
$files = UploadedFile::getInstance($model, 'files');
if($files === false){
$model->serialize = $oldFiles;
} else {
$serialize = [];
if($model->validate()){
foreach($files as $file){
$ext = end((explode(".", $file)));
$filename = Yii::$app->security->generateRandomString().".{$ext}";
$serialize[] = $filename;
$file->saveAs(Yii::$app->basePath . '/web/image/' . $filename);
}
} else {
}
//print_r($model->getErrors()); die();
$model->serialize = serialize($serialize);
}
$model->save();
return $this->redirect(['view', 'id' => $model->news_id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
So, $files is empty, why?
also i get a "4" code error in $_FILES array
It should be getInstances for multiple files.
$files = UploadedFile::getInstances($model, 'files');

How to implement kartik yii2 FileInput in form Update while using different models

I have followed this solution in working with multiple models to upload using files using kartik fileinput during actionCreate.
My problem is achieving the same during actionUpdate, I keep on receiving the error below:
Either 'name', or 'model' and 'attribute' properties must be specified.
My form view is as follows:
echo $form->field($document,'document[]')->widget(FileInput::classname(), [
'options' => ['multiple' => true],
'pluginOptions' => [
// 'previewFileType' => 'any',
'showPreview' => false,
'showUpload' => false
], ]);
Whereas my controller actionUpdate is as follows
public function actionUpdate($id)
{
//$document = new EmployeeDocuments();
$model = $this->findModel($id);
$document = EmployeeDocuments::find()->indexBy('employee_id')->all();
$empavatar=$model->avatar;
$oldavatar=Yii::$app->session['oldavatar'] = $empavatar;
if ($model->load(Yii::$app->request->post()) ) {
// print_r($model); exit;
// $attachments = UploadedFile::getInstances($document, 'document');
// print_r($attachments); exit;
if($model->avatar==""){
$model->avatar=$oldavatar;
}
if ($model->save()){
if(!empty($attachments)){
foreach($attachments as $attachment):
$ext = end((explode(".", $attachment)));
$filename=end((explode(">", $attachment)));
$filename = ucwords(substr($filename, 0, strpos($filename, '.')));
// generate a unique file name
$file2save = Yii::$app->security->generateRandomString().".{$ext}";
$path=Yii::getAlias('#loc').'/uploads/employees/docs/'; //set directory path to save image
$attachment->saveAs($path.$model->id."_".$file2save); //saving img in folder
$attachment = $model->id."_".$file2save; //appending id to image name
\Yii::$app->db->createCommand()
->insert('lcm_hrm_employee_documents', ['document' => $attachment, 'name'=>$filename,'employee_id'=>$model->id])
->execute(); //manually update image name to db /* */
endforeach;
}
return $this->redirect(['view', 'id' => $model->id]);
}
else {
return $this->render('update', [
'model' => $model, 'document'=>$document
]);
}
} else {
return $this->render('update', [
'model' => $model, 'document'=>$document
]);
}
}
Change your form view to
echo $form->field($document,'document[]')->widget(FileInput::classname(), [
'options' => ['multiple' => true],
'attribute' =>'document[]',
'pluginOptions' => [
// 'previewFileType' => 'any',
'showPreview' => false,
'showUpload' => false
], ]);

Yii CForm, Nested Forms Ajax Validation

I have created the following nested forms array;
return array(
'elements' => array(
'contact' => array(
'type' => 'form',
'elements' => array(
'first_name' => array(
'type' => 'text',
),
'last_name' => array(
'type' => 'text',
)
),
),
'lead' => array(
'type' => 'form',
'elements' => array(
'primary_skills' => array(
'type' => 'textarea',
),
),
),
),
'buttons' => array(
'save-lead' => array(
'type' => 'submit',
'label' => 'Create',
'class' => 'btn'
),
)
);
i have view page like this
echo $form->renderBegin();
echo $form['lead'];
echo $form['contact'];
echo $form->buttons['save-lead'];
echo $form->renderEnd();
my actionCreate is like this
$form = new CForm('application.views.leads.register');
$form['lead']->model = new Lead;
$form['contact']->model = new Contact;
// how can i perform ajax validation only for $form['contact']
$this->performAjaxValidation($model);
//if contact form save btn is clicked
if ($form->submitted('save-lead') && $form['contact']->validate() &&
$form['lead']->validate()
) {
$contact = $form['contact']->model;
$lead = $form['lead']->model;
if ($contact->save()) {
$lead->contact_id = $contact->id;
if ($lead->save()) {
$this->redirect(array('leads/view', 'id' => $lead->id));
}
}
}
ajax validation method is
protected function performAjaxValidation($model)
{
if (isset($_POST['ajax']) && $_POST['ajax'] === 'contact') {
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
so my question is how can i perform ajax validation on $form['contact'] and $form['lead'] elements individually?
You can have several forms in a page but they should not be nested.
Nested forms are invalid.
You should make your own validation
in actionCreate and actionUpdate of your controller you must add (i have main model "Invoice" and secondary "InvoiceDetails", and there could be more than 1 form for InvoiceDetails). But of course forms cannot be nested!
public function actionCreate()
{
...
$PostVar = 'Invoices';
if (Yii::app()->request->isAjaxRequest)
{ // if ajax
$this->performAjaxValidation($model, strtolower($PostVar) . '-form');
$PostVar = ucfirst($PostVar);
if (isset($_POST[$PostVar]))
{
$model->attributes = $_POST[$PostVar];
$dynamicModel = new InvoiceDetails(); //your model
$valid = self::validate($model, $dynamicModel);
if (!isset($_POST['ajax']))
{
if (isset($_POST['InvoiceDetails']))
{
$allDetails = array();
$allDynamicModels = $_POST['InvoiceDetails'];
//your own customization
foreach ($allDynamicModels as $key => $value)
{
$InvDet = InvoiceDetails::model()->findByPk($_POST['InvoiceDetails'][$key]['id']);
if (!isset($InvDet))
{
$InvDet = new InvoiceDetails();
}
$InvDet->attributes = $_POST['InvoiceDetails'][$key];
$InvDet->save();
$allDetails[] = $InvDet;
}
}
$model->invoicedetails = $allDetails;
if ($model->save())
{
echo CJSON::encode(array('status' => 'success'));
Yii::app()->end();
}
else
{
echo CJSON::encode(array('status' => 'error saving'));
Yii::app()->end();
}
}
// Here we say if valid
if (!isset($valid))
{
echo CJSON::encode(array('status' => 'success'));
}
else
{
echo $valid;
}
Yii::app()->end();
}
else
{
$this->renderPartial('_form', ...);
}
}
else
{
// not AJAX request
$this->render('_form', ...));
}
Nested Forms are invalid. You can use scenarios to validate the form at different instances.
Example:
`if ($form->submitted('save-lead'){
$form->scenario = 'save-lead';
if($form->validate()) {
$form->save();
}
} else {
$form->scenario = 'contact';
if($form->validate()){
$form->save();
}
}
$this->render('_form', array('form'=>$form);`