Plugins

Extending the core

[Since 0.5.0]

Introduction

Postfix offers a powerful plugin system, which allows you to expand your application quickly by other features that the community has developed. Of course, you can also develop plugins themselves and provide the community.

You will see that this is not very complicated.

Installing Plugins

List Plugins

The help screen of the plugin command lists all enabled plugins.

php console plugin --help

Downloading

Like the Pletfix Application, a Pletfix plugin is also a Composer package. So it can be installed the same way.

For example, let's install the actual useless Pletfix hello plugin as below:

  1. We have not deployed our hello plugin on Packagist, the Composers default package archive. Therefore Composer cannot find the plugin if we don't say where it is. To do this, add this into your composer.json:

    "repositories": [ { "type": "git", "url": "git@github.com:pletfix/hello-plugin.git" } ],

    You can step over this point if you find the plugin on Pletfix Plugin List or on Packagist.

  2. Fetch the package by running the following terminal command:

    composer require pletfix/hello-plugin

Registering

After downloading, the plugin has to be registered.

For example, enter this command in your terminal to register our hello plugin:

php console plugin pletfix/hello-plugin 

If the plugin provides a migration file, you have to execute the migrate command after the registration procedure, it won't run automatically!

php console migrate

Updating

If the plugin is already installed, you cannot install it once more. But you can use the --update option to update the manifest files, for our hello plugin like so:

php console plugin pletfix/hello-plugin --update        

Removing

Use the --remove option to unregister the plugin. Again the example with our hello plugin:

php console plugin pletfix/hello-plugin --remove 

The plugin package remains in the vendor directory. So you can register the plugin at any time again.

Registration Procedure

When you register a plugin, the following things are happened:

Definition of a term: What exactly is the name of the plugin?

The name of the plug-in is the name of the package without a vendor, and if present, without "pletfix-" as prefix and "-plugin" as suffix.

1. Configuration

If available and if not already done, the configuration file of the plugin is copied to the config directory under the name of the plugin, e.g. config/hello.php for our Hello plugin.

|-myapp/
   |-config/
      |-hello.php

The configuration file will be not updated if it already exists. So you may customize the configuration as you wish.

Of course, you can read the configuration like all other configurations:

$geeting = config('hello.gretting');   

2. Public Files

If available, public files of the plugin will be copied into the application's public folder. For example, our hello plugin has one image file:

|-myapp/
   |-public/
      |-images/
         |-hello/
            |-key.gif

3. Assets

If available, the asset build file of the plugin will be added to the .manifest/plugins/assets.php manifest. After this the AssetManager publishes the assets of the plugin. For example, our hello plugin provides a hello.js
script which will be published to public/js/hello.js.

<?php return array (
  'hello' => 
  array (
    'js/hello.js' => 
    array (
      0 => 'vendor/pletfix/hello-plugin/assets/js/hello.js',
    ),
  ),
);

You may repeat publishing the assets manually if you enter this command in a terminal:

php console asset --plugin=hello

4. Commands

If available, the commands embedded in the plugin will be added to the .manifest/plugins/commands.php manifest.
The command factory reads this manifest if you enter php console to list all files.

<?php return array (
  'examples:hello' => 
  array (
    'class' => 'Pletfix\\Hello\\Commands\\HelloCommand',
    'name' => 'hello:greeting',
    'description' => 'Say Hello!',
  ),
);

You can execute the commands provided by plugins like all other commands:

php console hello:greeting

5. Migrations

If available, the migration files embedded in the plugin will be added to the .manifest/plugins/migrations.php manifest.

<?php return array (
  '20170204121100_CreateHelloTable' => 'vendor/pletfix/hello-plugin/migrations/20170204121100_CreateHelloTable.php',
);

Pletfix loads this manifest if you run the migration.

6. Language Files

If available, the language files of the plugin will be added to the .manifest/plugins/lang manifest.

<?php return array (
  'de' => 
  array (
    'hello' => 'vendor/pletfix/hello-plugin/lang/de.php',
  ),
  'en' => 
  array (
    'hello' => 'vendor/pletfix/hello-plugin/lang/en.php',
  ),
);

Pletfix loads this manifest for translating, so you may retrieve the translation entries from the plugin as follows, where the top key is the plugin name:

echo t('hello.greeting');

7. Views

If available, the path of the plugin's views will be added to the .manifest/plugins/views.php manifest. Pletfix needs this manifest to find the template for rendering.

<?php return array (
  'admin.hello' => 'vendor/pletfix/hello-plugin/views/welcome.blade.php',
);

For example, the hello plugin provides a view welcome.blade.php, so you may referred it as follows, where the top key is the plugin name:

return view('hello.welcome');

