(Laravel) How can I get validation errors from User model? - php

I'm trying to register a user in my application while keeping all business logic in the model and as little as possible in the controller. To accomplish this, I'm running user validation in the model's boot() method when the Class::creating() event fires. If the validation fails, I simply return false, cancelling the event. You can see this here:
public static function boot() {
parent::boot();
User::creating(function(){
$validator = new Services\Validators\RUser;
if (! $validator->passes()) return false;
});
}
The validator class you see is simply rules and it contains a getErrors() function.
My question is, how can I rewrite this so that I can retrieve the validator's errors for use in a conditional redirect later?
My controller postRegister() (the function called when clicking submit on form) looks like this:
public function postRegister() {
$user = new User(Input::all());
$user->save();
}
I know I'm not handling that in the controller correctly, so I would appreciate some advice with that as well.
Thanks.

You would set a 'protected $errors;' property on the User model, and then
User::creating(function(){
$validator = new Services\Validators\RUser;
if (! $validator->passes()) {
$this->errors = $validation->getErrors();
return false;
}
});

Not a direct answer to your question, but you should check out the Ardent package which is great for automatic model validation and has some other nice accompanying features. Internally it uses native Laravel validators so it's easy to use and will do just what you ask about. It really saves a lot of work (DRY) and I find it very useful.
https://github.com/laravelbook/ardent
The basics from the docs:
Ardent models use Laravel's built-in Validator class. Defining
validation rules for a model is simple and is typically done in your
model class as a static variable:
class User extends \LaravelBook\Ardent\Ardent {
public static $rules = array(
'name' => 'required|between:4,16',
'email' => 'required|email',
'password' => 'required|alpha_num|between:4,8|confirmed',
'password_confirmation' => 'required|alpha_num|between:4,8',
);
}
Ardent models validate themselves automatically when Ardent->save() is
called. You can also validate a model at any time using the
Ardent->validate() method.
$user = new User;
$user->name = 'John doe';
$user->email = 'john#doe.com';
$user->password = 'test';
$success = $user->save(); // returns false if model is invalid
When an Ardent model fails to validate, a
Illuminate\Support\MessageBag object is attached to the Ardent object
which contains validation failure messages.
Retrieve the validation errors message collection instance with
Ardent->errors() method or Ardent->validationErrors property.
Retrieve all validation errors with Ardent->errors()->all(). Retrieve
errors for a specific attribute using
Ardent->validationErrors->get('attribute').
So in the end you can do:
$user = new User;
$user->name = 'John doe';
$user->email = 'john#doe.com';
$user->password = 'test';
if(!$user->save())
{
print_r($user->errors()->all()); //or whatever else you wish to do on failure
}

I installed Laravel for the first time less than 12 hours ago, so i may be acting a little prematurely, but to my knowledge...
You have two main options, return the validator class, or store the errors in the User model. I'm currently working with the former, so i have a validate() method which returns the Validator class, which i then do the if($v->passes()) in my controller and can output errors in the controller via $v->messages().
Using your method, you will want to store your errors in the User object if you want to continue returning false on failure. So you could change:
if (! $validator->passes()) return false;
to
if (! $validator->passes()) {
$this->errors = $validator->messages();
return false;
}
and in your controller do:
if(isset($user->errors)) {
//loop and print errors from validator
}
N.B: just to reiterate, im a complete newbie to laravel so i may have gotten something completely wrong. But if i have, someone will correct me and we'll both have learned something :)

Related

Protecting some properties of an entity from modification

