CakePHP - Validation rule has syntax error I can't see - validation

I'm getting Parse error: syntax error, unexpected T_VARIABLE, expecting ')' on the line commented below. Can't for the life of me figure out why it's throwing this error.
public $validate = array(
'password1' => array(
'rule1' => array('rule' => 'alphaNumeric', 'message' => 'Your password should only contain alphanumeric characters.'),
'rule2' => array('rule' => '/\d/', 'message' => 'Your password must contain at least one numeric character.'),
'rule3' => array('rule' => '/^(?=.*?[A-Z])(?=.*?[a-z])/', 'message' => 'Your password must contain at least one uppercase and one lowercase letter.'),
'rule4' => array('rule' => array('minLength', 8), 'message' => 'Your password must be at least 8 characters long.'),
),
'password2' => array(
// ERROR ON LINE BELOW
'rule' => array('_passwordsMatch', $this->data['PasswordReset']['password2']),
'message' => 'The passwords you entered do not match.'
)
);
/**
* Custom validation method to check that the entered passwords match
*
* #param string $password1
* #param string $password2
* #return bool
*/
protected function _passwordsMatch($password1, $password2) {
return ($password1 === $password2);
}
As you can see I'm trying to make a custom validation rule to check the two passwords coming from the user's submitted form. Related question would be is this the wrong way to be trying to pass the other field value to the custom rule?

