PhpStorm phpUnit autocomplete broken because of setUp method - php

Make PhpStorm autocomplete fields defined in phpUnit's setUp method.
If I define a mock in setUp method:
public function setUp()
{
$this->testRepo = $this->getMockBuilder(TestRepository::class)
->disableOriginalConstructor()
->getMock();
}
When I want to use this mock in other methods:
public function testExample()
{
$this->testRepo->.... at this point phpStorm does not show autocomplete options
}
I understand that phpStorm doesn't know that setUp method is run before each other test method but maybe there's a way to fix this behavior.
I also don't want to add phpDoc to each property defined. I find this pretty robust and ugly:
/**
* #var PHPUnit_Framework_MockObject_MockObject
*/
protected $testRepo;
PS: Stackoverflow editor is s**t

Change the PHPDoc annotation as follow:
/**
* #var \PHPUnit_Framework_MockObject_MockObject|TestRepository
*/
protected $testRepo;
hope this help

Related

PhpStorm show usages of __invoke methods

I have problems detecting the use of a __invoke method in PhpStorm.
Example of class that is used with the __invoke php method:
class InitNewsletterSubscribedCustomerUseCase
{
/**
* #param CustomerId $id
* #throws CustomerIsValidatedException
*/
public function __invoke(CustomerId $id)
{
...
And I would like, as in all php methods, to know where it is used in the project wiht PhpStorm.
The variable knows the type, but PhpStorm does not know it knows that it executes that magic method "__invoke".
/** #var InitNewsletterSubscribedCustomerUseCase $useCase */
$useCase = $this->useCase;
try{
$useCase($customerId);
}
catch (CustomerIsNewsletterSubscribedException $ex)
Is there any special phpdoc or note for this?
PD: I use the 2018.3.3 version of PhpStorm.
Accordingly to WI-34223 ticket, it should be fixed in 2019.1 only (currently in EAP stage).
Try EAP build from https://www.jetbrains.com/phpstorm/eap/ page.

Use variable in php comment

I need to add $variable in my php return document
for example I have this function :
/**
* #return \Panel\Model\{$Service}
*/
public function getService($Service){
// I call service `foo` from Model folder
}
I see this post : What's the meaning of #var in php comments but it has no information about how to do it , and also study #var-phpdoc but that has nothing for me.
if you ask me why I should do that , because I want use phpStorm Ctrl+Click advantage on $this->getService('foo')->bar()
thanks in advance
As LazyOne said in the comments already PHP interfaces should solve your problem. You can 't use variables in PHPDoc formatted comments. Sure, if you use an IDE like PHPStorm with a plugin that enables the usage of variables in PHPDoc comments, the problem is solved for yourself. What, when other developers, which don 't use PHPStorm or the relevant plugin, want to work in the same project? In my view you should use php native functionality to solve your issue.
Here 's a short example how to use interfaces.
declare('strict_types=1');
namespace Application\Model;
interface ModelInterface
{
public function getFoo() : string;
public function setFoo() : ModelInterface;
}
The only thing you have to do now is using this interface with your models like in the following example.
declare('strict_types=1');
namespace Application\Model;
class FooModel implements ModelInterface
{
protected $foo = '';
public function getFoo() : string
{
return $this->foo;
}
public function setFoo(string $foo) : ModelInterface
{
$this->foo = $foo;
return $this;
}
}
As you can see the FooModel class implements the ModelInterface interface. So you have to use the methods declared in the interface in you model class. This means, that your getService Method could look like the following example.
/**
* Some getter function to get a model
* #return \Application\Model\ModelInterface
*/
public function getService($service) : ModelInterface
{
return $service->get(\Application\Model\Foo::class);
}
Your IDE knows now which methods the returned class can use. It allows you to use chaining and some more features. While typing your IDE should know now, that the returned class can use getFoo and setFoo methods. Further the setFoo methods enables comfortable chaining for calls like ..
// variable contains the string 'foo'
// your ide knows all methods
$fooString = $this->getService($serviceLocator)->setFoo('foo')->getFoo();
Are you using Symfony? Then you could use the Symfony plugin that solves this problem for you. For other frameworks, there should be similar solutions. If you use your own framework, you need to write such a plugin on your own, as PhpStorm can not resolve the given class otherwise.
I think what you are looking for is phpdoc.
https://docs.phpdoc.org/guides/docblocks.html
/**
* #param string $Service This is the description.
* #return \Panel\Model\{$Service}
*/
public function getService($Service){
// I call service `foo` from Model folder
}

How to prevent PhpStorm from showing an Expected... warning when using PHPUnit mocks?

When mocking an interface in PHPUnit, PhpStorm complains when it's used as parameter for a type-hinted function.
Example
interface InterfaceA{
}
class ClassA{
public function foo(InterfaceA $foo){}
}
class PhpStormTest extends PHPUnit_Framework_TestCase
{
public function testFoo(){
$mock = $this->getMock("InterfaceA");
$a = new ClassA();
$a->foo($mock);
}
}
On $a->foo($mock); PhpStorm underlines $mock with the warning Expected InterfaceA, got PHPUnit_Framework_MockObject_MockObject
Image
I guess it's happening because PHPUnit creates the mock a runtime and PhpStorm cannot know that it's actually implementing the interface.
I found a workaround to this problem in the Jetbrain blog at PhpStorm Type Inference and Mocking Frameworks. The important part:
By default, PhpStorm is capable of figuring out the available methods
on the mock object. However, it only displays those for PHPUnit’s
PHPUnit_Framework_MockObject_MockObject class. Fortunately, we can
solve this by instructing PhpStorm to infer type information from
other classes as well, by using a simple docblock comment.
So to make the warning disappear, we need to add /** #var InterfaceA */ /** #var InterfaceA|PHPUnit_Framework_MockObject_MockObject */ (cudos to Supericy) to let PhpStorm know our mock actually implements InterfaceA:
interface InterfaceA{
}
class ClassA{
public function foo(InterfaceA $foo){}
}
class PhpStormTest extends PHPUnit_Framework_TestCase
{
public function testFoo(){
/** #var InterfaceA|PHPUnit_Framework_MockObject_MockObject */
$mock = $this->getMock("InterfaceA");
$a = new ClassA();
$a->foo($mock);
}
}
This bugged me for some time, hope it helps someone :)
Edit
Since PHPUnit_Framework_MockObject_MockObject is really ugly to type, you can abbreviate it via MOOMOO and let PHPStorms auto-complete do the rest:
Another plugin I have used for this is the Dynamic Return Type Plugin, it lets you configure return types of methods in a very dynamic way (the example is to have better type information from Mocks).
Another, less verbose but possibly riskier, approach can be to wrap the call to getMock() with your own function and mark that with #return mixed:
/**
*
* #return mixed
*/
public function myGetMock($str)
{
return $this->getMock($str);
}
Calling this method instead of $this->getMock() will make the warning disappear.

Type casting in PHPDocumentor

Is there any type casting for PHPDocumentor in PHPStorm?
My PHPStorm IntelliSense is stubborn and i need to teach him how to behave.
This is my case:
I have a manager that instantiates classes that all extend same class.
Usually i would cast my class after it was returned but PHP doesn't know how to do that.
IntelliSense and PHPDocumentor support would be enough for me but i don't know how to type cast.
This is the code:
class Plugin
{
}
class HelloPlugin extends Plugin
{
public function hello()
{
}
}
class PluginManager
{
/** #var HelloPlugin */
public $helloPlugin;
function __construct()
{
$this->helloPlugin = $this->getPlugin('HelloPlugin');
// Here my PHPStorm IntelliSense doesn't provide 'hello()' function for 'helloPlugin' because return type overwrote original type
// I get error: method 'hello' not found in class
$this->helloPlugin->hello();
}
/**
* #param string $pluginClass
* #return Plugin
*/
function getPlugin($pluginClass)
{
return new $pluginClass;
}
}
I do not think it's actually possible :( , unless you rewrite your code somehow (just for PhpStorm ... no way).
Your code and PHPDoc is fine -- it's an IDE issue -- it temporarily (within that method only) overwrites manually provided type hint with the one it detects (it will work fine in other methods). Please vote: http://youtrack.jetbrains.com/issue/WI-17047

Preserving auto-completion abilities with Symfony2 Dependency Injection

I'm using PHP Storm as my IDE, but I believe that other IDE's such as Netbeans will have the same issue as I'll explain below.
When using a framework like Symfony2, we have the wonderful world of Dependency Injection added. So objects can simply be instantiated using code like the following snippet:
$myThingy = $this->get('some_cool_service');
This is very handy, as objects are already configured beforehand. The one problem is, that auto-completion breaks entirely in basically any PHP IDE, as the IDE does not know what type the get() method is returning.
Is there a way to preserve auto-completion? Would creating for example an extension of Controller be the answer? For example:
class MyController extends Controller {
/**
* #return \MyNamespace\CoolService
*/
public getSomeCoolService() {
return new CoolService();
}
}
and then for application controllers, specify MyController as the base class instead of Controller?
What about using a Factory class, or any other possible methods?
It is more involving, but you can still do this with eclipse PDT:
$myThingy = $this->get('some_cool_service');
/* #var $myThingy \MyNamespace\CoolService */
UPDATE:
The example on this page shows you may also use the other way round with phpStorm:
$myThingy = $this->get('some_cool_service');
/* #var \MyNamespace\CoolService $myThingy */
You could define private properties in your controllers
class MyController extends Controller
{
/**
* #var \Namespace\To\SomeCoolService;
*/
private $my_service;
public function myAction()
{
$this->my_service = $this->get('some_cool_service');
/**
* enjoy your autocompletion :)
*/
}
}
I use base Controller class for bundle. You need to annotate the return in method. At least that works on Eclipse.
/**
* Gets SomeCoolService
*
* #return \Namespace\To\SomeCoolService
*/
protected function getSomeCoolService()
{
return $this->get('some_cool_service');
}
I don't like /*var ... */, because it gets too much into code.
I don't like private properties, because you can wrongly assume that services are already loaded.
I use Komodo Studio, and tagging variables with #var, even inside methods, preserves auto completion for me.
namespace MyProject\MyBundle\Controller;
use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\HttpFoundation\Request;
class WelcomeController extends ContainerAware
{
public function indexAction()
{
/*#var Request*/$request = $this->container->get('request');
$request->[autocomplete hint list appears here]
}
}
working with netbeans IDE 7.1.2 PHP

Categories