The sequence of calling functions in laravel route? - php

Example below:
Route::get('users/{id}', function ($id) {
//code
})->where('id', '[0-9]+');
The anonymous function will be called first or "where" function will be called first?
In my opinion, I think the anonymous function will be called first. But I think this is not reasonable, I think it is reasonable that only the id meet the regular expressions can call the anonymous function.
So what sequence is it exactly?

The where will be ran first.
Why?
the get function returns an object as well as the where. So if Laravel calls upon that Route, the Route object will be built first before firing the Route's actions.
$obj = Route::get() // returns an object, meaning that object returned has a function `where`.
$obj->where() // still returns the same object but validated.
So you have an object after the where call. That's what Laravel will use to perform an action on that route.
Like: performRoute($obj) // this is only for example
You can review the Route functions here: https://github.com/laravel/framework/blob/bd352a0d2ca93775fce8ef02365b03fc4fb8cbb0/src/Illuminate/Routing/Route.php

Related

dynamic function call parameters

Today I have used a Klein Semi Framework and I wanted to understand something which is really important for me to know.
$klein->respond('/report/latest', function ($request, $response, $service) {
$response->file('/tmp/cached_report.zip');
});
for example in this code we pass into the function three variables request, response and service. How does it know to put into the request variable the request class, to put into the response variable the response class, etc. no matter the order of the varaibles?
Is there any example of code that will help me to understand this?
Thanks!
Not familiar with the framework, but based on your explanation, I'd assume they are using reflection to get the name and order of the parameters you provided to the closure. You can see an example of this here: (https://3v4l.org/jjWa1)
$closure = function ($request, $response, $service) {
$response->file('/tmp/cached_report.zip');
};
$reflected = new ReflectionFunction($closure);
var_dump($reflected->getParameters());
ReflectionFunction allows you to get details about a function's definition.
$request, $response, and $service aren't variables in your current scope that you're passing into that function.
function ($request, $response, $service) { $response->file('/tmp/cached_report.zip'); }
Is an anonymous function, a callback that you're passing as the second argument to $respond. So the parameters for that function aren't defined at the time you call $klein->respond(). What you're doing there is creating a route by assigning that callback to the $klein object to handle the '/report/latest' route.
The idea of a router class like that is that you define functions to handle requests matching various routes, and when a route is matched, the router object will call the function you've defined for it and supply the necessary arguments to it at that time.
I'm not sure what you mean by "no matter the order of the variables". I think the callback needs to have those variables defined in the correct order.

How does Laravel's "withVariableName" works?

Looking at Laravel code I found they are passing variable from 'routes' to 'views' using the following method:
$arraysan = ['mike','robert','john']; **//Variable to be passed**
return view('home')->withArraysan($arraysan); **//Variable passed with** name "withArraysan"
In that above syntax they call a function named withArraysan which doesn't exist.
Can somebody explain how its been handled in Laravel?
For a while now, PHP has had the concept of magic methods - these are special methods that can be added to a class to intercept method calls that do not exist.
It appears that Laravel Views implement __call - this then intercepts a call to an undefined method on the object, and is passed both the name of the method being called as well as the arguments. In this way, the View object can then see that the withArraysan call began with and call the concrete method with, passing the second part Arraysan as the first argument, and the argument to withArraysan as the second part.
If I've got your question then in Laravel they had a class View using magic method __call to handle the above function and the code for that function is like as follows
public function __call($method, $parameters)
{
if (Str::startsWith($method, 'with')) {
return $this->with(Str::snake(substr($method, 4)), $parameters[0]);
}
throw new BadMethodCallException("Method [$method] does not exist on view.");
}
And you can find this within
your_project_folder/vendor/laravel/framework/src/Illuminate/View/View.php
$arraysan = ['mike', 'robert', 'john']; // Variable to be passed
return view('home')->with('AnyVariable', $arraysan);
Try this! This will work.
Also check in home.blade.php,
<?php
print_r($AnyVariable);die;
?>

With in Laravel and Validate double -> operator

