Yii2 hiddenInput does not react on options value - yii2

Going to change image field in model by changing value in hidden field:
View:
<?= HTML::activeHiddenInput($model, 'image_clean', [
'id' => 'cleaner',
'name' => 'cleaner',
'value' => false
])
?>
<?=
Html::button('Remove logo', [
'id' => 'btn_clean',
])
?>
at the end of view:
<?php
$this->registerJs(<<<JS
$('#btn_clean').on('click', function() {
alert('Going to remove logo'); // Reachable!
$('#cleaner').val(true);
});
JS
);
?>
Model:
public $image_clean; // Remove logo
public function rules() {
return [
//...
[['image_clean'], 'boolean'],
//...
];
}
public function attributeLabels() {
return [
//...
'image_clean' => 'Remove logo',
//...
];
}
public function beforeValidate() {
if($this->image_clean) { } // Never!
return parent::beforeValidate();
}
public function beforeSave($insert) {
if($this->image_clean) { } // Never!
return parent::beforeSave($insert);
}
Unfortunately, $this->image_clean in model's beforeValidate / beforeSave always false. Why?
Javascript btn_clean handler works as it should be.

Hiddeninput's name overrides default one.
So, I just remove 'name' => 'cleaner'. It's not required

Related

Yii2 Setting read-only property

