Laravel 5 返回 JSON 或 View 取决于是否使用 ajax
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29868903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Laravel 5 return JSON or View depends if ajax or not
提问by zeomega
I would like to know if there is a magic method to use this scenario :
我想知道是否有使用这种场景的神奇方法:
If I call a page via an AJAX request the controller returns a JSON object, otherwise it returns a view, i'm trying to do this on all my controllers without changin each method.
如果我通过 AJAX 请求调用一个页面,控制器返回一个 JSON 对象,否则它返回一个视图,我试图在我所有的控制器上执行此操作而不更改每个方法。
for example i know that i can do this :
例如,我知道我可以这样做:
if (Request::ajax()) return compact($object1, $object2);
else return view('template', compact($object, $object2));
but I have a lot of controllers/methods, and I prefer to change the basic behavior instead of spending my time to change all of them. any Idea ?
但我有很多控制器/方法,我更喜欢改变基本行为,而不是花时间去改变所有这些。任何的想法 ?
回答by ryanwinchester
The easiest way would be to make a method that is shared between all of your controllers.
最简单的方法是创建一个在所有控制器之间共享的方法。
Example:
例子:
This is your controller class that all other controllers extend:
这是所有其他控制器扩展的控制器类:
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
abstract class Controller extends BaseController
{
protected function makeResponse($template, $objects = [])
{
if (\Request::ajax()) {
return json_encode($objects);
}
return view($template, $objects);
}
}
And this is one of the controllers extending it:
这是扩展它的控制器之一:
<?php namespace App\Http\Controllers;
class MyController extends Controller
{
public function index()
{
$object = new Object1;
$object2 = new Object2;
return $this->makeResponse($template, compact($object, $object2));
}
}
Update for Laravel 5+
Laravel 5+ 更新
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
protected function makeResponse($request, $template, $data = [])
{
if ($request->ajax()) {
return response()->json($data);
}
return view($template, $data);
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MyController extends Controller
{
public function index(Request $request)
{
$object = new Object1;
$object2 = new Object2;
return $this->makeResponse($request, $template, compact($object, $object2));
}
}
回答by panos
There is no magic but you can easily override ViewService in 3 steps:
没有魔法,但您可以通过 3 个步骤轻松覆盖 ViewService:
1.create your view factory (your_project_path/app/MyViewFactory.php
)
1.创建您的视图工厂 ( your_project_path/app/MyViewFactory.php
)
<?php
/**
* Created by PhpStorm.
* User: panos
* Date: 5/2/15
* Time: 1:35 AM
*/
namespace App;
use Illuminate\View\Factory;
class MyViewFactory extends Factory {
public function make($view, $data = array(), $mergeData = array())
{
if (\Request::ajax()) {
return $data;
}
return parent::make($view, $data, $mergeData);
}
}
2.create your view service provider (your_project_path/app/providers/MyViewProvider.php
)
2.创建您的视图服务提供者 ( your_project_path/app/providers/MyViewProvider.php
)
<?php namespace App\Providers;
use App\MyViewFactory;
use Illuminate\View\ViewServiceProvider;
class MyViewProvider extends ViewServiceProvider {
/**
* Register the application services.
*
* @return void
*/
public function register()
{
parent::register();
}
/**
* Overwrite original so we can register MyViewFactory
*
* @return void
*/
public function registerFactory()
{
$this->app->singleton('view', function($app)
{
// Next we need to grab the engine resolver instance that will be used by the
// environment. The resolver will be used by an environment to get each of
// the various engine implementations such as plain PHP or Blade engine.
$resolver = $app['view.engine.resolver'];
$finder = $app['view.finder'];
// IMPORTANT in next line you should use your ViewFactory
$env = new MyViewFactory($resolver, $finder, $app['events']);
// We will also set the container instance on this view environment since the
// view composers may be classes registered in the container, which allows
// for great testable, flexible composers for the application developer.
$env->setContainer($app);
$env->share('app', $app);
return $env;
});
}
}
3.in your_project_path/config/app.php
:
change 'Illuminate\View\ViewServiceProvider',
to 'App\Providers\MyViewProvider',
3.in your_project_path/config/app.php
:'Illuminate\View\ViewServiceProvider',
改为'App\Providers\MyViewProvider',
What this do:
这是做什么的:
it tells your application to use another view provider which will register your view factory
$env = new MyViewFactory($resolver, $finder, $app['events']);
in line 33 of MyViewProvider.php
which will check if request is AJAX and return if true or continue with original behavior
return parent::make($view, $data, $mergeData);
in MyViewFactory.php
line 19
它告诉您的应用程序使用另一个视图提供程序,该提供程序将$env = new MyViewFactory($resolver, $finder, $app['events']);
在第 33 行注册您的视图工厂
,MyViewProvider.php
其中将检查请求是否为 AJAX,如果为真则返回或return parent::make($view, $data, $mergeData);
在MyViewFactory.php
第 19 行继续原始行为
Hope this help you,
希望这对你有帮助,
回答by bildstein
In laravel 5.1, this is the best way:
在 laravel 5.1 中,这是最好的方法:
if (\Illuminate\Support\Facades\Request::ajax())
return response()->json(compact($object1, $object2));
else
return view('template', compact($object, $object2));
回答by tomstig
The solution suggested by @ryanwinchester is really good. I, however, wanted to use it for the responses from update()
and delete()
, and there naturally return view()
at the end doesn't make a lot of sense as you mostly want to use return redirect()->route('whatever.your.route.is')
. I thus came up with that idea:
@ryanwinchester 建议的解决方案非常好。但是,我想将它用于来自update()
and的响应delete()
,并且自然而然地return view()
最后没有什么意义,因为您最想使用return redirect()->route('whatever.your.route.is')
. 于是我萌生了这个想法:
// App\Controller.php
/**
* Checks whether request is ajax or not and returns accordingly
*
* @param array $data
* @return mixed
*/
protected function forAjax($data = [])
{
if (request()->ajax()) {
return response()->json($data);
}
return false;
}
// any other controller, e.g. PostController.php
public function destroy(Post $post)
{
// all stuff that you need until delete, e.g. permission check
$comment->delete();
$r = ['success' => 'Wohoo! You deleted that post!']; // if necessary
// checks whether AJAX response is required and if not returns a redirect
return $this->forAjax($r) ?: redirect()->route('...')->with($r);
}