Laravel Email validation rules fail only on live server. Possible causes? - laravel

I run a customer order input through a simple form validation.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CreateOrderWebstoreRequest extends FormRequest
{
/**
* 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()
{
// Use additional Address valudation rules if Order is not picked up
// dd('debugging halt',request());
$address_rules = [];
if (! request()->is_pickup) {
$address_rules = [
'street' => 'required|min:3|max:100',
'house_number' => 'required|numeric|max:100000',
'house_number_suffix' => 'nullable|max:10',
'postal_code' => 'required|max:10',
'town' => 'required|min:3|max:50',
'country' => 'required|min:2|max:2',
'region' => 'nullable|min:3|max:50',
'owner' => 'nullable|min:3|max:25',
];
}
return array_merge([
'first_name' => 'required|min:3|max:50',
'middle_name' => 'nullable|min:1|max:15',
'last_name' => 'required|min:3|max:50',
'company_name' => 'nullable|min:3|max:50',
'email_address' => 'required|email:rfc,dns|max:50',
'telephone_number' => 'nullable|min:10|max:25',
'description' => 'nullable|min:5|max:250',
], $address_rules);
}
public function messages()
{
return [
];
}
}
The weird thing this has been working without customer having errors for months. But in de last week or so we suddenly got multiple customers complaining that the validation of their email failed (the first 'rule' that triggers the 'email' response from validation.php
The problem is that testing this on a local host we can't reproduce this, only on the live server.
The host is a shared host, dedicated for Laravel apps, currently running Laravel 6.18.15 and PHP 7.4.16. Local is running running Laravel 6.18.10 and PHP 7.4.2 We had some problems before where the host failed to update PHP, but that doesn't seem to be the case here (if even possible)
The problem is that I don't really know how to fix this or even circumvent it. Changing the email validation to
'email' => 'required|regex:/(.+)#(.+)\.(.+)/i'
is giving me an 'IDN Conversion Failed' error.

Related

Laravel Requests Validation rules only if value is not null?

I've created a request for my update method called CandidateProfileUpdateRequest.php:
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'photo' => ['mimes:jpeg,png,jpg,gif,bmp', 'max:4096'],
'video_one' => ['mimes:mp4,mov,ogg,qt', 'max:30720'],
'video_two' => ['mimes:mp4,mov,ogg,qt', 'max:30720'],
'video_three' => ['mimes:mp4,mov,ogg,qt', 'max:30720'],
'resume' => ['mimes:doc,docx,pdf', 'max:4096'],
'job_title' => ['required'],
];
}
public function messages()
{
return [
'photo.max' => 'The photo may not be greater than 4MB.',
'video_one.max' => 'The video may not be greater than 30MB.',
'video_two.max' => 'The video may not be greater than 30MB.',
'video_three.max' => 'The video may not be greater than 30MB.',
'resume.max' => 'The resume may not be greater than 4MB.',
];
}
For these 4 fields that aren't required photo, video_one, video_two, video_three,
I only want to apply these rules, if a file is being uploaded in either of these form fields.
So for example if video_two is empty i.e. the User isn't uploading anything here, and clicks Update, it shouldn't return any rules for video_two. Is this possible?
Check out the sometimes rule.
In some situations, you may wish to run validation checks against a field only if that field is present in the data being validated. To quickly accomplish this, add the sometimes rule to your rule list:
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'photo' => ['mimes:jpeg,png,jpg,gif,bmp', 'max:4096'],
'video_one' => ['mimes:mp4,mov,ogg,qt', 'max:30720'],
'video_two' => ['sometimes', 'mimes:mp4,mov,ogg,qt', 'max:30720'],
// ^^^^^^^^^^^
'video_three' => ['mimes:mp4,mov,ogg,qt', 'max:30720'],
'resume' => ['mimes:doc,docx,pdf', 'max:4096'],
'job_title' => ['required'],
];
}
The sometimes rule didn't work. Thank you to lagbox, the nullable rule worked!

Laravel avoid duplicate entry from model

I'm building a Laravel API. I have a models called Reservations. I want to avoid that a user creates two reservations for the same product and time period.
I have the following:
$reservation = Reservation::firstOrCreate([
'listing_id' => $request->listing_id,
'user_id_from' => $request->user_id_from,
'start_date' => $request->start_date,
'end_date' => $request->end_date,
]);
Edit after comments:
I'm also using validation
$validator = Validator::make($request->all(), [
'listing_id' => 'required|exists:listings,id',
'user_id_from' => 'required|exists:users,id',
'start_date' => 'required|date_format:"Y-m-d"|after:today',
'end_date' => 'required|date_format:"Y-m-d"|after:start_date'
]);
if ($validator->fails()) {
return response()->json(['error' => 'Validation failed'], 403);
}
Validation is working properly.
End of Edit
In my model I have casted the start_date and end_date as dates.
class Reservation extends Model
{
protected $fillable = ['listing_id', 'start_date', 'end_date'];
protected $dates = [
'start_date',
'end_date'
];
....
....
Documentation says:
The firstOrCreate method will attempt to locate a database record
using the given column / value pairs
However I notice that I'm still able to insert entries with the same attributes.
Any idea what I'm doing wrong or suggestions to fix it?
Probably there's a better way than this, but you can create an static method on Reservation to do this, like:
public static function createWithRules($data) {
$exists = $this->where('product_id', $data['product_id'])->whereBetween(*date logic that i don't remember right now*)->first();
if(!$exists) {
* insert logic *
} else {
* product with date exists *
}
}
So you can call Reservation::createWithRules($data)
You can achieve this using Laravel's built in ValidateRequest class. The most simple use-case for this validation, is to call it directly in your store() method like this:
public function store(){
$this->validate($request, [
'listing_id' => 'required|unique,
'start_date' => 'required|unique,
//... and so on
], $this->messages);
$reservation = Reservation::firstOrCreate([
'listing_id' => $request->listing_id,
'user_id_from' => $request->user_id_from,
'start_date' => $request->start_date,
'end_date' => $request->end_date,
]);
}
With this, you're validating users $request with by saying that specified columns are required and that they need to be unique, in order for validation to pass.
In your controller, you can also create messages function to display error messages, if the condition isn't met.
private $messages = [
'listing_id.required' => 'Listing_id is required',
'title.unique' => 'Listing_id already exists',
//... and so on
];
You can also achieve this by creating a new custom validation class:
php artisan make:request StoreReservation
The generated class will be placed in the app/Http/Requests directory. Now, you can add a few validation rules to the rules method:
public function rules()
{
return [
'listing_id' => 'required|unique,
'start_date' => 'required|unique,
//... and so on
];
}
All you need to do now 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:
public function store(StoreReservation $request)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $request->validated();
}
If you have any additional question about this, feel free to ask. Source: Laravel official documentation.

Validating not all fields in form - Laravel

In laravel, I have created a form. At the moment, I am working on the validation of the input fields of this form. I ran into a problem when I tried to validate some input fields and others not. For example, mail should be validated but catering_name not (it isn't necessary to fill in this field, its an option)
I have tried all validation methods I could find. I keep getting the same error.
Method Illuminate\Validation\Validator::validatePhone does not exist.
I guess I am missing something.
I have tried:
Validator::make($request->...
$this->validate(request(), [ ...
$request->validate([ ...
Bellow, you will find all the data that should be inputted in the database.
If I remove the validation part, the data got inserted into the database. I think the problem lays with how I try to validate. Thanks for any help.
$this->validate(request(), [
'add_name' => 'required|min:3',
'add_mail' => 'required|email',
'name' => 'required|min:3',
'email' => 'required|email',
'telefone' => 'numeric|phone',
'gsm' => 'numeric|phone',
'event' => 'required|min:3',
'date_start' => 'required|date|after:tomorrow',
'date_end' => 'required|date|after_or_equal:event_date_start',
'location' => 'required|min:3',
'number' => 'required',
]);
$event = new Event;
$event->add_name = request('add_name');
$event->add_mail = request('add_mail');
$event->name = request('name');
$event->email = request('email');
$event->telefone = request('telefone');
$event->gsm = request('gsm');
$event->name = request('name');
$event->date_start = request('date_start');
$event->date_end = request('date_end');
$event->location = request('location');
$event->number = request('number');
$event->catering = request('catering');
$event->catering_name = request('catering_name');
$event->remarks = request('remarks');
$event->status = Event::STATUS_0;
$event->save();
Unfortunately phone is not one of the default validation. You can try something like:
[
'telefone' => 'required|regex:/(01)[0-9]{9}/',
]
You can see the available list of validations given by Laravel here.
There are a wide variety of more complex options depending on how important it is to you.
There are packages for easy plug and play like Laravel-Phone.
You can create your own custom validation using php artisan make:rule phone_number and then editing the new rule made:
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class PhoneNumber implements Rule
{
/**
* Determine if the validation rule passes.
*
* #param string $attribute
* #param mixed $value
* #return bool
*/
public function passes($attribute, $value)
{
// logic here, most likely some sort of regex.
}
/**
* Get the validation error message.
*
* #return string
*/
public function message()
{
return 'The :attribute must be a valid phone number.';
}
}

