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?

3
  • 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. Commented May 25, 2018 at 21:52
  • Yeah, its ridiculous having to use a composer.json file. Commented Aug 16, 2018 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! Commented Sep 25, 2018 at 16:04

3 Answers 3

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().

2
  • 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. Commented Nov 16, 2018 at 9:52
  • @ClivePortman see my answer
    – fxfuture
    Commented Apr 16, 2019 at 15:43
5

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"
}
1
  • 1
    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. Commented Nov 5, 2019 at 9:36
2

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 and acknowledge you have read our privacy policy.

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