Considering the following route group in Laravel 5:
Route::prefix('{locale}')->group(function () {
// ... Other routes here
});
All routes that are nested within this route group have views that extend a certain layout.
Somewhere in this layout I loop all available locales in my application, and I put links to change to this locale. What would be the easiest way to print these links in my view, keeping the current route and possibly the other route parameters but changing only the {locale} parameter?
Had this problem and came up with this:
app('url')->toRoute(
request()->route(),
array_merge(request()->route()->parameters(), ['locale' => $otherLocale]),
true
);
You could turn it into a helper like route:
function current_route($params = [], $absolute = true)
{
return app('url')->toRoute(
request()->route(),
array_merge(request()->route()->parameters(), $params),
$absolute
);
}
and call it with current_route(['locale' => 'sv'])
Maybe just Type-hint the request and pass the prefix into your view through your controller and use it in your links:
public function ControllerWithLocaleLinks(Request $request)
{
$currentLocale = $request->route()->getPrefix();
return view('locale', compact('currentLocale'));
}
Related
Hi Folks i upgrading my slim framework from slim 2 to slim 4 for older project
for one route i added the one value before route using slim 2 slim.before in index.php
example code:
$app->hook('slim.before', function () use ($app) {
$env = $app->environment();
$path = $env['PATH_INFO'];
// spliting the route and adding the dynamic value to the route
$uriArray = explode('/', $path);
$dynamicvalue = 'value';
if(array_key_exists($uriArray[1], array)) {
$dynamicvalue = $uriArray[1];
//we are trimming the api route
$path_trimmed = substr($path, strlen($dynamicvalue) + 1);
$env['PATH_INFO'] = $path_trimmed;
}
});
i read about the add beforemiddleware but cannot able find correct way to add it and i cannot able to find the replacement for $app->environment();
i want to append the dynamic value directly to route
for example
i have one route like this
https://api.fakedata.com/fakeid
by using the above route splitting code i appending the value route using slim.before in slim 2
for example take the dynamic value as test
the route will be
https://api.fakedata.com/test/fakeid
the response of the both api will be same we want to just add value to the route
can any one help me how to do with slim 4
I assume you need to and PATH_INFO to the environment so you can later refer to it in the route callback. You can add a middleware to add attributes to the $request the route callback receives:
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Slim\Psr7\Response;
class PathInfoMiddleware {
public function __invoke(Request $request, RequestHandler $handler) : Response {
$info = 'some value, path_trimmed for example...'; // this could be whatever you need it to be
$request = $request->withAttribute('PATH_INFO', $info);
return $handler->handle($request);
}
}
// Add middleware to all routes
$app->add(PathInfoMiddleware::class);
// Use the attribute in a route
$app->get('/pathinfo', function(Request $request, Response $response){
$response->getBody()->write($request->getAttribute('PATH_INFO'));
return $response;
});
Now visiting /pathinfo gives the following output:
some value, path_trimmed for example...
How do I tell my API to display a particular result based on another column?
e.g. localhost:8000/api/gadgets/{{id}}
Normally it returns the particular information of the specific gadget with that ID and localhost:8000/api/gadgets/{{imei_code}} does not return any value or an error whereas imei_code is a column that I needed to pass as a GET request...
I'm using the normal resource controller
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response($response, 200);
}
Also I need help on how I can create like a search function in the controller.
You can`t do two similar URLs. I think your route for URL
localhost:8000/api/gadgets/{{imei_code}}
isn`t work. Also the order of the routes is important and route that defined firstly will be have higer priority then route that defined secondly.
Because your routes /api/gadgets/{{id}} and /api/gadgets/{{imei_code}} is similar in this case only the one described earlier will be processed.
You can define another router and handler, for example:
localhost:8000/api/gadgets
That will return a list of gadgets by default and you can add filters for imei_code. For example:
localhost:8000/api/gadgets?imei_code=123
And your handler for the new route may be writed something like that:
public function showList(Request $request): GadgetResource
{
if ($imeiCode = $request->query('imei_code')) {
$list = Gadget::query()->where('imei_code', $imeiCode)->get();
} else {
$list = Gadget::query()->take(10)->get();
}
return GadgetResource::collection($list);
}
Or like alternative solution you can create diferent route for searching of gadgets exactly by imei_code to get rid of any route conflicts
localhost:8000/api/gadgets/by_imei/123
public function findByImei(Request $request): GadgetResource
{
$imeiCode = $request->route('imei_code');
$item = Gadget::query()->where('imei_code', $imeiCode)->first();
return new GadgetResource($item);
}
You can specify the model key by scoping - check docs
Route::resource('gadgets', GadgetController::class)->scoped([
'gadget' => 'imei_code'
]);
Than, when Laravel try to bind Gadget model in Controller - model will will be searched by key imei_code.
This code equvalent of
Route::get('/gadget/{gadget:imei_code}');
Try to change response
public function show(Gadgets $gadget)
{
$response = ['data' => new GadgetResource($gadget), 'message' => 'specific gadget'];
return response()->json($response);
}
When pressing my send button it's giving error like this-
Here is my routes web.php bellow-
Route::group(['prefix'=>'ajax', 'as'=>'ajax::'], function() {
Route::resource('message/send', 'MessageController#ajaxSendMessage')->name('message.new');
Route::delete('message/delete/{id}', 'MessageController#ajaxDeleteMessage')->name('message.delete');
});
Here is my controller MessageController.php bellow:
public function ajaxSendMessage(Request $request)
{
if ($request->ajax()) {
$rules = [
'message-data'=>'required',
'_id'=>'required'
];
$this->validate($request, $rules);
$body = $request->input('message-data');
$userId = $request->input('_id');
if ($message = Talk::sendMessageByUserId($userId, $body)) {
$html = view('ajax.newMessageHtml', compact('message'))->render();
return response()->json(['status'=>'success', 'html'=>$html], 200);
}
}
}
Resource routes should be named differently:
Route::prefix('ajax')->group(function () {
Route::resource('messages', 'MessageController', ['names' => [
'create' => 'message.new',
'destroy' => 'message.destroy',
]]);
});
Resource routes also point to a controller, instead of a specific method. In MessageController, you should add create and destroy methods.
More info at https://laravel.com/docs/5.4/controllers#restful-naming-resource-routes
You can't name a resource. Laravel by default name it, if you want to name all routes you must specify each one explicitly. It should be like this:
Route::group(['prefix'=>'ajax', 'as'=>'ajax::'], function() {
Route::get('message/send', 'MessageController#ajaxSendMessage')->name('message.new');
Route::delete('message/delete/{id}', 'MessageController#ajaxDeleteMessage')->name('message.delete');
});
Update
Another mistake of yours was trying to resource a single method. A Route::resource() is used to map all basic CRUD routes in Laravel by default. Therefore, you have to pass the base route and the class i.e:
<?php
Route::resource('message', 'MessageController');
Look at web.php line 28.
Whatever object you think has a name() method, hasn't been set, therefore you try and call a method on null.
Look before that line and see where it is (supposed to be) defined, and make sure it is set to what it should be!
So the title describes my problem pretty well I think, but let me explain why I want to do this as theremight be an other solution to my problem that I haven't thought about.
Let's say that I have a route specifying the class of the object it will patch:
Route::patch('{class}/{id}', array(
'as' => 'object.update',
function ($class, $id) {
$response = ...;
// here I want to call the update action of the right controller which will
// be named for instance CarController if $class is set to "car")
return $response;
}
));
This is something pretty easy to do with $app->make($controllerClass)->callAction($action, $parameters); but doing it this way won't call the filters set on the controller.
I was able to do it with laravel 4.0 with the callAction method, passing the app and its router, but the method has changed now and the filters are called in the ControllerDispatcher class instead of the Controller class.
If you have routes declared for your classes then you may use something like this:
$request = Request::create('car/update', 'POST', array('id' => 10));
return Route::dispatch($request)->getContent();
In this case you have to declare this in routes.php file:
Route::post('car/update/{id}', 'CarController#update');
If you Use this approach then filters will be executed automatically.
Also you may call any filter like this (not tested but should work IMO):
$response = Route::callRouteFilter('filtername', 'filter parameter array', Route::current(), Request::instance());
If your filter returns any response then $response will contain that, here filter parameter array is the parameter for the filter (if there is any used) for example:
Route::filter('aFilter', function($route, $request, $param){
// ...
});
If you have a route like this:
Route::get('someurl', array('before' => 'aFilter:a_parameter', 'uses' => 'someClass'));
Then the a_parameter will be available in the $param variable in your aFilter filter's action.
So I might have found a solution to my problem, it might not be the best solution but it works. Don't hesitate to propose a better solution!
Route::patch('{class}/{id}', array(
'as' => 'object.update',
function ($class, $id) {
$router = app()['router']; // get router
$route = $router->current(); // get current route
$request = Request::instance(); // get http request
$controller = camel_case($class) . 'Controller'; // generate controller name
$action = 'update'; // action is update
$dispatcher = $router->getControllerDispatcher(); // get the dispatcher
// now we can call the dispatch method from the dispatcher which returns the
// controller action's response executing the filters
return $dispatcher->dispatch($route, $request, $controller, $action);
}
));
I am currently trying to create a link on the index page that'll allow users to create an item. My routes.php looks like
Route::controller('items', 'ItemController');
and my ItemController looks like
class ItemController extends BaseController
{
// create variable
protected $item;
// create constructor
public function __construct(Item $item)
{
$this->item = $item;
}
public function getIndex()
{
// return all the items
$items = $this->item->all();
return View::make('items.index', compact('items'));
}
public function getCreate()
{
return View::make('items.create');
}
public function postStore()
{
$input = Input::all();
// checks the input with the validator rules from the Item model
$v = Validator::make($input, Item::$rules);
if ($v->passes())
{
$this->items->create($input);
return Redirect::route('items.index');
}
return Redirect::route('items.create');
}
}
I have tried changing the getIndex() to just index() but then I get a controller method not found. So, that is why I am using getIndex().
I think I have set up my create controllers correctly but when I go to the items/create url I get a
Unable to generate a URL for the named route "items.store" as such route does not exist.
error. I have tried using just store() and getStore() instead of postStore() but I keep getting the same error.
Anybody know what the problem might be? I don't understand why the URL isn't being generated.
You are using Route::controller() which does generate route names as far as I know.
i.e. you are referring to "items.store" - that is a route name.
You should either;
Define all routes specifically (probably best - see this blog here)
Use Route::resource('items', 'ItemController'); see docs here
If you use Route::resource - then you'll need to change your controller names
The error tells you, that the route name is not defined:
Unable to generate a URL for the named route "items.store" as such route does not exist.
Have a look in the Laravel 4 Docs in the Named Routes section. There are several examples that'll make you clear how to use these kind of routes.
Also have a look at the RESTful Controllers section.
Here's an example for your question:
Route::get('items', array(
'as' => 'items.store',
'uses' => 'ItemController#getIndex',
));
As The Shift Exchange said, Route::controller() doesn't generate names, but you can do it using a third parameter:
Route::controller( 'items',
'ItemController',
[
'getIndex' => 'items.index',
'getCreate' => 'items.create',
'postStore' => 'items.store',
...
]
);