Skip to content
Grav 2.0 is officially stable. Read the announcement →

Community guidelines

Please keep discussions civil and on-topic. Repeated violations may lead to a temporary ban.

Plugins

Extending class from another plugin

plugins

Solved by pamtbaau View solution

Started by Jeffrey Bennett 5 years ago · 11 replies · 2439 views
5 years ago

I'm trying to add some functionality to the Lightslider plugin by creating a plugin that extends Lightslider. I'm doing this the same way as you would create a child theme.
Everything works except for the php. Instead of having my class extend Plugin, I want to extend LightsliderPlugin. However, I'm getting the error Class 'Grav\Plugin\LightsliderPlugin' not found in <path to my plugin's php>.
I've tried extending LightsliderPlugin and [code]\Grav\Plugin\LightsliderPlugin[/code]. PHPStorm recognizes what I'm trying to do. What am I doing wrong?

5 years ago

@Jrbdog I've tried the following which seems to extend another plugin and override its parent's methods.

In fresh install of Graf 1.7

  • Create plugin Base: $ bin/plugin devtools new-plugin
  • Add event handlers:

    PHP
    class BasePlugin extends Plugin
    {
    ...
    
    // Add event subscriptions
    'onPagesInitialized' => ['onPagesInitialized', 0],
    'onPageInitialized' => ['onPageInitialized', 0],
    
    ...
    
    // Add eventhandlers
    public function onPagesInitialized($event) {
        echo 'Base: onPagesInitialized';
    }
    
    public function onPageInitialized($event) {
        echo 'Base: onPageInitialized';
    }
    
  • Create plugin Child: $ bin/plugin devtools new-plugin

    PHP
    // Add import
    use Grav\Plugin\BasePlugin;
    
    class ChildPlugin extends BasePlugin
    {
    
    // Removed getSubscribedEvents()
    
    // Add overriding eventhandler
    public function onPageInitialized($event) {
        echo 'Child: onPagesInitialized';
        parent::onPageInitialized($event);
    }
    
  • Update composer.json of Child:
    TXT
    "psr-4": {
    "Grav\\Plugin\\Child\\": "classes/",
    // Add path to class of BasePlugin
    "Grav\\Plugin\\BasePlugin\\": "../base"
    },
    
  • Run $ composer update

Note:

  • Removed getSubscribedEvents() in Child
  • Plugin Base must be disabled else Grav will continue calling eventhandlers of Base in parallel to Child.

When debugging the following breakpoints are hit:

  1. echo 'Base: onPagesInitialized';
  2. echo 'Child: onPageInitialized';
  3. echo 'Base: onPageInitialized'; (called by parent::onPageInitialized($page);)

Update:
I've renamed 'Parent' to 'Base', it seems 'Parent' doesn't work as expected...

👍 1
last edited 01/10/21 by pamtbaau
5 years ago

I tried doing what you did and got the same error. I eventually got it working with
[code]
require './user/plugins/lightslider/lightslider.php';

class MyPlugin extends LightsliderPlugin
{
}
[/code]

5 years ago

@Jrbdog, That seems like a hack for an issue with 'autoload'...

From your solution I guess:

  • Grav has not called '/vendor/autoload.php' in your plugin
  • or your 'psr-4' section in composer.json isn't configured properly
  • or you may have forgotten to recreate the autoload files

Are you sure you added the code that allows Grav to call require __DIR__ . '/vendor/autoload.php'; in your plugin?

Could you try running $ bin/plugin devtools new-plugin and see if your code matches the required autoloader code as in the generated skeleton.

Could you try doing the steps as I outlined? Does that work?

5 years ago

I already tried creating a skeleton parent and child plugin and went through the steps you said. That didn't work either. Could it have something to do with the local server it's running on?

5 years ago

@Jrbdog,

I'm using localhost using Windows Subsystem for Linux with Apache inside Ubuntu 20.04

Did you debug and set a breakpoint inside function autoload() to check if vendor/autoload is indeed loaded?

TXT
public function autoload(): \Composer\Autoload\ClassLoader
{
    return require __DIR__ . '/vendor/autoload.php';
}
5 years ago

Autoload does appear to be working. I think the problem is that the autoload() function is inside the child class. It works when I include autoload php for the class declaration.

5 years ago

@Jrbdog, I was trying to setup autoloader again and noticed something that may have set things up for failure...

I initialially created plugins 'Xx' (parent) and 'Yy' (child) which worked fine. For clearity, I named them 'Parent' and 'Child' here on the forum. However, I can't get Parent/Child working. Maybe because 'parent' is a reserved work...

Using names like Base/Child or any other combination works fine though. I've update my example.

Wonder if you can get Base/Child to work.

5 years ago

Yes, changing the name of the parent class worked.
However, it doesn't seem to be actually extending the class. If you change the child class to extend Plugin your echos still echo.
I think you have to require the autoload class before the class declaration because the class won't run if it can't extend the parent class, so the autoload function won't run either.

5 years ago

@Jrbdog, Just to be sure if we are on the same page...

Setup:

  • Create plugin 'Base'
    • $ bin/plugin devtools new-plugin
    • $ cd /user/plugins/base
    • $ composer update
    • In 'user/plugins/base/base.yaml' switch of the plugin
      TXT
      enabled: false
      
  • Create plugin 'Child'

    • $ bin/plugin devtools new-plugin
    • $ cd /user/plugins/child
    • Update psr-4 section in '/user/plugins/child/composer.json' to:
      TXT
      "psr-4": {
      "Grav\\Plugin\\Child\\": "classes/",
      "Grav\\Plugin\\BasePlugin\\": "../base"
      },
      
    • $ composer update
    • Update code in 'user/plugins/child/child.php' to:
      PHP
      
      <?php
      namespace Grav\Plugin;
      

    use Grav\Plugin\BasePlugin;

    class ChildPlugin extends BasePlugin
    {
    public function onPluginsInitialized(): void
    {
    parent::onPluginsInitialized();
    }
    }

    TXT
    
    

Testing:
Set breakpoints in every method of Base and Child.

Running Grav 1.6, the following breakpoints are hit:

  • Base::getSubscribedEvents()
  • Base::autoload()
  • Child::onPluginsInitialized()
    • Base::onPluginsInitialized()
      Called in Child by parent::onPluginsInitialized();

Running Grav 1.7, the following breakpoints are hit:

  • Base::autoload()
    Called because 1.7 calls autoload directly
  • Base::getSubscribedEvents()
  • Base::autoload()
    getSubscribed() should be update to remove subscripion to autoload
  • Child::onPluginsInitialized()
    • Base::onPluginsInitialized()
      Called in Child by parent::onPluginsInitialized();

Breakpoints after update Child to inherit from standard 'Plugin'.

  • Child::onPluginsInitialized()
    Exception thrown because method Plugin::onPluginsInitialized() does not exist.

Looking at the above results, IMHO, Child inherits/extends from Base.

5 years ago

Ok, so nothing special is actually needed. I created a Base and Child plugin. Ended up not doing anything with autoloader, didn't require any files. I simply extended the Base plugin. It worked.
In my original plugin, I extended both the Form and Error plugins. That worked. Only Lightslider can't be extended normally. It can't be extended through the autoload class either.

5 years ago Solution

@Jrbdog, I cannot get LightSlider to work either using autoloader, but the following workaround does work (using Grav 1.7.0-rc.20) :

  • No need to alter default '/user/plugins/child/composer.json'
  • To override LightSlider::onTwigSiteVariables() in 'child.php' use:

    PHP
    <?php
    namespace Grav\Plugin;
    
    use Composer\Autoload\ClassLoader;
    
    require __DIR__ . '/../lightslider/lightslider.php';
    
    use Grav\Plugin\LightsliderPlugin;
    
    class ChildPlugin extends LightSliderPlugin
    {
    public function autoload(): ClassLoader
    {
      return require __DIR__ . '/vendor/autoload.php';
    }
    
    public function onTwigSiteVariables() {
        parent::onTwigSiteVariables();
    }
    }
    
👍 1

Suggested topics

Topic Participants Replies Views Activity
Plugins · by Rene, 1 week ago
2 47 1 week ago
Plugins · by Xavier, 4 weeks ago
2 56 4 weeks ago
Plugins · by Luka Prinčič, 7 years ago
3 1183 1 month ago
Plugins · by Sebastian van de Meer, 1 month ago
1 50 1 month ago
Plugins · by PIERROT Alain, 2 months ago
3 74 2 months ago