Laravel action when form validation generates error

I am working with a form request file like this:
ProjectCreateRequest.php
public function rules()
{
$project_name = $this->project_name;
$meta_activity = $this->meta_activity;
return [
'project_name' => 'required|max:255|unique:projects',
'customer_name' => 'required|max:255',
'otl_project_code' => 'sometimes|max:255|unique:projects,otl_project_code,NULL,id,meta_activity,'.$meta_activity,
'estimated_start_date' => 'date',
'estimated_end_date' => 'date',
'LoE_onshore' => 'numeric',
'LoE_nearshore' => 'numeric',
'LoE_offshore' => 'numeric',
'LoE_contractor' => 'numeric',
'revenue' => 'numeric',
'win_ratio' => 'integer'
];
}
There is the otl_project_code that must be unique with the meta_activity.
In case someone enters a pair of otl_project_code and meta_activity that already exists, it goes back to the create page with the error written below.
I would like to get instead that in the controller, I can catch this information, do something on the database then redirect to an update url.
Because I am working with a form validation request file, everything is entered in my controller like this:
public function postFormCreate(ProjectCreateRequest $request)
and I don't know how to catch this specific error in my controller to execute some actions with all the fields I submitted and not go back to the create page. Of course, this needs to happen only when there is the specific error I mentionned above.
Override the FormRequest response function in your ProjectCreateRequest:
/**
* Get the proper failed validation response for the request.
*
* #param array $errors
* #return \Symfony\Component\HttpFoundation\Response
*/
public function response(array $errors)
{
if ($this->expectsJson()) {
return new JsonResponse($errors, 422);
}
return $this->redirector->to($this->getRedirectUrl())
->withInput($this->except($this->dontFlash))
->withErrors($errors, $this->errorBag);
}
That's the public response on the FormRequest class so you can write your own logic to perform DB queries and redirect where needed.

