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?

August Miller
  • 3,380
  • 9
  • 25
  • 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

3 Answers3

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

August Miller
  • 3,380
  • 9
  • 25
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"
}
fxfuture
  • 279
  • 2
  • 10
  • 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. – Clive Portman Nov 05 '19 at 09: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.

José Veríssimo
  • 318
  • 2
  • 12