Laravel request remove fields before validation - laravel

I am trying to remove some fields before they are validated.
Trying to attempt this inside prepareForValidation()
use Illuminate\Foundation\Http\FormRequest;
class VideoRequest extends ApiRequest
{
// ..code..
protected function prepareForValidation()
{
$this->merge([
'public' => $this->toBoolean($this->public),
'notify' => $this->toBoolean($this->notify),
]);
$video_id = $this->route('video_id');
if($this->isMethod('put') && Video::salesStarted($video_id)){
Log::info('removing sales');
// attempt 1
$this->except(['sales_start', 'tickets', 'price']);
// attempt 2
$this->request->remove('sales_start');
// attempt 3
$this->offsetUnset('sales_start');
}
if($this->isMethod('put') && Video::streamStarted($video_id)){
Log::info('removing streams');
// attempt 1
$this->except(['stream_start', 'stream_count', 'archive']);
// attempt 2
$this->request->remove('sales_start');
// attempt 3
$this->offsetUnset('sales_start');
}
$thumb = $this->uploadThumbnail($video_id);
if($thumb !== null){
$this->merge($thumb);
}
}
// ..code..
}
I made sure the code was entering inside the if statement, however the fields are not being removed.
Running $this->request->remove() and $this->except() have no effect.
If I add safe() it throws Call to a member function safe() on null.
I also tried to use unset() but nothing seems to work.
The rules for the dates are like so:
'sales_start' => 'sometimes|required|date|after:now|before:stream_start',
'stream_start' => 'sometimes|required|date|after:now',
but the $request->validated() returns the errors although it shouldn't be validating the deleted fields.
"sales_start": [
"The sales start must be a date after now."
],
"stream_start": [
"The stream start must be a date after now."
]
Why are the fields not being deleted?
Edit
As requested I added some code.
This is what ApiRequest looks like:
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
abstract class ApiRequest extends FormRequest
{
protected function failedValidation(Validator $validator): void
{
$response['data'] = [];
$response['api_status'] = 'ng';
$response['status_message'] = 'failed validation';
$response['errors'] = $validator->errors()->toArray();
throw new HttpResponseException(
response()->json( $response, 422 )
);
}
protected function toBoolean($booleable)
{
return filter_var($booleable, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
}
}
And the request is called from the controller like so:
public function update(VideoRequest $request, $video_id)
{
... some code ...
$validated = $request->validated();
... some code ...
}
so $this refers to the VideoRequest that extends FormRequest.

Can't find anything about deleting. But acording to Laravel docs you pick what keys you need from a request as follows:
$request->only(['username', 'password']);
// plug everything you need into the array.
$request->except(['username', 'password']);
//plug everything you don't need into the array
The latter is probably most useful to you.
Example:
Say I have the following keys: ['username', 'password', 'randomVal'];
$request->only(['username', 'password']);
// Output:
['username', 'password']
$request->except(['username', 'password']);
// Output:
['randomVal']

To remove (unset) a key from a Request before it goes to the Controller you can use offsetUnset()
inside your request:
protected function prepareForValidation()
{
$this->offsetUnset('sales_start');//same goes for the other key to remove...
}

This is a bit of an ugly answer.
Instead of modifying the request before the validation, I tried adding exclude when getting rules().
So something along these lines:
public function rules() {
$ex = $this->isMethod('put') && Video::salesStarted($video_id) ? 'exclude|' : '';
return [
'sales_start' => $ex.'sometimes|required|other_stuff',
];
}
Note that the validation 'exclude' only works if added first.
So this won't work:
'sometimes|required|other_stuff|exclude' //exclude is called last
I am still unable to find out why remove(), exclude(), offsetUnset() were not working, so this is not the right answer, but I hope it helps if someone is having the same issue.
Edit
Setting this as correct answer as I was unable to find an alternative solution/fix.

Related

How to check data exists in the database

I have a function to add new property. But i want to check for duplicate data at column "code" before add new data into database. If data exists will appear a message error.
function addPro(Request $req)
{
$id = $req->type_id;
$type = AssetType::find($id);
if($req->save == 'save'){
$pro = new TypeProperties;
$pro->name = $req->name;
$pro->code = $req->code;
$pro->type = $req->type;
$pro->assettype_id = $req->type_id;
$pro->save();
Schema::table($type->code, function ($table) use ($pro) {
if ($pro->type == "textbox")
$table->string($pro->code )->nullable();
if ($pro->type == "textarea")
$table->text($pro->code )->nullable();
});
return redirect(url($type->id.'/add/property'))->with('message','Save successful');
}
return redirect(url('asset/type/'.$type->id));
}
You can use laravel Request Validation
function addPro(Request $req)
{
$id = $req->type_id;
$type = AssetType::find($id);
if($req->save == 'save'){
$req->validate([
'code' => 'required|unique:tablename'
]);
$pro = new TypeProperties;
$pro->name = $req->name;
$pro->code = $req->code;
$pro->type = $req->type;
$pro->assettype_id = $req->type_id;
$pro->save();
Schema::table($type->code, function ($table) use ($pro) {
if ($pro->type == "textbox")
$table->string($pro->code )->nullable();
if ($pro->type == "textarea")
$table->text($pro->code )->nullable();
});
return redirect(url($type->id.'/add/property'))->with('message','Save successful');
}
return redirect(url('asset/type/'.$type->id));
}
The most simple way to do this is by checking if code is_null :
if (is_null($pro->code)) {
// It does not exist
} else {
// It exists
}
The other way is to make a validation 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:
$this->validate($req, [
'code' => 'required|unique,
//... and so on
], $this->messages);
With this, you're validating users $req 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 = [
'code.required' => 'Code is required',
'code.unique' => 'Code already exists',
//... and so on
];
You can also achieve this by creating a new custom validation class:
php artisan make:request StorePro
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 [
'code' => '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(StorePro $req)
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $req->validated();
}
If you have any additional question about this, feel free to ask. Source: Laravel official documentation.
What does your migration look like for AssetType?
I ask because you can do this in the schema with ->unique() added to the column on the creation or make a migration to add the constraint.
You can also check with something like this:
// Search database table for entry
$entry = AssetType::where('code', '=', $pro->code)->first();
// If not found
if ($entry === null) {
// Save method here.
}
Otherwise, you can use the manual validator or create a Request with validation
References:
https://laravel.com/docs/5.8/queries#where-clauses
https://laravel.com/docs/5.8/validation#creating-form-requests
https://laravel.com/docs/5.8/validation#manually-creating-validators