I'm newbye of OOP and Laravel , but i have noticed that the operator with in laravel is used for a lot of things: for example i have found this part of code in the documentation:
return Redirect::to('register')->withErrors($validator);
withErrors? I know that with is used to pass multiple element to a view: is there more that i need to know about this operator?
Another Question: the validate class in php have this type of operator:
$validator->required('You must supply an email address.')->email('You must supply a valid email address')->validate('email', 'Email');
why i can use multiple "->" for a instance of the class validator? I know that in this way:
$object = new object();
$object->something(); //metod or attribute
but i know that it's impossible use the operator "-" for indicate multiple method/attribute for a class(even if it is a library).
thank you for all and i'm sorry for,maybe,the stupid question! Thank you!
Well Redirect::to() returns an instance of Illuminate\Http\RedirectResponse. This class has a method withErrors which is called in the example.
However this with* method is a bit different than the one to pass data to a view. withErrors flashes the data to the session so it is available for the next request (after the redirect happens)
Regarding your second question, this: $validator->required()->email() is called method chaining. It is used a lot (not only in Laravel) to achieve a nice and brief syntax.
What happens is that the methods return $this so you can call the next method on the same object right away.
Let's look at another example:
$result = User::where('active', true)->where('name', 'like', 'a%')->get();
If we now take a look at the where() method in Illuminate\Database\Eloquent\Builder you can see that after the where logic happens it returns $this so we can continue calling methods.
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
// code omitted for brevity
return $this;
}
Many Laravel classes implement this so-called Fluent Interface that allows method chaining for nearly every function call. Only methods that have an obvious return value can't be chained. Like retrieving a result with get(). Of course it has to return the result and it can't return $this as well.
You seem to understand the purpose of with() just fine.
As for your second question, you can "chain" object methods if the methods each return the object like this:
<?php
class MyClass {
public function myMethod()
{
// do stuff
return $this;
}

Passing a variable to an anonymous function without using the use keyword

I have a Router class:
$router->
get($pattern, $callback); // creates a new route
[...]
And an Application class:
$app->
get($pattern, $callback); // calls the router `get()` method
[...]
The problem is, when I'm setting the callback, inside each function I need the $app instance. I know I can use the use keyword, but using it for every route, every callback will by annoying and pointless.
Example:
Change:
$app->get('here/is/my/pattern', function () use ($app) {
$app->controller('just_an_example');
});
To:
$app->get('here/is/my/pattern', function () {
$app->controller('just_an_example');
});
How can I pass a variable to an anonymous function without the use keyword?
Short Answer
Just use in the variable.
Long Answer
Seriously, just use the variable.
Alternate Answer
You could rebind the callback, if it's a closure:
function rebind(App $app, Closure $closure) {
return $closure->bindTo($app);
}
$app->get('here/is/my/pattern', rebind($app, function () {
$this->controller('just_an_example');
}));
$this is now bound to $app, and $this is always available in the scope of a non-static closure.
But that isn't gaining you much aside from unnecessary indirection; please refer to the Short Answer and/or Long Answer.
Your design is wrong.
It is not the Router's job to call the Controller. Instead, your Router should return something (usually a Route object) the corresponds to the match route. Generally like so:
$router = new Router($reuqest->getURI()); //The request URI
$router->addRoute("some/pattern", "SomeController");
$router->addRoute("some/other/pattern", "SomeOtherController");
$route = $router->route(); //$route now has a Route object.
$controllerClass = $route->getResource();
$app->$controllerClass($request); //Pass the Request object with GET and POST and whatever into the controller
This way, the router doesn't know it goes to some controller, and the controller doesn't know it came from a route. The two components are now completely reusable.

Laravel filter with parameter in construct

I searched on Stack and see this question How to add filter parameters to controllers in Laravel?.
I have a similar question but this time, I need to pass an flexible $myparam argument, the code looks like bellow:
In Route.php
Route::filter('diffauthor',function($myparam){
if(Authority::cannot('edit', 'postedit', $myparam))
return View::make('permdeny.index');
});
and in Controller:
public function __construct() {
parent::__construct();
$this->filter('before','diffauthor', $myparam);
}
How do I pass $myparam base on user request?
You can only pass parameters to filters as strings:
$this->filter('before', 'diffauthor:param1,param2');
Sometimes to get around this limitation I use the Session class as a sort of temporary store, or even inspect variables that are being passed to the method by looking at the object returned by Request::route() within my filter.

Categories