laravel change message bug variable names - php

I have two models, which are NextPage and MasterInformation. However, I have one view for them. That view has input fields. when the user submits the form, I need to validate the data.
I do that like this:
$dataMasterInformation = [
'container' => Input::get('container')
];
$dataNextPage = [
'xpath' => 'next_page_xpath',
'prefix' => 'next_page_prefix',
'suffix' => 'next_page_suffix'
];
$validationMasterInformation = Validator::make($dataMasterInformation, MasterInformation::$rules);
$validationNextPage = Validator::make($dataNextPage, NextPage::$rules);
if(($validationMasterInformation->passes()) && ($validationNextPage->passes())){}else{
return Redirect::back()->withInput()->withErrors($validationNextPage->messages()->merge($validationMasterInformation));
}
The rules of the NextPage model is:
public static $rules = array(
'xpath' =>'required'
);
The rules of the MasterInformation Model is:
public static $rules = array(
'container' => 'required'
);
My blade code for the view is:
<li>
{{Form::text('container', '', array('placeholder' => 'Container'))}}
<span>{{$errors->first('container')}}</span>
</li>
<li>
{{Form::text('next_page_xpath', '', array('placeholder' => 'Next Page Xpath'))}}
<span>{{$errors->first('next_page')}}</span>
</li>
<li>
{{Form::text('next_page_prefix', '', array('placeholder' => 'Next Page Prefix'))}}
<span>{{$errors->first('next_page_prefix')}}</span>
</li>
<li>
{{Form::text('next_page_suffix', '', array('placeholder' => 'Next Page Suffix'))}}
<span>{{$errors->first('next_page_suffix')}}</span>
</li>
<li>
<input type="submit" value="Save" />
</li>
My problem
The names in the rules are different from the names in the form. Thus, if there are errors with the entered data, I can discover them but I am not able to use them in the $errors->first() variable in the blade code.
How to solve that please?
I know that I could use the exact names, but, unfortunately, I couldn't because there would be conflicts in the names since the models share some same variable names.

i could be wrong, but if i remember correctly, the $errors is a MessageBag type, which means for each message, it actually has a key which might has something to do with the input name.
if you dd($errors), it might help, here's the doc for MessageBag, http://laravel.com/api/class-Illuminate.Support.MessageBag.html. What I used most is get(), and merge(), and has().

Related

Why the changes function does not return the changes?

652/5000
I am using in my project of Laravel 5 the package https://github.com/spatie/laravel-activitylog in its version 2.3. I have a page where I go through a list of activities and try to get the changes but it returns an empty array.
This is my Controller
public function history($id) {
$incidence = Incidence::find($id);
$activities = Activit::where('subject_id', $incidence->id)->get ();
return view('incidence.history', compact('activities'));
}
This is my html page
#foreach ($activities as $activity)
<p> {{ $activity->created_at }} </p>
<p> {{ $activity->changes() }} </p>
#endforeach
And this is the output in the browser
Clarify that I have done 4 update to the same record which I see reflected in the activity_log table of the database that uses the package. But I do not understand why the arrangement of the changes is not shown as indicated by the site's documentation:
Calling $ activity-> changes will return this array:
[
'attributes' => [
'name' => 'updated name',
'text' => 'Lorum',
],
'old' => [
'name' => 'original name',
'text' => 'Lorum',
],
];
Since it uses a database table I'm certain this has to do with the way Laravel allows methods to be chained. When you do $activity->changes() it expects you to continue the query. IE: $activity->changes()->where('etc', 1)->get() or something similar. So by calling $activity->changes() you are just sending a partial query to eloquent.

Select box validation (in laravel)

I have a form containing text inputs and select box. I was trying to apply laravel validation. Now i wanted to retain the user inputted values, if validation doesn't success.
I am able to get this done on input box, but not on select box. How to show previously selected value(in select box) if validation doesn't pass.
This is my code
{{Form::select('vehicles_year', $modelYears, '-1', ['id' => 'vehicles_year'])}}
<span class="help-block" id="vehicles_year_error">
#if ($errors->has('vehicles_year')) {{$errors->first('vehicles_year')}} #endif
</span>
-1 is the key of default value that i am showing when the form loads.
What I do is that I add "default" option which value is set to "nothing".
In validation rules I say this value is required. If user does not pick
one of the other options, validation fails.
$options = [
'value' => 'label',
'value' => 'label',
'value' => 'label',
'value' => 'label',
];
$options = array_merge(['' => 'please select'], $options);
{{ Form::select('vehicles_year', $options, Input::old('vehicles_year'), ['id' => 'vehicles_year']) }}
#if ($errors->has('vehicles_year'))
<span class="help-block" id="vehicles_year_error">
{{ $errors->first('vehicles_year') }}
</span>
#endif
// Validation rules somewhere...
$rules = [
...
'vehicles_year' => 'required|...',
...
];
The controller code is missing. I will suppose your handle the POST in a controller method and then you Redirect::back()->withInput();
Thanks to ->withInput() You can use in your view something like Input::old() to get the Input values of your previous request.
So to select your previous item AND have -1 by default, you can use Input::old('vehicles_year', -1)
The first argument is the Input name, and the second is the default value.
{{Form::select('vehicles_year', $modelYears, Input::old('vehicles_year', -1), ['id' => 'vehicles_year'])}}
Hope this helps

