Inherit Controller - Controllers that inherit from the site controller

Yet another plugin to provide a kind of global controller. :slight_smile:

https://github.com/jenstornell/kirby-inherit-controller

Inherit Controller

Version 0.1

// Site controller
controllers/site.php

// Site prefixed controllers. Inherit from the site controller
controllers/site-default.php
controllers/site-projects.php

// Controllers. Does not inherit anything.
controllers/default.php
controllers/projects.php

In Kirby there there is no global controller. This plugin solves it by merging the site controller and a site- prefixed controller.

Maybe you need to:

  • Redirect all pages that has the field value published.
  • Remove all pages from the $pages collection that has the slug revision.
  • Just do something globally in a controller.

Without this a plugin the above needs to be done in every controller. With many controllers it can end up with a mess.

Controller inheritance keeps things DRY.

Installation

Use one of the alternatives below.

1. Kirby CLI

If you are using the Kirby CLI you can install this plugin by running the following commands in your shell:

$ cd path/to/kirby
$ kirby plugin:install jenstornell/inherit-controller

2. Clone or download

  1. Clone or download this repository.
  2. Unzip the archive if needed and rename the folder to inherit-controller.

Make sure that the plugin folder structure looks like this:

site/plugins/inherit-controller/

3. Git Submodule

If you know your way around Git, you can download this plugin as a submodule:

$ cd path/to/kirby
$ git submodule add https://github.com/jenstornell/inherit-controller site/plugins/inherit-controller

Setup

1. Change your site controller

Add /site/controllers/site.php if it does not already exists in your installation.

<?php
return function( $site, $pages, $page ) {
  return array_merge( array (
    'foo' => 'Foo from site',
    'bar' => 'Bar from site'
      ), inheritController::template( $site, $pages, $page, $args = [] )
  );
};

The big difference is the array_merge function. It merges the site controller with the site- prefixed controller.

2. Add a site- custom controller

Add a controller like you normally would, but prefix it site-.

Something like this:

<?php
return function($site, $pages, $page) {
  return array(
    'bar' => 'Bar from site-default'
  );
};

3. Print them in the template

Add this into your /site/templates/header.php or whatever you template is:

echo $foo; // Foo from site
echo $bar; // Bar from site-default

Nonprefixed controllers

If you add a nonprefixed controller like default.php it will override both site.php and site-default.php.

That means that you can still use you templates as you normally would, until you need a change.

1 Like

Is there any difference between doing this and including the site.php controller from your other controllers?

return include __DIR__ . '/site.php';?>

Yes. What you are doing with that line of code is to tell the controller to return the data of the site controller. That would as far as I can tell the same thing as deleting the controller because it would then use the site controller as a fallback.

If you would use my plugin and add for example a controller named site-projects.php it would use all the data from site as a starting point and then override them with the data from site-projects.php. You would then have a mix of values, all the data from site-projects.php and some global data from site.php where it’s missing in site-projects.php.

I see your point. I haven’t tested including the site and returning other values as well. Have you tried it without success?

I’m not sure how you mean. I just tested this:

<?php
return include __DIR__ . '/site.php';

return function($site, $pages, $page) {
	return array(
		'foo' => 'some',
		'bar' => 'value',
	);
};

As expected it return the site controller. The first return rules. The second one will never run.

But I’m not sure what you are trying to do.

Untested but this is what I mean

<?php
include __DIR__ . '/site.php';

return function($site, $pages, $page) {
  somecode
  return compact('some array from the site controller','something from this controller'); 
};

More like this, right?

<?php

return function($site, $pages, $page) {
  $siteController = include __DIR__ . '/site.php';
  return array_merge(
    $siteController(),
    ['otherValue' => 'something']
  );
};

Another option is to define a utility function in a plugin, and use that function in your controllers/site.php and other controllers. One can write DRY code without using inheritance. :wink:

1 Like

That would probably not work but now I see what you mean. The idea with some modifications would probably work but then you need to add that include and compact (if that works) to every controller that needs to inherit the site controller.

Here is my plugin, yes it’s the whole thing :slight_smile: :

You don’t need to understand this to use it but maybe you want some insight in how it works.

<?php
class inheritController {
	public static function template( $site, $pages, $page, $args = [] ) {
		$controller = kirby()->registry()->get( 'controller', 'site-default' );
		if( is_a( $controller, 'Closure' ) ) {
			return (array)call_user_func_array( $controller, array(
				$site,
				$pages,
				$page,
				$args,
			));
		}
		return array();
	}
}

site.php

The magic with my plugin is to add a function to the site controller, instead of every other controller. So this is the new site controller:

<?php
return function( $site, $pages, $page ) {
  return array_merge( array (
    'foo' => 'Foo from site',
    'bar' => 'Bar from site'
      ), inheritController::template( $site, $pages, $page, $args = [] )
  );
};

site-projects.php

If you template/controller name is normally projects you can use a prefixed version site-projects.php. No includes needed. Magically it merges it with the site controller.

<?php
return function($site, $pages, $page) {
  return array(
    'bar' => 'Bar from site-default'
  );
};

Gotcha,
I’ll give it a try next time I face this kind of situation :slight_smile:

1 Like

Another option is to define a utility function in a plugin, and use that function in your controllers/site.php

Yes, that’s exactly what this plugin does. :slight_smile: