Laravel6 multi dimensional array validation - laravel-6

I am creating a recipe posting application with Laravel6.
I have implemented a mechanism to dynamically add an image submission form in JavaScript.
I set the validation in FormRequest, but the mandatory input validation for dynamically added form fields does not work.
blade
<input type="file" name="upload_image[cooking_image][]" class="howto-image" style="display:none" accept="image/*">
FormRequest
public function rules(Request $request)
{
return [
'upload_image.cooking_image.*' => 'required|image|mimes:jpeg,png,jpg',
];
}
But the following works.
FormRequest
public function rules(Request $request)
{
return [
'upload_image.cooking_image.0' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.1' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.2' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.3' => 'required|image|mimes:jpeg,png,jpg',
'upload_image.cooking_image.4' => 'required|image|mimes:jpeg,png,jpg',
];
}
I want to make mandatory input validation work for all dynamically added form input fields.

I think it sometimes not really possible to make it easily dynamic. Personally, in those case, I update my rules array on the fly.
I think this should help you : How to use required_if on file array fields with an array for first argument?
Good luck!

Related

How to use a single form to collect data for two or more models in Yii2?

My problem is to dynamically create forms through jquery.
The user should be able to dynamically generate inputs such that he can save multiple rows into the corresponding model/table in one go.
Now I don't know how do I generate the name attribute for the forms for multiple models. I suppose it should be something like ModelName[Property][] (but I would preferably want to do it in 'Yii way' instead of hardcoding the names)
To understand this better, Here I found a similar post in Yii Wiki.
using a single form to collect data for two or more models
How can this be modified for Yii2? So that the user should be able to fill in data for all the (dynamically generated) rows and submit them in one go.
Tutorial of tabular form for multiple models.
Try this, Reference
public function actionCreate()
{
$user = new User;
$profile = new Profile;
if ($user->load(Yii::$app->request->post()) && $profile->load(Yii::$app->request->post()) && Model::validateMultiple([$user, $profile])) {
$user->save(false); // skip validation as model is already validated
$profile->user_id = $user->id;
$profile->save(false);
return $this->redirect(['view', 'id' => $user->id]);
} else {
return $this->render('create', [
'user' => $user,
'profile' => $profile,
]);
}
}

Filter empty values in DetailView

Is there an easy way to force DetailView in Yii2 to ignore these fields in its attributes list, that for particular model are empty?
Or the only way is to define every attribute on attributes list with own function and filter empty fields inside it (sound like a little bit of madness)?
Edit: I thought, that this is pretty self-explanatory, but it turned out, it isn't. So, basically, I want to force DetailView to ignore (not render) rows for these elements of attributes list, that have empty (null, empty string) values in corresponding model and thus would result in rendering empty table cell:
You can define template parameter of DetailView widget as a callback function with following signature function ($attribute, $index, $widget) and this callback will be called for each attribute, so you can define desired rendering for your rows:
DetailView::widget([
'model' => $model,
'template' => function($attribute, $index, $widget){
//your code for rendering here. e.g.
if($attribute['value'])
{
return "<tr><th>{$attribute['label']}</th><td>{$attribute['value']}</td></tr>";
}
},
//other parameters
]);
Would something like this work better? It preserves some of the niceties like: updated_at:datetime, which with one of the solutions above will just show the underlying value, not a converted value.
<?= DetailView::widget([
'model' => $model,
'attributes' => [
'id',
[
'attribute' => 'my_attribute',
'visible' => !empty($model->my_attribute)
],
]
]);

Yii2 attributeLabels - wrap part of the label in a tag

Inside User model, I am using attributeLabels method to create text for the field:
public function attributeLabels()
{
return [
'terms' => 'I accept the Terms and Coditions'
];
}
And in the view I am using standard $form->field method to show the input field:
<?php $form->field($model, 'terms')->checkbox() ?>
I need to wrap Terms and Coditions inside a tag with a link. How can I do this?
The checkbox() method takes an options array where you can override the default label:
$form->field($model, 'terms')->checkbox([
'label' => 'I accept the Terms and Conditions'
]);
Detailed Checkbox Options are in the API Documentation at http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html#checkbox()-detail

Yii, custom filter is not working

