Take the 2-minute tour ×
Craft CMS Stack Exchange is a question and answer site for administrators, end users, developers and designers for Craft CMS. It's 100% free, no registration required.

It would make my day to be able to have PHPStorm recognize third-party services. Has anyone figured out how to get this working yet?

share|improve this question

4 Answers 4

up vote 3 down vote accepted

I'm actually not sure how it would work if you're trying to reference another plugin's services.

It works in Craft by defining the property in the PHPDoc in WebApp.php.

@property AssetsService $assets

That lets PHPStorm know that there exists an AssetsService object off of craft()->assets.

And it's not like we can add a hook for the PHPDoc so plugins can inject their own... maybe through some crazy reflection magic, but it'd be super hackey.

share|improve this answer

Absolutely, just add the app directory as a external library.

  1. Double click on the 'external libraries'.
  2. Add the interpreter
  3. Include the path to the 'app' directory

enter image description here

share|improve this answer
    
Is this the only solution for getting this to work? Additionally, I'm a little confused. In your first sentence you said the "app" directory and that's what appears to be illustrated in your screenshot but in your numbered instructions you say the "craft" directory. –  Tyler Willingham Jul 28 at 18:40
    
Typo, I will correct it. –  Jason McCallister Jul 28 at 18:41
    
Also, to enable phpstorm to auto complete - you have to reference the library (craft) so it knows where to load the code from. –  Jason McCallister Jul 28 at 19:09
    
Is this supposed to work for third-party plugins' services? I'm not able to get that working. –  Tyler Willingham Jul 30 at 20:17
    
I'm actually not sure how that would work for a plugin. It works in Craft by defining the property in the PHPDoc in WebApp.php. So @property AssetsService $assets, lets PHPStorm know that there exists an AssetsService object off of craft()->assets. And it's not like we can add a hook for the PHPDoc. Maybe through some crazy reflection magic, but it'd be super hackey. –  Brad Bell Jul 30 at 21:21

I handled it by adding a global function and singleton object similar to Craft's WebApp. All of my plugin's services are access from my custom global function myPlugin() while Craft's services continue to be started from the craft() global function. In the doc block for the new object, I specify properties for each service. Each new service must be added by hand, but all members of that service are recognized by the IDE.

This should work across all IDEs (including PHPStorm where this was developed).

<?php
namespace Craft;
/**
 * Class MyPlugin
 * @package Craft
 */

/**
 * @property MyPlugin_CategoriesService $categories MyPlugin Categories Service
 * @property MyPlugin_TriviaService     $trivia     MyPlugin Trivia Service
 */
class MyPlugin {

    public function __get($memberName)
    {
        $craftName = 'myPlugin_' . strtolower($memberName);
        return craft()->$craftName;
    }

    /**
     * Return singleton instance of the rantAPI service manager
     * @return MyPlugin
     */
    public static function app()
    {
        static $inst = null;
        if ( $inst === null) {
            $inst = new MyPlugin();
        }
        return $inst;
    }
}


/**
 * Returns the myPlugin equivalent to webApp class that serves up all the services.
 *
 * @return MyPlugin
 */
function myPlugin()
{
    return MyPlugin::app();
}

In my controller, I reference my services and craft's services in the following way.

$parentEntry = craft()->entries->getEntryById(999);
$triviaToAdd = myPlugin()->trivia->getByKeyword('nerds');

In the example above, both entries and trivia are recognized as valid objects and their methods are available for intelligent code completion.

share|improve this answer
    
Nice and clever! –  Brad Bell Aug 5 at 20:10

I'm kinda late to the party here but Brandon suggested I add the technique I use to this thread.

What I do in order for PHPStorm to resolve my own craft()->myService is to not use that at all because you can't type hint services that get created at runtime. What I do instead, is to declare a function with the name of my plugin that is properly type hinted.

Let's say that I have a plugin called PatrolPlugin with a service called PatrolService which has a method called protect(). If I want to navigate to the method definition/declaration for PatrolService.protect(), I would do something like this.

  1. Create a properly type hinted service getter, this can be a global function or a static method in your plugin class.
/**
 * Tells PHPStorm or any other smart IDE that patrol() returns my service
 *
 * @return PatrolService
 */
function patrol()
{
    return Craft::app()->getComponent('patrol');
}
  1. Call that function/method instead of using craft()->patrol
patrol()->protect()
  1. Place the cursor inside protect and go to definition.

That's what I do anyways, and it works for me.


If I had other services that I wanted type hinted, I can just add them as properties of the main service.

/**
 * @property Patrol_OtherService $other
 */
class PatrolService extends BaseApplicationComponent
{
    public $other;

    public function init()
    {
        $this->other = Craft::app()->getComponent('patrol_other');
    }
}

Note: I'm using Craft::app()->getComponent('service') because it is a bit faster than craft()->service but they are basically the same.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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