You can, of course, customize the views. To do this, create a subfolder named as the plugin under resources/views. Copy all files, that are stored under the plugin's view folder, into this subfolder. For example, the welcome view of our hello plugin have to stored like this:

|-myapp/
   |-resources/
      |-views/
         |-hello/
            |-welcome.blade.php

8. Controllers

If available, the controllers embedded by the plugin will be added to the .manifest/plugins/controllers.php manifest.

<?php return array (
  'HelloController' => 
  array (
    0 => 'Pletfix\\Hello\\Controllers\\HelloController',
  ),
);

Pletfix uses this manifest to find the controller, so you can reference the controllers in the routes without the full namespace unless the name is unique by the enabled plugins:

$route->get('hello', 'HelloController@index');

If the name of the controller without "My-Vender/My-Plugin/Controllers/" portion is not unique, you must use the fully qualified name:

$route->get('hello', '\Pletfix\Hello\Controllers\HelloController@index');

9. Middleware

If available, the middleware embedded by the plugin will be added to the .manifest/plugins/middleware.php manifest.

<?php return array (
  'Hello' => 
  array (
    0 => 'Pletfix\\Hello\\Middleware\\Hello',
  ),
);

As with the controllers, the middleware can also be referenced:

$route->middlware('Hello');

The same applies here, if the name of the middleware without "My-Vender/My-Plugin/Middlware/" portion is not unique, you must use the fully qualified name:

$route->middlware('\Pletfix\Hello\Middleware\Hello');

10. Drivers

All classes that stored in a subdirectory under the plugin's ./src/Drivers directory will be added to the .manifest/plugins/drivers.php manifest, grouped to the top subdirectory. Contracts (classes that are stored in a Contracts folder) are not listed.

<?php return array (
  'SocialMedia' => 
  array (
    'Dropbox' => 
    array (
      0 => 'Pletfix\\OAuth\\Drivers\\SocialMedia\\Dropbox',
    ),
    'Facebook' => 
    array (
      0 => 'Pletfix\\OAuth\\Drivers\\SocialMedia\\Facebook',
    ),
    'GitHub' => 
    array (
      0 => 'Pletfix\\OAuth\\Drivers\\SocialMedia\\GitHub',
    ),
  ),
);

So you can read all social media drivers provided by the enabled plugins as follows:

$drivers = include manifest_path('plugins/drivers.php');
$socials = isset($drivers['SocialMediaDriver']) ? $drivers['SocialMediaDriver'] : [];

11. Routes

If available, the embedded route entries will be added to the .manifest/plugins/routes.php manifest.

<?php

use Core\Services\Contracts\Route;

$route = \Core\Application::route();

///////////////////////////////////////////////////////////////////////////////
// pletfix/hello-plugin

$route->get('hello-service', function() {
    return di('hello')->sayHello();
});

$route->get('hello', 'HelloController@index', 'Hello');

When the application is started, the HTTP router loads this manifest.

You could overwrite this route entries in the application's route file boot/routes.php.

12. Services

If available, the services, provided by the plugin, will be added to the .manifest/plugins/services.php manifest.

<?php

$di = \Core\Services\DI::getInstance();

///////////////////////////////////////////////////////////////////////////////
// pletfix/hello-plugin

$di->set('hello', \Pletfix\Hello\HelloService::class, true);

The Dependency Injector loads this manifest when the application is started.

You could overwrite this entries in the application's service file boot/swervices.php.

13. Bootstraps

If available, the bootstraps, which the plugin includes, will be added to the .manifest/plugins/bootstrap.php manifest.

<?php

///////////////////////////////////////////////////////////////////////////////
// pletfix/hello-plugin

(new Pletfix\Hello\Bootstraps\Plugin)->boot();

The application loads this manifest when booting, see also Lifecycle Web Request

14. Enable Plugin

Finally, the plugin will be added to the .manifest/plugins/packages.php manifest to mark that the plugin has been registered successfully.

<?php return array (
  'pletfix/hello-plugin' => 'vendor/pletfix/hello-plugin',
);   

Writing Plugins

If you want to write your own plugin, follow the instructions on https://github.com/pletfix/hello-plugin to create a workbench with a fresh plugin skeleton. After this you are ready to add services, assets, commands or what ever you like.

If you preferred it, you could use "pletfix-" as prefix and "-plugin" as suffix for the plugin name. This parts are ignored while the registration procedure.

Assets

You may add assets to the plugin by creating the asset build file under assets/build.php.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-assets/
            |-js/
            |-css/
            |-build.php

Read chapter Assets to learn how the asset management works. The only difference to the assets of the application is that the asset build file is not stored under resources/assets, but in your plugin under assets directory.

Convention Notes