My custom filter isn't working. Can anyone please correct me?
In my
public function actionAdmin($mid=null) {
// the appropriate codes here...
$date = ">= ".date("Y-m-d");
$this->render('admin', array(
'model' => $model,
'mid' => $mid,
'date'=>$date,
));
}
In my admin.php, I added this line in the appropriate field, in this case, dateEnd.
UPDATED
array(
'name'=>'dateEnd',
'htmlOptions'=>array('width'=>'150px'),
'filter'=>array('0'=>'', '1'=>$date),
),
Okay, so here's the problem. No matter what I click on, it's not filtering anything. I want it to filter either a blank space OR a date of today.
Can I please know what have I done wrong? Please feel free to correct me. Thanks!
You can't access passed variable inside cgridview. For this purpose, you can define a global variable inside your controller, and access it inside cgridview, something like this:
class Yourcontroller extends Controller {
public $date;
public function actionAdmin($mid=null) {
// the appropriate codes here...
$this->date = ">= ".date("Y-m-d");
$this->render('admin', array(
'model' => $model,
'mid' => $mid
));
}
}
Now, you can access date inside grid:
array(
'name'=>'dateEnd',
'htmlOptions'=>array('width'=>'150px'),
'filter'=>array('0'=>'', '1'=>$this->date),
),
Change this line :
'filter'=>array('0'=>'', '1'=>$date),
To this line:
'filter' => array(">= ".date("Y-m-d") => Yii::t('app', 'Still On Leave')),
Basically the first parameter is the real value, where as the second part is the View to be displayed.
In the First line, '1'=>$date means 1 value but to display a $date field on the CGridView's filter. It will take the value 1 to filter instead of the $date field.
Treat it like the Select element in HTML, where you have this line:
<select>
<option value="1">One</option>
<option value="2">Two</option>
</select>
Javascript basically takes the value instead of the word One being displayed.
This is the same explanation for it.

Creating Prestashop back-office module with settings page

I'm creating a back-office module for Prestashop and have figured out everything except the best way to display the admin page. Currently I'm using the renderView() method to display the content of view.tpl.
I would like to display a table with values and an option to add a new row. Should I just create it in the view.tpl or is there a better way? I've seen the renderForm() method but haven't figured out how it works yet.
The biggest question I have is, how do I submit content back to my controller into a specific method?
ModuleAdminController is meant for managing some kind of records, which are ObjectModels. Defauly page for this controller is a list, then you can edit each record individually or view it's full data (view).
If you want to have a settings page, the best way is to create a getContent() function for your module. Besides that HelperOptions is better than HelperForm for this module configuration page because it automatically laods values. Define the form in this function and above it add one if (Tools::isSubmit('submit'.$this->name)) - Submit button name, then save your values into configuration table. Configuration::set(...).
Of course it is possible to create some sort of settings page in AdminController, but its not meant for that. If you really want to: got to HookCore.php and find exec method. Then add error_log($hook_name) and you will all hooks that are executed when you open/save/close a page/form. Maybe you'll find your hook this way. Bettter way would be to inspect the parent class AdminControllerCore or even ControllerCore. They often have specific function ready to be overriden, where you should save your stuff. They are already a part of execution process, but empty.
Edit: You should take a look at other AdminController classes, they are wuite simple; You only need to define some properties in order for it to work:
public function __construct()
{
// Define associated model
$this->table = 'eqa_category';
$this->className = 'EQACategory';
// Add some record actions
$this->addRowAction('edit');
$this->addRowAction('delete');
// define list columns
$this->fields_list = array(
'id_eqa_category' => array(
'title' => $this->l('ID'),
'align' => 'center',
),
'title' => array(
'title' => $this->l('Title'),
),
);
// Define fields for edit form
$this->fields_form = array(
'input' => array(
array(
'name' => 'title',
'type' => 'text',
'label' => $this->l('Title'),
'desc' => $this->l('Category title.'),
'required' => true,
'lang' => true
),
'submit' => array(
'title' => $this->l('Save'),
)
);
// Call parent constructor
parent::__construct();
}
Other people like to move list and form definitions to actual functions which render them:
public function renderForm()
{
$this->fields_form = array(...);
return parent::renderForm();
}
You don't actually need to do anything else, the controller matches fields to your models, loads them, saves them etc.
Again, the best way to learn about these controller is to look at other AdminControllers.