CakePHP 3 - how to patchEntities where form data is collected within a foreach - cakephp-3.0

My scenario is similar to this post here: CakePHP 3 - Form data format for patchEntities()
However, I am trying to update multiple entries that are represented within a foreach.
The Form looks like this:
<?= $this->Form->create(null, ['url' => ['controller' => 'Products', 'action' => 'index']]); ?>
<?php foreach ($products as $key => $product): ?>
<?= $this->Form->hidden("{$key}.id", ['value' => $product->id]); ?>
<?= $this->Form->control("{$key}.reduced_price", ['value' => $product->reduced_price]); ?>
<?= $this->Form->control("{$key}.price", ['value' => $product->price]); ?>
<?php endforeach; ?>
<?= $this->Form->end(); ?>
Output of $this->getRequest()->getData()
0 => array:3 [▼
"id" => "7319"
"reduced_price" => "987"
"price" => "200"
]
1 => array:3 [▼
"id" => "7318"
"reduced_price" => "875785"
"price" => "299.5"
]
Controller Action:
if ($this->getRequest()->is('post')) {
$products = $this->Products->find()->toArray();
$entities = $this->Products->patchEntities($products, $this->getRequest()->getData());
$this->Products->saveMany($entities);
}
If I follow ndm's advice then the entries would have to be updated, but they won't. But why?
Update:
If i use save() inside a foreach the records are being saved
$products = $this->Products->find()->toList();
$entities = $this->Products->patchEntities($products, $this->request->getData());
foreach ($entities as $entity) {
$this->Products->save($entity);
}
But why does saveMany not work for me?

Related

yii2 - two modal in one active form

