Automatic generation of rules in laravel from migration - laravel

When I describe in database migration some field, that it must be at maximum 256 characters long I have to describe this in model too, so that when user enters 257 characters database does not generate exception.
May be there is a better way to do it?

The best practice for this would be to use request validation in your controller when you submit your form. I can give you an example of this
Firstly make a request using artisan
php artisan make:request MyRequest
This will make a file called MyRequest.php in App/Http/Requests
Add your validation rules to the rules() function
public function rules()
{
return [
'text_field_name' => 'required|string|max:256'
];
}
You can find all the validation options here
https://laravel.com/docs/5.4/validation#available-validation-rules
You then just need to apply the request to the function that accepts your POST data. The Data will be validated before the function is run, ensuring that you will not get database exceptions from string length
In your controller
public function myPostController(\App\Http\Requests\MyRequest $request)
{
//Do something
}

Related

How will I identify resource default url in laravel?

I am running this command for model, migration, resource controller.
`php artisan make:model QuestionAnswer -mc -r` ..
Laravel give me in Resource Controller
public function show(QuestionAnswer $questionAnswer) {
// return $questionAnswer;
}
public function edit(QuestionAnswer $questionAnswer) {
// return $questionAnswer;
}
public function update(Request $request, QuestionAnswer $questionAnswer){
// return $questionAnswer;
}
if I write in web.php
Route::resource('question-answer','QuestionAnswerController'); or
Route::resource('questionAnswer','QuestionAnswerController'); or
Route::resource('question_answer','QuestionAnswerController'); laravel resolve route model binding...
that means....
Example as a
public function edit(QuestionAnswer $questionAnswer)
{
return $questionAnswer;
}
$questionAnswer return object for this url {{route('admin.question-answer.edit',$questionAnswer->id)}}
but if I write in web.php Route::resource('faq','QuestionAnswerController');
laravel can not resolve route model binding...
that means.. $questionAnswer return null for this url {{route('admin.faq.edit',$questionAnswer->id)}}
also in show and update function $questionAnswer; return null...
for working as a faq url.. i need change in edit function variable($faq) . or Route::resource('faq','QuestionAnswerController')->parameters(['faq' => 'questionAnswer']);I
But These three url questionAnswer,question-answer,question_answer by default work...
I check it on "laravel/framework": "^6.0" (LTS)
Question
is there possible way to find out what exact url I will write ? .. like question-answer.. or is there any command line ...
after running auth command .. php artisan route:list command give us all route list.. and when I make model Category laravel create table name categories and follow grammar rules
Actually Laravel has got Naming Convection Rules In its core.
These Convictions make it to default binding database_tables to model, model to controllers ....
if you want, you can tell your custom parameters but if you dont, The Laravel uses its own default and searching for them.
for example: if you have a model named bar, laravel look for a table named plural bars . and if you dont want this behave, you can change this default by overriding the *Models* $table_name` attribute for your custom parameter.
There are some Name Convection Rules Like :
tables are plural and models are singular : its not always adding s (es) in trailing.
sometimes it acts more complicate. like : model:person -> table: people
pivot table name are seperate with underline and should be alphabetic order: pivot between fooes and bars table should be bar_foo (not foo_bar)
table primary key for Eloquent find or other related fucntion suppose to be singular_name_id : for people table : person_id
if there are two-words name in model attribute, all of these are Alias :
oneTwo === one_two == one-two
check this out:
class Example extends Model{
public function getFooBarAttribute(){
return "hello";
}
}
all of this return "hello" :
$example = new Example();
$example->foo_bar();
$example->fooBar();
// $example->foo-bar() is not working because - could be result of lexical minus
there is a page listing laravel naming conventions :
https://webdevetc.com/blog/laravel-naming-conventions/
Name Conventions : is The Language Between The Laravel and Developer
it made it easy to not to explicitly mention everything
like Natural Language we can eliminate when we think its obvious.
or we can mention if its not (like ->parameter(...)).
How will I know I need to write question-answer this ? by default it works... when i write faq i need to change in edit function variable($faq) .
How will I know by default url (question-answer) will work ..when php
artisan route:list command give us all route list.. and when I make
model Category laravel create table name categories and follow grammar
rules
think about i will create 20 model ,migration & controller by cmd... i will not change edit,show and update function variable ...how i will know the default url for 20 model and controller ?
Laravel is an opinionated framework. It follows certain conventions
Let us understand a route parts
Route::match(
['PUT', 'PATCH'],
'/question-answer/{questionAnswer}',
[QuestionAnswerController::class, 'update']
)->name('question-answers.update')
In the above route:
1st argument: ['PUT', 'PATCH'] are the methods which the route will try to match for an incoming request
2nd argument: '/question-answer/{questionAnswer}' is the url wherein
/question-answer is say the resource name and
{questionAnswer} is the route parameter name
3rd argument: [QuestionAnswerController::class, 'update'] is the controller and the action/method which will be responsible to handle the request and provide a response
When you create a model via terminal using
php artisan make:model QuestionAnswer -mc -r
It will create a resource controller for the 7 restful actions and take the method parameter name for show, edit, update and delete routes as camel case of the model name i.e. $questionAnswer
class QuestionAnswerController extends Controller
{
public function show(QuestionAnswer $questionAnswer){}
public function edit(QuestionAnswer $questionAnswer){}
public function update(Request $request, QuestionAnswer $questionAnswer){}
public function delete(QuestionAnswer $questionAnswer){}
}
Which means if you don't intend to change the parameter name in the controller methods then you can define the routes as below to get the benefit of implicit route model binding
//Will generate routes with resource name as questionAnswer
//It would not be considered a good practice
Route::resource('questionAnswer', QuestionAnswerController::class);
//OR
Route::resource('question-answer', QuestionAnswerController::class)->parameters([
'question-answer' => 'questionAnswer'
]);
//OR
Route::resource('foo-bar', QuestionAnswerController::class)->parameters([
'foo-bar' => 'questionAnswer'
]);
RFC 3986 defines URLs as case-sensitive for different parts of the URL. Since URLs are case sensitive, keeping it low-key (lower cased) is always safe and considered a good standard.
As you can see, you can name the url resource anything like foo-bar or question-answer instead of questionAnswer and yet keep the route parameter name as questionAnswer to match the Laravel convention when generating controller via php artisan make:model QuestionAnswer -mc -r and without having to change the parameter name in controller methods.
Laravel is an opinionated framework which follows certain conventions:
Route parameter name ('questionAnswer') must match the parameter name in controller methods ($questionAnswer) for implicit route model binding to work
Controller generated via artisan commands, have parameter name as camelCase of the model name
Routes generated via Route::resource('posts', PostController::class) creates routes with resource name equal to the first argument of the method and route parameter name as the singular of the first argument
Route::resource() provides flexibility to use a different name for route resource name and route parameter name
Read more at Laravel docs:
https://laravel.com/docs/8.x/controllers#restful-naming-resource-route-parameters
https://laravel.com/docs/8.x/controllers
https://laravel.com/docs/8.x/routing#route-model-binding
If you want to know how the php artisan make:model works you can study the code in vendor/laravel/framework/src/Illuminate/Foundation/Console/ModelMakeCommand.php and have a look at the various stubs these commands use to generate the files.
For almost all artisan commands you will find the class files with code in
vendor/laravel/framework/src/Illuminate/Foundation/Console and the stubs used by the commands to generate files in vendor/laravel/framework/src/Illuminate/Foundation/Console/stubs folder.
If you study these command classes properly then you will get an idea of the various conventions Laravel follows when generating files via the artisan commands
I think its becuse of dependency injection which you used in youre method.
Try this
public function edit($id)
{
// return $questionAnswer;
return view('backend.faq.edit',get_defined_vars());
}

laravel using validation request with except method

I am using request validation as
php artisan make:request ClientRequest
As you can see, on client edit form if password field is not empty I am able to use $request->validated() method on database update,
However if password field empty(user dont want to change password),
I am not able to use $request->except('password')->validated() method.
I use $request->except() method due to this situation.
Does this pose a security problem?
public function update(ClientRequest $request, Client $client)
{
$validated = $request->validated();
if($request->filled('password') )
{
Client::whereId($client->id)->update($validated);
}else{
Client::whereId($client->id)->update($request->except('password'));
}
return redirect('/clients')->with('success', 'success');
}
Client::whereId($client->id)->update($request->except('password'));
That line is does pose a big security problem especially if you are relying on validation to set fields rather than the fillable attribute. $request->except('password') will return all the other fields that the user submitted so if the user had added something like is_admin => true in the request, you'll end up setting it on the db if it exists.
You can use \Illuminate\Support\Arr::except() on the validated data to make sure that you are only getting the data you expect. That would change the that particular line to
Client::whereId($client->id)->update(\Illuminate\Support\Arr::except($request->validated(), 'password'));
PS: You already have the client through route model binding so you don't need to query it you can update that client directly i.e
$client->update(\Illuminate\Support\Arr::except($request->validated(), 'password'));
You are validating all fields sent to update() in both scenarios.
You would have had an issue if you sent the password field in both cases, but only validated it in one of them. That's not the case.
So looks fine to me from that perspective.

Laravel form request duplicate query

I want to fetch a record and perform validation with that.
So I see two option using validation in the controller and using form request
I prefer using form request
So according to a document I can fetch a record in Form request and use it.
But the problem is I need that record in the controller too, So if I going this way I load one record twice.
I'm solving my problem with property in the form request
for example
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$this->post = Post::find($this->input('id'));
return [
... // my rules base on $this->post
];
}
and then in the controller, I can access the post value
public function store(PostPublishCreate $request)
{
$request->post;
....
1.But I'm confused in this way, Is there a problem in my way? Is there a better solution to do it in laravel?
2.In this example I don't use dependency injection, So how I can approach this with dependency injection?
public function store(PostPublishCreate $request,Post $post)
{
// how to prevent to my record provided twice
// PostPublishCreate load post because of the rules
// Post loaded again with DI
....
I try to use the Rule class for my custom validation, But I'm not sure how to pass the record to Rule without reloading it
Form Request is not loading the record. It just validates the parameters present in the $request object. In the second example, $post is automatically retrieved by DI where then you can manipulate your record as you wish.

Make email authentication case insensitive in Laravel 5.7

I use the default email authentication in Laravel 5.7.3 (just updated from 5.4) with a sqlite DB. At login my email address gets validated case sensitive which is not what I want. It should be allowed to login with "JohnDoe#foobar.com" as well as "johndoe#foobar.com".
I've tried to add an accessor at my user model to always lowercase the database value.
public function getEmailAttribute($value) {
return strtolower($value);
}
But this one doesn't seem to be used by Auth at all. Additionally I don't know where to change the user input in the incomming request to lower case.
Is there a simple config case sensitive switch? Or where do I need to change/add scripts?
Thanks for your support
Daniel
Your accessor should be fine, but you should make sure that you also lowercase the given value, e.g. In your controller:
Assuming that you're using the default LoginController shipped from Laravel:
I overwrote the credentials method from AuthenticatesUsers in App\Http\Controllers\Auth\LoginController
protected function credentials(Request $request)
{
$credentials = [
$this->username() => strtolower($request->get($this->username())),
"password" => $request->get("password")
];
return $credentials;
}
This works fine, when all emails stored in the database are already stored all-lowercase. If you're starting from scratch you can enforce the emails to be stored lowercase by default. Just implement the following mutator in your App\User:
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtolower($value);
}
If you have stored mixed-case email already, you can update all emails to lowercase emails using this query:
UPDATE users SET email = LOWER(email);
But this still feels kind of incomplete and you maybe don't want to manipulate your data this way. I am pretty much sure that there are more possibilities to make this happen but unfortunately I am not able to dig into this further for now. However my next attempt would be to extend/write a custom UserProvider.
You have to call getEmailAttribute(/your email here/)
before login and signup like this
$request->email = getEmailAttribute($request->get('email'));

Models accessible only for authenticated user THAT CREATED THEM (Laravel)

I'm writing a software application to let the people have their own private archive of cooking recipes.
The RecipeController constructor contains:
$this->middleware('auth')
because only registered users can use recipes, but I need to protect also the access to the models.
The point is that users can view and modify only their own recipes.
Example: The user TortelliEngineer can create a recipe "Tortelli Secret Recipe" using the model Recipe; he can view, update and delete his recipe(s), but nobody else can see his precious "Tortelli Secret Recipe".
So, which is the cleanest way?
I added a user_id attribute to the model Recipe.
I must use this parameter every single time that I ask to the database for a Recipe (goodbye "findOrFail" by ID)
That means that every time I make a request I must access the Request object that contains User that contains User_id
using Auth::id() EVERY SINGLE TIME that I need one (or n) recipe
Like this:
class RecipeRepository{
public function all(){
return Recipe::where('user_id', Auth::id())
->orderBy('created_at', 'asc')
->get();
}
public function find($recipe_id){
return Recipe::where('user_id', Auth::id())
->where('id', $recipe_id)
->firstOrFail();
}
Is that correct? Do you hate me for this? Do you know better or more correct ways to do it?
Most of the time I make a method inside the model to check if someone is authorised, owner etc.. of something.
An example would be:
// User model
public function owns_recipe($recipe)
{
return ($recipe->user_id == $this->id);
}
You can call this at the very beginning in of the methods of your controller:
// Controller
public function index (Request $request)
{
$recipe = Recipe::find($request->id); // Get recipe
$user = ... // Get user somehow
if (!$recipe) App::abort(404); // Show 404 not found, or something
if (!$user->owns_recipe($recipe)) App::abort(403); // Show 403 permission denied, or something
... // Do whatever you want :)
}
While there are many ways of approaching this, Laravel does provide some built-in methods for handling general authentication of actions. In the first place I'd do something along the lines of what you intended (have a getRecipesByOwner method in RecipeRepository) and you can pass the user to it from the injected Request object:
// RecipeController
public function index(Request $request)
{
$recipes = $this->recipeRepo->findRecipesByOwner($request->user());
}
In addition though, I'd recommend creating policies to manage whether or not a user is capable of updating/deleting/viewing individual recipes. You can then authorize their actions in the controllers/blade templates/etc. via built-in methods like:
// Controller
public function update(Request $request, Recipe $recipe)
{
$this->authorize('update', $recipe);
}
// Blade template
#can('update', $recipe)
#endcan
The documentation is available at: https://laravel.com/docs/5.3/authorization#creating-policies

Resources