Laravel

This guide describes the integration of CKBox in a Laravel application. If you prefer to jump straight to the code, you can find the complete code of the application described in this guide on GitHub.

# Prerequisites

Before we start, please ensure that you have composer installed in your system. If the tool is not available from the command line, please follow Composer’s installation instructions first.

# Creating the application

As a base in our example, we will create a new Laravel project using the Composer create-project command:

composer create-project laravel/laravel ckbox-laravel-example

After the project is created, you can enter the directory and start the development server:

cd ckbox-laravel-example
php artisan serve

The application will be available under http://127.0.0.1:8000.

# Creating the controller

First, let’s create a controller. The controller will contain two actions: one for displaying the HTML content of the example and the second one for serving the token URL, used to authenticate users in CKBox.

# Token URL

CKBox, like other CKEditor Cloud Services, uses JWT tokens for authentication and authorization. All these tokens are generated on your application side and signed with a shared secret that you can obtain in the CKEditor Ecosystem dashboard. For information on how to create access credentials, please refer to the Creating access credentials article in the Authentication guide

Now that we have the required access credentials, namely: the environment ID and the access key, let’s create the token endpoint. As a base, we will use the code of the generic token endpoint in PHP.

First, let’s install the firebase/php-jwt library for creating JWT tokens:

composer require firebase/php-jwt

As a base, we will use the code of the generic token endpoint in PHP. Let’s wrap the logic of the PHP token endpoint in Laravel action and generate a token with the payload required by CKBox.

# Complete controller code

// app/Http/Controllers/CKBoxExampleController.php

namespace App\Http\Controllers;

use \Firebase\JWT\JWT;
use Illuminate\Http\Response;
use Illuminate\View\View;

class CKBoxExampleController extends Controller
{
    /**
     * Show the CKBox example.
     */
    public function show(string $example = null): View
    {
        if (in_array($example, ['ckeditor', 'modal', 'full-page'])) {
            return view('ckbox-example-' . $example);
        }

        return view('ckbox-example-list');
    }

    /**
     * Create CKBox JWT token.
     */
    public function token(): Response
    {
        $environmentId = env('CKBOX_ENVIRONMENT_ID');
        $accessKey = env('CKBOX_ACCESS_KEY');

        $payload = [
            'aud' => $environmentId,
            'iat' => time(),
            'sub' => 'unique-user-id', // Unique user ID in your application
            'auth' => [
                'ckbox' => [
                    'role' => 'superadmin',
                ]
            ]
        ];

        $jwtToken = JWT::encode($payload, $accessKey, 'HS256');

        return new Response($jwtToken);
    }
}

As you can see on the code listing above, the access credentials required to sign JWT tokens are obtained from the environment variables. Thanks to this, you can conveniently add them to the .env file:

# .env
CKBOX_ENVIRONMENT_ID=REPLACE-WITH-ENVIRONMENT-ID
CKBOX_ACCESS_KEY=REPLACE-WITH-ACCESS-KEY

Now, let’s register the required routes:

// routes/web.php

use App\Http\Controllers\CKBoxExampleController;
use Illuminate\Support\Facades\Route;

Route::get('/ckbox/token', [CKBoxExampleController::class, 'token'])->name('ckbox_token');
Route::get('/{example?}', [CKBoxExampleController::class, 'show'])->name('ckbox_example');

# Adding CKBox script to the page

CKBox can be embedded in the application in multiple ways. For simplicity, in our example, we will use the CKBox script served from the CDN.

Examples in this guide will cover three popular scenarios of using CKBox:

  • CKBox integrated with CKEditor
  • CKBox used as a file picker in dialog mode
  • CKBox used as a full-page application

To avoid code repetition, let’s prepare a base Blade template that includes CKBox script, which we will reuse in all three examples:

<!-- resources/views/ckbox-example-layout.blade.php -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8"/>
        <script src="https://cdn.ckbox.io/ckbox/2.5.1/ckbox.js"></script>
        @stack('head')
        <title>CKBox example</title>
    </head>
    <body>
    @yield('content')
    </body>
</html>

Now, let’s add views for the three examples.

# CKBox with CKEditor 5

In this example, we will use the quickest and easiest way to run CKEditor 5 – served from the CDN. For more advanced integration scenarios, please refer to the CKEditor 5 documentation.

Let’s create the child view that extends the layout we have created in the previous step:

<!-- resources/views/ckbox-example-ckeditor.blade.php -->
@extends('ckbox-example-layout')

@push('head')
    <script type="importmap">
        {
            "imports": {
                "ckeditor5": "https://cdn.ckeditor.com/ckeditor5/42.0.0/ckeditor5.js",
                "ckeditor5/": "https://cdn.ckeditor.com/ckeditor5/42.0.0/"
            }
        }
    </script>
    <link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/42.0.0/ckeditor5.css" />
@endpush

@section('content')
    <textarea id="editor"><?php echo htmlspecialchars('<h1>Example</h1><p>Hello world</p>'); ?></textarea>

    <script type="module">
        import {
            ClassicEditor,
            CKBox,
            Essentials,
            Bold,
            Italic,
            Font,
            Paragraph
        } from 'ckeditor5';

        ClassicEditor
            .create( document.querySelector( '#editor' ), {
                plugins: [ CKBox, Essentials, Bold, Italic, Font, Paragraph ],
                ckbox: {
                    tokenUrl: 'https://your.token.url',
                    theme: 'lark'
                },
                toolbar: [
                    'ckbox', '|', 'undo', 'redo', '|', 'bold', 'italic', '|',
                    'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor'
                ],
            } )
            .catch( error => {
                console.error( error );
            } );
    </script>
@endsection

The above example includes a predefined CKEditor build from the CDN, which includes the required CKBox plugin. Then, CKEditor is configured to use CKBox by setting the required parameters of the ckbox attribute. Please note that in the ckbox.tokenUrl configuration option we pass the URL of the token endpoint created in one of the previous steps, which will be used to obtain JWT tokens used to authenticate users in CKBox.

# CKBox as file picker

One of the common scenarios is to use CKBox as a file picker, where the user can choose one of the files stored in the file manager. After choosing the file, we want to obtain information about the chosen files, especially their URLs. This can be achieved using the assets.onChoose callback passed as the CKBox’s configuration option:

<!-- resources/views/ckbox-example-modal.blade.php -->
@extends('ckbox-example-layout')

@section('content')
    <input type="text" id="file-url"></input><button id="choose">Choose file</button>
    <div id="ckbox"></div>
    <script>
        document.getElementById('choose').addEventListener('click', function () {
            CKBox.mount(document.querySelector('#ckbox'), {
                tokenUrl: '{{ route('ckbox_token') }}',
                dialog: true,
                assets: {
                    // Callback executed after choosing assets
                    onChoose: (assets) => {
                        document.getElementById('file-url').value = assets[0].data.url;

                        assets.forEach((asset) => {
                            console.log(asset.data.url);
                        })
                    }
                }
            });
        });
    </script>
@endsection

# CKBox in full-page mode

To start CKBox in full-page mode, you can attach it to the document.body and adjust the required CSS styles:

@extends('ckbox-example-layout')

@push('head')
    <style>
        html, body {
            margin: 0;
            padding: 0;
            height: 100vh;
        }
    </style>
@endpush

@section('content')
    <script>
        CKBox.mount(document.body, {
            tokenUrl: '{{ route('ckbox_token') }}'
        });
    </script>
@endsection

# Complete code

On GitHub, you can find the complete code of the application described in this guide.