Laravel form request duplicate query - laravel

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.

Related

Laravel request validation by groups

So, I have a Creators table with all informations related to the creator.
This table has some nullable columns that can be filled depending on what type of creator you are.
As an example one can be an "indipendent" creator or a "company" creator. In the second case the creator will have to fill in the columns related to his company.
At the moment I am arranging it with something like this inside the Controller:
public function isValid(Request $request)
{
$creator = //creator validation rules;
$company = //company validation rules;
$transfer = //another set of rules;
if (!$request->indipendent)
$creator = array_merge($creator, $company);
$creator = array_merge($creator, $transfer);
return $request->validate($creator);
}
I want to however create a new CreatorRequest that validates the request.
The only method I could think of was to override the validate() function, but is there a way to do this by only utilizing the rules() function?
Ideally I would like to have the $creator $company and $transfer inside the rules and be able to choose which groups I want validated.
For example:
$request->validate(['creator', 'company']); //doesn't validate transfer
What is the best approach?
I say the best approach here is to break your request out into three separate request classes, and inject them using the laravel container:
public function isValid(CreateCreatorRequest $creator, CreateCompanyRequest $company, TransferRequest $transfer)
{
if (!$request->indipendent)
$creator = array_merge($creator, $company);
$creator = array_merge($creator, $transfer);
return $request->validate($creator);
}
Laravel will automatically handle passing the current request into those request classes, and you'll get your validated data as an array. The handy advantage here is you can force an interface directly against an intended action - you can apply the same CreateCompanyRequest in a different controller action and have a central place for all the validation rules.
https://laravel.com/docs/9.x/validation#creating-form-requests

Laravel Nova - Save multiple rows to database on create

I'm converting a Laravel app that was using Backpack across to Laravel Nova.
One of my models Images allows the user to add multiple images with a base set of information from the initial form. The form in this instance asks how many images are in the series via a dropdown and then has a number of relevant fields that will be used for all of the new images being added. When saving, in the controller, I'm using the following eloquent feature to run a number of tasks and insert the required number of rows:
public function store(StoreRequest $request){
//Get some info
//Make some tweaks
//Use for loop to save multiple records
for ($k = 0; $k < $addim; $k++){
//Do some stuff
parent::storeCrud(${"request"});
}
}
This works perfectly and inserts however many records are required.
In Laravel Nova, I can't see a way to use this same approach. Using an event listener in the model doesn't seem like the right way to save multiple records and I can't find any reference to a controller function I can use to achieve this.
I would really appreciate some thoughts and guidance on the best way to complete this part.
If someone has stumbled upon this type of problem.
You can use Laravel Observers.
In order to restrict the event to be fired only when resource is created and only using nova you can declare Observer in NovaServiceProvider.php as follows
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
parent::boot();
Nova::serving(function () {
Image::observe(ImageObserver::class);
});
}
Above code will only be triggered when your image object is modified using nova system only.
For ref Observer code will look like following
<?php
namespace App\Observers;
use App\Models\Document;
class ImageObserver
{
/**
* Handle the Image "created" event.
*
* #param \App\Models\Image $image
* #return void
*/
public function created(Image $image)
{
//logic to create multiple records
}
}
You can use the saving event in an observable
https://laravel.com/docs/5.8/eloquent#events

Sending request to a post controller function from another controller function

I have a controller like this.
public function barcode_approve(Request $request)
{
$barcodes = $request->input('barcode_values');
$upload_ids = $request->input('upload_id');
....
}
It is defined as post in route without any problem.
Route::post('my/url','BarcodeScanController#barcode_approve');
I would like to use barcode_approve by sending request from controller like
public function push_approve(){
$request = ['barcode_values' => '23ssdwe','upload_id'=>234234];
$this->barcode_approve($request);
.....
}
But $reqeust->input doesn't give the value when I send it through controller function (push_approve)
How can I send values from another controller function as input in $request?
Your barcode_approve expects a Request object, not an array. While you could instantiate a new Request object and potentially inject your fake inputs, I would consider that a bad practice.
Whenever you find yourself trying to call a controller method from another controller method, it usually means you have logic that can be extracted, either to a model, a trait, or in the case of the same controller, a separate protected function.
The purpose of a controller is to be the transport method, you shouldn't have much business logic in it, extract logic to the models when you can.
Required argument in barcode_approve() method must be instance of Request, not just array even if u call it $request.
So if you realy need your code to work, you must create Request instance at your push_approve method()
$request = new Request(['barcode_values' => '23ssdwe','upload_id'=>234234]);
But better way will be to route Request to push_approve() initially
extends your controller with the controller you want to used
then call the function this->barcode_approve($request)

