4

In Craft 2, services were auto-loaded when using the craft()->plugin_serviceName->myMethodName() signature, but it seems like there's a catch in Craft 3, when using the new MyPlugin::getInstance()->myServiceName->myMethod().

I'm working on a business-logic plugin using a local path repository in my project's composer.json, and there are a rash of problems that come of this, mainly to do with creating + renaming services, as the service locator seems to cache them pretty aggressively.

How can I ensure these changes are picked up right away?

  • 1
    Reason for asking: I was having to edit composer.json and re-install my plugin (and sometimes edit Craft's plugins.php cache) every time I changed a service. – August Miller May 25 '18 at 21:52
  • Yeah, its ridiculous having to use a composer.json file. – Dan Zuzevich Aug 16 '18 at 18:04
  • Also worth noting, since this seems like it might be an early point of frustration for folks getting started with extending Craft and/or plugin development: be sure and evaluate using a Module over of a Plugin, in your project! – August Miller Sep 25 '18 at 16:04
5

It turns out there's a handy method for manually registering your services, or in Yii2 parlance, just "components":

namespace example\myplugin;

use example\myplugin\services\Example as ExampleService;

use Craft;
use craft\base\Plugin as BasePlugin;

class MyPlugin extends BasePlugin
{
    public static $plugin;

    public function init()
    {
        parent::init();
        self::$plugin = $this;

        $this->setComponents([
            'example' => ExampleService::class
        ]);
    }
}

Then, somewhere else in your plugin, your service is immediately available as:

MyPlugin::$plugin->example->myMethod();

…where example is the key in the hash of classes you passed to $this->setComponents().

  • 1
    This works but I'd love to know how you achieve the same result with Composer. It doesn't feel right having some services registered with composer and others in the plugin file itself. – Clive Portman Nov 16 '18 at 9:52
  • @ClivePortman see my answer – fxfuture Apr 16 at 15:43
2

You can do this in Composer with the following:

"extra": {
    "name": "My Plugin",
    "handle": "my-plugin",
    "hasCpSettings": false,
    "hasCpSection": false,
    "components": {
        "myPluginService": "author\\myplugin\\services\\MyPluginService"
    },
    "class": "prove\\myplugin\\MyPlugin"
}
  • Thanks. Just adding that "composer dump-autoload" doesn't do the trick here and that you need to remove and then require the plugin again. – Clive Portman Nov 5 at 9:36
1

If you have a module instead of a plugin, make sure your new service is registered in the config/app.php

Like so:

return [
    'modules' => [
        'core-module' => [
            'class' => \modules\coremodule\CoreModule::class,
            'components' => [
                'member' => [
                    'class' => 'modules\coremodule\services\Member',
                ],
                'invoices' => [
                    'class' => 'modules\coremodule\services\Invoices',
                ],
            ],
        ],
    ],
    'bootstrap' => ['core-module'],
];

Also, make sure that you setting your services in the main plugin/module .php file.

use modules\coremodule\services\Invoices as InvoicesService;
// .....
$this->setComponents([
     'invoices' => InvoicesService::class,
]);

In this case, my new service is called Invoices.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.