I have a Symfony 3 app that uses Doctrine ORM for Entity management. Currently, I am working on enabling CRUD support. I've already found out that I can use security voters to restrict access to entities or controllers. For example, I configured it the way that only admins can create, update or delete entities of type A.
For instances of my entity type B I also want to give the respective owner the power to update (not create or delete), which I managed to do easily. However, an owner shouldn't be allowed to modify all of the entity's properties - just some of them. How can I realize this with Symfony? Also, I am using the Form Bundle to create and validate forms.
EDIT: I added some related code. The controller invokes denyAccessUnlessGranted, which triggers the voter. Just to clarify, that code works fine already. My question is related to code I don't yet have.
Controller:
public function editAction(Request $request, int $id) {
$em = $this->getDoctrine()->getManager();
$project = $em->getRepository(Project::class)->findOneBy(['id'=>$id]);
$this->denyAccessUnlessGranted(ProjectVoter::EDIT, $project);
$users = $em->getRepository(EntityUser::class)->findAll();
$groups = $em->getRepository(Group::class)->findAll();
$tags = $em->getRepository(Tag::class)->findAll();
$form = $this->createForm(ProjectType::class, $project, [
'possibleAdmins' => $users,
'possibleRequiredGroups' => $groups,
'possibleTags' => $tags,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$project = $form->getData();
$em->flush();
return $this->redirectToRoute('projects_show', ['id'=>$project->getId()]);
}
return $this->render('project/editor.html.twig',
['project'=>$project, 'form'=>$form->createView()]);
}
Voter:
protected function voteOnAttribute($attribute, $subject, TokenInterface $token) {
/** #var UserInterface $user */
$user = $token->getUser();
if (!$user instanceof UserInterface) {
// the user must be logged in; if not, deny access
return false;
}
else if ($this->decisionManager->decide($token, ['ROLE_ADMIN'])) {
return true; // system-wide admins shall always have access
}
switch($attribute) {
case self::SHOW:
return ($subject->isVisible() || $subject->getAdmins()->contains($user);
case self::EDIT:
return $subject->getAdmins()->contains($user);
case self::REMOVE:
return false;
}
return false;
}
As far as I know there is no access functionality specifically related to individual properties. Of course as soon as I post this, someone else will come by with exactly that.
What you might consider doing is to define two edit roles, EDIT_BY_ADMIN and EDIT_BY_OWNER. You could then test the condition and select which form type to use.
$projectTypeClass = null;
if ($this->isGranted(ProjectVoter::EDIT_BY_ADMIN,$project)) {
$projectTypeClass = ProjectAdminType::class);
}
elseif ($this->isGranted(ProjectVoter::EDIT_BY_OWNER,$project)) {
$projectTypeClass = ProjectOwnerType::class);
}
if (!$projectTypeClass) {
// throw access denied exception
}
$form = $this->createForm($projectTypeClass, $project, [
And that should do the trick. There are of course many variations. You could stick with one project type and do the access testing within the type class though that would require a form listener.
If you need more granularity then you could instead add some EDIT_PROP1, EDIT_PROP2 type roles.
And of course if you were really into it then you could move some of the access code into a database of some sort. Or maybe take a look at some of the Access Control List components out there.
I came up with this solution in the end:
Instead of having multiple FormTypes I stuck with only a single one and ended up enabling or disabling the property's form field based on the result of the voter. For that I defined a new switch case as Cerad suggested (named ProjectVoter::MODIFY_PROTECTED_PROPERTY in this answer for demonstration purposes) and added the business logic per my liking.
I just enabled or disabled the form field because I actually want the user to see that he/she can't edit that property. But it would likely easily be possible to not add the field in the first place as well, so it's not visible.
Form Type:
Info: $this->tokenStorage and $this->accessDecisionManager are injected services ("security.token_storage" and "security.access.decision_manager" respectively).
public function buildForm(FormBuilderInterface $builder, array $options) {
$token = $options['token'] ?? $this->tokenStorage->getToken();
$project = $builder->getData();
$builder
->add('name')
// ...
->add('protectedProperty', null, [
'disabled' => !$this->accessDecisionManager->decide($token, [ProjectVoter::MODIFY_PROTECTED_PROPERTY], $project),
])
;
}
I also added an option to the form type called token in its configureOptions function which defaults to null, so that the form can be built for an arbitrary user instead of the one currently logged-in, if required.

PHPunit for my UserController is not covering all lines

Symfony project PHPunit coverage test
UserController
public function userEdit($id, Request $request)
{
$user = $this->userRepository->findOneByCode($id);
if (!$user) {
throw new Exception("User not found!");
}
$userForm = $this->createForm(UserForm::class, $user);
$userForm->handleRequest($request);
if ($userForm->isSubmitted() && $userForm->isValid()) {
$this->userService->save($user);
return $this->redirectToRoute('user_list');
}
return $this->render(
'user/user.html.twig', [
'form' => $userForm->createView(),
]
);
}
TestUserController
public function testUserEdit()
{
$client = static::createClient();
$crawler = $client->request('GET', '/user/test/edit');
$formData = array(
'username' => 'test',
'email' => 'test#test.nl',
'roles' => 'ROLE_ADMIN'
);
$this->assertEquals(
200,
$client->getResponse()->getStatusCode()
);
$form = $this->factory->create(UserForm::class);
$object = User::fromArray($formData);
$form->submit($formData);
$this->assertTrue($form->isSynchronized());
$this->assertEquals($object, $form->getData());
$view = $form->createView();
$children = $view->children;
foreach (array_keys($formData) as $key) {
$this->assertArrayHasKey($key, $children);
}
}
In the userEdit method we have a if loop. But When we run PHPunit coverage test the if loop is not executed. The other if loop for submit is also not covered.
What goes wrong and what can I do in order to cover the test ? Also is this the best solution for Symfony form test since I am new to PHPunit.
I noticed a few things in your code that seem wrong:
The userEdit method name should be userEditAction.
Select the form like this:
$form = $crawler->selectButton('submit')->form();
That 'submit' text is the label on the submit button (e.g. Save).
And then, after filling the fields:
$crawler = $client->submit($form);
You check if the submit was successful by asserting that the resulting HTML page contains expected element (e.g.):
$this->assertGreaterThan(0, $crawler->filter('h1')->count());
Btw. put: $client->followRedirects(true); after instantiating the Client.
Examples are from the official docs.
Regarding the some lines that were not covered by test: whenever you have if clause, you need to test for both conditions. In your case, first you probably have a valid user, instance of User and the other case should be that you pass there an invalid user (null or whatever else). That is usually accomplished by using #dataProvider annotation and method. The data provider method supplies sets of data to the test method. There can be more than one set, so another set contains invalid data to cover the other outcome of the if() clause.
This blog has great examples.
To cover the content of the if-conditions you have to fulfill the conditions new tests. To enter the first if for example you have to write a test where you mock the userRepository and make findOneByCode return null. Then the following if-condition will be executed and throw an exception. Finally you test for a thrown exception in the test.
For the other if-condition you proceed in a similar manner. Write a new test which is designed to fulfill the condition and test the code inside it.

Laravel 5.4 - How to use multiple error messages for the same custom validation rule

In order to reuse code, I created my own validator rule in a file named ValidatorServiceProvider :
class ValidatorServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('checkEmailPresenceAndValidity', function ($attribute, $value, $parameters, $validator) {
$user = User::where('email', $value)->first();
// Email has not been found
if (! $user) {
return false;
}
// Email has not been validated
if (! $user->valid_email) {
return false;
}
return true;
});
}
public function register()
{
//
}
}
And I use this rule like this :
public function rules()
{
return [
'email' => 'bail|required|checkEmailPresenceAndValidity'
];
}
But, I want to set different error messages for each case, something like this :
if (! $user) {
$WHATEVER_INST->error_message = 'email not found';
return false;
}
if (! $user->valid_email) {
$WHATEVER_INST->error_message = 'invalid email';
return false;
}
But I don't figure out how to achieve this without doing 2 different rules ...
Of course it could work with multiple rules but it will also perform multiple SQL queries, and I really want to avoid that.
Also, keep in mind that in real case I could have more than 2 validations like theses in a single rule.
Does anyone have an idea ?
=====
EDIT 1 :
Actually, I think that I want something that works in a similar way to the between or size rules.
They represent one single rule, but provide multiple error messages :
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],
Laravel checks if the value represents a numeric, a file, a string or an array ; and gets the right error message to use.
How do we achieve this kind of thing with custom rule ?
Unfortunately Laravel doesn't currently provide a concrete way to add and call your validation rule directly from your attribute params array. But that does not exclude a potential and friendly solution based on Trait and Request usage.
Please find below my solution for example.
First thing is to wait for the form to be processed to handle the form request ourselves with an abstract class. What you need to do is to get the current Validator instance and prevent it from doing further validations if there's any relevant error. Otherwise, you'll store the validator instance and call your custom user validation rule function that you'll create later :
<?php
namespace App\Custom\Validation;
use \Illuminate\Foundation\Http\FormRequest;
abstract class MyCustomFormRequest extends FormRequest
{
/** #var \Illuminate\Support\Facades\Validator */
protected $v = null;
protected function getValidatorInstance()
{
return parent::getValidatorInstance()->after(function ($validator) {
if ($validator->errors()->all()) {
// Stop doing further validations
return;
}
$this->v = $validator;
$this->next();
});
}
/**
* Add custom post-validation rules
*/
protected function next()
{
}
}
The next step is to create your Trait which will provide the way to validate your inputs thanks to the current validator instance and handle the correct error message you want to display :
<?php
namespace App\Custom\Validation;
trait CustomUserValidations
{
protected function validateUserEmailValidity($emailField)
{
$email = $this->input($emailField);
$user = \App\User::where('email', $email)->first();
if (! $user) {
return $this->v->errors()->add($emailField, 'Email not found');
}
if (! $user->valid_email) {
return $this->v->errors()->add($emailField, 'Email not valid');
}
// MORE VALIDATION POSSIBLE HERE
// YOU CAN ADD AS MORE AS YOU WANT
// ...
}
}
Finally, do not forget to extend your MyCustomFormRequest. For example, after your php artisan make:request CreateUserRequest, here's the easy way to do so :
<?php
namespace App\Http\Requests;
use App\Custom\Validation\MyCustomFormRequest;
use App\Custom\Validation\CustomUserValidations;
class CreateUserRequest extends MyCustomFormRequest
{
use CustomUserValidations;
/**
* Add custom post-validation rules
*/
public function next()
{
$this->validateUserEmailValidity('email');
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'email' => 'bail|required|email|max:255|unique:users',
'password' => 'bail|required',
'name' => 'bail|required|max:255',
'first_name' => 'bail|required|max:255',
];
}
}
I hope that you'll find your way in what I suggest.
If you are using Laravel 8 and would like to display different error messages for a specific validation, follow the steps below.
I am going to create a validation rule that checks if a field is a valid email or a valid phone number. It will also return different error messages.
Make a custom validtion rule like
php artisan make:rule EmailOrPhone
Navigate to the created file in Rules Folder ie Root->App->Rules->EmailOrPhone.php
Paste the following code
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
class EmailOrPhone implements Rule
{
public $error_message;
public function __construct()
{
}
public function passes($attribute, $value)
{
$value = trim($value);
if (is_numeric($value)){
if (strlen($value) != 10){
$this->error_message = "Phone number must contain 10 digits";
return false;
}else if (!Str::startsWith($value, '0')){
$this->error_message = "Phone number must start with 0";
return false;
}else{
return true;
}
}else{
$validator = Validator::make(['email' => $value],[
'email' => 'required|email'
]);
if($validator->passes()){
return true;
}else{
$this->error_message = "Please provide a valid email address";
return false;
}
}
}
public function message()
{
return $this->error_message;
}
}
You can now use the custom validation in your validator like
return Validator::make($data, [
'firstname' => ['required', 'string', 'max:255'],
'lastname' => ['required', 'string', 'max:255'],
'email_phone' => ['required', 'string', 'max:255', new EmailOrPhone()],
'password' => ['required', 'string', 'confirmed'],
]);
Poor handling of custom validation rules is why I ditched laravel (well, it was one of many reasons, but it was the straw that broke the camel's back, so to speak). But anyway, I have a three part answer for you: a reason why you don't want to do this in this specific case, a quick general overview of the mess you have to deal with, and then the answer to your question in case you still want to do it.
Important security concern
Best security practices for managing logins dictate that you should always return one generic error message for login problems. The quintessential counter-example would be if you returned "That email is not registered with our system" for an email-not-found and "Wrong password" for a correct email with the wrong password. In the case where you give separate validation messages, you give potential attackers additional information about how to more effectively direct their attacks. As a result, all login-related issues should return a generic validation message, regardless of the underlying cause, something to the effect of "Invalid email/password combination". The same is true for password recovery forms, which often say something like, "Password recovery instructions have been sent to that email, if it is present in our system". Otherwise you give attackers (and others) a way to know what email addresses are registered with your system, and that can expose additional attack vectors. So in this particular case, one validation message is what you want.
The trouble with laravel
The issue you are running into is that laravel validators simply return true or false to denote whether or not the rule is met. Error messages are handled separately. You specifically cannot specify the validator error message from inside your validator logic. I know. It's ridiculous, and poorly planned. All you can do is return true or false. You don't have access to anything else to help you, so your pseudo code isn't going to do it.
The (ugly) answer
The simplest way to create your own validation messages is to create your own validator. That looks something like this (inside your controller):
$validator = Validator::make($input, $rules, $messages);
You would still have to create your validator on boot (your Valiator::Extend call. Then you can specify the $rules normally by passing them in to your custom validator. Finally, you can specify your messages. Something like this, overall (inside your controller):
public function login( Request $request )
{
$rules = [
'email' => 'bail|required|checkEmailPresenceAndValidity'
]
$messages = [
'checkEmailPresenceAndValidity' => 'Invalid email.',
];
$validator = Validator::make($request->all(), $rules, $messages);
}
(I don't remember if you have to specify each rule in your $messages array. I don't think so). Of course, even this isn't very awesome, because what you pass for $messages is simply an array of strings (and that is all it is allowed to be). As a result, you still can't have this error message easily change according to user input. This all happens before your validator runs too. Your goal is to have the validation message change depending on the validation results, however laravel forces you to build the messages first. As a result, to really do what you want to do, you have to adjust the actual flow of the system, which isn't very awesome.
A solution would be to have a method in your controller that calculates whether or not your custom validation rule is met. It would do this before you make your validator so that you can send an appropriate message to the validator you build. Then, when you create the validation rule, you can also bind it to the results of your validation calculator, so long as you move your rule definition inside of your controller. You just have to make sure and not accidentally call things out of order. You also have to keep in mind that this requires moving your validation logic outside of the validators, which is fairly hacky. Unfortunately, I'm 95% sure there really isn't any other way to do this.
I've got some example code below. It definitely has some draw backs: your rule is no longer global (it is defined in the controller), the validation logic moves out of the validator (which violates the principle of least astonishment), and you will have to come up with an in-object caching scheme (which isn't hard) to make sure you don't execute your query twice, since the validation logic is called twice. To reiterate, it is definitely hacky, but I'm fairly certain that this is the only way to do what you want to do with laravel. There might be better ways to organize this, but this should at least give you an idea of what you need to make happen.
<?php
namespace App\Http\Controllers;
use User;
use Validator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class LoginController extends Controller
{
public function __construct() {
Validator::extend('checkEmailPresenceAndValidity', function ($attribute, $value, $parameters, $validator) {
return $this->checkLogin( $value ) === true ? true : false;
});
}
public function checkLogin( $email ) {
$user = User::where('email', $email)->first();
// Email has not been found
if (! $user) {
return 'not found';
}
// Email has not been validated
if (! $user->valid_email) {
return 'invalid';
}
return true;
}
public function login( Request $request ) {
$rules = [
'email' => 'bail|required|checkEmailPresenceAndValidity'
]
$hasError = $this->checkLogin( $request->email );
if ( $hasError === 'not found' )
$message = "That email wasn't found";
elseif ( $hasError === 'invalid' )
$message = "That is an invalid email";
else
$message = "Something was wrong with your request";
$messages = [
'checkEmailPresenceAndValidity' => $message,
];
$validator = Validator::make($request->all(), $rules, $messages);
if ($validator->fails()) {
// do something and redirect/exit
}
// process successful form here
}
}
Also, it is worth a quick note that this implementation relies on $this support for closures, which (I believe) was added in PHP 5.4. If you are on an old version of PHP you'll have to provide $this to the closure with use.
Edit to rant
What it really boils down to is that the laravel validation system is designed to be very granular. Each validation rule is specifically only supposed to validate one thing. As a result, the validation message for a given validator should never have to be changed, hence why $messages (when you build your own validator) only accepts plain strings.
In general granularity is a good thing in application design, and something that proper implementation of SOLID principles strive for. However, this particular implementation drives me crazy. My general programming philosophy is that a good implementation should make the most common uses-cases very easy, and then get out of your way for the less-common use-cases. In this cases the architecture of laravel makes the most common use-cases easy but the less common use-cases almost impossible. I'm not okay with that trade off. My general impression of Laravel was that it works great as long as you need to do things the laravel way, but if you have to step out of the box for any reason it is going to actively make your life more difficult. In your case the best answer is to probably just step right back inside that box, i.e. make two validators even if it means making a redundant query. The actual impact on your application performance likely will not matter at all, but the hit you will take to your long-term maintainability to get laravel to behave the way you want it will be quite large.
Alternatively to the other proposals, I think you could also call Validator::replacer('yourRule', function()) in addition to Validator::extend('yourRule', function(...)) and keep track of what causes validation failures in the service provider class you're extending the validator from. This way, you are be able to completely replace the default error message with another one.
According to docs, replacer() is meant for making placeholder replacements in the error message before it is being returned, so while this is not strictly that case, it is close enough. Of course, it's kind of an ugly(ish) workaround, but it will probably work (at least it seems to work for me, at a first glance).
One thing to keep in mind though is that you'll probably have to keep track of these failure causes in an array if you want to avoid automatically returning same message for all fields that failed your custom validation rule.
Where have you found the error messages for the size validation?
I looked up the validation rules in the
Illuminate\Validation\ConcernsValidatesAttributes trait and all functions return a bool value (also the size validation).
protected function validateSize($attribute, $value, $parameters)
{
$this->requireParameterCount(1, $parameters, 'size');
return $this->getSize($attribute, $value) == $parameters[0];
}
What you have found belongs to this part:
$keys = ["{$attribute}.{$lowerRule}", $lowerRule];
In this case it's only for formatting the the output by setting a lowerRule value, that laravel handles in special cases, like the size validation:
// If the rule being validated is a "size" rule, we will need to gather the
// specific error message for the type of attribute being validated such
// as a number, file or string which all have different message types.
elseif (in_array($rule, $this->sizeRules)) {
return $this->getSizeMessage($attribute, $rule);
}
So as long as validation rules have to return a bool value there is no way to return more than one error message. Otherwise you have to rewrite some party of the validation rules.
An approach for your problem with the validation you could use the exists validation:
public function rules()
{
return [
'email' => ['bail', 'required', Rule::exists('users')->where(function($query) {
return $query->where('valid_email', 1);
})]
];
}
So you would need 2 exists validation rules. I would suggest to use the existing one from laravel to check if the email is set and a custom one to check if the account is validated.

Using a CustomRequest for Form Validation in Laravel 5.1 fails?

I've created a custom Request called CustomerRequest that I want to use to validate the form fields when a new customer is created. I cannot get it to work, it appears to be continuing into the store() method even when it should fail.
I have three required fields: givenname, surname, email
Here is my CustomerRequest:
public function rules()
{
return [
'givenname' => 'required|max:3',
'surname' => 'required',
'email' => 'required|unique:customers,email',
];
}
Here is my CustomerController:
use pams\Http\Requests\CustomerRequest;
-----------------------------------------
public function store(CustomerRequest $request, Customer $customer)
{
$request['created_by'] = Auth::user()->id;
$request['modified_by'] = Auth::user()->id;
$customer->create($request->all());
return redirect('customers');
}
When I submit the form using a givenname of "Vince" it should fail because it is greater than 3 characters long, but instead I get this error:
FatalErrorException in CustomerController.php line 52: Cannot use object of type pams\Http\Requests\CustomerRequest as array
Line 52 in the controller is $request['created_by'] = Auth::user()->id;
From what I understand, if the CustomerRequest fails then the user should be redirected back to the customers.create page and not run the code contained in the store() method.
I found the problem.
CustomerRequest had:
use Request;
instead of:
use pams\Http\Requests\Request;
Now the validation passes and fails as expected.
From docs, in Form Request Validation:
All you need to do is type-hint the request on your controller method.
The incoming form request is validated before the controller method is
called, meaning you do not need to clutter your controller with any
validation logic
Solution would be if you use it like so:
CustomerController.php
use Illuminate\Http\Request;
// ...
public function store(CustomerRequest $customerRequest, Customer $customer,Request $request)
{
$request['created_by'] = Auth::user()->id;
$request['modified_by'] = Auth::user()->id;
$customer->create($request->all());
return redirect('customers');
}
So what you want to know is that FormRequest -- which you are extending in your custom request validator CustomerRequest.php -- is a bit different than request that resides in Illuminate\Http namespace.
actually, you may find out why if you run (with your old code) dd($request['created_by'] = Auth::user()->id);. you should get the word forbidden or maybe! an exception telling that it'is not instantiable. (in my case I got forbidden because I've tested it on 5.2 right now).
$request is object, use it like following
use pams\Http\Requests\CustomerRequest;
-----------------------------------------
public function store(CustomerRequest $request, Customer $customer)
{
$inputs = $request->all();
$inputs['created_by'] = Auth::user()->id;
$inputs['modified_by'] = Auth::user()->id;
$customer->create($inputs);
return redirect('customers');
}

