I have and api endpoint which should return a user based on his id : user/{id}.
In my controller i have the following code:
/**
* #Api\Get("user/{id}")
* #SWG\Parameter(name="id", type="string", in="path", required=true)
*/
public function getUser(Request $request, string $id) {
$user = $this->getDoctrine()->getManager()->getRepository('App\Entity\User')->findUser($id);
return $this->view($user);
}
In my repository i have the following code:
public function findUser(string $id) {
$qb = $this->createQueryBuilder('a');
$qb->andWhere($qb->expr()->eq('a.id',':id'))->setParameter('id',$id);
return $qb->getQuery()->getOneOrNullResult();
}
it is working fine when getting user/4, but it is also working when getting user/4ruqbu.
I just want to get the user on user/4 and no result on user/4ruqbu. It should return the exact match. I think the problem is that the id parameter is a string. if i change it to int it is working, but i get an error instead of no result if i try user/4eiugq.
Is there a way to handle that?
Your route accepts any string for your id parameter which means that any value will make its way to your repository method. Then if you try to use a string which starts with a numeric value as an integer, you will get that integer.
Try for yourself on 3v4l.org:
var_dump((int)'4ruqbu'); // output: int(4)
You could make use of parameters validation using a Regex:
/**
* #Api\Get("user/{id<\d+>}")
*/
public function getUser(Request $request, int $id) {
// ...
}
This should now fail for URIs such as /user/4ruqbu as it does not meet the route requirements.
Some improvements:
If you installed sensio/framework-extra-bundle you can benefit of the ParamConverter and replace string $id with a user:
public function getUser(User $user, Request $request)
{
// ...
}
Avoid fetching services related to Doctrine with $this->getDoctrine() etc. Use autowiring instead.
If you need the Entity Manager to save/update/remove entities, add a Doctrine\ORM\EntityManagerInterface argument to your controller method. If you need to query for entities using a repository, add an argument typed with its class like App\Repository\UserRepository in your case:
// Example of controller method fetching services by autowiring:
public function myAction(EntityManagerInterface $em, UserRepository $userRepo)
{
// ...
}
Related
I've tried to combine the Laravel docs on implicit binding and optional parameters and have the following code.
routes file:
Route::get('go/{example?}', [ExampleController::class, 'click'])->name('example');
And in the controller:
public function click(Example $example = null)
{
// Execution never reaches here
}
Execution never reaches the controller unless there is an Example with the correct slug, as it throws a 404. I want to check if $example is null in the controller and use custom logic there. How can this be accomplished?
Try this
Route::get('go/{example?}', [ExampleController::class, 'click'])->name('example');
public function click($example)
{
if($example != null){
$example = Example::findOrfail($example);
}
}
in model binding it will automatically run findOrfail to that model so don't you that so you will have control over it then you can manage
the #ettdro answer is perfect (and all credit is to him), but i think an answer with actual code would be useful:
routes:
Route::get('go/{example?}', [ExampleController::class, 'click'])->name('example');
controller:
public function click(Example $example)
{
// Stuff
}
Model of Example:
/**
* Retrieve the model for a bound value.
*
* #param mixed $value
* #param string|null $field
* #return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null)
{
$result=$this->where('id', $value)->first();
return ($result)?$result:new Example();
}
You should obtain in the controller always a valid object, empty or not.
Had the same problem, and i'm happy with this solution.
To do that, you need use 'id' as your primary key in database and model,
if you are using another name for your pimary key, then you need to define it at your route:
Route::get('go/{example:number?}', [...]);
After creating a model with -mcr (php artisan make:model Institution -mrc), the show function in controller was scaffolded as:
/**
* Display the specified resource.
*
* #param \App\Organization\Institution $institution
* #return \Illuminate\Http\Response
*/
public function show(Institution $institution)
{
return view('institutions.show', ['institution' => $institution]);
}
The return view... was inserted by me. I was expecting it to have it populated with the object whose id was sent in the parameters.
/institutions/1
But, after using dd($institution), I verified that it has the ID, not the object.
Shouldn't this variable return me the object?
This is called Route Model Binding. Your route will need to look something like:
Route::get('institutions/{institution}', 'InstitutionController#show');
and then as per your controller
public function show(Institution $institution)
{
return view('institutions.show', compact($institution))
}
You can read more on this here.
I imagine your route had the parameter called {id} rather than {institution}.
Replace the parameter of show function
public function show(Institution $institution)
{
return view('institutions.show', compact($institution))
}
becomes
public function show($id)
{
$institution = App\Institution::findOrFail($id);;
return view('institutions.show', compact('institution'));
}
and in your routes
Route::get('institutions/{id}', 'InstitutionController#show');
I am Using Resource controller in Laravel 5.6. I am following this tutorial. I found here Resource controller uses the Route model binding, This means that you dont need to fetch the specified task by the id. Laravel will do it for you. $task variable which is passed into the show() method is passed to the view via compact method.
In my code I am using below code in Controller.
/**
* Display the specified resource.
*
* #param \App\sura $sura
* #return \Illuminate\Http\Response
*/
public function show(Sura $sura)
{
return $sura;
}
Here I am getting the Whole Sura object not the id.
Why I am getting the whole object not the id ? Where is the issue ?
https://laravel.com/docs/5.6/routing#route-model-binding
When dependency inject model
public function show(Sura $sura)
{
return $sura; // it is instance of Sura
}
For get id use this
public function show($suraId)
{
dd($suraId);// return integer number
}
I have a PHP trait that I will use in any model that can do a certain set of actions. For example one of these actions is completion where completed_at is marked with a timestamp.
The trait method is:
/**
* #return $this
* #throws Exception
*/
public function markCompleted(){
if($this->canDoAction('complete')){
$this->completed_at = Carbon::now();
return $this;
}
}
In my controller I am calling this on a model that can do this action like below.
$app->markCompleted()->save();
The $app when I view its contents it is not null.
Running this command returns an error like
local.ERROR: Call to a member function save() on null
Wouldn't $this represent the model that uses this trait?
Another variation on what The Alpha said.
/**
* #return $this
* #throws Exception
*/
public function markCompleted(){
if($this->canDoAction('complete')){
$this->completed_at = Carbon::now();
}
return $this;
}
This way you always return a model, and you can chain other functions before the save is performed if you needed.
If the condition doesn't meet then null will be returned, so instead of calling the save separately, do that inside that method, for example:
public function markCompleted()
{
if ($this->canDoAction('complete')) {
$this->completed_at = Carbon::now();
return $this->save(); // true/false
}
}
Then use it like:
$app->markCompleted();
The way way, you coded, the save method will be called even if the condition doesn't match and that's a side effect.
I am using Symfony 2.4, and according to the Docs, the correct way of retrieving the Request object in the controller is the following:
/**
* #Route("/register/next", name="next_registration_step")
*/
public function nextAction(Request $request = null) {...}
This works as expected. However, if I add a parameter to the controller, $request becomes null at runtime:
/**
* #Route("/register/next/{currentStep}", name="next_registration_step")
*/
public function nextAction(Request $request = null, $currentStep = 0) {...}
How do I work around this issue without using any older-but-deprecated methods for getting the request?
Note: if possible, a solution that does not involve the Request Stack recently introduced to Symfony 2.4 would be great, as it seems like overkill.
This works,
as I think the only difference is that I do not pass = null in parameters declaration
use Symfony\Component\HttpFoundation\Request;
/**
* #Route("/hello/{name}", name="_demo_hello")
*/
public function helloAction(Request $request, $name)
{
var_dump($request, $name);die();
In Symfony2 controllers it's not a good Idea to declare default value in the method definition - it should be done in routing definition.
In your case:
/*
*
* #Route("/register/next/{currentStep}", name="next_registration_step", defaults={"currentStep" = 0})
*/
public function next(Request $request, $currentStep) {...}
regards,