2017-11-06 21:17:17 -08:00
|
|
|
|
<?php
|
2021-06-10 13:15:52 -07:00
|
|
|
|
|
2017-11-06 21:17:17 -08:00
|
|
|
|
namespace App\Providers;
|
|
|
|
|
|
2024-02-13 17:35:37 -08:00
|
|
|
|
use App\Models\CustomField;
|
2022-11-09 13:11:33 -08:00
|
|
|
|
use App\Models\Department;
|
2023-11-15 10:50:40 -08:00
|
|
|
|
use App\Models\Setting;
|
2017-11-06 21:17:17 -08:00
|
|
|
|
use DB;
|
2024-02-13 17:35:37 -08:00
|
|
|
|
use Illuminate\Support\Facades\Log;
|
2019-03-13 20:12:03 -07:00
|
|
|
|
use Illuminate\Support\ServiceProvider;
|
2022-11-09 13:11:33 -08:00
|
|
|
|
use Illuminate\Validation\Rule;
|
2019-03-13 20:12:03 -07:00
|
|
|
|
use Validator;
|
2017-11-06 21:17:17 -08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This service provider handles a few custom validation rules.
|
|
|
|
|
*
|
|
|
|
|
* PHP version 5.5.9
|
|
|
|
|
* @version v3.0
|
|
|
|
|
*/
|
|
|
|
|
class ValidationServiceProvider extends ServiceProvider
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Custom email array validation
|
|
|
|
|
*
|
|
|
|
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
|
|
|
* @since [v3.0]
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function boot()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Email array validator
|
|
|
|
|
Validator::extend('email_array', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
$value = str_replace(' ', '', $value);
|
|
|
|
|
$array = explode(',', $value);
|
|
|
|
|
|
|
|
|
|
foreach ($array as $email) { //loop over values
|
2021-06-10 13:15:52 -07:00
|
|
|
|
$email_to_validate['alert_email'][] = $email;
|
2017-11-06 21:17:17 -08:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
$rules = ['alert_email.*'=>'email'];
|
|
|
|
|
$messages = [
|
|
|
|
|
'alert_email.*'=>trans('validation.email_array'),
|
|
|
|
|
];
|
2017-11-06 21:17:17 -08:00
|
|
|
|
|
|
|
|
|
$validator = Validator::make($email_to_validate, $rules, $messages);
|
|
|
|
|
|
|
|
|
|
return $validator->passes();
|
|
|
|
|
});
|
|
|
|
|
|
2023-11-21 04:36:11 -08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Unique only if undeleted.
|
|
|
|
|
*
|
|
|
|
|
* This works around the use case where multiple deleted items have the same unique attribute.
|
|
|
|
|
* (I think this is a bug in Laravel's validator?)
|
|
|
|
|
*
|
|
|
|
|
* $attribute is the FIELDNAME you're checking against
|
|
|
|
|
* $value is the VALUE of the item you're checking against the existing values in the fieldname
|
|
|
|
|
* $parameters[0] is the TABLE NAME you're querying
|
|
|
|
|
* $parameters[1] is the ID of the item you're querying - this makes it work on saving, checkout, etc,
|
|
|
|
|
* since it defaults to 0 if there is no item created yet (new item), but populates the ID if editing
|
|
|
|
|
*
|
|
|
|
|
* The UniqueUndeletedTrait prefills these parameters, so you can just use
|
|
|
|
|
* `unique_undeleted:table,fieldname` in your rules out of the box
|
|
|
|
|
*/
|
2017-11-06 21:17:17 -08:00
|
|
|
|
Validator::extend('unique_undeleted', function ($attribute, $value, $parameters, $validator) {
|
2023-11-21 05:47:49 -08:00
|
|
|
|
|
2017-11-06 21:17:17 -08:00
|
|
|
|
if (count($parameters)) {
|
2023-11-21 04:36:11 -08:00
|
|
|
|
|
|
|
|
|
// This is a bit of a shim, but serial doesn't have any other rules around it other than that it's nullable
|
|
|
|
|
if (($parameters[0]=='assets') && ($attribute == 'serial') && (Setting::getSettings()->unique_serial != '1')) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$count = DB::table($parameters[0])
|
|
|
|
|
->select('id')
|
|
|
|
|
->where($attribute, '=', $value)
|
|
|
|
|
->whereNull('deleted_at')
|
|
|
|
|
->where('id', '!=', $parameters[1])->count();
|
2021-06-10 13:15:52 -07:00
|
|
|
|
|
2017-11-06 21:17:17 -08:00
|
|
|
|
return $count < 1;
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-11-21 07:03:59 -08:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Unique if undeleted for two columns
|
|
|
|
|
*
|
|
|
|
|
* Same as unique_undeleted but taking the combination of two columns as unique constrain.
|
|
|
|
|
* This uses the Validator::replacer('two_column_unique_undeleted') below for nicer translations.
|
2023-11-21 07:36:11 -08:00
|
|
|
|
*
|
|
|
|
|
* $parameters[0] - the name of the first table we're looking at
|
|
|
|
|
* $parameters[1] - the ID (this will be 0 on new creations)
|
|
|
|
|
* $parameters[2] - the name of the second table we're looking at
|
|
|
|
|
* $parameters[3] - the value that the request is passing for the second table we're
|
|
|
|
|
* checking for uniqueness across
|
|
|
|
|
*
|
2023-11-21 07:03:59 -08:00
|
|
|
|
*/
|
2023-11-21 04:36:11 -08:00
|
|
|
|
Validator::extend('two_column_unique_undeleted', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
if (count($parameters)) {
|
|
|
|
|
$count = DB::table($parameters[0])
|
|
|
|
|
->select('id')->where($attribute, '=', $value)
|
|
|
|
|
->whereNull('deleted_at')
|
|
|
|
|
->where('id', '!=', $parameters[1])
|
|
|
|
|
->where($parameters[2], $parameters[3])->count();
|
2023-11-15 10:50:40 -08:00
|
|
|
|
|
|
|
|
|
return $count < 1;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2023-11-21 04:36:11 -08:00
|
|
|
|
|
2023-11-21 07:03:59 -08:00
|
|
|
|
/**
|
|
|
|
|
* This is the validator replace static method that allows us to pass the $parameters of the table names
|
|
|
|
|
* into the translation string in validation.two_column_unique_undeleted for two_column_unique_undeleted
|
|
|
|
|
* validation messages.
|
|
|
|
|
*
|
|
|
|
|
* This is invoked automatically by Validator::extend('two_column_unique_undeleted') above and
|
|
|
|
|
* produces a translation like: "The name value must be unique across categories and category type."
|
2023-11-21 07:36:11 -08:00
|
|
|
|
*
|
|
|
|
|
* The $parameters passed coincide with the ones the two_column_unique_undeleted custom validator above
|
|
|
|
|
* uses, so $parameter[0] is the first table and so $parameter[2] is the second table.
|
2023-11-21 07:03:59 -08:00
|
|
|
|
*/
|
|
|
|
|
Validator::replacer('two_column_unique_undeleted', function($message, $attribute, $rule, $parameters) {
|
|
|
|
|
$message = str_replace(':table1', $parameters[0], $message);
|
|
|
|
|
$message = str_replace(':table2', $parameters[2], $message);
|
|
|
|
|
|
|
|
|
|
// Change underscores to spaces for a friendlier display
|
|
|
|
|
$message = str_replace('_', ' ', $message);
|
|
|
|
|
return $message;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
2020-12-18 17:18:04 -08:00
|
|
|
|
// Prevent circular references
|
|
|
|
|
//
|
|
|
|
|
// Example usage in Location model where parent_id references another Location:
|
|
|
|
|
//
|
|
|
|
|
// protected $rules = array(
|
|
|
|
|
// 'parent_id' => 'non_circular:locations,id,10'
|
|
|
|
|
// );
|
|
|
|
|
//
|
|
|
|
|
Validator::extend('non_circular', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
if (count($parameters) < 2) {
|
|
|
|
|
throw new \Exception('Required validator parameters: <table>,<primary key>[,depth]');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Parameters from the rule implementation ($pk will likely be 'id')
|
|
|
|
|
$table = array_get($parameters, 0);
|
|
|
|
|
$pk = array_get($parameters, 1);
|
|
|
|
|
$depth = (int) array_get($parameters, 2, 50);
|
|
|
|
|
|
|
|
|
|
// Data from the edited model
|
|
|
|
|
$data = $validator->getData();
|
|
|
|
|
|
|
|
|
|
// The primary key value from the edited model
|
|
|
|
|
$data_pk = array_get($data, $pk);
|
|
|
|
|
$value_pk = $value;
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
// If we’re editing an existing model and there is a parent value set…
|
2020-12-18 17:18:04 -08:00
|
|
|
|
while ($data_pk && $value_pk) {
|
|
|
|
|
|
|
|
|
|
// It’s not valid for any parent id to be equal to the existing model’s id
|
|
|
|
|
if ($data_pk == $value_pk) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Avoid accidental infinite loops
|
|
|
|
|
if (--$depth < 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the next parent id
|
|
|
|
|
$value_pk = DB::table($table)->select($attribute)->where($pk, '=', $value_pk)->value($attribute);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
2017-11-06 21:17:17 -08:00
|
|
|
|
// Yo dawg. I heard you like validators.
|
|
|
|
|
// This validates the custom validator regex in custom fields.
|
|
|
|
|
// We're just checking that the regex won't throw an exception, not
|
|
|
|
|
// that it's actually correct for what the user intended.
|
|
|
|
|
|
|
|
|
|
Validator::extend('valid_regex', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
|
|
|
|
|
// Make sure it's not just an ANY format
|
2021-06-10 13:15:52 -07:00
|
|
|
|
if ($value != '') {
|
2017-11-06 21:17:17 -08:00
|
|
|
|
|
|
|
|
|
// Check that the string starts with regex:
|
2017-11-06 21:25:40 -08:00
|
|
|
|
if (strpos($value, 'regex:') === false) {
|
2017-11-06 21:17:17 -08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$test_string = 'My hovercraft is full of eels';
|
|
|
|
|
|
|
|
|
|
// We have to stip out the regex: part here to check with preg_match
|
2021-06-10 13:15:52 -07:00
|
|
|
|
$test_pattern = str_replace('regex:', '', $value);
|
2017-11-06 21:17:17 -08:00
|
|
|
|
|
|
|
|
|
try {
|
2017-11-06 21:26:30 -08:00
|
|
|
|
preg_match($test_pattern, $test_string);
|
2021-06-10 13:15:52 -07:00
|
|
|
|
|
2017-11-06 21:17:17 -08:00
|
|
|
|
return true;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
return true;
|
2017-11-06 21:17:17 -08:00
|
|
|
|
});
|
|
|
|
|
|
2020-11-02 20:03:26 -08:00
|
|
|
|
// This ONLY works for create/update user forms, since the Update Profile Password form doesn't
|
|
|
|
|
// include any of these additional validator fields
|
|
|
|
|
Validator::extend('disallow_same_pwd_as_user_fields', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
$data = $validator->getData();
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
if (array_key_exists('username', $data)) {
|
2020-11-02 20:03:26 -08:00
|
|
|
|
if ($data['username'] == $data['password']) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
if (array_key_exists('email', $data)) {
|
2020-11-02 20:03:26 -08:00
|
|
|
|
if ($data['email'] == $data['password']) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
if (array_key_exists('first_name', $data)) {
|
2020-11-02 20:03:26 -08:00
|
|
|
|
if ($data['first_name'] == $data['password']) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
if (array_key_exists('last_name', $data)) {
|
2020-11-02 20:03:26 -08:00
|
|
|
|
if ($data['last_name'] == $data['password']) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
return true;
|
2020-11-02 20:03:26 -08:00
|
|
|
|
});
|
|
|
|
|
|
2019-12-10 19:32:50 -08:00
|
|
|
|
Validator::extend('letters', function ($attribute, $value, $parameters) {
|
|
|
|
|
return preg_match('/\pL/', $value);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Validator::extend('numbers', function ($attribute, $value, $parameters) {
|
|
|
|
|
return preg_match('/\pN/', $value);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Validator::extend('case_diff', function ($attribute, $value, $parameters) {
|
|
|
|
|
return preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Validator::extend('symbols', function ($attribute, $value, $parameters) {
|
|
|
|
|
return preg_match('/\p{Z}|\p{S}|\p{P}/', $value);
|
|
|
|
|
});
|
|
|
|
|
|
2020-10-23 16:55:10 -07:00
|
|
|
|
Validator::extend('cant_manage_self', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
// $value is the actual *value* of the thing that's being validated
|
|
|
|
|
// $attribute is the name of the field that the validation is running on - probably manager_id in our case
|
|
|
|
|
// $parameters are the optional parameters - an array for everything, split on commas. But we don't take any params here.
|
|
|
|
|
// $validator gives us proper access to the rest of the actual data
|
|
|
|
|
$data = $validator->getData();
|
|
|
|
|
|
2021-06-10 13:15:52 -07:00
|
|
|
|
if (array_key_exists('id', $data)) {
|
2020-10-23 16:55:10 -07:00
|
|
|
|
if ($value && $value == $data['id']) {
|
|
|
|
|
// if you definitely have an ID - you're saving an existing user - and your ID matches your manager's ID - fail.
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// no 'id' key to compare against (probably because this is a new user)
|
|
|
|
|
// so it automatically passes this validation
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-11-09 13:11:33 -08:00
|
|
|
|
|
|
|
|
|
Validator::extend('is_unique_department', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
$data = $validator->getData();
|
2023-01-03 14:45:23 -08:00
|
|
|
|
if ((array_key_exists('location_id', $data) && $data['location_id'] != null) && (array_key_exists('company_id', $data) && $data['company_id'] != null)) {
|
2022-11-09 13:11:33 -08:00
|
|
|
|
$count = Department::where('name', $data['name'])
|
|
|
|
|
->where('location_id', $data['location_id'])
|
|
|
|
|
->where('company_id', $data['company_id'])
|
|
|
|
|
->whereNotNull('company_id')
|
|
|
|
|
->whereNotNull('location_id')
|
|
|
|
|
->count('name');
|
|
|
|
|
|
|
|
|
|
return $count < 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-10-18 10:41:24 -07:00
|
|
|
|
|
|
|
|
|
Validator::extend('not_array', function ($attribute, $value, $parameters, $validator) {
|
|
|
|
|
return !is_array($value);
|
|
|
|
|
});
|
2024-02-13 17:35:37 -08:00
|
|
|
|
|
2024-02-14 00:12:31 -08:00
|
|
|
|
// This is only used in Models/CustomFieldset.php - it does automatic validation for checkboxes by making sure
|
|
|
|
|
// that the submitted values actually exist in the options.
|
2024-02-13 17:35:37 -08:00
|
|
|
|
Validator::extend('checkboxes', function ($attribute, $value, $parameters, $validator){
|
2024-02-13 22:52:50 -08:00
|
|
|
|
$options = CustomField::where('db_column', $attribute)->first()->formatFieldValuesAsArray();
|
2024-02-14 00:12:31 -08:00
|
|
|
|
if(is_array($value)) {
|
|
|
|
|
$invalid = array_diff($value, $options);
|
|
|
|
|
if(count($invalid) > 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-02-13 22:52:50 -08:00
|
|
|
|
// for legacy, allows users to submit a comma separated string of options
|
2024-02-14 00:12:31 -08:00
|
|
|
|
elseif(!is_array($value)) {
|
2024-02-13 17:35:37 -08:00
|
|
|
|
$exploded = explode(',', $value);
|
2024-02-13 22:52:50 -08:00
|
|
|
|
$invalid = array_diff($exploded, $options);
|
|
|
|
|
if(count($invalid) > 0) {
|
|
|
|
|
return false;
|
2024-02-13 17:35:37 -08:00
|
|
|
|
}
|
2024-02-14 09:41:46 -08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
2024-02-13 17:35:37 -08:00
|
|
|
|
});
|
2017-11-06 21:17:17 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register any application services.
|
|
|
|
|
*
|
|
|
|
|
* @return void
|
|
|
|
|
*/
|
|
|
|
|
public function register()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
}
|