I am trying to sanitize the user input in my application following this article
Below is my request
class TestRequest extends Request
{
public function authorize()
{
return true;
}
public function rules()
{
$this->sanitize();
return [
'title'=>'required|max:100'
];
}
public function sanitize()
{
$input = $this->all();
if(!empty($input))
{
$input['title'] = trim(strip_tags($input['title']));
$this->replace($input);
}
}
}
Tough the title is required field, if I try to put <h1></h1> as input in the title field, as per the logic in sanitize() function the tags are stripped away, but an empty string is saved in the database. The required field validation in the rules in not taking any effect.
How to handle this?
Update:
Below is the controller method for saving the request.
public function save(TestRequest $request)
{
$input = $request->all();
...
}
First option is to use merge() instead of replace() in your code, i.e.:
$this->merge( ['title' => trim(strip_tags($input['title']))] );
Second option is to override the all() function, i.e.:
public function all()
{
$input = parent::all();
if( !empty($input) )
{
$input['title'] = trim(strip_tags($input['title']));
}
return $input;
}
In the last code example you dont have to use the sanitize() function.
Related
My Controller File
public function enquiryExport($id, Request $request)
{
$id[] = $request->explode(",",$id);
return Excel::download(new EnquiryExport($id), 'enquiry.xlsx');
}
and My Export File
protected $id;
function __construct($id) {
$this->id = $id;
}
public function collection()
{
return Enquiry::whereIn('id',explode(",",$this->id))->get();
/* return Enquiry::all(); */
}
Route is like
Route::get('enquiryExport', 'enquiryController#enquiryExport');
Still I am getting this error
"message": "Too few arguments to function App\\Http\\Controllers\\enquiryController::enquiryExport(), 1 passed and exactly 2 expected",
I am checkbox id through AJAX here.
The problems is your Route method.
Get method: the query string (name/value pairs) is sent in the URL of a GET request
Post method: the data sent to the server with POST is stored in the request body of the HTTP request
If you use Get method: try this (I have just read it, not tried)
Route::get('enquiryExport/{id}', 'enquiryController#enquiryExport')->name('enquiryExport');
Submit
If you use Post method: try this (I am used to use this)
Route::post('enquiryExport', 'enquiryController#enquiryExport');
public function enquiryExport(Request $request)
{
return Excel::download(new EnquiryExport($request->input('id')), 'enquiry.xlsx');
}
You can read more here: https://www.w3schools.com/tags/ref_httpmethods.asp
Try this
In controller:
public function enquiryExport(Request $request, $id)
{
return Excel::download(new EnquiryExport($request->id), ''.date('Y-m-d'). '.xlsx', \Maatwebsite\Excel\Excel::XLSX);
}
In Export File:
protected $id;
function __construct($id) {
$this->id = $id;
}
public function collection()
{
return Enquiry::where('id', $this->id)->get();
}
public function map($enquiry): array
{
return [
// $enquiry->WRITE YOUR RECORDS,
// ...
];
}
public function headings(): array
{
return [
//NAME HEADINGS(TITLE) OF YOUR RECORDS IN SIDE SINGLE QUOTATION,
// ...
];
}
In Route:
Route::get('enquiryExport/{id}', 'enquiryController#enquiryExport');
We are moving an older PHP project over to laravel. We are trying to post JSON to our api we created, but are not aware how to have the JSON be bound to a model. We added the model as a parameter to the function, it is created but none of the properties are set on it from the JSON. Does this type of model binding exist in laravel?
class CalculatorModel
{
/**
* Value A.
*
* #var integer
*/
public $A;
/**
* Value B.
*
* #var integer
*/
public $B;
}
class CalculatorController
{
// What is trying to be achieved.
public function add(CalculatorModel $model)
{
return Calculator::Add($model);
}
// What we are trying to avoid
// as there is a lot of properties/objects in our real world JSON
public function add(Request $request)
{
$a = $request->json()->all();
$m = new CalculatorModel();
$m->A = $a['A'];
$m->B = $a['B'];
....
return Calculator::Add($m);
}
}
// in reoutes/api.php
Route::post('add', 'API\CalculatorController#add');
// External library's class
class Calculator
{
public static function Add(CalculatorModel $m)
{
return $m->A + $m->B;
}
}
Simple JSON post
{
"A": 2,
"B": 2
}
In ASP.Net, we are able to add a [FromBody] attribute to the parameter so that ASP.Net would bind the content body as the model instead of form content. We are looking for similar functionality in laravel.
There is no such binding in Laravel. Laravel binding is about Models/DB access as #PKeidel said. All you need is controller method without any models.
public function add(Request $request)
{
return $request->A + $request->B;
}
UPD: What about new constructor for CalculatorModel class?
public function __construct(array $properties = [])
{
foreach ($properties as $key => $value) {
$this->{$key} = $value;
}
}
public function add(Request $request)
{
$m = new CalculatorModel($request->all());
return Calculator::Add($m);
}
In any case Laravel does not offer out of the box solution for this.
Try this to wrap your API, which can then be used by Eloquent as if it were a database model:
https://github.com/CristalTeam/php-api-wrapper
All what models are about is saving/reading something from the database. So if this is not what you want, forget about it. Because in Laravel models are bound to database tables ;-)
If you just want so receive some values as json, do a calculation and return a value you are thinking to complicated.
Create a route:
Route::post('add', function() {
$data = request()->json();
return $data->get('A') + $data->get('B');
});
Or:
Route::post('add', function(\Illuminate\Http\Request $r) {
return $r->A + $r->B;
});
This is all it takes.
After that just make sure to send your data with json header. Like so:
fetch('/add', {
method:"post",
headers: {'Content-Type': 'application/json'},
body: '{"A": 2,"B": 2}'
})
.then((d) => d.text())
.then((html) => {
output.innerHTML = html;
})
See it in action here: https://laravelplayground.com/#/snippets/006b4871-5d92-4a2d-b8af-8a21423024e6
To transform a database entity to an API response Laravel support resources, eg. UserResource extends JsonResource. The resource allows me to cleanly define which fields from the entity should be included in the response, how to transform them etc.
Is there a similar functionality for requests? My requests typically look like this:
public function create(JsonRequest $request): UserResource
{
$data = $request->json()->all();
/* Remove, transform, add request fields etc. */
$user = User::create($data);
$user->save();
return new UserResource($user);
}
In our case we have a legacy database behind a modern API so there are a number of fields that need to transformed, renamed etc. before pushing them into the entity class. The fields differ from request to request but the steps are very similar. Is there a less boilerplate-y way to do this, something similar to how resources transform entities to responses?
Something like:
class UserRequest extends JsonRequest {
public function fromArray(JsonRequest $request) {
…
}
}
Then the request could look like this:
public function create(UserRequest $request): UserResource
{
$user = User::create($request);
$user->save();
return new UserResource($user);
}
I suppose, that most of your problems can solve form request. See example below
Form request class:
namespace App\Http\Requests;
use Carbon\Carbon;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
class TestRequest 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()
{
return [
'date' => 'required|date_format:Y-m-d H:i:s',
'name' => 'required|string',
];
}
// here you can specify custom error messages
public function messages()
{
return [
'date.required' => 'No date specified',
'date.date_format' => 'Invalid date format',
'name.required' => 'No name specified',
'name.string' => 'Invalid name format',
];
}
// here you can implement some data mapping before validation
protected function validationData()
{
return $this->transform($this->all());
}
// some data transformation logic
// You can place it anywhere in your applciation services
protected function transform($input)
{
$transformed = [];
foreach ($input as $field => $value) {
if ($field == 'name') {
$value = strtoupper($value);
} elseif ($field == 'date') {
$value = Carbon::parse($value)->toDateTimeString();
}
$transformed[$field] = $value;
}
return $transformed;
}
public function failedValidation(Validator $validator)
{
// here you can implement custom validation failure
parent::failedValidation($validator);
}
}
Here is my test route: Route::get('/test', 'TestController#index');
And controller:
use App\Http\Requests\TestRequest;
class TestController extends Controller
{
public function index(TestRequest $request)
{
return response()->json($request->validated());
}
}
So, then requesting route: curl -H 'Accept: application/json' 'http://localhost:8000/test?date=01.01.2019&name=petya'
And getting response: {"date":"2019-01-01 00:00:00","name":"PETYA"}
And dont be shy to see source code of request and form request, cause of not all methods you wish are described in docs. Hope this helps
I have a model called Property which has an 'active' flag. I want a metric at the top of my resource which shows a count of active Properties.
My calculate method is exactly as in the doc but this shows all Properties rather than active ones:
public function calculate(Request $request)
{
return $this->count($request, Property::class);
}
How can I add a filter?
I've tried a where clause:
public function calculate(Request $request)
{
return $this->count($request, Property::class)->where('active','=',1);
}
And a query scope:
public function calculate(Request $request)
{
return $this->count($request, Property::class)->active();
}
I thought I might be able to use the Nova filter I set up on the resource list page but that didn't seem to work either. I'm sure it's really easy but I haven't worked it out. Thanks for your help!
Your can use every type of Eloquent\Builder instance in the $model param.
Instead of:
public function calculate(Request $request)
{
return $this->count($request, Property::class);
}
Set a Scope on your Model
App\Property.php
...
public function scopeActive($query)
{
return $query->where('active', 1);
}
public function scopeInactive($query)
{
return $query->where('active', 0);
}
And use this scope as the $model param in your calculate method, because the call of the scope returns a Eloquent\Builder Instance
public function calculate(Request $request)
{
return $this->count($request, Property::active());
// return $this->count($request, Property::inactive());
}
Edit
Of course you can make the Eloquent Builder call inline:
public function calculate(Request $request)
{
return $this->count($request, Property::where('active', 1));
}
How can I return a variable from Form Requests (App\Http\Requests) to Controller (App\Http\Controllers)?
I am saving a record on function persist() on Form Requests.
My goal is to pass the generated id so that I can redirect the page on edit mode for the user. For some reason, the Controller cannot receive the id from Form Requests.
App\Http\Requests\MyFormRequests.php:
function persist()
{
$business = Business::create([
'cart_name' => $this['cart_name'],
'product' => $this['product']
]);
return $myid = $business->id;
}
App\Http\Controllers\MyControllers.php:
public function store(MyFormRequests $request)
{
$request->persist();
return redirect()->route('mypage.edit.get', $request->persist()->$myid);
}
Important
I must add that this is not the recommended way. Your FormRequest should only be responsible for validating the request, while your Controller does the storing part. However, this will work:
App\Http\Requests\MyFormRequests.php:
function persist()
{
return Business::create([
'business_name' => $this['business_name'],
'nationality' => $this['nationality']
])->id;
}
App\Http\Controllers\MyControllers.php:
public function store(MyFormRequests $request)
{
$id = $request->persist();
return redirect()->route('register.edit.get', $id);
}
A guy name Snapey helped me:
public function store(MyFormRequests $request)
{
$business = $this->persist($request);
return redirect()->route('register.edit.get', $business->id);
}
private function persist($request)
{
....
return $business;
}
hope this could help someone in the future.