Automatic generation of rules in laravel from migration

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
}

Best way of passing response information from Model to Controller using Laravel

The Model View Controller architecture tells me that all my business logic should be inside the Model, while the data flow should be handled by the Controller.
Knowing this, while I'm dealing with my logic inside the Model, I need to let the Controller know if he's supposed to redirect to another url, redirect back, what kind of message or variable to pass during the redirection, etc.
What is the best way of doing this?
I can think of some ways, like throwing exceptions on the Modeland catching them on the Controller or returning an array from the Model and treating it on the Controller, but none of them seem very nice. The easiest way would be calling the Redirect->to() (or back()) inside the Model and just returning the Model's return on the Controller, but it seem to break the architecture's separation of rules.
Is there a "right" way of doing this? What would be the pros and cons of each way?
EDIT:
The answer below is old. Laravel now includes a bunch of different ways of handling common problems.
For example, use Laravel's FormRequest's as a way of validating data easily on controller methods, and Jobs to handle business logic for creating / updating models.
OLD POST:
This is a common question, and while the 'MVC' pattern is nice for a basic starting point for a web app, I feel like the majority of developers always need another intermediate service for validation, data handling, and other problems that come up during development.
To answer your question without bias: There is no right way.
To answer your question with my own personal bias, I feel the majority of developers will use the Repositories or Services pattern to handle intermediate data handling between the controller and the model, and also have separate classes for validation as well.
In my opinion, Repositories are better for a framework and data agnostic design (due their interface driven implementation), and Services are better for handling the business logic / rules. Controllers are better used for handling responses and for passing the input data to the repository or the service.
The paths for each of these patterns are the same though:
Request -> Controller (Validation) -> Service -> Model -> Database
Request -> Controller (Validation) -> RepositoryInterface -> Model -> Database
Validation is in brackets since input isn't passed from the validator to the service / repository, the input sent to the validator, gives the 'OK', and let's the controller know it's ok to send the data to the Service / Repository to be processed.
I only use Services when I'm absolutely positive I won't be changing frameworks or data sources. Otherwise I'll use Repositories. Repositories are just a little more work to setup, since you'll need to make Laravel resolve the interface to your repository class through its IoC.
Services Example:
The Service:
namespace App\Services;
use App\Models\Post;
class PostService
{
/**
* #var Post
*/
protected $model;
/**
* Constructor.
*
* #param Post $post
*/
public function __construct(Post $post)
{
$this->model = $post;
}
/**
* Creates a new post.
*
* #param array $input
*/
public function create(array $input)
{
// Perform business rules on data
$post = $this->model->create($input);
if($post) return $post;
return false;
}
}
The Controller:
namespace App\Http\Controllers;
use App\Services\PostService;
use App\Validators\PostValidaor;
class PostController extends Controller
{
/**
* #var PostService
*/
protected $postService;
/**
* #var PostValidator
*/
protected $postValidator;
/**
* Constructor.
*
* #param PostService $postService
* #param PostValidator $postValidator
*/
public function __construct(PostService $postService, PostValidator $post Validator)
{
$this->postService = $postService;
$this->postValidator = $postValidator;
}
/**
* Processes creating a new post.
*/
public function store()
{
$input = Input::all();
if($this->postValidator->passes($input)) {
// Validation passed, lets send off the data to the service
$post = $this->postService->create($input);
if($post) {
return 'A post was successfully created!';
} else {
return 'Uh oh, looks like there was an issue creating a post.';
}
} else {
// Validation failed, return the errors
return $this->postValidator->errors();
}
}
}
Now with this pattern, you have a nice separation of all your processes, and a clear indication of what each of them do.
For a repository example, Google 'Laravel Repository Pattern'. There are tons of articles about this.
Actually - in Laravel 5 that is not the best way to do it. Business logic should not be in models. The only thing that models should do is retrieve and store data from your database.
You are better off using the CommandBus or ServiceProviders to handle application logic and business rules. There are many articles on the web about these, but personally I prefer laracasts.com as the best learning resource.

Resources