I need to setup Route model binding in the group which defined subdomain.
When I run this code:
Route::bind('app', function ($value) {
return App\Models\App::where([
'slug' => $value,
])->firstOrFail();
});
Route::group(['domain' => '{appSlug}.upman.dev'], function(App\Models\App $app) {});
I just get the error message:
Argument 1 passed to App\Providers\RouteServiceProvider::{closure}()
must be an instance of App\Models\App, instance of
Illuminate\Routing\Router given.
I don't known, how to get it works.
Thank so much guys for any response!
You should define your explicit model bindings in the boot method of the RouteServiceProvider class:
public function boot(){
parent::boot();
Route::bind('app', function ($value) {
return App\Models\App::where([
'slug' => $value,
])->firstOrFail();
});
}
It should looks like this:
class IndexPageController extends Controller
{
public function index($domain, App\IndexPage $page = null) {
//$domain will send first parameter
}
}
to disable this parameter you can use in your middleware
$request->route()->forgetParameter('domain');
Related
I've created a Service Provider with a class that has a model passed into the constructor.
The model needs to be a specific record based off the $id taking from the URL eg /path/{$id}
How can I use the requested model in the Service Provider?
An option is to pass the model into the execute method but for now I'll need to pass it into the construct.
MyController
class MyController {
public function show(MyClass $myClass, $id)
{
$model = MyModel::find($id);
return $myClass->execute();
}
}
MyClass
class MyClass
{
$private $myModel;
public function __construct(MyModel $myModel)
{
$this->myModel = $myModel;
}
public function execute()
{
//do something fun with $this->myModel
return $theFunStuff;
}
}
MyServiceProvider
public function register()
{
$this->app->singleton(MyClass::class, function ($app) {
return new MyClass(/* How can I use $myModel? */);
});
}
I don't see any value / reason to use a singleton here.
The service provider registers the singleton before your route is resolved, so there is no way to pass the $model from the controller into the register method. I would remove the service provider and do the following:
From the docs:
If some of your class' dependencies are not resolvable via the
container, you may inject them by passing them as an associative array
into the makeWith method:
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
So in your case something like this:
public function show($id)
{
return app()->makeWith(MyClass::class, ['myModel' => MyModel::find($id)])->execute();
}
Or shorter with the help of route model binding:
public function show(MyModel $myModel)
{
return app()->makeWith(MyClass::class, compact('myModel'))->execute();
}
Note that the argument names passed to makeWith have to match the parameter names in the class constructor.
All my requests are starting with a prefix, so I created a Route Group with multiple endpoints:
routes/web.php
Route::group(array('prefix' => $prefix), function() {
Route::get("/test/test2/{lang}", ['uses' => 'TestController#test2']);
...
});
Controller:
class TestController {
public function test2(Request $request, $lang) {}
}
With the following test URL:
domain.com/customprefix/test/test2/en
I reach my controller and can access $lang (=en). But how can I pass $prefix to my controller methods? (It should evaluate to "customprefix" in this example)
Unfortunately I didn't find information about that in the documentation or in the API specification.
In your Controller you can get prefixes as one of these solutions:
1.With $reques:
public function TestController(\Illuminate\Http\Request $request)
{
$request->route()->getPrefix();
}
2.Without $request:
$this->getRouter()->getCurrentRoute()->getPrefix()
Did you try to use route prefix already ? . If not, so it should look like this
public function test2(Request $request, $lang){
dd($request->route()->getPrefix());
}
I am having an issue setting up an injection on both the constructor and the method in a controller.
What I need to achieve is to be able to set up a global controller variable without injecting the same on the controller method.
From below route;
Route::group(['prefix' => 'test/{five}'], function(){
Route::get('/index/{admin}', 'TestController#index');
});
I want the five to be received by the constructor while the admin to be available to the method.
Below is my controller;
class TestController extends Controller
{
private $five;
public function __construct(PrimaryFive $five, Request $request)
{
$this->five = $five;
}
public function index(Admin $admin, Request $request)
{
dd($request->segments(), $admin);
return 'We are here: ';
}
...
When I run the above, which I'm looking into using, I get an error on the index method:
Symfony\Component\Debug\Exception\FatalThrowableError thrown with message "Argument 1 passed to App\Http\Controllers\TestController::index() must be an instance of App\Models\Admin, string given"
Below works, but I don't need the PrimaryFive injection at the method.
class TestController extends Controller
{
private $five;
public function __construct(PrimaryFive $five, Request $request)
{
$this->five = $five;
}
public function index(PrimaryFive $five, Admin $admin, Request $request)
{
dd($request->segments(), $five, $admin);
return 'We are here: ';
}
...
Is there a way I can set the constructor injection with a model (which works) and set the method injection as well without having to inject the model set in the constructor?
One way you could do this is to use controller middleware:
public function __construct()
{
$this->middleware(function (Request $request, $next) {
$this->five = PrimaryFive::findOrFail($request->route('five'));
$request->route()->forgetParameter('five');
return $next($request);
});
}
The above is assuming that PrimaryFive is an Eloquent model.
This will mean that $this->five is set for the controller, however, since we're using forgetParameter() it will no longer be passed to your controller methods.
If you've specific used Route::model() or Route::bind() to resolve your five segment then you can retrieve the instance straight from $request->route('five') i.e.:
$this->five = $request->route('five');
The error is because of you cannot pass a model through the route. it should be somethiing like /index/abc or /index/123.
you can use your index function as below
public function index($admin,Request $request){}
This will surely help you.
Route::group(['prefix' => 'test/{five}'], function () {
Route::get('/index/{admin}', function ($five, $admin) {
$app = app();
$ctr = $app->make('\App\Http\Controllers\TestController');
return $ctr->callAction("index", [$admin]);
});
});
Another way to call controller from the route. You can control what do you want to pass from route to controller
Previously i have this code working in laravel 5.2
RouterServiceProvider
public function boot(Router $router)
{
parent::boot($router);
// Model binding
$router->model('house', 'App\house');
}
and in controller
public function show(House '$house')
{
return view('house.show', compact('house'));
}
and when i upgrade to Laravel 5.4 this code doesn't work.
So i change my code to this in RouterServiceProvider
public function boot()
{
//
parent::boot();
Route::model('house', App\House::class);
}
But I dont know what to change in the controller codes below
public function show(House '$house')
{
return view('house.show', compact('house'));
}
, when I run the code I got this error
(1/1) FatalThrowableError
Parse error: syntax error, unexpected ''$house'' (T_CONSTANT_ENCAPSED_STRING), expecting variable (T_VARIABLE)
I need Route Model Binding to simplify my code-> (house = House::FindOrFail($id);)
Thanks for the help!
Change this
public function show(House '$house')
{
return view('house.show', compact('house'));
}
to this
public function show(House $house)
{
return view('house.show', compact('house'));
}
Implicit binding works out of the box:
Implicit Binding
Laravel automatically resolves Eloquent models defined in routes or
controller actions whose type-hinted variable names match a route
segment name. For example:
Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});
Since the $user variable is type-hinted as the App\User Eloquent
model and the variable name matches the {user} URI segment, Laravel
will automatically inject the model instance that has an ID matching
the corresponding value from the request URI. If a matching model
instance is not found in the database, a 404 HTTP response will
automatically be generated.
But in case you want to declared explicitly, you can check the Explicit Binding of the documentation:
Explicit Binding
To register an explicit binding, use the router's model method to
specify the class for a given parameter. You should define your
explicit model bindings in the boot method of the
RouteServiceProvider class:
public function boot()
{
parent::boot();
Route::model('user', App\User::class);
}
Next, define a route that contains a {user} parameter:
Route::get('profile/{user}', function (App\User $user) {
//
});
Since we have bound all {user} parameters to the App\User model, a
User instance will be injected into the route. So, for example, a
request to profile/1 will inject the User instance from the
database which has an ID of 1.
If a matching model instance is not found in the database, a 404
HTTP response will be automatically generated.
So, in your case:
RouteServiceProvider.php
public function boot()
{
parent::boot();
Route::model('house', App\House::class);
}
Then in your controller:
HousesController.php
public function show(House $house)
{
return view('house.show', compact('house'));
}
I'm trying to resolve a primitive inside a controller method.
This is the register method of my Provider:
public function register()
{
$this->app->when('App\Http\Controllers\InvalidCustomerController')
->needs('$customers')
->give(function () {
return InvalidCustomer::latest()
->paginate(20);
});
}
And this is the controller method I'm trying to resolve $customers:
public function index($customers)
{
return view(
'customer.invalid.index',
compact('customers')
);
}
$customers is not filled.
Everything will work if I resolve that on constructor.
What am I doing wrong?
ps: I'm using Laravel 5.2
Not sure if you found a solution but to use a primitive in a controller, pass it through the __constructor of the controller class as so:
private $customers;
public function __construct($customers) {
parent::__construct();
$this->customers = $customers;
}
This $customers variable can then be used elsewhere inside of the class.