Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 5 return JSON or View depends if ajax or not

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.

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 ?

like image 740
zeomega Avatar asked Apr 25 '15 18:04

zeomega


2 Answers

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+

<?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));
    }
}
like image 198
ryanwinchester Avatar answered Oct 01 '22 01:10

ryanwinchester


There is no magic but you can easily override ViewService in 3 steps:

1.create your view factory (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)

<?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',

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

Hope this help you,

like image 30
panos Avatar answered Oct 01 '22 01:10

panos