Client sends something like this:
foo.1.bar=hello
in my FormRequest class I have tried:
public function rules()
{
return [
'foo.1.bar' => 'string|nullable' // does not work
'foo' => 'array|nullable' // does not work
'foo' => [ // does not work
'1' => [
'bar' => 'string|nullable'
]
]
Any idea how to handle this?
Try getting the value of the parameter manually and then validating it:
class YourRequest extends FormRequest
{
public function rules(): array
{
return [...];
}
public function withValidator(Validator $validator): void
{
$value = $this->get('foo.1.bar') ?: $this->get('foo_1_bar');
$validator->after(function (Validator $validator) use ($value) {
if ($value == null) {
$validator->errors()->add('foo.1.bar', 'Error Message.');
$validator->errors()->add('foo_1_bar', 'Error Message.');
}
});
}
}
Related
Can I set a default value to a not-existing field in a FormRequest in Laravel?
For example, if a field called "timezone" does not exist in the incoming request, it get set to "America/Toronto".
Well I wrote a trait for this, which checks a function called 'defaults' exist in the form request it will replace the default values
trait RequestDefaultValuesTrait {
protected function prepareForValidation(){
// add default values
if( method_exists( $this, 'defaults' ) ) {
foreach ($this->defaults() as $key => $defaultValue) {
if (!$this->has($key)) $this->merge([$key => $defaultValue]);
}
}
}
}
the thing that you need to do is adding this trait to FormRequest class and then add a function like this:
protected function defaults()
{
return [
'country' => 'US',
'language' => 'en',
'timezone' => 'America/Toronto',
];
}
Being honest I don't link this method, but It works.
Try this
if(!$request->has('timezone') {
$request->merge(['timezone' =>'America/Toronto']);
}
I'm not so sure if you need to do it in this way, but if you want to:
class CreateUpdateDataFormRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
return [];
}
protected function getValidatorInstance()
{
$data = $this->all();
if(!isset($data['timezone'])) {
$data['timezone'] = 'America/Toronto';
$this->getInputSource()->replace($data);
}
// modify data before sending to validator
return parent::getValidatorInstance();
}
in request class add
public function prepareForValidation()
{
$this->mergeIfMissing([
'timezone' => 'America/Toronto'
]);
}
I'm using an Encryptable trait to encrypt my data for the a Room model.
RoomController (/rooms) returns the decrypted data but ApiRoomController (/api/rooms) does not.
How could I make it returns the decrypted data?
Encryptable Trait
trait Encryptable
{
public function getAttribute($key)
{
$value = parent::getAttribute($key);
if (in_array($key, $this->encryptable) && $value !== '' && $value !== null ) {
$value = Crypt::decrypt($value);
}
return $value;
}
public function setAttribute($key, $value)
{
if (in_array($key, $this->encryptable)) {
$value = Crypt::encrypt($value);
}
return parent::setAttribute($key, $value);
}
}
RoomController index function
public function index()
{
$rooms = Room::select('id', 'name')->get()->sortBy('name')->values()->all();
return view('rooms.index')->withRooms($rooms);
}
ApiRoomController index function
public function index()
{
$rooms = Room::select('id', 'name')->get()->sortBy('name')->values()->all();
return response()->json($rooms);
}
I found a way using API Resources:
php artisan make:resource Rooms --collection
Then in your app/Http/Resources/Rooms.php file:
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
// more fields here
];
}
Then in your ApiRoomController.php file:
use App\Http\Resources\Rooms;
public function index()
{
$rooms = Room::select('id', 'name')->get()->sortBy('name')->values()->all();
return Rooms::collection($rooms);
}
Seems like #emotality came up with a good solution for this already...
However, the reason for this not working as you expected is because the underlying Model's toArray() / toJson() methods do not call the getAttribute() method in your trait.
This is important because the response()->json() method maps the given collection and calls the toJson() method on each model in order to prepare it for a response.
Therefore, you can also solve this by overwriting the toArray method in your model.
class Room extends Model
{
use Encryptable;
public function toArray()
{
return [
'id' => $this->id,
'name' => $this->name,
// ...
];
}
}
What's wrong with this code ?
class DeleteDetail extends FormRequest {
public function authorize() {
return true;
}
public function rules() {
$request = Request::all();
$rules = [
'hobby' => [
'string',
'between:3,20',
Rule::exists('user_hobby')->where(function ($query) use ($request) {
$query->where('hobby', $request['hobby'])->where('user_id', Auth::user()->id);
}),
],
];
return Validator::make($request, $rules);
}
}
Error that I'm getting :
Argument 2 passed to Illuminate\Validation\Factory::make() must be of the type array, object given
You are returning the wrong value from inside the rules method itself, you should return the array containing your validation rules instead of Validation::make:
public function rules() {
...
return $rules;
}
Your rules function should return the array with the rules.
public function rules() {
$request = Request::all();
$rules = [
'hobby' => [
'string',
'between:3,20',
Rule::exists('user_hobby')->where(function ($query) use ($request) {
$query->where('hobby', $request['hobby'])->where('user_id', Auth::user()->id);
}),
],
];
return $rules;
}
Then in your controller:
public function store(DeleteDetail $request)
{
// the code in here has passed the validation..
}
i have a field that required, and can be 2 value type : String (path) and Image file
how can write validation rule for this ?
if value is string check file_exist and if is file must be image
thanks
Maybe there's an easier way to do this. However, I think a custom rule as such should work.
$validator = Validator::make($request->all(), [
'image' => [
'required',
function ($attribute, $value, $fail) {
if(is_file($value)) {
if (true !== mb_strpos($value->getMimeType(), "image")) {
return $fail($attribute.' is invalid.');
}
}
if (is_string($value)) {
if(! file_exists($value)) {
return $fail($attribute.' is invalid.');
}
}
},
],
]);
i found my answer with FormRequest
MyTestFormRequest
<?php
use Illuminate\Foundation\Http\FormRequest;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class MyTestFormRequest extends FormRequest
{
public function rules()
{
$rules = [
"image" => ['required']
];
if(is_string($this->image)) {
$rules['image'][] = new FileExistsRule;
} else if($this->image instanceof UploadedFile) {
$rules['image'][] = 'image';
$rules['image'][] = 'dimensions:ratio=1/1';
}
return $rules;
}
}
FileExistsRule
<?php
use Illuminate\Contracts\Validation\Rule;
class FileExistsRule implements Rule
{
public function passes($attribute, $value)
{
return file_exists(public_path($value));
}
public function message()
{
return 'The file not exists';
}
}
I have set of input fields to be validated. I have removed commas (since user enters comma as thousand separator) before validation takes place. But it still complains that the number is not numeric.
class UpdateFamilyExpense extends FormRequest
{
public function authorize()
{
return true;
}
public function sanitize()
{
$attributes = $this->all();
for ($i=1; $i<=15; $i++)
{
$attributes['e'.$i] = str_replace(',', '', $attributes['e'.$i]);
}
$this->replace($attributes);
}
public function rules()
{
$this->sanitize();
return [
'e1' => 'required|numeric',
];
}
public function messages()
{
return [
'e1.required' => 'required',
'e1.numeric' => 'must be a numeric',
];
}
}
I cannot figure out where I am wrong. Can someone help me figure out what I am missing here?
Override prepareForValidation as:
protected function prepareForValidation()
{
$this->sanitize();
}