Yii2 UploadedFile::getInstance() returns null - yii2

When my form is sent UploadedFile::getInstance($model, 'images') returns null. I also tried UploadedFile::getInstanceByName('images'). In the $_POST array the images key is empty e.g. 'images' => ['']. The file exists in $_FILES array.
My code is pretty simple. My view:
<?php $form = ActiveForm::begin([
'options' => [
'class' => 'validation-wizard wizard-circle floating-labels',
'enctype'=>'multipart/form-data'
],
]); ?>
<?= $form->field($model, 'images[]')->fileInput([
'id' => 'image_0',
'class' => 'dropify',
'data-default-file' => ''
]) ?>
<?php ActiveForm::end() ?>
In my model I have:
public $images;
public function rules()
{
return [
['images', 'each', 'rule' => ['file']],
];
}

If you want to access an array of files, you need to use UploadedFile::getInstances() instead of UploadedFile::getInstance().
$files = UploadedFile::getInstances($model, 'images');
Good example of handling multiple files can be found in guide in Uploading Multiple Files section.

Related

kartik-v/yii2 select2-widget not working with render partial

I am trying to add dynamic drop downs, which will added from javascript on clicking add new button.
view file
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use kartik\select2\Select2;
use kartik\select2\Select2Asset;
use yii\helpers\ArrayHelper;
Select2Asset::register($this);
?>
<div class='row'>
<div class='form-group'>
<?=
Select2::widget([
'name' => 'coupons',
'value' => $model->coupon_id,
'data' => ArrayHelper::map($coupons, 'id', 'name'),
'options' => ['placeholder' => 'Select a state ...'],
'pluginOptions' => [
'allowClear' => true
],
]);
?>
</div>
</div>
controller
public function actionNewCoupon()
{
$coupon = new DealCoupon();
$deal = Yii::$app->request->get('deal');
$order = Yii::$app->request->get('order');
$coupon->deal_id = $deal;
$coupon->order = $order;
$coupon->save();
$coupons = Coupon::find('id','name')->all();
return $this->renderPartial('_form', [
'model' => $coupon,
'coupons' => $coupons
],true, true);
}
js file
.get(BASE_URL + '/coupon/new-coupon', { deal: dealId, order: order }, function(data) {
var dealWidget = newStep.find('.coupon-panel');
$(newStep).find('.coupon-panel').html(data);
});
What I am getting
Any help to resolve this issue is appreciable, as I am totaly lost.
Thanks in advance.
yii\web\Controller::renderPartial() doesn't include registered JS or CSS files. Try using yii\web\Controller::renderAjax() instead. It's similar but it injects registered JS/CSS files into rendered html code.

One search form to 3 Gridview in same page