Laravel Validation unique/exists with different database connection

In the documentation, I saw you could set a connection for the unique rule which is great. However, the exists doesn't seem to follow the same logic. Take this for example:
$rules = [
'username' => 'required|max:40|unique:user',
'name' => 'sometimes|required',
'email' => 'required|email|max:255|unique:int.user',
'password' => 'sometimes|required|confirmed|min:6',
'password_current' => 'sometimes|required'
];
The unique rule works GREAT in this instance. It uses my database connection called 'int' and calls the user table. HOWEVER, when the rules are reversed like so:
$rules['email'] = 'required|email|max:255|exists:int.user';
I got this error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'int.user'
doesn't exist (SQL: select count(*) as aggregate from int.user where
email = haleybuggs6#gmail.com)
It's trying to call an int.user table instead of using the int database connection.
Is there a reason exists doesn't act the same way as unique? Thanks.
instead of using connection name you can try with straight Database name which is defined in "int" connection. faced similar problem and these way worked for me. like
$rules['email'] = 'required|email|max:255|exists:DB_Name.user';
You can use
'email' => 'exists:mysql2.users|required'
Where mysql2 is second database settings array in the database.php file
Try it.
$rules = [
'username' => 'required|max:40|unique:connection_name.user',
'name' => 'sometimes|required',
'email' => 'required|email|max:255|unique:connection_name.user',
'password' => 'sometimes|required|confirmed|min:6',
'password_current' => 'sometimes|required'
];
Ultimately for Laravel 5.6.* you need to look at an existing instance of the model you are trying to validate, or specify ...
{db_connection_name}.{schema_name}.{table_name}
... to ensure that you are looking at the proper table.
Validation Example
validate it...
<?php
// for instance...
// maybe auth user is in a different db
// = so you cannot validate with your default db connection
$default_user = Auth::user();
// pass the instance in order to allow Validator to qualify the proper connection/name
\App\Validation\User::validate($_POST, $default_user);
User Validation class
<?php
namespace App\Validation;
class User extends Validator
{
/**
* #param \Illuminate\Database\Eloquent\Model|string $mixed
* #param string $default
* #return string
*/
public static function table($mixed,$default='default_connection.app_schema.users_table')
{
if($mixed instanceof \Illuminate\Database\Eloquent\Model){
$table = $mixed->getConnectionName().'.'.$mixed->getTable();
} else {
if (! empty($mixed)) {
$table = $mixed;
} else {
$table = $default;
}
}
return $table;
}
/**
* validation to create a new user
*
* #param array $data
* #param \App\User|string $mixed
* #return array
* #throws \Illuminate\Validation\ValidationException
*/
public static function validate(array $data, $mixed='default_connection.app_schema.users_table'){
return Validator::validate($data,[
'username' => 'required|max:40|unique:'.self::table($mixed),
'name' => 'sometimes|required',
'email' => 'required|email|max:255|unique:'.self::table($mixed),
'password' => 'sometimes|required|confirmed|min:6',
'password_current' => 'sometimes|required'
]);
}
}
$default_connection = 'db_name';
$rules = [
'username' => 'required|max:40|unique:{$default_connection}.user',
'name' => 'sometimes|required',
'email' => 'required|email|max:255|unique:int.user',
'password' => 'sometimes|required|confirmed|min:6',
'password_current' => 'sometimes|required'
];

Resources