Laravel validation attributes "nice names"

I'm trying to use the validation attributes in "language > {language} > validation.php", to replace the :attribute name (input name) for a proper to read name (example: first_name > First name) . It seems very simple to use, but the validator doesn't show the "nice names".
I have this:
'attributes' => array(
'first_name' => 'voornaam'
, 'first name' => 'voornaam'
, 'firstname' => 'voornaam'
);
For showing the errors:
#if($errors->has())
<ul>
#foreach ($errors->all() as $error)
<li class="help-inline errorColor">{{ $error }}</li>
#endforeach
</ul>
#endif
And the validation in the controller:
$validation = Validator::make($input, $rules, $messages);
The $messages array:
$messages = array(
'required' => ':attribute is verplicht.'
, 'email' => ':attribute is geen geldig e-mail adres.'
, 'min' => ':attribute moet minimaal :min karakters bevatten.'
, 'numeric' => ':attribute mag alleen cijfers bevatten.'
, 'url' => ':attribute moet een valide url zijn.'
, 'unique' => ':attribute moet uniek zijn.'
, 'max' => ':attribute mag maximaal :max zijn.'
, 'mimes' => ':attribute moet een :mimes bestand zijn.'
, 'numeric' => ':attribute is geen geldig getal.'
, 'size' => ':attribute is te groot of bevat te veel karakters.'
);
Can someone tell me what i'm doing wrong. I want the :attribute name to be replaced by the "nice name" in the attributes array (language).
Thanks!
EDIT:
I noticed that the problem is I never set a default language for my Laravel projects. When I set the language to 'NL' the code above works. But, when I set my language, the language will appear in the url. And I prefer it doesn't.
So my next question: Is it possible to remove the language from the url, or set the default language so it just doesn't appear there?
Yeahh, the "nice name" attributes as you called it was a real "issue" a few month ago.
Hopefully this feature is now implemented and is very simply to use.
For simplicity i will split the two options to tackle this problem:
Global Probably the more widespread. This approach is very well explained here but basically you need to edit the application/language/XX/validation.php validation file where XX is the language you will use for the validation.
At the bottom you will see an attribute array; that will be your "nice name" attributes array. Following your example the final result will be something like this.
<!-- language: lang-php -->
'attributes' => array('first_name' => 'First Name')
Locally This is what Taylor Otwell was talking about in the issue when he says:
You may call setAttributeNames on a Validator instance now.
That's perfectly valid and if you check the source code you will see
<!-- language: lang-php -->
public function setAttributeNames(array $attributes)
{
$this->customAttributes = $attributes;
return $this;
}
**So, to use this way see the following straightforward example:**
<!-- language: lang-php -->
$niceNames = array(
'first_name' => 'First Name'
);
$validator = Validator::make(Input::all(), $rules);
$validator->setAttributeNames($niceNames);
Resources
There is a really awesome repo on Github that have a lot of languages packages ready to go. Definitely you should check it out.
The correct answer to this particular problem would be to go to your app/lang folder and edit the validation.php file at the bottom of the file there is an array called attributes:
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => array(
'username' => 'The name of the user',
'image_id' => 'The related image' // if it's a relation
),
So I believe this array was built to customise specifically these attribute names.
Since Laravel 5.2 you could...
public function validForm(\Illuminate\Http\Request $request)
{
$rules = [
'first_name' => 'max:130'
];
$niceNames = [
'first_name' => 'First Name'
];
$this->validate($request, $rules, [], $niceNames);
// correct validation
In the "attributes" array the key is the input name and the value is the string you want to show in the message.
An example if you have an input like this
<input id="first-name" name="first-name" type="text" value="">
The array (in the validation.php file) should be
'attributes' => array(
'first-name' => 'Voornaam'),
I tried the same thing and it works great. Hope this helps.
EDIT
Also I am noticing you don't pass a parameter to $errors->has() so maybe that's the problem.
To fix this check out in the controller if you have a code like this
return Redirect::route('page')->withErrors(array('register' => $validator));
then you have to pass to the has() method the "register" key (or whatever you are using) like this
#if($errors->has('register')
.... //code here
#endif
Another way to display error messages is the following one which I prefer (I use Twitter Bootstrap for the design but of course you can change those with your own design)
#if (isset($errors) and count($errors->all()) > 0)
<div class="alert alert-error">
<h4 class="alert-heading">Problem!</h4>
<ul>
#foreach ($errors->all('<li>:message</li>') as $message)
{{ $message }}
#endforeach
</ul>
</div>
In Laravel 4.1 the easy way to do this is go to the lang folder -> your language(default en) -> validation.php.
When you have this in your model, for example:
'group_id' => 'Integer|required',
'adult_id' => 'Integer|required',
And you do not want the error to be "please enter a group id", you can create "nice" validation messages by adding a custom array in validation.php.
So in our example, the custom array would look like this:
'custom' => array(
'adult_id' => array(
'required' => 'Please choose some parents!',
),
'group_id' => array(
'required' => 'Please choose a group or choose temp!',
),
),
This also works with multi-language apps, you just need to edit (create) the correct language validation file.
The default language is stored in the app/config/app.php configuration file, and is English by default.
This can be changed at any time using the App::setLocale method.
More info to both errors and languages can be found here validation and localization.
In Laravel 7.
use Illuminate\Support\Facades\Validator;
Then define niceNames
$niceNames = array(
'name' => 'Name',
);
And the last, just put $niceNames in fourth parameter, like this:
$validator = Validator::make($request->all(), $rules, $messages, $niceNames);
I use my custom language files as Input for the "nice names" like this:
$validator = Validator::make(Input::all(), $rules);
$customLanguageFile = strtolower(class_basename(get_class($this)));
// translate attributes
if(Lang::has($customLanguageFile)) {
$validator->setAttributeNames($customLanguageFile);
}
$customAttributes = [
'email' => 'email address',
];
$validator = Validator::make($input, $rules, $messages, $customAttributes);
The :attribute can only use the attribute name (first_name in your case), not nice names.
But you can define custom messages for each attribute+validation by definine messages like this:
$messages = array(
'first_name_required' => 'Please supply your first name',
'last_name_required' => 'Please supply your last name',
'email_required' => 'We need to know your e-mail address!',
'email_email' => 'Invalid e-mail address!',
);
Well, it's quite an old question but I few I should point that problem of having the language appearing at the URL can be solved by:
Changing the language and fallback_language at config/app.php;
or by setting \App::setLocale($lang)
If needed to persist it through session, I currently use the "AppServiceProvider" to do this, but, I think a middleware might be a better approach if changing the language by URL is needed, so, I do like this at my provider:
if(!Session::has('locale'))
{
$locale = MyLocaleService::whatLocaleShouldIUse();
Session::put('locale', $locale);
}
\App::setLocale(Session::get('locale'));
This way I handle the session and it don't stick at my url.
To clarify I'm currently using Laravel 5.1+ but shouldn't be a different behavior from 4.x;

Add class attribute to Form Errors

I´m developing an application using Zend Framework 2 and I use FormRow helper to render a label, the input and errors (if present) in a Form.
//within the view
echo $this->formRow($form->get('Name'));
When a user submits the form without filling the required input text field FormRow render´s it with the following error message:
<label>
<span>Name: </span>
<input class="input-error" type="text" value="" placeholder="Insert Name Here" name="Name">
</label>
<ul>
<li>Value is required and can't be empty</li>
</ul>
How can I set a class for the li tag to style it afterwards?
I know that I can echo the formElementErrors with the desired class attribute via..
<?php echo $this->formElementErrors($form->get("Name"), array('class' => "valuerequired", 'message' => "errortestmessage")); ?>
..but FormRow will still render the error message without the class.
Just for reference I´m setting the entity this way:
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
'name' => 'Name',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 100,
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
See the code of formElementErrors
Basically you could do something like:
$this->formElementErrors($elem)
->setMessageOpenFormat('<ul%s><li class="some-class">')
->setMessageSeparatorString('</li><li class="some-class">');
But that is quite unhandy...
The better solution would be to extend the Zend\Form\View\Helper\FormElementErrors by your own class and then register the view-helper formElementErrors to your class. So basically you'd have something like this:
namespace Mymodule\Form\View\Helper;
use Zend\Form\View\Helper\FormElementErrors as OriginalFormElementErrors;
class FormElementErrors extends OriginalFormElementErrors
{
protected $messageCloseString = '</li></ul>';
protected $messageOpenFormat = '<ul%s><li class="some-class">';
protected $messageSeparatorString = '</li><li class="some-class">';
}
Last thing then would be to register the view helper with this new Class. For this you provide the following code inside your Modules Module.php
public function getViewHelperConfig()
{
return array(
'invokables' => array(
'formelementerrors' => 'Mymodule\Form\View\Helper\FormElementErrors'
),
);
}
displaimer: This code isn't tested, let me know if there are some errors, but i think this should work out quite well.
Ok, the solution to my own problem was right in front of me, instead of using:
//within the view
echo $this->formRow($form->get('Name'));
I called each element of the form individually:
//within the view
echo $this->formLabel($form->get('Name'));
echo $this->formInput($form->get('Name'));
echo $this->formElementErrors($form->get("Name"), array('class' => "some_class", 'message' => "errormessage"));
Don´t know if it´s the most efficient way of doing it, plz drop a line if you think otherwise.
FormRow check if "form_element_errors" plugin registered. And if so use it as default to display error messages.
So Sam's example work. You should redefine standard plugin and inform mvc about it.
I'v done it in module.config.php
'view_helpers' => array(
'invokables' => array(
'formElementErrors'=> 'MyModule\View\Helper\FormElementErrors',
and FormRow start display errors as I wish :)
As your problem, please try
Change
//within the view
echo $this->formRow($form->get('Name'));
to
//within the view
echo $this->formRow($form->get('Name'),null,false);
// Note: add more 2 last parameters, false- for $renderErrors => will NOT render Errors Message.
//Look original function in helper/formrow.php: function __invoke(ElementInterface $element = null, $labelPosition = null, $renderErrors = null, $partial = null)
Render Errors Message as your funciton
echo $this->formElementErrors($form->get('name'), array('class' => 'your-class-here'));
From the documentation of ZF2. Here's the link: http://framework.zend.com/manual/2.0/en/modules/zend.form.view.helpers.html#formelementerrors
echo $this->formElementErrors($element, array('class' => 'help-inline'));
// <ul class="help-inline"><li>Value is required and can't be empty</li></ul>
I use echo $this->formElementErrors($form, array('class' => "error-messages")); to show all error messages in one place:
echo $this->formElementErrors($form, array('class' => "error-messages"));// Print all error messagess
echo $this->formLabel($form->get('Name'));
echo $this->formInput($form->get('Name'));
echo $this->formLabel($form->get('Name2'));
echo $this->formInput($form->get('Name2'));

Datamapper validation with form validation - Codeigniter

I'm using this datamapper http://datamapper.wanwizard.eu
problem is datamapper have validation methods similar with codeigniter form validation.but not as same.
An example, a model admins model validation array:
public $validation = array(
'username' => array(
'rules' => array('unique', 'required', 'trim', 'max_length' => 60, 'min_length' => 3),
'label' => 'User'
),
'password' => array(
'rules' => array('required', 'trim', 'encrypt', 'min_length' => 6),
'label' => 'Password'
)
);
but form validation array must be like that:
public $form_validation = array(
array(
'field' => 'username',
'label' => 'User',
'rules' => 'unique|required|trim|max_length[60]|min_length[3]'
),
array(
'field' => 'password',
'label' => 'Password',
'rules' => 'required|trim|encrypt|min_length[6]'
)
);
I don't want to make two manual validation for new admin adding (first form validation, after datamapper validation). I think there is a way to make this with just one manual validation.
sorry my bad English, I hope you understand. Thanks in advance.
Using the Datamapper's validation alone should be enough, without the CI's form library.
When you try to save the model, the save() method will return a true or false depending on if the save was successful. If it isn't the model's error property should be filled with the error messages generated for the validation that failed. The messages can be loaded from language files with keys named appropriately, also the codeigniter's form validation library's form_validaton_lang.php is loaded too.
In your controller you could make use of them like this:
Class TheController extends CI_Controller {
function save() {
// get the model object somehow
// ...
// update attributes
$model->prop0 = $this->input->post('prop0');
$model->prop1 = $this->input->post('prop1');
// try to save it
if ($model->save()) {
// save successful
redirect(...);
} else {
// save failed load form again, with the model
$this->load->view('path/to/the/form', array('model' => $model));
}
}
}
The view could work like this:
<form method="post" action="...">
<label>prop0</label>
<input type="text" name="prop0" value="<?php print $model->prop0?> ">
<?php if (!empty($model->error->prop0)):?>
<div class="error"><?php print $model->error->prop1; ?></div>
<?php endif; ?>
<label>prop1</label>
<input type="text" name="prop1" value="<?php print $model->prop1?> ">
<?php if (!empty($model->error->prop0)):?>
<div class="error"><?php print $model->error->prop1; ?></div>
<?php endif; ?>
<buton type="submit">go</button>
</form>
The same form can be used when no previous model exists in the database, just create an empty instance of the model you need, and pass it to the form.

Categories