I have tried showing an error message in a Controller and it doesn't work, but when I use dd, it works.
My Code:
if ($validation->fails())
{
/*Doesn't work
foreach ($validation->fails() as $messages) {
$messages // Doesn't work
}
*/
dd($validation->errors); //This works
}
I noticed none of the provided examples here actually work! So here you go. This was my found solution after realizing that validator->messages() returns a protected object which isn't retrievable.
if ($validator->fails())
{
foreach ($validator->messages()->getMessages() as $field_name => $messages)
{
var_dump($messages); // messages are retrieved (publicly)
}
}
I would reference MessageBag, which is what messages() returns. And for additional acknowledgement of the Validator class - reference this.
$validation->fails() returns a boolean of whether or not the input passed validation. You can access the validation messages from $validation->messages() or pass them to the view where they will be bound to the $errors variable.
See the validator docs.
This is what I have just used in an artisan 5.0 console command, to validate the arguments. This is in the fire() method:
// Create the validator.
$validator = Validator::make(
$this->argument(),
['field1' => 'required|other|rules']
);
// Validate the arguments.
if ($validator->fails())
{
// Failed validation.
// Each failed field will have one or more messages.
foreach($validator->messages()->getMessages() as $field_name => $messages) {
// Go through each message for this field.
foreach($messages AS $message) {
$this->error($field_name . ': ' . $message);
}
}
// Indicate the command has failed.
return 1;
}
This is an extension on the answer from #tfont
You may need to change where the message is sent ($this->error()) if this command is not being run as an console command, ie CLI, command-line.
Related
I have a Validation class and a failure method which takes 2 strings as parameters. My problem is that I have to go through all the ifs and finally put as parameters for this function, which fields have passed the validation and display the appropriate message. With the current code, unfortunately, it only displays a message for the last field that did not pass validation, and it should for all that did not pass. I will be grateful for your help.
class Validation
{
private function __construct(private array $fieldsAndMessages)
{
}
public static function failure(string $fieldName, string $message): Validation
{
return new self([$fieldName => $message]);
}
}
$field = '';
$message = '';
if ($request->settingsSubmit()) {
if ($request->wantsSubmitPhoto()) {
$extensionPhoto = new PhotoExtension($request->photo());
if (!in_array($extensionPhoto->getExtension(), ['jpg', 'png', 'jpeg'])) {
$field = 'photo';
$message = 'Invalid photo';
}
}
if ($request->wantsSubmitAvatar()) {
$extensionAvatar = new AvatarExtension($request->avatar());
if (!in_array($extensionAvatar->getExtension(), ['jpg', 'png', 'jpeg'])) {
$field .= 'avatar';
$message .= 'Invalid avatar';
}
return new SettingsView($userId, Validation::failure($field, $message));
UPDATE
as the OP has mentioned that he cannot modify the failure method (which should've done in the question itself), I will provide a potentially possible workaround.
The idea is to keep the Validation class as is without modifying it and instead you may have an array that will hold instances of the Validation class where each error found will create a new instance of Validation class.
/** this variable will hold all the potential errors where each error is an instance of Validation class */
$errors = [];
if ($request->settingsSubmit()) {
if ($request->wantsSubmitPhoto()) {
$extensionPhoto = new PhotoExtension($request->photo());
if (!in_array($extensionPhoto->getExtension(), ['jpg', 'png', 'jpeg']))
$errors[] = Validation::failure('photo', 'Invalid photo');
}
if ($request->wantsSubmitAvatar()) {
$extensionAvatar = new AvatarExtension($request->avatar());
if (!in_array($extensionAvatar->getExtension(), ['jpg', 'png', 'jpeg']))
$errors[] = Validation::failure('avatar', 'Invalid avatar');
}
}
/**
* pass the array ($errors) containing the errors to the SettingsView class.
* the "SettingsView" class should expect an array of `Validation` class as the second parameter.
*/
return new SettingsView($userId, $errors);
Original Answer
With your current implementation, you keep on overriding the $field and $message variables and you'll always have 0 or 1 error.
To allow having more than one error, you may tweak your Validation class' failure method and have it accept an array of error messages instead of a expecting a field and a message which will allow you to display all the found errors when your validation process fails.
The errors array that the failure method expects should have the following structure: the keys are the field name and the values are the actual messages (not required, I based that upon the usage of field names in your code and because you try to store the names of the fields having errors).
Here's an example of an error messages array that you may now pass to your method:
$errors = [
/** the keys are the fields | the values are the messages */
'photo' => 'Invalid photo',
'avatar' => 'Invalid avatar',
];
Your failure method could be refactored as the following to accept an array of error messages:
/** accepts an array of error messages where the keys act as the field names and the values as the actual error messages for the fields */
public static function failure(array $errors): self
{
/** pass the received array to the constructor */
return new self($errors);
}
An example of usage that is based on your validation flow could be as follows:
/** this variable will hold all the potential errors */
$errors = [];
if ($request->settingsSubmit()) {
if ($request->wantsSubmitPhoto()) {
$extensionPhoto = new PhotoExtension($request->photo());
if (!in_array($extensionPhoto->getExtension(), ['jpg', 'png', 'jpeg']))
$errors['photo'] = 'Invalid photo';
}
if ($request->wantsSubmitAvatar()) {
$extensionAvatar = new AvatarExtension($request->avatar());
if (!in_array($extensionAvatar->getExtension(), ['jpg', 'png', 'jpeg']))
$errors['avatar'] = 'Invalid avatar';
}
}
/** pass the array ($errors) containing the errors to the failure method */
return new SettingsView($userId, Validation::failure($errors));
Now your Validation class should have the errors in an array which you may later loop through those errors and display them for the user.
Disclaimer: The above code examples are not expected to work as is as they only meant to showcase the answer's idea and to demonstrate it. I recommend you take the idea from them and the above logic/explanations above and build upon. Also, that's one way of doing the things and it's definitely not the only possible way to get you on track.
I want to create a console command in Yii2 where I can take the input from the user.
I have looked into the Yii2 documentation here-
http://www.yiiframework.com/doc-2.0/guide-tutorial-console.html
But I could not find anything helpful.
I have also searched on Google and StackOverflow with no luck.
CLI command prompt for any user string:
class CronController extends yii\console\Controller
{
public function actionSendTestmail()
{
$emailTo = \yii\helpers\BaseConsole::input("Recipient email: ");
...
}
}
or just ask for confirmation [yes|no]:
class CronController extends yii\console\Controller
{
public function actionSendTestmail()
{
$emailTo = Yii::$app->params["email.to"];
if(!$this->confirm("Send email to {$emailTo}?")){
exit("Sending email interrupted.\n")
}
...
}
}
Check out yii\helpers\BaseConsole helper class method input().
input('Enter your name');
Will prompt you for your name.
Or you can define arguments for the action method to pass values to the action.
static function actionDoSomething (arg1, arg2, ...);
You can use the method prompt() provided in the yii\console\Controller that calls the yii\helpers\BaseConsole::prompt() and gives you additional control to validate the input too after the user enters or just mark it as required so that it is not empty
$code = $this->prompt(
'Enter 4-Chars-Pin',
[
'required' => true,
'validator' => function ($input, &$error) {
if (strlen($input) !== 4) {
$error = 'The Pin must be exactly 4 chars!';
return false;
}
return true;
},
]
);
I followed this short tutorial: http://blog.elenakolevska.com/laravel-alpha-validator-that-allows-spaces/.
Now my question is, how can i add errors to it? Because now i just get this as an error:
validation.alpha_spaces
I'm also curious on how to add numbers to the validator?
Thanks!
Edit:
If you don't want to open the link, this is basicly my code:
Validator::extend('alpha_spaces', function($attribute, $value) {
return preg_match('/^[\pL\s]+$/u', $value);
});
You need to pass a custom error message as well, for example:
Validator::extend('alpha_spaces', function($attribute, $value) {
// ...
});
Now prepare a message for this custom rule:
$messages = array('alpha_spaces' => 'Your custom error message for :attribute');
Use it like this (with $messages):
$validator = Validator::make($input, $rules, $messages);
Here :attribute will be replace with the form's field name.
To add a new validation to Laravel I have done this:
made a new file called customValidation.php in app/start/
and then included it in app/start/global.php and tested it with an echo() and it worked. So it is loaded into the application now.
Then I wrote the following code to validate checkboxes in Laravel:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
class customValidate extends Illuminate\Validation\Validator
{
public function validateCheckbox($attribute, $value, $parameters)
{
//if(isset($value)) { return true; } else { return true; }
echo "this is the: " . $value;
}
}
/**
* Resolvers for Custom Validations
*/
Validator::resolver(function($translator, $data, $rules, $message){
return new customValidate($translator, $data, $rules, $message);
});
However, in my validation rules, I define :
`array('sex'=>'checkbox')`
But it does not work. Nothing happens. No error is thrown. The application behaves as if it has not executed the function at all. Also when I echo something from within the function,nothing get echoed, another evidence for the function not being called at all.
I would create custom app/validators folder for this then.
1, Create app/validators/CustomValidate.php
<?php
class CustomValidate extends Illuminate\Validation\Validator
{
public function validateCheckbox($attribute, $value, $parameters)
{
echo "this is the: " . $value;
}
}
2, run php artisan optimize or composer dumpautoload
3, Somewhere register your custom validator. Perhaps add app/validators.php into start/global.php
Validator::resolver(function($translator, $data, $rules, $message){
return new CustomValidate($translator, $data, $rules, $message);
});
4, Validate
$rules = ['agreed' => 'checkbox'];
$data = ['agreed' => 0];
$v = Validator::make($data, $rules);
dd($v->passes());
When submitting the form, the radios were not set in their initial states, and this made Laravel not to look for the validator of the item. So, it doesn't have any workaround for that. What I did was I simply added an initial state to the radios and they worked.
Much Like said by Andreyco
I am developing an REST API using Codeigniter.
I need to have all error messages from Form validation in array format so that
I can easily respond in either JSON or XML.
Right now Codeigniter is delivering error messages with <p> as delimiters (see below)
but that is not good for a REST based API.
<p>There was an error with this item</p>
How can I get errors in an array?
Thankful for all input!
The form validation library stores errors in an array and loops through them to generate the error string. They are stored in a private variable called $_error_array. You could extend the library with a simple method that returns the error array.
class MY_Form_validation extends CI_Form_validation
{
function get_error_array()
{
return $this->_error_array;
}
}
I assume you are familiar with extending core CI libraries, but this extension of the form validation library will give you a method to return the errors as an array with the name attribute's value as the key and the message as the value. I tested it out on one of my projects and it worked fine.
You can transform it easily:
/**
* #param $errors string
* #return array
*/
function transformErrorsToArray ($errors) {
$errors = explode('</p>', $errors);
foreach ($errors as $index => $error) {
$error = str_replace('<p>', '', $error);
$error = trim($error);
// ... more cleaning up if necessary
$errors[$index] = $error
}
return $errors;
}