How to pass variables through model binding in laravel? - php

I need to get variable "type"
Route::model('type', \App\Models\Document::class, function($type) {
return (new \App\Models\ShareFactory($type));
});
than return object and use it in other bind
Route::model('key', \App\Models\Document::class, function($key) {
return $objectFromFactory::where('share_key', $key)->first();
});
And after all I need to set controller that will process request
Route::get('share/{type}/{key}', 'ProcessShareController#share');
Is it possible? Or I'm trying to code in a wrong way?

It is possible, although solution is not future-proof. This will also work only if in your resolution logic you are using route parameters that appear in the route before the parameter currently resolved.
When route parameters are resolved by Router, they are processed in the same order as they are defined in the path. Each resolved parameter is added to route parameters list.
You can access the list of already resolved parameters by calling
$parameters = Route::getCurrentRoute()->parameters();
You will see all route parameters there even if some have not yet been resolved. Before resolution you will see the string from the URL as their value.
So, in your case, you need the following:
Route::model('type', \App\Models\Document::class, function($type) {
return (new \App\Models\ShareFactory($type));
});
Route::model('key', \App\Models\Document::class, function($key) {
$parameters = Route::getCurrentRoute()->parameters();
$objectFromFactory = $parameters['type'];
return $objectFromFactory::where('share_key', $key)->first();
});
Warning:
Remember that key parameter will always be resolved with above logic, even if there is no type parameter in the route. This might lead to errors, as you always have to make sure that if you define one parameter, you also define the other.
As mentioned, this solution is not future-proof. The logic here relies on the assumption, that route parameters are always processed in the order they are defined. Although I don't see a reason why it could change in the future, there is no guarantee that this won't happen.

Related

Laravel : form does not change the URL after submit, causing me to be unable to do another POST in web.php