How to Convert received data from Database to string in laravel?

So before everything this is not duplicate.
I've got a callback method which will get 2 parameters from payment getway. the function they gave us need Amount to make sure everything is correct and base on Amount they gonna gave us payment status, but they won't post it, i should get it from my Database which i've did base on this code :
public function order(Request $request){
$MerchantID = 'xxxxxxxxxxx';
$Authority =$request->get('Authority') ;
$Amount = Invoice::select('invoice_balance')->where('authority',$Authority)->get();
if ($request->get('Status') == 'OK') {
$client = new nusoap_client('https://www.localhost.com/pg/services/WebGate/wsdl', 'wsdl');
$client->soap_defencoding = 'UTF-8';
$result = $client->call('PaymentVerification', [
[
'MerchantID' => $MerchantID,
'Authority' => $Authority,
'Amount' => $Amount,
],
]);
if ($result['Status'] == 100) {
return 'Done.';
} else {
return 'Error with 1';
}
}
else
{
return 'Error with 2';
}
// return $Amount;
}
when i use this code i get The Response content must be a string or object implementing __toString(), "boolean" given. which i'm pretty sure it's just about Amount part, because when use manual value for Amount (exact amount of cart in $Amount = amount), it's gonna gave me The Response content must be a string or object implementing __toString(), "boolean" given. Error.
I've also tried someways in other questions but didn't worked. if u remove whole if(status... part and only return $Amount to make sure it work it gonna gave [{"invoice_balance":"2000"}] which i don't know if this is my mistake or not. please help me, i'm in learning process.
Invoice Model(if needed):
class Invoice extends Model {
protected $fillable = [
'from_user_id', 'to_user_id', 'invoice_title', 'invoice_description', 'invoice_balance', 'invoice_due_date', 'status'
];
protected $hidden = [
'authority'
];
public function user()
{
return $this->belongsTo(User::class);
}
}
well the solution was changing
$Amount = Invoice::select('invoice_balance')->where('authority',$Authority)->get();
to
$Amount = Invoice::select('invoice_balance')->where('authority',$Authority)->value('authority');
Need more information:
Do this and tell me what the output is:
public function order(Request $request){
dd($request->input());
}

Laravel 5.5 / Validator / Custom rules

(edited to clearer purpose)
I discovered Laravel some months ago and I followed some Laracast videos. Now, I'm stuck with a problem of custom Validator.
I've got normal and permanent rules (date | required | min / max) to verify my form request. This part works.
But I've got a custom validation which could be verified as a normal rule IF one of the request parameter - select1 - is set to 1 (for exemple).
I read a dozen of explanation but nothing clear enough.
So, let start with my code. Thank you for your indulgence...
My question is into the customTest function on the bottom.
Thank you,
1/ I made a new Request with
php artisan make:controller priceRequest.php
2/ I made some rules and changed some lines.
public function authorize()
{
return true;
}
// Permanent RULES
public function rules()
{
$rules = [
'field1' => 'required|min:1|max:15',
'field2' => 'required',
'date1' => 'required|date',
'select1' => 'required',
];
return $rules;
}
Then I integrated a new function to perform a custom verification
public function withValidator($validator) {
$validator->after(function ($validator) {
if (!$this->customTests($this->request->get('data'))){
$validator->errors()->add('custom', 'Something is wrong');
}
});
}
Finally, I wrote the customTests function and it is inside this one I'm stuck !!
public function customTests($data) {
if ($data['select1'] == 1) {
// HERE MY QUESTION
// I'd like to verify that $data['date2']
// is a date and is set. So, I'd like to
// add a rule to rules (has I made with
// 'date1' => 'required|date',
// and return TRUE if the rule match or
// FALSE
}
}
So, I found the solution to my problem.
I made a mistake and a confusion because I tried to add the new rule into the ->after() function.
So, the correct code is the following :
public function withValidator($validator)
{
$validator->sometimes('ticket.price', 'required|integer|min:0.1', function ($input) {
if ($any_condition_who_need_to_verify_new_rule) {
return true;
}
else {
# Everything is perfect, this rule cas be omitted
}
$validator->after(function ($validator) use ($ticket) {
/* New test more complicated which cannot be
tested with a rule */
if ($this_test_is_complex_and_fails) {
$validator->errors()->add('validateTicket', 'This is another problem');
return false;
}
});
return $validator;
}

Yii2 custom validation rule not working

I'm trying to write some custom validation for a model in yii2, but I can't figure out why the validation always is positive, although my validation function always adds an error.
for example the rules
public function rules()
{
return [
...
[['myattribute'], 'myvalidation'],
];
}
public function myvalidation($attribute, $params)
{
$this->addError($attribute, "error");
}
the validate() function still returns true. What's the problem?
In validation rule add skipOnError => false
[
['myattribute', 'myvalidation', 'skipOnError' => false],
]
Then
$model->validate(); // should return false;
What I will recommend you is watch this lesson on custom roles and
read docs on it. It's not the best video tutorial, but this guy made it work correctly.
In your case :
1.In [['myattribute'], 'myvalidation'], remove extra array from here, make your model rules and custom valdation function look like this
public function rules()
{
return [
...
['myattribute', 'myvalidation'],
];
}
public function myvalidation($attribute, $params)
{
$this->addError($attribute, "error");
}
it's not wrong, but it's used when you have more than one attribute.
2.Then go to your form and put `` to your ActiveForm so it will look like this
<?php $form = ActiveForm::begin(['enableAjaxValidation' => true]); ?>
I mean, your need to do it in case if you want to validate it without reloading (using ajax).
3.Also add this to your controller's action that is connected to your view
if(Yii::$app->request->isAjax && $model->load($_POST)) {
Yii::$app->response->format = 'json';
return \yii\widgets\ActiveForm::validate($model);
}
This will validate your input in the form via ajax, if it's not ajax, this will not work.
['reg_date','validateDate', 'skipOnEmpty' => false, 'skipOnError' => false]
add this to your rules
public function validateDate($attribute,$params,$validator)
{
$validator->addError($this,$attribute,"Bugungi sana bo'lishi kerak!");
}
check this in your controller side like this
if($model->validate()){
echo "validate works";
}

Route resources set before auth not working in Laravel 4

I added this in routes.php, expected it will check the authentication session for the page, however it is not working.
Route::resource('ticket', 'TicketController', array('before' => 'auth') );
Then I go to the controller, work in another way. It's work.
class TicketController extends BaseController {
public function __construct()
{
$this->beforeFilter('auth');
}
May I know where can get more documentation regarding the Route::resource(), what type of argument it able to accept?
OK... I found the answer.
in
\vendor\laravel\framework\src\Illuminate\Routing\Router.php
public function resource($resource, $controller, array $options = array())
{
// If the resource name contains a slash, we will assume the developer wishes to
// register these resource routes with a prefix so we will set that up out of
// the box so they don't have to mess with it. Otherwise, we will continue.
if (str_contains($resource, '/'))
{
$this->prefixedResource($resource, $controller, $options);
return;
}
// We need to extract the base resource from the resource name. Nested resources
// are supported in the framework, but we need to know what name to use for a
// place-holder on the route wildcards, which should be the base resources.
$base = $this->getBaseResource($resource);
$defaults = $this->resourceDefaults;
foreach ($this->getResourceMethods($defaults, $options) as $method)
{
$this->{'addResource'.ucfirst($method)}($resource, $base, $controller);
}
}
protected function getResourceMethods($defaults, $options)
{
if (isset($options['only']))
{
return array_intersect($defaults, $options['only']);
}
elseif (isset($options['except']))
{
return array_diff($defaults, $options['except']);
}
return $defaults;
}
as you can see, it only accept only and except arguement only.
If you want to archive the same result in route.php, it can be done as below
Route::group(array('before'=>'auth'), function() {
Route::resource('ticket', 'TicketController');
});

Resources