You are not allowed to reference $this during the initialization syntax of a class property. If you really need that, you must move the array definition to the class constructor.
Quoting the Documentation:
[Properties] are defined by using one of the keywords public, protected, or private, followed by a normal variable declaration. This declaration may include an initialization, but this initialization must be a constant value--that is, it must be able to be evaluated at compile time and must not depend on run-time information in order to be evaluated.
This rule is enforced at compile time, so there are grammar rules for static array() syntax that do not allow arbitrary expressions. This is why you get a syntax error: Instead of $this, the parser expects a ) that closes array(.

funny how this comes up this often right now
check out CakePHP validation rule to match field1 and field2 for a clean behavior approach on this subject (see my answer)
also note:
your alphanumeric rule is out of line in my opinion. you should never force a user to use less chars then he wants in a password field. many users use at least some special char and DONT use your upper or lower case style.
i think you are restricting the user more than needed.

Related

Laravel 5.5 form validation numeric/integer accepts non-digital characters like "+"

I want to validate the form data if it is just numeric/integer (as in just numbers). Based on Laravel's documentation there are two specific validators for that. But the problem I'm facing is that both the validators accept non-numeric characters such as "+" or "-".
numeric
The field under validation must have a numeric value.
integer
The field under validation must be numeric.
How can I make the validation to only accept numbers and not other non-numeric characters?
'main_telephone' => 'numeric',
'main_fax' => 'integer',
'direct_telephone' => 'integer',
'mobile' => 'integer',
Below is the screenshot
if anyone has come across this problem the best possible solution is to use regex. I do not know why I didn't think of this before.
'main_telephone' => 'integer|regex:/^[0-9]*$/',
'main_fax' => 'integer|regex:/^[0-9]*$/',
'direct_telephone' => 'integer|regex:/^[0-9]*$/',
'mobile' => 'integer|regex:/^[0-9]*$/',

How to have a CakePHP model field requirement checked manually?

QUESTION UPDATED: I found out more information and therefor changed my question.
I want to save my user with his license number, but only if he selects that he has a license. I have three possible values for the pilot_type field (ROC, ROC-light and recreative) and only the last option should allow for an empty string to be submitted.
In order to achieve this, I wrote the following validation function:
$validator
->add('license_nr', 'present_if_license', [
'rule' => function ($value, $context) {
return $context['data']['pilot_type'] == 'recreative' || !empty($value);
},
'message' => "If you don't fly recreatively, a license number needs to be supplied"
]);
The problem is that setting any validation rule on a field will trigger an additional check in the CakePHP Model class that will reject the value if it's empty. I tried to fix this by adding ->allowEmpty('license_nr'), but that rule makes for the model to accept an empty string without even running my custom function. Even putting them in order and using 'last' => true on my custom rule doesn't resolve this problem:
$validator
->add('license_nr', 'present_if_license', [
'rule' => function ($value, $context) {
return false;
// return $context['data']['pilot_type'] == 'recreative' || !empty($value);
},
'last' => true,
'message' => "If you don't fly recreatively, a license number needs to be supplied"
])
->allowEmpty('license_nr');
How do I make CakePHP run my custom function in order to see if the field can be empty, rather than just assuming that it can never be empty or must always be empty?
By default fields aren't allowed to be empty, so that's the expected behavior and you'll have to explicitly allow empty values.
In order to achieve what you're trying to do, instead of using an additional rule, you should customize the allowEmpty() rule, use the second argument to supply a callback (note that unlike rule callbacks it will receive a single argument that provides the context).
So you'd do something like this, which you may need to modify a bit, for example depending on whether you need it to work differently for creating ($context['newRecord'] = true) and updating ($context['newRecord'] = false) records:
->allowEmpty(
'license_nr',
function ($context) {
return $context['data']['pilot_type'] === 'recreative';
},
"If you don't fly recreatively, a license number needs to be supplied"
)
As of CakePHP 3.7 you can use allowEmptyString(), it will work the same way, you just need to swap the second and third arguments, as allowEmptyString() takes the message as the second argument, and the callback as the third argument.
See also
Cookbook > Validation > Conditional Validation

Validate a phone number in Laravel

How would I go about validating a number in laravel.
I need the number stored in the following format 353861111111.
353 will be the prefix, and the user types in the rest. If the user types in 086, this is invalid.
You can use regex as:
'phone' => 'required|regex:/(353)[0-9]{9}/'
This checks for the pattern with starting with 353 followed by 9 digits having values from 0-9.
Or you can build a custom validator in boot method of AppServiceProvider.php:
Validator::extend('phone_number', function($attribute, $value, $parameters)
{
return substr($value, 0, 3) == '353';
});
This will allow you to use the phone_number validation rule anywhere in your application, so your form validation could be:
'phone' => 'required|numeric|phone_number|size:11'
In your validator extension you could also check if the $value is numeric and 11 characters long.
Here is how I did it on an older Laravel 4 project we have to update from time to time:
'phone' => 'required|regex:/^\d{3}-\d{3}-\d{4}$/',
Try this regex expression:
'number' => 'required|regex:^[3][5][3][\d]{8}[\d]$'

Laravel validation rule `confirmed` message show on wrong field

For example you have 2 inputs: password and password_confirmed.
model
$rule = array (
'password' => 'min:4|confirmed',
'password_confirmed' => 'min:4',
);
If the user inputs the wrong password in the password_confirmed input, the validator sends the message to password so that the error message gets displayed with the password errors and not the password_confirmation errors.
How do I make the confirmation error go to the password_confirmation messages?
Well, this may not be a direct answer to your question, but will still give desired result.
Look into custom messages for your validation:
$messages = [
'password.confirmed' => 'Your passwords were mismatched',
'password_confirmation.min' => 'Your password must be at least 4 characters'
];
You should be able to get the desired message for any of your fields by utilizing this feature. Unless I am misunderstanding your issue?

First Or Create

I know using:
User::firstOrCreate(array('name' => $input['name'], 'email' => $input['email'], 'password' => $input['password']));
Checks whether the user exists first, if not it creates it, but how does it check? Does it check on all the params provided or is there a way to specifiy a specific param, e.g. can I just check that the email address exists, and not the name - as two users may have the same name but their email address needs to be unique.
firstOrCreate() checks for all the arguments to be present before it finds a match. If not all arguments match, then a new instance of the model will be created.
If you only want to check on a specific field, then use firstOrCreate(['field_name' => 'value']) with only one item in the array. This will return the first item that matches, or create a new one if not matches are found.
The difference between firstOrCreate() and firstOrNew():
firstOrCreate() will automatically create a new entry in the database if there is not match found. Otherwise it will give you the matched item.
firstOrNew() will give you a new model instance to work with if not match was found, but will only be saved to the database when you explicitly do so (calling save() on the model). Otherwise it will give you the matched item.
Choosing between one or the other depends on what you want to do. If you want to modify the model instance before it is saved for the first time (e.g. setting a name or some mandatory field), you should use firstOrNew(). If you can just use the arguments to immediately create a new model instance in the database without modifying it, you can use firstOrCreate().
As of Laravel 5.3 it's possible to do this in one step with firstOrCreate using a second optional values parameter used only if a new record is created, and not for the initial search. It's explained in the documentation as follows:
The firstOrCreate method will attempt to locate a database record using the given column / value pairs. If the model cannot be found in the database, a record will be inserted with the attributes resulting from merging the first array argument with the optional second array argument.
Example
$user = User::firstOrCreate([
'email' => 'dummy#domain.example'
], [
'firstName' => 'Taylor',
'lastName' => 'Otwell'
]);
This returns the User for the specified email if found, otherwise creates and returns a new user with the combined array of email, firstName, and lastName.
This technique requires Mass Assignment to be set up, either using the fillable or guarded properties to dictate which fields may be passed into the create call.
For this example the following would work (as a property of the User class):
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['email', 'firstName', 'lastName'];
firstOrCreate() checks for all the arguments to be present before it finds a match.
If you only want to check on a specific field, then use firstOrCreate(['field_name' => 'value']) like:
$user = User::firstOrCreate([
'email' => 'abcd#gmail.com'
], [
'firstName' => 'abcd',
'lastName' => 'efgh',
'veristyName'=>'xyz',
]);
Then it checks only the email.
An update:
As of Laravel 5.3 doing this in a single step is possible; the firstOrCreate method now accepts an optional second array as an argument.
The first array argument is the array on which the fields/values are matched, and the second array is the additional fields to use in the creation of the model if no match is found via matching the fields/values in the first array:
See the Laravel API documentation
You can always check if in current instance the record is created with the help of
$user->wasRecentlyCreated
So basically you can
if($user->wasRecentlyCreated){
// do what you need to do here
}

Resources