phalcon/ide-stubs

Phalcon\Di\Injectable::setDI has wrong type 'mixed'

RayHughes opened this issue · 12 comments

Phalcon 4.0.5
DevTools 4.0.3
Stubs 4.0.4
PHP 7.4.x

Running psalm vendor/bin/psalm results in several variations of the errors below:

INFO: MethodSignatureMismatch - MyModel.php:12:7 - 
Argument 1 of Phalcon\Di\AbstractInjectionAware::setDI has wrong type 'mixed', expecting 'Phalcon\Di\DiInterface' as defined by Phalcon\Di\InjectionAwareInterface::setDI (see https://psalm.dev/042)
class MyModel extends Model
INFO: MethodSignatureMismatch - Validator.php:11:7 - 
Argument 1 of Phalcon\Di\Injectable::setDI has wrong type 'mixed', expecting 'Phalcon\Di\DiInterface' as defined by Phalcon\Di\InjectionAwareInterface::setDI (see https://psalm.dev/042)
class Validator extends Validation

@RayHughes Could you please help us to reproduce the issue. As I can see IDE stubs declares setDi in a proper way so there is no visible reason to throw an error.

The error seems to be occurring with anything that implements the Di.

For instance models, validators, and anything that extends Injectable such as my class below

class BugDemo extends Injectable
{
}

Index.php

try {
    $di = new FactoryDefault();

    //serices, router, and config

    $config = $di->getConfig();

    $application = new Application($di);

    echo $application->handle($_SERVER['REQUEST_URI'])->getContent();
} catch (Exception $exception) {
    //exception handling
}

Router.php

$router = new Router(false);
$router->setDI($di);

//route registration

$router->handle($_SERVER['REQUEST_URI']);

return $router;

Services.php

$di->setShared('config', function (): Config {
    return include CONFIG_PATH;
});

//db and other services

$di->set('router', function () use ($di): Router {
        return include ROUTER_PATH;
});

$di->setShared('dispatcher', function(): Dispatcher {
    $dispatcher = new Dispatcher();
    $dispatcher->setDefaultNamespace('MyApp\Controller');

    return $dispatcher;
});

AbstractController.php

public function onConstruct(): void
{
      $this->config = $this->di->getShared('config');
}

public function beforeExecuteRoute(Dispatcher $dispatcher): bool
 {
	//some auth logic
}

psalm.xml

<?xml version="1.0"?>
<psalm
    name="Psalm Config"
    totallyTyped="true"
    errorLevel="3"
    resolveFromConfigFile="true"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
    <projectFiles>
        <directory name="app" />
        <directory name="src" />
        <ignoreFiles>
            <directory name="vendor" />
            <directory name="app/config" />
            <directory name="public" />
            <directory name="tests" />
        </ignoreFiles>
    </projectFiles>
    <issueHandlers>
        <UndefinedConstant errorLevel="suppress" />
        <MethodSignatureMismatch errorLevel="info"/>
        <PropertyNotSetInConstructor>
            <errorLevel type="suppress">
                <directory name="src/**/Model"/>
                <directory name="src/**/Dto"/>
            </errorLevel>
        </PropertyNotSetInConstructor>
        <MissingConstructor>
            <errorLevel type="suppress">
                <directory name="app/Controller"/>
            </errorLevel>
        </MissingConstructor>
    </issueHandlers>
</psalm>

./vendor/bin/psalm --show-info=true

Scanning files...
Analyzing files...

III░░I░░░░░IIIII░░I░I░I░░III░░░░░I░░░░II░░░░░░░░I░I░I░I░░░II 60 / 65 (92%)
░I░░I

------------------------------
No errors found!
------------------------------
26 other issues found
------------------------------
INFO: MethodSignatureMismatch - app/Controller/AbstractApiController.php:15:16 - Argument 1 of Phalcon\Di\Injectable::setDI has wrong type 'mixed', expecting 'Phalcon\Di\DiInterface' as defined by Phalcon\Di\InjectionAwareInterface::setDI (see https://psalm.dev/042)
abstract class AbstractApiController extends AbsractPhalconController


INFO: MethodSignatureMismatch - src/BugDemo.php - Argument 1 of Phalcon\Di\Injectable::setDI has wrong type 'mixed', expecting 'Phalcon\Di\DiInterface' as defined by Phalcon\Di\InjectionAwareInterface::setDI (see https://psalm.dev/042)
class BugDemo extends Injectable

All my models, controllers and things that extend Injectable are listed. I do not want to have to disable the method mismatch signature as its valuable.

Still have no idea :-/ I'm pretty sure everything is OK with stubs. MB psalm retrieves wrong info from compiled extension? @weirdan Do you have any idea?

@sergeyklay could it be the stubs conflicting with the stubs in devtools?

@RayHughes In general yes

Okay so I individually removed each Phalcon package from composer and tested. Its still happening. Looks to be an issue with the compiled extension itself. I am using Phalcon 4.0.5

  • phalcon/ide-stubs
  • phalcon/incubator-test
  • phalcon/devtools

@RayHughes Correct me if I'm wrong. You removed from project any PHP dependency that may provide IDE stubs (including this project) but the issues still remains. Correct?

Correct. I removed all phalcon stuff except the framework itself.

psalm.xml above doesn't seem to mention any stub (there's no <stubs> element) - how Psalm is supposed to know it should read those files?

Thank you @weirdan. I did not realize there was a way to stub files in psalm. The mention is a bit vague in the documentation. I was able to get it working with the following config.

<stubs>
    <file name="vendor/phalcon/ide-stubs/src/Phalcon/Di/Injectable.php" />
    <file name="vendor/phalcon/ide-stubs/src/Phalcon/Di/AbstractInjectionAware.php"/>
    <file name="vendor/phalcon/ide-stubs/src/Phalcon/Mvc/Model.php"/>
    <file name="vendor/phalcon/ide-stubs/src/Phalcon/Validation.php"/>
    <file name="vendor/phalcon/ide-stubs/src/Phalcon/Http/Response.php"/>
    <file name="vendor/phalcon/ide-stubs/src/Phalcon/Http/Request.php"/>
</stubs>

After fixing the prior issue another popped up where its throwing an error about the container not being set in the constructor on classes that extend Injectable.

ERROR: PropertyNotSetInConstructor - src/Ns/Mapper/MyMapper.php:14:7 
- Property My\Ns\Mapper\ MyMapper.php::$container is not defined in constructor of 
MyNs\Ns\Mapper\ MyMapper.php and in any private or final methods called in the constructor 

(see https://psalm.dev/074)
class MyMapper.php extends Injectable

container not being set in the constructor on classes that extend Injectable

You'd likely have to suppress that.

@weirdan Thank you for the clarification and help!