If possible, you should define a single javascript file and a single stylesheet file with the name of your plugin, provided of course, these are needed. For example, the build file of our hello plugin looks like below:

return [
   'js/hello.js' => [
       __DIR__ . '/js/greeting.js',
   ],
]; 

If your plugin needs multiple files, you can also use subfolders that are named as your plugin. Again, an example with our hello plugin:

return [
   'css/hello/greeting.css' => [
       __DIR__ . '/css/how-do-you-do.css',
       __DIR__ . '/css/good-day.css',
   ],
   'css/hello/bye.css' => [
       __DIR__ . '/css/bye.css',
   ],
]; 

Bootstraps

If you like to modify the boot process, write a class that inherit from Bootable and store the file under the plugin's src/Bootstraps directory:

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-src/
            |-Bootstraps/
                |-Whatever.php

The class implements a boot method that is executed while booting.

namespace Core\Bootstraps;

use Core\Services\DI;
use Core\Bootstraps\Contracts\Bootable;

class WhatEver implements Bootable
{
    /**
     * Bootstrap
     */
    public function boot()
    {
        // add code here 
    }
}

Commands

You may also add commands to your plugin. The right place for the class files is src/Commands:

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-src/
            |-Commands/
                |-WhateverCommand.php

Read chapter Commands to learn how you write commands.

Convention Notes To avoid naming conflicts with other plugins, you should use a command group named like your plugin. For example, our hello plugin includes a command hello:greeting which you can execute with the following command:

php console hello:greeting

Configuration

Of course, you can configure your plugin in a similar way as the application itself. Save the plugin's configuration under config.php:

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-config.php

The registration procedure copies the file into the config directory under the name of the plugin.

Read chapter Configuration to learn more about configuration and environment variables.

Controllers

Add your controllers into the plugin's src/Controllers directory:

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-src/
            |-Controllers/
               |-MyController.php

Read chapter Controllers to learn how you write controllers.

Convention Notes You should choose meaningful class names so the controller could be specified into the routes without the full namespace. As long as it is unique within the application, you can reference the controller with the name without "My-Vender/My-Plugin/Controllers/" portion. If your plugin uses only one controller, you could use the name of the plugin as a prefix of the controller name. For example, our hello plugin provides the controller Pletfix\Hello\Controllers\HelloController.php.

Drivers

If you like to provide drivers for a factory, create a subdirectory under src/Drivers to group the types of the driver and store the driver classes into them.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-src/
            |-Drivers/
               |-MyDriverType/
                  |-MyDriver.php

Language Files

If the plugin have to translate something, save the language files under the plugins lang folder like this:

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-lang/
            |-de.php
            |-en.php

Note that the file structure is different from the application's language file structure, but the structure of the language file itself does not differ.

Middleware

You may also add middleware to your plugin. The right place for the class files is src/Middleware:

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-src/
            |-Middleware/
               |-MyMiddleware.php

Read chapter Middleware to learn how you write your own middleware.

Convention Notes You should choose meaningful class names so the middleware could be specified into the routes without the full namespace. Remember, as long as it is unique within the application, you can reference the middleware with the name without "My-Vender/My-Plugin/Middleware/" portion. If your plugin uses only one middleware, you could use the name of the plugin as the middleware name. For example, our hello plugin provides the middleware Pletfix\Hello\Middleware\Hello.php.

Migrations

Does your plugin need an own database table? No problem, add a migration file to the plugin under the migrations folder.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-migrations/
            |-20170204121100_CreateWhatever.php

The structure of the migration file corresponds to the application's migration file.

Public Files

Put all things, that finally should be placed in the applications public folder, into the public folder of your plugin.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-public/     

Convention Notes To avoid naming conflicts with other plugins, you should use subfolders with the name of your plugin to store your files. For example, our hello plugin stores an image key.gif into the folder public/images/hello.

Routes

Add default route entries to the plugin's boot/routes.php file.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-boot/
            |-routes.php

Read chapter HTTP Routing for details on routing.

Services

You should set the services, which are provided by the plugin, into the Dependency Injection Container. As like the services of the application, you may register the services in the Plugin's boot/services.php file.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-boot/
            |-services.php

Note, the Dependency Injection entries of the plugin could be overwritten by the application's boot/services.php.

Views

If your plugin needs views, add the templates into the view folder under the plugin.

|-workbench/
   |-my-vendor/
      |-my-plugin/
         |-views/
            |-my-view.blade.php

Deploying Plugins

When you have finished your plugin, you can submit it on Packagist to share with the community. Do not forget to set the keyword "pletfix" in the composer.jsonfile so that the plugin is automatically listed on the Pletfix plugin page.

"keywords": ["pletfix", "plugin"],

Don't forget to test before uploading the plugin.


(edit on GitHub)