This site is built with Viewi itself. It is experimental and still in development. If you see any bugs please do not hesitate and open an issue or DM me on Twitter.

Laravel Integration

Laravel

You can find the source code here ivanvoitovych/viewi-laravel. And here ivanvoitovych/viewi-laravel-demo.

Basic concept and application flow

This example shows you how to build a basic Laravel application that handles all HTTP requests, and dispatches the calls through routes to your Viewi application. Viewi then renders the html response and returns it back to Laravel to be emitted to the web browser.

For server side rendering Viewi application will catch api calls and directly process them via your Laravel application.

Installation and setup

Install and prepare Laravel

Install Laravel adapter for Viewi

composer require viewi-lib/viewi-laravel

Create a demo app

vendor/bin/viewi new -e -a

Include Viewi routes

In routes\web.php include your Viewi app
require __DIR__ . '/../viewi-app/viewi.php';

All done, you are ready to go.

Adapter under the hood

The adapter is doing two things:

- Registers Viewi routes in Laravel in order to intercept Viewi components.

- Handles internal API requests for server-side rendering (SSR) and returns the data back to Viewi component in its original state.

For example, in this component, your callback expects it to be PostModel:

$http->get('/api/posts/5')->then(function (PostModel $data) {
    $this->post = $data;
}, function ($error) {
    echo $error;
});

For that your Response should preserve the original data returned from the API call. Important thing: fully typed instances are only supported on server side during SSR. Javascript doesn't support types.

Route::get('/posts/{id}', function ($id) {
    $postModel          = new PostModel();
    $postModel->Id      = (int)$id;
    $postModel->Name    = 'Laravel ft. Viewi';
    $postModel->Version = 1;
    return new JsonResponse($postModel);
});

The adapter itself:

<?php

namespace ViewiLaravel\Adapters;

use App\Http\Kernel;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Viewi\Routing\RouteAdapterBase;
use Illuminate\Support\Facades\Route;
use Symfony\Component\HttpFoundation\Response;

class ViewiLaravelAdapter extends RouteAdapterBase
{
    public function register($method, $url, $component, $defaults)
    {
        $action = function (Request $request) use ($component) {
            return (new $component)($request->route()->parameters());
        };
        if ($url === '*') {
            Route::fallback($action);
        } else {
            $route = Route::match([$method], $url, $action);
            if ($defaults !== null) {
                $route->setDefaults($defaults);
            }
            $route->name(trim($url," /"));
        }
    }

    public function handle($method, $url, $params = null)
    {
        $request = Request::create($url, strtoupper($method), [], $_COOKIE);
        $kernel = resolve(Kernel::class);
        $response = $kernel->handle($request);
        if ($response instanceof JsonResponse) {
            return $response->original;
        } else {
            /** @var Response $response */
            return $response->getContent();
        }
    }
}

What it does:

  • register($method, $url, $component, $defaults): void delegates routes information from Viewi to your Laravel application.
  • handle($method, $url, $params = null) is being invoked during server side rendering when the component uses HttpClient to get the data from the server.
    It creates a virtual (fake) request and runs it through your Laravel application as it would be any regular request from a browser.
    It's here where we need our original data without modifications:
    return $response->original

To make things easier to install, let's create a Service Provider:

<?php

namespace ViewiLaravel\Providers;

use Illuminate\Support\ServiceProvider;
use Viewi\Routing\Route as ViewiRoute;
use ViewiLaravel\Adapters\ViewiLaravelAdapter;

class ViewiServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        $adapter = new ViewiLaravelAdapter();
        ViewiRoute::setAdapter($adapter);
    }
}

And to make Laravel install this Service Provider for you, let's define it in composer.json extras:

"extra": {
        "laravel": {
            "providers": [
                "ViewiLaravel\\Providers\\ViewiServiceProvider"
            ]
        }
    }

After the installation, you just need to include Viewi app after your Laravel routes:

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

// No need, Viewi will intercept this url
// Route::get('/', function () {
//     return view('welcome');
// });

// include viewi app with routes here after all Laravel routes
require __DIR__ . '/../viewi-app/viewi.php';

And that's it. Thank you and feel free to reach out for help if you need any.