Trying to create custom validation in laravel 4

I'm trying to create a custom validation rule within laravel 4 and am struggling to get it to work or understand what I'm doing.
Currently - when I try to submit a form and validate it i get the following in my browser:
/**/
Which I'm taking as something is broken!
I have created a class in app/validators/customValidate.php
class CustomValidate extends Illuminate\Validation\Validator
{
public function uniqueMailchimp($attribute, $value, $parameters)
{
$mailchimp = MailchimpWrapper::lists()
->memberInfo(
'xxxxxxx',
array('emails'=>array(
'email'=>$value
)
));
//dd($$mailchimp['success_count']);
return ($mailchimp['success_count'] > 0 ? false : true );
}
I have run composer dump-autload
In my controller I am doing the following:
$rules = array(
'email' =>'email|uniqueMailchimp',
);
$messages = array(
'uniqueMailchimp'=>'The email provided has already been used.'
);
$validator = Validator::make($data, $rules, $messages);
}
I am then checking for a valid form with:
if($validator->passes()) {
# code
}
if validation fails the controller should redirect to the view:
return Redirect::route('members.create')
->withInput()
->withErrors($validator)
->with('errMessage', $message);
I've probably missed a step. I've seen posts about registering the rule in global.php but I'm not sure what I'm doing.
Any help appreciated
You are quite right - you need to register your rule with the validator. In any bootstrap-like file (a service provider is the best candidate if you have one, else app/start/global.php is good, and routes.php wouldn't be crazy either) you need the following code:
Validator::extend('foo', 'CustomValidate#uniqueMailchimp');
However, if you take a look at the docs you'll see that you don't need a whole class for this - you can just do it as a closure. A class is useful if you want the automatic IoC DI carried out for you though (although you don't appear to use that in your validator).

Categories