Hooking into Laravel

Because Codice is based on the Laravel framework, an important part of the Plugin API is just to define a bridge between your plugin and underlying framework code. In this chapter we will demonstrate how to extend Codice with your own routes, controllers, models, views, language files and even database migrations.

Theory: namespaces

Apart from PHP namespace convention mentioned in context of defining main plugin class (CodicePlugin\{StudlyIdentifier}), Laravel also has it's own kind of namespaces for framework-specific assets, like views or language files. Their purpose is exactly the same – to prevent collisions between application's and third party code (such as plugins).

Laravel namespace for your plugin will be its raw identifier and the separator is ::. For example, note how views and language lines are referenced in code samples below.


If you want your plugin to define any routes, create routes.php in its directory. Any route defined inside this file will automagically be placed within a route group with CodicePlugin\{StudlyIdentifier}\Controllers as the namespace.

Let's create basic route for our Upcoming tasks plugin.

Route::get('upcoming', ['as' => 'upcoming', 'uses' => 'UpcomingController@getIndex']);


Autoloading in Codice adheres to PSR-4 standard so our controller must be saved in plugins/docs-upcoming/Controllers/UpcomingController.php.


namespace CodicePlugin\DocsUpcoming\Controllers;

use Carbon\Carbon;
use Codice\Http\Controllers\Controller;
use Codice\Note;

class UpcomingController extends Controller
    public function __construct()

    public function getIndex()
        $notes = Note::mine()
            ->where('expires_at', '>', Carbon::now())
            ->where('status', '0')
            ->orderBy('expires_at', 'asc')

        return view('docs-upcoming::upcoming', [
            'notes' => $notes,

As you can see, it is a regular Laravel controller. We started with applying auth middleware in the constructor (it can be done in route definition, if you want).

The most important part is the Eloquent query. We fetch notes using custom Codice's mine() scope, which only fetch items for currently logged in user. Then we join labels table, require expiration time to be greater than now, status to be undone and sort results.

Check out core models inside /app and you should use to it very quickly.

Last thing we do is to pass data into the view. Do note docs-upcoming:: part in its name. This is Laravel namespace.


Views prefixed with plugin-identifier:: should be placed in /plugins/plugin-identifier/views, so the full path for our view will be /plugins/docs-upcoming/views/upcoming.blade.php.


    <h2 class="page-heading">@lang('docs-upcoming::main.title')</h2>

    @each('note.single', $notes, 'note', 'note.none')

Once again, this view is nothing special. Moreover, we basically reference other views provided by Codice. app being the main template for the authenticated user and views meant for displaying notes conveniently inside the @each directive.

Language files

As you probably noticed, we referenced translation way using same method as for views. The core will look for it in /plugins/docs-upcoming/lang/{LOCALE}/main.php and then title key.

Place this content in lang/en/main.php to support default Codice's language:


return [
    'title' => 'Upcoming tasks',

You can of course provide other languages, such as Polish (lang/pl/main.php):


return [
    'title' => 'Nadchodzące zadania',


Even though our sample plugin does not provide any models, adding them is pretty straightforward. Knowing that plugin files are PSR-4 autoloaded, you only need to create a model class somewhere inside the plugin directory and then use it. As in the Laravel itself, there is no specific directory for models, althought you can create one — just remember to reflect that ins the namespace.


Plugins can provide database migrations as well. There is no CLI helper for creating them yet, so remember that their order is determined by the filename. You probably just want to prefix them with current datetime, as Laravel does.

Migrations are applied (up()) on plugin install and rolled back (down()) when it's uninstalled (not disabled) — it's simple as that.

Remember to always provide down() method, do it well. Do not let your plugin to leave cluttered (or worse, corrupted) database after uninstallation. Be civilized and revert any changes you've made.

The last thing we are going to do is adding our page to the menu. The process has been described in Other APIs chapter.