Good day everyone
When I try to create a client, I get an error: Setting read-only property: app\models\form\ClientForm::Clientclient
How can I fix this error?
This is my ClientClient(model)
class ClientClient extends \yii\db\ActiveRecord
{
/**
* {#inheritdoc}
*/
public static function tableName()
{
return 'client_client';
}
public $clientclients;
/**
* {#inheritdoc}
*/
public function rules()
{
return [
[['age', 'client_id'], 'integer'],
[['first_name', 'patronymic', 'last_name', 'clientclients'], 'string', 'max' => 255],
];
}
/**
* {#inheritdoc}
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'first_name' => 'First Name',
'patronymic' => 'Patronymic',
'last_name' => 'Last Name',
'age' => 'Age',
'client_id' => 'Client Id',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getClient_id()
{
return $this->hasOne(ClientPhone::class, ['client_id' => 'id']);
}
public function getPhone()
{
return $this->hasOne(ClientPhone::class, ['phone_digital' => 'id']);
}
}
This is my ClientForm(model):
class ClientForm extends model
{
private $_client;
private $_phone;
public function rules()
{
return [
[['ClientClient'], 'required'],
[['ClientPhone'], 'safe'],
];
}
public function afterValidate()
{
$error = false;
if (!$this->ClientClient->validate()) {
$error = true;
}
if (!$this->ClientPhone->validate()) {
$error = true;
}
if ($error) {
$this->addError(null); // add an empty error to prevent saving
}
parent::afterValidate();
}
public function save()
{
if (!$this->validate()) {
return false;
}
$transaction = Yii::$app->db->beginTransaction();
if (!$this->ClientClient->save()) {
$transaction->rollBack();
return false;
}
$this->ClientPhone->client_id = $this->ClientClient->id;
if (!$this->phone->save(false)) {
$transaction->rollBack();
return false;
}
$transaction->commit();
return true;
}
public function getClientclient()
{
return $this->_client;
}
public function setClient($client)
{
if ($client instanceof Client) {
$this->_client = $client;
} else if (is_array($client)) {
$this->_client->setAttributes($client);
}
}
public function getphone()
{
if ($this->_phone === null) {
if ($this->client->isNewRecord) {
$this->_phone = new Phone();
$this->_phone->loadDefaultValues();
} else {
$this->_phone = $this->client->phone;
}
}
return $this->_phone;
}
public function setPhone($phone)
{
if (is_array($phone)) {
$this->phone->setAttributes($phone);
} elseif ($phone instanceof Phone) {
$this->_phone = $phone;
}
}
public function errorSummary($form)
{
$errorLists = [];
foreach ($this->getAllModels() as $id => $model) {
$errorList = $form->errorSummary($model, [
'header' => '<p>Please fix the following errors for <b>' . $id . '</b></p>',
]);
$errorList = str_replace('<li></li>', '', $errorList); // remove the empty error
$errorLists[] = $errorList;
}
return implode('', $errorLists);
}
private function getAllModels()
{
return [
'Client' => $this->client,
'Phone' => $this->phone,
];
}
}
_form
<div class="clientclient-form">
<?php $form = ActiveForm::begin(); ?>
<?= $form->field($clientForm->Clientclient, 'first_name')->textInput(['maxlength' => true]) ?>
<?= $form->field($clientForm->Clientclient, 'patronymic')->textInput(['maxlength' => true]) ?>
<?= $form->field($clientForm->clientphone, 'last_name')->textInput(['maxlength' => true]) ?>
<?= $form->field($clientForm->clientphone, 'phone_digital')->widget( MaskedInput::class, ['mask' => '9999999999'])?>
<?= $form->field($clientForm->Clientclient, 'age')->textInput() ?>
<div class="form-group">
<?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
and Controller
public function actionCreate()
{
$clientForm = new ClientForm();
$clientForm->Clientclient = new ClientClient();
$clientForm->setAttributes(Yii::$app->request->post());
if (Yii::$app->request->post() && $clientForm->save()) {
Yii::$app->getSession()->setFlash('success', 'Clientclient has been created.');
return $this->redirect(['update', 'id' => $clientForm->Clientclient->id]);
} elseif (!Yii::$app->request->isPost) {
$clientForm->load(Yii::$app->request->get());
}
return $this->render('create', ['clientForm' => $clientForm]);
}
public function actionUpdate($id)
{
$clientForm = new ClientForm();
$clientForm->ClientClients = $this->findModel($id);
$clientForm->setAttributes(Yii::$app->request->post());
if (Yii::$app->request->post() && $clientForm->save()) {
Yii::$app->getSession()->setFlash('success', 'clientClient has been created.');
return $this->redirect(['update', 'id' => $clientForm->ClientClient->id]);
} elseif (!Yii::$app->request->isPost) {
$clientForm->load(Yii::$app->request->get());
}
return $this->render('create', ['clientForm' => $clientForm]);
}
Why is Clientclient::tags read-only? And whats the proper way to set a model relationship?
I get an error: Setting read-only property:
app\models\form\ClientForm::Clientclient
You are using Yii getter and setter class methods instead of public properties but only getter method is defined inside your ClientForm class. You need to also add the Setter method:
public function setClientclient($value)
{
$this->_client = $value;
}
See Concept Properties in official documentation for more details.
Easiest approach is to use setAttributes. Call it before or after $model->load(Yii::$app->request->post())
$model->setAttribute('_client', $value);

yii2 custom validation addError message doesn't show

when i use custom validations on yii2 dynamic forms it doesn't show any error messages below the input field.Below I have posted my model.
It doesn't show any error messges when qty field gets validated
namespace frontend\models;
use Yii;
class OrderD extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'order_d';
}
public function rules()
{
return [
[['item_id', 'qty', 'price', 'value'], 'required'],
[['item_id'], 'integer'],
[['price', 'value'], 'number'],
[['order_code'], 'string', 'max' => 10],
[['item_id'], 'exist', 'skipOnError' => true, 'targetClass' => Item::className(), 'targetAttribute' => ['item_id' => 'id']],
[['order_code'], 'exist', 'skipOnError' => true, 'targetClass' => OrderH::className(), 'targetAttribute' => ['order_code' => 'code']],
['qty', 'validateQty']
];
}
public function validateQty($attribute)
{
$qty = $this->$attribute;
if ($qty >= 5)
{
$this->addError('qty', "qty validation successful");
}
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'item_id' => 'Item ID',
'order_code' => 'Order Code',
'qty' => 'Qty',
'price' => 'Price',
'value' => 'Value',
];
}
/**
* #return \yii\db\ActiveQuery
*/
public function getItem()
{
return $this->hasOne(Item::className(), ['id' => 'item_id']);
}
/**
* #return \yii\db\ActiveQuery
*/
public function getOrderCode()
{
return $this->hasOne(OrderH::className(), ['code' => 'order_code']);
}
}
Be sure to know custom validations are php functions and not convert as javascript to validate in runtime .. those will work after the page has submit and send to controller ..
here is simple sample you want :
['qty','custom_function_validation'],
];
}
public function custom_function_validation($attribute, $params){
if($this->$attribute>5){
$this->addError($attribute,'it\'s more than 5');
}
}
To create a validator that supports client-side validation, you should implement the yii\validators\Validator::clientValidateAttribute() method which returns a piece of JavaScript code that performs the validation on the client-side.
public function clientValidateAttribute($model, $attribute, $view)
{
return <<<JS
// your validation
JS;
}
See the documentation here: http://www.yiiframework.com/doc-2.0/guide-input-validation.html#implementing-client-side-validation
Use method addError() in a controller and then just render your view file
Example
if ($promo_code) {
if ($promo_code->status == '1') {
$message = 'This combination is incorrect.';
$model->addError('promo_code', $message);
return $this->render('index', compact('model'));
}
$promo_code->status = '1';
$promo_code->save();
$model->save();
}

YII2 Call to a member function isAttributeRequired() on a non-object

