Factory Autocomplete

 

 

I want to have autocompletion for a factory that returns only a few classes (only 2 currently, max 5). I tried the following but it did not work.

I read somewhere that the factory methods had to be static, but for my purposes I may not need them to be static. So if it would be different for non-static factory methods, please let me know what to do in that situation.

What happens right now is the autocomplete contains the combined methods for every class (ClassA and ClassB)

I attempted to follow this link: https://confluence.jetbrains.com/display/PhpStorm/PhpStorm+Advanced+Metadata

class Factory
{
    
    public static function get($id) {
        
        if ($id === 1) {
            return new ClassA();
        }
        elseif ($id === 2) {
            return new ClassB();
        }
        else {
            throw new Exception('Bad ID');
        }
    }
}

$obj3 = Factory::get(2);
// $obj3-> // I want to autocomplete class B methods

This is in my ".phpstorm.meta.php" file in the root of my project:

<?php

namespace PHPSTORM_META {
    
    override( \Factory::get(0),         // method signature //argument number is ALWAYS 0 now.
        map( [ //map of argument value -> return type
            1 => \ClassA::class,                //Reference target classes by ::class constant
            2 => \ClassB::class,
            \ExampleFactory::EXAMPLE_B => ExampleB::class,  // FYI, we can now support class constant argument values
            \EXAMPLE_B => \ExampleB::class,              // and global constants too
            //non mapped value, e.g. $getByClassNameConst case above will be returned automatically
        ]));
}
0
Avatar
Permanently deleted user

As a follow up I would also like to know how to pass arguments to the factory which are then used in the construction of the returned class. Thank you!

0
Avatar
Permanently deleted user

Can someone please tell me how I might get this working, if it is possible, or if I am even on the right track with this? I basically want to get autocompletion for multiple known return types from a function.

0

I've just tried your sample and I'm getting methods from both classA and classB on $obj3->.... Are you getting the same?

0
Avatar
Permanently deleted user

Yes, I am getting methods from both A and B at the same time, instead of just A or B exclusively (which is what I want). This is the default behavior that I get if there is no  .phpstorm.meta.php file at all.

0

@Dmitry Tronin

>I've just tried your sample and I'm getting methods from both classA and classB on $obj3->.... Are you getting the same?

That's because it's very simple example and both classes explicitly used in factory method .. so Metadata does not even participate there (as both classes are automatically deducted as return types).

At the same time: only members of ClassB are expected there.

@Notta A

Better code sample is needed.

In general Advanced Metadata works .. as it's used in Laravel framework a lot ... and it works in Laravel projects in PhpStorm.

0
Avatar
Permanently deleted user

Thanks for the help so far!

@Andriy We may have posted at the same time so you might not have seen my above post, but you are right the example is very simple but the real implementation is not much more complicated - the example above is pretty much it, except there are a few more ID-to-class relationships. I pass in an ID explicitly hardcoded in code and only want to autocomplete the class associated with the ID, but instead I am getting all of the methods in all classes being offered as auto complete suggestions. Is there a way around it using the .phpstorm.meta.php file (or something else)? Or is it that autocompletion for this sort of code structure not possible (and if so, what structure would you suggest that would be compatible with phpstorm's autocompletion)?

0
Avatar
Permanently deleted user

I am still trying to find a solution to this. Can someone please help? Is there a way to only receive autocompletions based on the ID of the class provided to the factory, and not all possible return values? I am willing to change things to accommodate for this, but the phpstorm meta file, and its override method, apparently either don't work the way that would be expected, or I am configuring it incorrectly.

0

Well ...

1) Use string IDs instead of numbers

2) Use "@return mixed" signature for factory method

It works.

 

1) I'm using "aa" and "bb" as IDs here. The rest -- identical to yours

<?php
namespace PHPSTORM_META {
    override( \Factory::get(0),         // method signature //argument number is ALWAYS 0 now.
        map( [ //map of argument value -> return type
            'aa' => \ClassA::class,                //Reference target classes by ::class constant
            'bb' => \ClassB::class,
            \ExampleFactory::EXAMPLE_B => ExampleB::class,  // FYI, we can now support class constant argument values
            \EXAMPLE_B => \ExampleB::class,              // and global constants too
            //non mapped value, e.g. $getByClassNameConst case above will be returned automatically
        ]));
}

2) More proper in such case "@return mixed" and string IDs

<?php

class ClassA {
    public function methodAAA()
    {
    }
}

class ClassB {
    public function methodBBB()
    {
    }
}

class Factory
{

    /**
     * My super nice factory method
     *
     * @param $id
     * @return mixed
     */
    public static function get($id) {

        if ($id === 'aa') {
            return new ClassA();
        }
        elseif ($id === 'bb') {
            return new ClassB();
        }
        else {
            throw new \Exception('Bad ID');
        }
    }
}

$obj3 = Factory::get('bb');
$obj3-> // I want to autocomplete class B methods

Notice that $obj3 is detected as "ClassB|mixed" and completion shows only methods from that class; if you change ID to "aa", it will be "ClassA|mixed".

 

 

 

2
Avatar
Permanently deleted user

That worked perfectly, thank you! (And thanks for the images to show the proof of it working.)

Is there any reason why integers can't be used instead of strings, or was it just a preference here? I tried substituting integers again for strings and was unsuccessful. I can just type coerce in the factory so it is not a big problem, but I am curious if this is a limitation of the override() method in phpstorm.meta.php.

0

>Is there any reason why integers can't be used instead of strings, or was it just a preference here? 

No idea. Maybe responsible dev can shed some light on it. But integer IDs have little sense here (IMO).

Keep in mind that this Metadata was created to cover cases like FactoryClass::make('User'); .. that returns instance of "\App\Models\UserModel" class as well as FactoryClass::make(\App\Models\UserModel::class, $constructorParams); String IDs are natural choice here.

0

请先登录再写评论。