How to do restful ajax routes to methods in Laravel 5? - php

So I have a route that looks like this:
Route::any('some/page', ['as' => 'some-page', 'uses' => 'SomePageController#index']);
However, I also have ajax calls at the same URL (using a request parameter called ajax like: some/page/?ajax=my_action) that I want to hit methods on my controller:
index already routes: 'SomePageController#index'
ajax = my_action needs to route: 'SomePageController#ajaxMyAction'
ajax = my_other_action needs to route: 'SomePageController#ajaxMyOtherAction'
ajax = blah_blah needs to route: 'SomePageController#ajaxBlahBlah
...
What's the elegant solution to setting this up in my routes.php file?

After inspection of Laravel's Http Request and Route classes, I found the route() and setAction() methods could be useful.
So I created a middleware to handle this:
<?php namespace App\Http\Middleware;
class Ajax {
public function handle($request, Closure $next)
{
// Looks for the value of request parameter called "ajax"
// to determine controller's method call
if ($request->ajax()) {
$routeAction = $request->route()->getAction();
$ajaxValue = studly_case($request->input("ajax"));
$routeAction['uses'] = str_replace("#index", "#ajax".$ajaxValue, $routeAction['uses']);
$routeAction['controller'] = str_replace("#index", "#ajax".$ajaxValue, $routeAction['controller']);
$request->route()->setAction($routeAction);
}
return $next($request);
}
}
Now my route looks like:
Route::any('some/page/', ['as' => 'some-page', 'middleware'=>'ajax', 'uses' => 'SomePageController#index']);
And correctly hits my controller methods (without disturbing Laravel's normal flow):
<?php namespace App\Http\Controllers;
class SomePageController extends Controller {
public function index()
{
return view('some.page.index');
}
public function ajaxMyAction(Requests\SomeFormRequest $request){
die('Do my action here!');
}
public function ajaxMyOtherAction(Requests\SomeFormRequest $request){
die('Do my other action here!');
}
...
I think this is a fairly clean solution.

You can't make this dispatch in the routing layer if you keep the same URL. You have two options :
Use different routes for your AJAX calls. For example, you can prefix all your ajax calls by /api. This is a common way :
Route::group(['prefix' => 'api'], function()
{
Route::get('items', function()
{
//
});
});
If the only different thing is your response format. You can use a condition in your controller. Laravel provides methods for that, for example :
public function index()
{
$items = ...;
if (Request::ajax()) {
return Response::json($items);
} else {
return View::make('items.index');
}
}
You can read this http://laravel.com/api/5.0/Illuminate/Http/Request.html#method_ajax and this http://laravel.com/docs/5.0/routing#route-groups if you want more details.

Related

how to redirect properly using a global middleware in Laravel?

I created a custom middleware to redirect short urls to other urls, I have a Url model that has this information:
{
"id":1,
"original_url":"http://www.google.com",
"short_url":"http://127.0.0.1:8000/wGjxw",
"updated_at":"2023-02-08T21:05:39.000000Z",
"created_at":"2023-02-08T21:05:39.000000Z"
}
so I have created a middleware:
<?php
namespace App\Http\Middleware;
use App\Models\Url;
use Closure;
use Illuminate\Http\Request;
class RedirectMiddleware
{
public function handle(Request $request, Closure $next)
{
//dd('here'); // is not reaching this code
$url = Url::where('short_url', $request->fullUrl())->first();
if ($url) {
return response()->redirectTo($url->original_url);
}
return $next($request);
}
}
app/Http/Kernel.php
....
....
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\RedirectMiddleware::class,
...
...
But, when I hit the url http://127.0.0.1:8000/wGjxw I get a 404 error,
This is the web.php
Route::get('/', function () {
return view('main');
});
Route::post('/urls', [UrlsController::class, 'store'] );
These routes are for showing the page with the form, and for creating the short url and those are working properly, the problem is that it looks like the middleware is not registered or I don't know what is happening, what I want is the short_url gets redirected to the original_url, what can I do? thanks
If the middleware approach isn't working, you could make a route specifically for it using route model binding with short_url as the key.
https://laravel.com/docs/9.x/routing#customizing-the-key
Route::get('/{url:short_url}', fn (Url $url) => redirect()->away($url->original_url));
My error was that the middleware was in the $middlewareGroups property, and it should be in the $middleware property, now it is working properly

How can you create wildcard routes on Lumen?

Let's say I have a controller called TeamsController. Controller has following method, that returns all teams user has access to.
public function findAll(Request $request): JsonResponse
{
//...
}
Then I have bunch of other controllers with the same method. I would like to create a single route, that would work for all controllers, so I would not need to add a line for each controller every time I create a new controller.
I am unable to catch the controller name from URI. This is what I have tried.
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
// This works
//$router->get('teams', 'TeamsController#findAll');
// This just returns TeamsController#findAll string as a response
$router->get('{resource}', function ($resource) {
return ucfirst($resource) . 'Controller#findAll';
});
});
You return a string instead of calling a controller action:
I believe Laravel loads the controllers this way (not tested)
$router->group(['middleware' => 'jwt.auth'], function () use ($router) {
$router->get('{resource}', function ($resource) {
$app = app();
$controller = $app->make('\App\Http\Controllers\'. ucfirst($resource) . 'Controller');
return $controller->callAction('findAll', $parameters = array());
});
});
But again, I don't really think it's a good idea.

Laravel Routing Group - use value in Controller

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());
}