I have 2 modals in one active form. Let's say first one is modal-ticket and second one is contract-ticket. First time, I click button to show modal-ticket, and it was fine, but when I click button to show modal-contract, it also call script modal-ticket or otherwise. why?
this is my code.
<?php $form = ActiveForm::begin(); ?>
<div id="BtnSearchTicket">
<?= Html::button('Search Ticket', [
'value' => Url::to('../ticket-timbangan/list'),
'class' => 'btn btn-primary',
'id' => 'BtnModalTicketList',
'data-toggle'=>"modal",
'data-target'=>"#modalTicketList",
]) ?>
</div>
<div id="BtnSearchContract">
<?= Html::button('Search Contract', [
'value' => Url::to('../contract/list'),
'class' => 'btn btn-primary',
'id' => 'BtnModalContractList',
'data-toggle'=>"modal",
'data-target'=>"#modalContractList",
]) ?>
</div>
<?php ActiveForm::end(); ?>
<?php
Modal::begin([
'header' => 'Ticket List',
'id' => 'modalTicketList',
'size' => 'modal-lg',
'class' => 'style=width:auto'
]);
echo "<div id='modalContentTicket'></div>";
Modal::end();
?>
<?php
Modal::begin([
'header' => 'Contract List',
'id' => 'modalContractList',
'size' => 'modal-lg',
'class' => 'style=width:auto'
]);
echo "<div id='modalContentContract'></div>";
Modal::end();
?>
<?php
$script = <<< JS
$('#BtnModalTicketList').click(function(e){
e.preventDefault();
$('#modalTicketList').modal('show')
.find('#modalContentTicket')
.load($(this).attr('value'));
return false;
});
$('#BtnModalContractList').click(function(e){
e.preventDefault();
$('#modalContractList').modal('show')
.find('#modalContentContract')
.load($(this).attr('value'));
return false;
});
JS;
$this->registerJs($script);
?>
this are the error found in console web browser
GET http://localhost/pks/web/ticket-timbangan/get-ticket?id=1 404 (Not Found)
GET http://localhost/pks/web/contract/get-contract?id=2 404 (Not Found)
please help.
Try This: using one modal on your form:
<?php $form = ActiveForm::begin(); ?>
<div id="BtnSearchTicket">
<?= Html::button('Search Ticket', [
'value' => Url::to('../ticket-timbangan/list'),
'class' => 'btn btn-primary showModal',
'id' => 'BtnModalTicketList',
'title' => 'Search Ticket',
]) ?>
</div>
<div id="BtnSearchContract">
<?= Html::button('Search Contract', [
'value' => Url::to('../contract/list'),
'class' => 'btn btn-primary showModal',
'title' => 'Search Contract',
'id' => 'BtnModalContractList',
]) ?>
</div>
<?php ActiveForm::end(); ?>
<?php
Modal::begin([
'headerOptions' => ['id' => 'modalHeader'],
'id' => 'modal',
'size' => 'modal-lg',
'closeButton' => [
'id'=>'close-button',
'class'=>'close',
'data-dismiss' =>'modal',
],
'class' => 'style=width:auto',
'clientOptions' => [
'backdrop' => false, 'keyboard' => true
]
]);
echo "<div id='modalContent'></div>";
Modal::end();
?>
<?php
$script = <<< JS
$(document).on('click', '.showModal', function(){
if ($('#modal').hasClass('in')) {
$('#modal').find('#modalContent')
.load($(this).attr('value'));
document.getElementById('modalHeader').innerHTML = '<h4>' + $(this).attr('title') + '</h4>';
} else {
$('#modal').modal('show')
.find('#modalContent')
.load($(this).attr('value'));
document.getElementById('modalHeader').innerHTML = '<h4>' + $(this).attr('title') + '</h4>';
}
});
JS;
$this->registerJs($script);
?>
From viewing your code what calls my attention is how you use the Url::to() function. Not sure why you use ../. I have fiddled with using more than one modal in a form and the code is similar to what your are doing. I suggest you try changing your Url::to() function as follows:
Url::to('/ticket-timbangan/list')
and
Url::to('/contract/list')
Another suggestion would be to try with
Yii::$app->urlManager->createUrl('/ticket-timbangan/list')
and
Yii::$app->urlManager->createUrl('/contract/list')
Let me know if this helps.
First, many thanks to kalu who has helped me 2 days to solve my problem. Two modals which contains grid need to define different classes to prevent execute previous script.
'value' => Url::to('../ticket-timbangan/list') and 'value' => Url::to('../contract/list'), both has two gridview and same select-row class. This class is root cause of the problem, because it's same class and execute both script.
Thanks Kalu, you save my day.

Yii2 get value from view file to controller

In controller file i print this,
in controller am getting NULL after printing.
how to the know if button is clicked ?
var_dump(\Yii::$app->request->post('submit'));
In view file
<?php $form = ActiveForm::begin([
'id' => 'button',
]); ?>
<?= Html::submitButton('submit', ['name' => 'submit', 'value' => 'submit_1', 'class' => 'btn']) ?>
<?php ActiveForm::end(); ?>

Kartik datepicker extention not working on array input form