Friends,
I have an INDEX page with 3 GRIDVIEW components (model Keys, model Products, model Indicators). And on that same page I have a search form with a dropdownlist (company).
I need to: When you select for example company 02 the 3 GRIDVIEW are filtered only company records 02.
_search.php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use kartik\date\DatePicker;
?>
<div class="ideas-search">
<?php $form = ActiveForm::begin([
'options' => [
'class' => 'form-inline',
],
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'pa')->dropdownList([..])?>
...
index.php
<?php echo $this->render('_search', ['model' => $searchBase]); ?>
<?php Pjax::begin(['id' => '1']) ?>
<?= GridView::widget([
'id' => 'grid1',
'dataProvider' => $dataProviderKey,
'columns' => [
...
],
]); ?>
<?php Pjax::end() ?>
<?php Pjax::begin(['id' => '2']) ?>
<?= GridView::widget([
'id' => 'grid2',
'dataProvider' => $dataProviderProduct,
'columns' => [
...
],
]); ?>
<?php Pjax::end() ?>
<?= GridView::widget([
'dataProvider' => $dataProviderIndicators,
'summary' => false,
'columns' => [
...
],
]); ?>
== UPDATE==
BaseController
public function actionIndex()
{
$searchBase = new BaseSearch();
$searchBase->pa = 0;
$searchBase->data = date("Y-m-d");
$dataProviderBase = $searchBase->search(Yii::$app->request->queryParams);
$searchMobilizadores = new MobilizadoresSearch();
$dataProviderMobilizadores = $searchMobilizadores->search(Yii::$app->request->queryParams);
$searchIndicadores = new IndicadoresSearch();
$dataProviderIndicadores = $searchIndicadores->search(Yii::$app->request->queryParams);
return $this->render('index', [
'searchBase' => $searchBase,
'dataProviderBase' => $dataProviderBase,
'searchMobilizadores' => $searchMobilizadores,
'dataProviderMobilizadores' => $dataProviderMobilizadores,
'searchIndicadores' => $searchIndicadores,
'dataProviderIndicadores' => $dataProviderIndicadores,
]);
}
dont forget define filterModel in your Gridview Widget
view file
GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
1st Approach :
You may use a single model that extend from model that joint all 3 table and create a search model for it. If u insist on separating all 3 table in the view, you may just declare different column for each grid.
a tip to achieve this, you may create a view and use gii tool to generate view file.
the tricky part is that 1 model can only hold one table except you joint. But, by joining table, you may get extra rows that are not necessarily needed for lets say your $dataProviderKey grid.
2nd Approach :
manually check for params from Yii::$app->request->get() add filter for each $dataprovider.
controller file
if(isset($id = Yii::$app->request->get('company_id'))) {
$dataProviderKey->query->andFilterWhere(['company.id' => $id]);
$dataProviderProduct->query->andFilterWhere(['company.id' => $id]);
$dataProviderIndicators->query->andFilterWhere(['company.id' => $id]);
}
== UPDATE ==
to answer your update question, you may assign your base search attributes to the respective attributes from others searchModel like this :
public function actionIndex()
{
$searchBase = new BaseSearch();
$searchBase->pa = 0;
$searchBase->data = date("Y-m-d");
$dataProviderBase = $searchBase->search(Yii::$app->request->queryParams);
$searchMobilizadores = new MobilizadoresSearch();
$searchMobilizadores->company = $searchBase->company; -->add this
$dataProviderMobilizadores = $searchMobilizadores->search(Yii::$app->request->queryParams);
$searchIndicadores = new IndicadoresSearch();
$searchIndicadores->company = $searchBase->company; -->add this
$dataProviderIndicadores = $searchIndicadores->search(Yii::$app->request->queryParams);

Yii2 Basic sql query in view

I'm trying to get the user profile image of the author of the content inside the view , my view is channel I created but I get this error on my view
Undefined variable: queryAvatar
on my view I did
//Yii2 View code
use yii\helpers\Html;
use yii\widgets\DetailView;
/* #var $this yii\web\View */
/* #var $model app\models\Channel */
$this->title = $model->Channel_name;
?>
<div class="channel-view">
<h1><?= Html::encode($this->title) ?></h1>
<div><?php echo $queryAvatar; ?></div> // THE LINE I ADD
<?php if($model->uid == Yii::$app->user->id):?>
<p>
<?= Html::a('Update', ['update', 'id' => $model->Channel_id], ['class' => 'btn btn-primary']) ?>
<?= Html::a('Delete', ['delete', 'id' => $model->Channel_id], [
'class' => 'btn btn-danger',
'data' => [
'confirm' => 'Are you sure you want to delete this item?',
'method' => 'post',
],
]) ?>
</p>
<?php endif;?>
</div>
and on my controller I created this function
//function on my controller
public function actionChannel($id)
{
$cchannel = new Channel();
$queryAvatar = (new \yii\db\Query())
->select(['uavatar'])
->from('userlogin')
->where(['uid' => $cchannel->uid])
->All();
return $this->render('channel', [
'model' => $this->findModel($id),
'queryAvatar '=> $queryAvatar ,
]);
}
in your controller you define an empty model so your $cchannel->uid is empty.
You must define first your model like this
public function actionChannel($id)
{
$cchannel = $this->findModel($id);
$queryAvatar = (new \yii\db\Query())
->select(['uavatar'])
->from('userlogin')
->where(['uid' => $cchannel->uid])
->All();
return $this->render('channel', [
'model' => $cchannel ,
'queryAvatar '=> $queryAvatar ,
]);
}
The problem can be caused by space when you created array of variable before giving to view.
return $this->render('channel', [
'model' => $this->findModel($id),
'queryAvatar '=> $queryAvatar ,
]);
remove space from 'queryAvatar '
Like this:
return $this->render('channel', [
'model' => $this->findModel($id),
'queryAvatar'=> $queryAvatar ,
]);
Another problem can be caused by partial view in side view. For example when you call view:channel from controller inside it may be you view called like this.
<?=$this->render('your_view')?>
So, you should pass your variable to this view also like this.
<?=$this->render('your_view',['queryAvatar'=>$queryAvatar])?>
And finally you cannot echo the varable $queryAvatar beacuse it is array of objects. Therefore use the function print_r();
Like this.
<div><?php print_r($queryAvatar); ?></div> // THE LINE I ADD

Yii2 unique validator ignored

In the rules() of my RegisterForm model:
[ 'user_username', 'unique', 'targetClass' => 'app\models\User', 'message' => 'This username is already been taken.' ],
In my controller:
$model = new RegisterForm();
if ( $model->load( Yii::$app->request->post() ) ) {
if ( $user = $model->register() ) {
return $this->redirect( [ '/login' ] );
}
}
In RegisterForm:
public function register() {
$user = new User();
$user->user_firstname = $this->user_firstname;
$user->user_lastname = $this->user_lastname;
$user->user_username = $this->user_username;
$user->user_email = $this->user_email;
$user->setPassword( $this->user_password );
if ( !$user->validate() ) {
return null;
}
if ( $user->save() ) {
return $user;
}
return null;
}
Form:
<?php $form = ActiveForm::begin(); ?>
<?= $form->field( $model, 'user_firstname' )->textInput( [ 'maxlength' => true ] ) ?>
<?= $form->field( $model, 'user_lastname' )->textInput( [ 'maxlength' => true ] ) ?>
<?= $form->field( $model, 'user_username' )->textInput( [ 'maxlength' => true ] ) ?>
<?= $form->field( $model, 'user_email' )->textInput( [ 'maxlength' => true ] ) ?>
<?= $form->field( $model, 'user_password' )->passwordInput() ?>
<?= $form->field( $model, 'user_password_repeat' )->passwordInput() ?>
<?= Html::submitButton( 'Register', [ 'class' => 'btn btn-primary', 'name' => 'register-button' ] ) ?>
<?php ActiveForm::end(); ?>
Yet when I enter a username that I know already exists, the error never comes up and the record tries to save, though I get: Integrity constraint violation: 1062 Duplicate entry ...
EDIT: if I add the unique rule to the User model itself the form will not submit if I input a username that exists, the errors just don't show up
Like I have suspected, you are not checking for unique user_username attribute in client side. The reason why it's not working it's because you are not sending Ajax requests to check the results from database. Unlike other rules, unique rule requires additional Ajax requests to server since it would be pretty bad thing if Javascript would retrieve all currently registered username and store somewhere in Client side.
To solve you problem, in form write something like this:
$form = ActiveForm::begin([
'enableAjaxValidation' => true,
'validationUrl' => [<URL HERE>],
]);
Now you have to create a method (action) in controller that returns validation (not just unique, all of them) back to ActiveForm. So it could be something like this:
public function actionAjaxValidation()
{
$post = Yii::$app->request->post();
$model = new YourClass();
if (!$model->load($post)) {
throw new HttpException(403, 'Cannot load model');
}
$array = ActiveForm::validate($model);
return json_encode($array);
}

Trying to get property of non-object while using kartik-v for image uploading in Yii2

I'm using yii2-widget-fileinput for an image uploading in a form.
When I click on upload or the create button I get Trying to get property of non-object error in controller.
Controller
public function actionCreate()
{
Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/uploads/';
$model = new Ads();
$provinces = ArrayHelper::map(Province::find()->all(), 'name', 'name');
if ($model->load(Yii::$app->request->post())){
$image = UploadedFile::getInstances($model, 'image');
$model->filename = $image->name;
$ext = end((explode(".", $image->name)));
$avatar = Yii::$app->security->generateRandomString().".{$ext}";
$path = Yii::$app->params['uploadPath'].$avatar;
if ($model->save()) {
$image->saveAs($path);
$model->image_adr = $path;
return $this->redirect(['view', 'id' => $model->id]);
}else{
echo "error on saving the model";
}
}
return $this->render('create', [
'model' => $model,
'provinces'=>$provinces,
]);
}
model rules
public function rules()
{
return [
[['type', 'explanation', 'cost', 'province_name', 'address'], 'required'],
[['type', 'explanation', 'image_adr', 'address'], 'string'],
[['cost'], 'integer'],
[['province_name'], 'string', 'max' => 20],
[['province_name'], 'exist', 'skipOnError' => true, 'targetClass' => Province::className(), 'targetAttribute' => ['province_name' => 'name']],
[['image'],'safe'],
[['image'], 'file', 'extensions'=>'jpg, gif, png', 'maxFiles'=>3,],
];
and finnally the view
<?= $form->field($model, 'image[]')->widget(FileInput::classname(), [
'options'=>['accept'=>'image/*', 'multiple'=>true],
'pluginOptions'=>['allowedFileExtensions'=>['jpg','gif','png'], 'overwriteInitial'=>false,]
]); ?>
the problem should refer to this part in the controller I think
$image = UploadedFile::getInstances($model, 'image');
An image of the error might be helpful
You should check first is image in post or not.
....
$image = UploadedFile::getInstances($model, 'image'); //getInstanceByName
if (!empty($image))
$model->filename = $image->name;
.....
if ($model->save()) {
if (!empty($image))
$image->saveAs($path);
.........
Make sure in your form ency type is added:
$form = ActiveForm::begin([
'id' => 'form_id',
'options' => [
'class' => 'form_class',
'enctype' => 'multipart/form-data',
],
]);
The problem is when you're using UploadedFile::getInstances($model, 'image'); you should work with foreach or treat it like an array.
Something that made me a problem was that even if you're using UploadedFile::getInstanc (notice the obsoleted s in the end) you should still treat it like an array and in all parts you should use $image[0], not $iamge lonely.