PHP Laravel protected route for subpage without authentication

I'm building a Laravel-app and I have a route where I need to include a third-party script/iframe. I want to protect that route with a simple access code without setting up the laravel-authentication.
Is that possible? If so, how can I achieve that?
All solutions I give below suggest you are trying to access your route with code=X URI/GET parameter.
Simple Route
You can simply check for the given code to be correct in each route's method, and redirect somewhere if that's not the case.
web.php
Route::get('yourRouteUri', 'YourController#yourAction');
YourController.php
use Request;
class YourController extends Controller {
public function yourAction(Request $request) {
if ($request->code != '1234') {
return route('route-to-redirect-to')->redirect();
}
return view('your.view');
}
}
Route with middleware
Or you can use middlewares for avoiding to repeat the condition-block in each route if you have many of them concerned by your checking.
app/Http/Middleware/CheckAccessCode.php
namespace App\Http\Middleware;
use Request;
use Closure;
class CheckAccessCode
{
public function handle(Request $request, Closure $next)
{
if ($request->code != '1234') {
return route('route-to-redirect-to')->redirect();
}
return $next($request);
}
}
app/Http/Kernel.php
// Within App\Http\Kernel Class...
protected $routeMiddleware = [
// Other middlewares...
'withAccessCode' => \App\Http\Middleware\CheckAccessCode::class,
];
web.php
Route::get('yourRouteUri', 'YourController#yourAction')->middleware('withAccessCode');
You can create your own middleware.
Register the middleware in the $routesMiddleware of your app/Http/Kernel.php file.
Then use it like this:
Route::get('script/iframe', 'YourController#index')->middleware('your_middleware');
-- EDIT
You can access the route like this:
yoururl.com/script/iframe?code=200
Then in the middleware handle method:
if ($request->code !== 200) {
// you don't have access redirect to somewhere else
}
// you have access, so serve the requested page.
return $next($request);

Laravel: How does Controller access parameters from Route?

I am very obviously a noob to Laravel and hope that someone can help me out.
The about screen is accessed through the route
Route::get('/about', array('as' => 'about', function()
{
return View::make('about')->with('title','About Screen')->with('class','about');
}));
The variables $title and $class are accessible in about.blade.php by {{ $title }} and {{ $class }}. If instead, I have a Controller in between,
Route::get('hello/create', array('as' => 'create', 'uses' =>
'HelloController#create', function()
{
return View::make('hello/create')->with('title','Create')->with('class','hello.create');
}));
How do I access $title and $class in the HelloController.php code (so that I can propagate the values to the coming View)?
P.S. I do know about the /hello/create/{name of variable} which is the answer on nearly all questions similar to this, but don't know how to use it to transmit variables NOT keyed onto the Http Request.
$title and $class are the values you are manually giving to the blade. These aren't the values that you are receiving in GET parameters in your route. So, you would do it the same way as you did in the closure.
Your route:
Route::get('hello/create', array('as' => 'create', 'uses' => 'HelloController#create'));
Controller method:
class HelloController{
public function create(){
return View::make('hello/create')->with('title','Create')->with('class','hello.create');
}
}
UPDATE:
From what I understood, you can also call controller's method inside the route's closure and pass parameters to the controller and call the view with these values inside the controller's method.
Your route file:
use App\Http\Controllers\HelloController;
Route::get('hello/create',function(){
$hello_obj = new HelloController();
return $hello_obj->create('create','hello.create');
});
Controller method:
class HelloController{
public function create($title,$class){
return View::make('hello/create')->with('title',$title)->with('class',$class);
}
}
First you need to clear your flow. You are -at the moment- manually setting the variables to be returnet to the view, so your route should look like this:
Route::get('hello/create', 'HelloController#create');
Then, your controller handles the logic:
public function create(Request $request)
{
return view('hello.create')->with('title','Create')->with('class','hello.create');
}
Now, if you need to send parameters from your frontend to your controller, you have two options:
Define route parameters.
Use query params.
Option 1
For the first option, you'll need to define your required/optional parameters in the route itselft:
Route::get('hello/create/{a_variable}', 'HelloController#create');
Then you access this parameter in any of this ways:
public function create(Request $request)
{
return view('hello.create')->with('a_variable', $request->a_variable);
}
or injecting the variable in the method:
public function create(Request $request, $a_variable)
{
return view('hello.create')->with('a_variable', $a_variable);
}
Option 2
For the use of query params, you should include this options when making the request. If your route looks like this:
Route::get('hello/create', 'HelloController#create');
You could specify query params like this:
GET www.my-domain.com/hello/create?first_parameter=value_1&second_parameter=value_2
So in your controller you access this values like this:
public function create(Request $request)
{
$value_1 = $request->get('first_parameter');
$value_2 = $request->get('second_parameter');
return view('hello.create')
->with('value_1', $value_1)
->with('value_2', $value_2);
}
You are alreading sending data to view using with().
Echo it in your view file using $variablename set in with() Example: <?php echo $title; ?>

Categories