I have a form field "dob[]" with array input like
<?php $form = ActiveForm::begin();
for($i=0;$i<= 3;$i++):
echo $form->field($model, 'dob[]')->widget(DatePicker::classname(), [
'options' => ['placeholder' => 'Date Of Birth'],
'type' => DatePicker::TYPE_INPUT,
'pluginOptions' => [
'format' => 'mm/dd/yyyy',
'autoclose' => true,
]
]);
endfor; ?>
<div class="form-group">
<?= Html::button('Submit', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>
Datepicker working only on first "dob" field but rest of the field having only button format of datepicker but calendar not working.
This is because the javascript cannot determine the correct input fields, after the first one. Take a look in your source code. All widgets have properly the same id and/or name. You have to setup a unique ID for each of the generated widgets.
By the way, it is always a good approach to name form data accordingly.
That is documented at the demo page.
The following should work:
<?php
$form = ActiveForm::begin();
for ($i=0; $i < 3; $i++) {
echo $form->field($model, 'date_end')->widget(DatePicker::classname(), [
'options' => [
'placeholder' => 'Date Of Birth',
'name' => 'DOB' .$i,
'id' => 'DOB-ID' . $i,
],
'type' => DatePicker::TYPE_INPUT,
'pluginOptions' => [
'format' => 'mm/dd/yyyy',
'autoclose' => true,
],
]);
}
?>
<div class="form-group">
<?= Html::button('Submit', ['class' => 'btn btn-success']) ?>
</div>
<?php ActiveForm::end(); ?>

Yii2=>ActiveForm=> add "has-error" (or "has-access") by default on page open

I have a simple form:
<?php $form = ActiveForm::begin([
'id' => 'answer-form',
'action' => Yii::$app->getUrlManager()->createUrl('test'),
'enableClientValidation' => false,
]); ?>
<?= $form->field($user_answer, 'user_text')->textInput(['value' => $text])->label('Text') ?>
<?php ActiveForm::end(); ?>
I want to show input with red color (div with class "has-error" by default)- like somebody added wrong data to the input. How can i do it?
Try this
<?= $form->field($user_answer, 'user_text', [ 'options' => [ 'class' => 'has-error'])->textInput(['value' => $text])->label('Text') ?>

Split ActiveForm fields into different tabs with Tabs widget

I'm creating a form view and I want to organize the form fields with tabs structure, using the official Tabs widget.
Is it possible init the Tabs widget with the id (or class) of the div elements that contains the active form fields?
One example of how you can manage it is doing like this:
First, divide your contact-form into one view-file for each tab.
Place the ActiveForm::begin() and ActiveForm::end() around the Tabs::widget()
Render the contact-form pages into content, with parameters $model and $form
Example code:
views/site/contact.php
<?php
/* #var $this yii\web\View */
$this->title = 'Contact';
use yii\bootstrap\Tabs;
use yii\bootstrap\ActiveForm;
?>
<?php $form = ActiveForm::begin(['id' => 'contact-form']); ?>
<?= Tabs::widget([
'items' => [
[
'label' => 'One',
'content' => $this->render('contact_form1', ['model' => $model, 'form' => $form]),
'active' => true
],
[
'label' => 'Two',
'content' => $this->render('contact_form2', ['model' => $model, 'form' => $form]),
],
]]);
?>
<?php ActiveForm::end(); ?>
views/site/contact_form1.php
<?= $form->field($model, 'name') ?>
<?= $form->field($model, 'email') ?>
<?= $form->field($model, 'subject') ?>
views/site/contact_form2.php
<?php
use yii\helpers\Html;
use yii\captcha\Captcha;
?>
<?= $form->field($model, 'body')->textArea(['rows' => 6]) ?>
<?= $form->field($model, 'verifyCode')->widget(Captcha::className(), [
'template' => '<div class="row"><div class="col-lg-3">{image}</div><div class="col-lg-6">{input}</div></div>',
]) ?>
<div class="form-group">
<?= Html::submitButton('Submit', ['class' => 'btn btn-primary', 'name' => 'contact-button']) ?>
</div>
Hope this helps!
Just add at the top of your contact.php global $form; and all works fine.
I have another solution:
When we call $form->field($model, 'name')->textInput(), it will return the model of class yii\widgets\ActiveField, so just continue calling a method of this class as $form->field($model, 'name')->textInput()->render(). It will return a string then you can use it for the tab's content.
I have an example code in my application for translating multi languages as the following code:
<?php
$items = [];
foreach ($translateModels as $translateModel) {
$tabContent = $form->field($translateModel, "[{$translateModel->code}]name")->textInput()->render();
$items[] = [
'label' => $translateModel->language->name,
'content' => $tabContent,
];
}
?>
<?= Tabs::widget([
'options' => [
'class' => 'nav-tabs',
'style' => 'margin-bottom: 15px',
],
'items' => $items,
]) ?>
Maybe it's help.