I have a bit of a complicated issue. I could use some help.
I have a form that is being handled by the following function:
$module = request('module');
$classe = request('classe');
$horaire = request('horaire');
$date = request('date');
$students = DB::select('SELECT * FROM `etudiants` WHERE etudiants.id_classe = '.$classe);
return view('g_absence.absence',['module'=> $module, 'classe'=>$classe,'horaire'=>$horaire,'date'=>$date,'students'=>$students]);
I take the values $module, $class, $horaire, $date and $students and need to use them inside a different view: g_absence.absence. This works fine and when the view is returned I have access to said variables.
The issue is, inside the g_absence.absence view, I have another form that also needs to be handled, and because the url remains the same even tho a different view is returned, I cant make two posts for the same path.
web.php:
Route::get('/testboy', [App\Http\Controllers\g_absence::class,'index'])->name('marquer');
Route::post('/testboy',[App\Http\Controllers\g_absence::class, 'marquer']);
Route::post('/testboy',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
The first line is the one that send to the form page just a simple
return view
The second one handle the form in that view
The third one, I want it to handle the form inside the
g_absence.absence view, but they share the same path.
Excuse me if I'm being unclear, I'm a bit of a beginner in Laravel
your problem is using the same route for different methods
basically the first route gets executed every time you use the '/testboy' action that is why your second function never get's called.
you can solve this issue by changing your urls for example:
Route::post('/testboy-marquer',[App\Http\Controllers\g_absence::class, 'marquer']);
Route::post('/testboy-ajoutabsence',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
Or you can use one function that's handle both with one url by pathing additional parameter to your url depending on your function call :
Route::post('/testboy?type=marquer',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
in your function check the type :
if(request('type') == 'marquer') {
execute marquer logic here...
} else {
execute absence logic here...
}
Using method and path with two functionalities is wrong, but if you want to somehow use both routes my same method and path which I don't recommend you must let the request to pass through like a middleware in your first block of code Instead of return a view.
Recommended way is to have 2 routes with different paths or at least one route with a parameter by which you can determine what code block must be executed.

Laravel Merge / Replace Request - Files

I've been using the merge() and replace() methods on the Request class. It's been working for the most part, but I was under the impression that merge() would add or override the existing parameters, while replace() wipes out all the parameters and adds the new array of ones passed in. However, they both work how I imagined merge() works. Am I missing something here?
Also, is there a way to merge() or replace() with a file, while still having the hasFile() method work? Basically what I'm doing is adapting a request from an API call. So I'm receiving the file in the request as one parameter, and remapping it to another parameter name so it matches what the backend is expecting. After using either method, the request looks correct at a glance when I do a dd($request->all()), but hasfile() returns false.
I did do some digging into the Http\Illuminate\Request class, and I think I'm finding that the issue is my file not being set it $_FILES. So it does work as intended I suppose.
With that being said, is there is particular way I can accomplish what I'm trying to do?
To Answer the first part of your question:
I went directly to the source and confirmed that the functions are indeed different:
Merge calls the add function which uses array_replace (php.net):
public function add(array $parameters = array())
{
$this->parameters = array_replace($this->parameters, $parameters);
}
while
Replace simply replaces the whole variable(array)
public function replace(array $parameters = array())
{
$this->parameters = $parameters;
}
So your initial impression is actually correct.

How to access values of multiple parameters passed to Laravel controller

I am trying to figure out how to access two (or more) parameters passed to a Laravel controller. I know how to create the route, and the URL is created correctly, but then I can only access the first passed parameter in my controller.
Route:
Route::get('managers/{id}/{parameter2}', array('as'=>'dosomething', 'uses'=> 'ManagersController#dosomething'));
where the first parameter is obviously the $id for managers, and the second parameters is to be processed by the controller.
View:
Do Something
generates the URL:
http://domain/managers/1/2
where 1 is easily accessed as the $id for managers, but when I try to access the 2nd parameter "2" using $parameter2, e.g. using a simple return: "id=$id and parameter2=$parameter2" statement, I get an "unidentified variable: $parameter2" error.
What am I doing wrong?
Is there a better way to pass multiple parameters? I'm especially asking the "better way?" question because what I want to do is use the 2nd parameter to change a value in a database table, and using a 'get' method, somebody could change the parameter value in the URL and therefore cause mischief. Must I use a 'post' method? I'd love to be able to use a link, since that works much better with the design of my application.
Thanks!
I was asked to include the controller, which I'm happy to do. Initially, just for testing, as I mentioned, my controller was a simple return to display the values of the two passed parameters. But here is what I want to be able to do, including the actual name of the function ("update_group" rather than "dosomething") --
ManagersController:
public function update_group($id)
{
DB::table('groups')->where('id','=',$parameter2)->update(array('manager_id'=>$id));
return Redirect::route('managers.show', array('id'=>$id));
}
The update table works perfectly if I replace $parameter2 with an actual value, so that syntax is fine. The issue is that Laravel says that $parameter2 is an undefined variable, despite the fact that the URL contains the value of $parameter2 as you can see above.
And since it occurs to me that the answer to this may involve adding a function to the Manager model, here is the current
Manager.php
class Manager extends Eloquent {
protected $table = 'managers'; ... (mutator and error functions)
}
Just change
public function update_group($id)
to
public function update_group($id, $parameter2)
All looks ok in your route. Seeing the controller code would help, but likely, you may not have a second parameter in your controller's dosomething() method.
public function dosomething($id, $parameter2){
var_dump($id).'<br />';
var_dump($paremter2);
}
If that isn't the case, you can try dumping it from the route's callback to further diagnose.
Route::get('managers/{id}/{parameter2}', function($id, $parameter2)
{
var_dump($id).'<br />';
var_dump($paremter2);
});
Depending on your use case, you can pass them in a query string like so: but it isn't really the 'best way', unless you're doing something like building an API that won't use the same variables in the same order all the time.
/managers?id=1&paramter2=secondParameter
var_dump(Request::query('id')).'<br />';
var_dump(Request::query('paramter2'));

Fat Free Framework use $args['name'] or PARAM.name for route parameters?

In Fat Free Framework code and examples online I sometimes see URL parameters referenced like this:
route_func($f3, $args) {
echo $args['name']
}
i also see:
route_func($f3, $args) {
$param=$f3->get('PARAMS.name');
echo $param;
}
Which method is preferred? Are there any caveats to one or the other?
The PARAMS variable can be accessed from anywhere in the code, so $f3->get('PARAMS.name') works everywhere.
Anyway, for convenience purpose, at routing time the route parameters are passed to the route handler. So you can spare one line of code by using the 2nd argument passed to the route handler.
In other words, the 2 examples you provided are equivalent, so choose the one that you understand best.
See this answer for more details about arguments passed at routing time.
NOTE:
As #user3587554 suggested, the 2 syntaxes differ on the treatment of non-existing keys: $args['name'] throws an error while $f3->get('PARAMS.name') returns NULL. So to be perfectly identical, the first syntax should be #$args['name']. But most of the time, this precaution is useless since there's no doubt about the parameter name(s).

Laravel routes with regex portions that don't get passed as parameters

Is there any way I can have a route set up with one regex section that doesn't get passed as a parameter?
For example:
Route::get('{string}/method/{id}', function($id)
{
return 'only one parameter passed, ID is ' . $id;
});
Specifically I'm routing to a controller and the methods need to be compatible with routes coming from elsewhere, which don't include this first parameter.
The most important thing is that, routes has to be matched according to it's declaration, for example, if you define a route like your example here
Route::get('{string}/method/{id}', function($id)
{
return 'only one parameter passed, ID is ' . $id;
});
Then the requested url has to be matched with same numbers of parameters including the http method (GET here) and in this case, the route will match only with something like this
httP//example.com/something/method/10
Here the second parameter 10 is not bound to be digits because you didn't make it to be a digit using where(...) so, it could be anything but two parameters must be required.
As an alternative, you may define a missing method in your controller like this (An idea only)
public function missingMethod($args = array())
{
// $args will contain all parameters
}
This is a special method in Laravel that any controller may contain it and whenever a non-existing method will be called in that controller, then this missingMethod would be called and all the parameters will be passed to it's $args parameter as an array, so if you have two parameters in the url and calling method is missing in the controller then you may get those parameters within this method scope, something like [param1, param2] and from this method you may call your desired method depending on the count of params.
So, if you just point the route's action to this controller which has the missing method then from the missingMethod you may call another method using different parameters according to your other method.
Also check PHP Overloading and call_user_func_array to get the real idea of missingMethod.

Categories