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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 11:26:42  来源:igfitidea点击:

Laravel 5 return JSON or View depends if ajax or not

phplaravelcontrollerlaravel-5

提问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.phpwhich will check if request is AJAX and return if true or continue with original behavior return parent::make($view, $data, $mergeData);in MyViewFactory.phpline 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);
    }