I am new with Yii2, im trying to make sales transaction, but i have problem for dropdownlist in detail section.
for this module, i have 3 tables :
1. for header, table salesheader
2. for detail, table salesdetail
3. for item, table item
this is my code :
on controller :
public function actionUpdate($id)
{
$model = $this->findModel($id); //find appropriate record in salesheader
//$modeldetail = salesdetail::findModel($id);
$modeldetail = new salesdetail();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['index']);
} else {
$item = item::find()->select(["concat('[',code,'] - ', name) as item", "id"])->indexBy('id')->column();
$detail = salesdetail::find()->select(["*"])->all(); //find appropriate record in salesdetail
return $this->render('update', [
'model' => $model,
'modeldetail' => $modeldetail,
'item' => $item,
'detail' => $detail
]);
}
}
on salesheader model
namespace app\models;
use Yii;
class salesheader extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'salesheader';
}
public function rules()
{
return [
[['partnerId', 'date', 'term', 'name'], 'required'],
[['name', 'invNumber'], 'string'],
[['partnerId', 'term'], 'integer']
];
}
public function attributeLabels()
{
return [
'partnerId' => 'Customer',
'date' => 'Date',
'invNumber' => 'Inv. Number',
'term' => 'Term',
'name' => 'Name'
];
}
on salesdetail model
namespace app\models;
use Yii;
class salesdetail extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'salesdetail';
}
public function rules()
{
return [
[['itemId', 'qty', 'price'], 'required'],
[['unit'], 'string']
];
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'itemId' => 'Item',
];
}
}
on my view
<?= $form->field($detail, 'itemId')->dropDownList($item)->label(false) ?>
and when open the page in browser, i got this error "Call to a member function isAttributeRequired() on a non-object"
and if i change this line on controller
//$modeldetail = salesdetail::findModel($id);
$modeldetail = new salesdetail();
to this one
$modeldetail = salesdetail::findModel($id);
//$modeldetail = new salesdetail();
then the error would be "Call to undefined method app\models\salesdetail::findModel()"
can somebody tell me what am i doing wrong ?
and how to get appropriate data from salesdetail based on salesheader and put it on dropdownlist ?
Thank you for ur help

action download in gridview yii2

I'm very new with YII2. I want to create a download function to the file that was uploaded before. I've referred how to create action download at Gridview in Yii2. However, when I click button download, it load the blank page. Here the code.
At gridview
<?=GridView::widget([
'dataProvider'=>$dataProvider,
'id'=>'mygrid',
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'project_name',
'project_file',
'created_date',
[
'class' => 'yii\grid\ActionColumn',
],
['attribute'=>'Download',
'format'=>'raw',
'value' => function($data)
{
return
Html::a('Download file', ['firstyear/download', 'id' => $data->id],['class' => 'btn btn-primary']);
}
],
]
]);
?>
At actionDownload
public function actionDownload($id)
{
$download = Firstyear::findOne($id);
$path=Yii::getAlias('#webroot').'/uploads/'.$download->project_file;
if (file_exists($path)) {
return Yii::$app->response->sendFile($path);
}
}
At actionCreate (upload file)
public function actionCreate()
{
$model = new Firstyear();
if ($model->load(Yii::$app->request->post()))
{
$project =$model->project_name;
$model->file= UploadedFile::getInstance($model,'file');
$model-> file->saveAs('uploads/'.$project.'.'.$model->file->extension);
$model->project_file='uploads/'.$project.'.'.$model->file->extension;
$model->save();
Yii::$app->getSession()->setFlash('success','Data saved!');
return $this->redirect(['view','id'=> $model->id]);
}
else {
return $this ->renderAjax('create', [
'model'=>$model,
]);
}
}
Thanks.
I suspect that the $path is not correct, in the action create, you already include the uploads folder in your $model->project_file
public function actionCreate()
{
$model = new Firstyear();
if ($model->load(Yii::$app->request->post()))
{
.......
$model->project_file='uploads/'.$project.'.'.$model->file->extension;
$model->save();
....
}
}
but you use it again in actionDownlaod
public function actionDownload($id)
{
.....
$path=Yii::getAlias('#webroot').'/uploads/'.$download->project_file;
if (file_exists($path)) {
return Yii::$app->response->sendFile($path);
}
}
you should try to remove the uploads folder in the actionDownlaod, and added some debug message
public function actionDownload($id)
{
.....
$path=Yii::getAlias('#webroot').'/'.$download->project_file;
if (file_exists($path)) {
return Yii::$app->response->sendFile($path);
} else {
throw new NotFoundHttpException("can't find {$download->project_file} file");
}
}

Yii2: Returning an array of primary keys

Maybe I'm missing the essentials but why the following code will throw a Bad Request error (#400) complaining on "Missing parameter id" when rendering a view on a MySQL view?
In model:
public static function primaryKey()
{
return [
'vcostumbre_id',
'vbibliografia_id',
'vpagina_inicial',
];
}
In controller:
public function actionView($id)
{
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
But this will work:
public function actionView($vcostumbre_id, $vbibliografia_id, $vpagina_inicial)
{
$id = [
'vcostumbre_id' => $vcostumbre_id,
'vbibliografia_id' => $vbibliografia_id,
'vpagina_inicial' => $vpagina_inicial,
];
return $this->render('view', [
'model' => $this->findModel($id),
]);
}
Because in the URL you have not the parameter "id".
It should be /mycontroller/view?id=42".
Check the view file where the link is. It should be :
Url::to(['/controller/view', 'id' => 42])