5

I get the following error when running bin/magento setup:di:compile:

Errors during configuration scanning:
        IntegerNet\SolrSuggest\Implementor\Factory\AppFactory
                Invalid Factory for nonexistent class IntegerNet\SolrSuggest\Implementor\Factory\App in file [...]/vendor/integer-net/solr-magento2/src/Model/Cache.php

The AppFactory is actually a real interface from a library, it should not be generated by Magento. As far as I understood the generation, factories are only generated if the class does not exist. I double checked that the file exists and the directory is registered in vendor/composer/autoload_psr4.php.

This is how the class that depends on the factory looks like:

Cache.php

<?php
namespace IntegerNet\Solr\Model;
use IntegerNet\SolrSuggest\Implementor\Factory\AppFactory;
class Cache
{
    /**
     * @var AppFactory
     */
    private $appFactory;
    public function __construct(AppFactory $appFactory)
    {
        $this->appFactory = $appFactory;
    }
}

And this is the factory:

AppFactory.php

<?php
namespace IntegerNet\SolrSuggest\Implementor\Factory;
use IntegerNet\SolrSuggest\Implementor\Factory\CacheWriterFactory;
use IntegerNet\SolrSuggest\Implementor\Factory\ConfigFactory;
interface AppFactory extends ConfigFactory, CacheWriterFactory
{
}

I defined a preference for the interface in di.xml:

<preference for="IntegerNet\SolrSuggest\Implementor\Factory\AppFactory" type="IntegerNet\Solr\Model\Bridge\AppFactory" />

Any idea what I can do about these messages?

Observation

In developer mode where I don't explicitly run the compile command, I don't get any errors. And although I get these error messages, compilation runs through and everything works - which proves that the factory classes can be used.

2

That's an interesting issue and I'm not entirely sure why is this happening.

What I can suggest is debugging directly in the _findMissingClasses method from Magento/Setup/Module/Di/Code/Scanner/PhpScanner that's where the error is coming from:

protected function _findMissingClasses($file, $classReflection, $methodName, $entityType)
{
    $missingClasses = [];
    if ($classReflection->hasMethod($methodName)) {
        $constructor = $classReflection->getMethod($methodName);
        $parameters = $constructor->getParameters();
        /** @var $parameter \ReflectionParameter */
        foreach ($parameters as $parameter) {
            preg_match('/\[\s\<\w+?>\s([\w\\\\]+)/s', $parameter->__toString(), $matches);
            if (isset($matches[1]) && substr($matches[1], -strlen($entityType)) == $entityType) {
                $missingClassName = $matches[1];
                try {
                    if (class_exists($missingClassName)) {
                        continue;
                    }
                } catch (\RuntimeException $e) {
                }
                $sourceClassName = $this->getSourceClassName($missingClassName, $entityType);
                if (!class_exists($sourceClassName) && !interface_exists($sourceClassName)) {
                    $this->_log->add(
                        Log::CONFIGURATION_ERROR,
                        $missingClassName,
                        "Invalid {$entityType} for nonexistent class {$sourceClassName} in file {$file}"
                    );
                    continue;
                }
                $missingClasses[] = $missingClassName;
            }
        }
    }
    return $missingClasses;
}

That method is called from the _fetchFactories method which also logs the same error so you need to find out, where the error is coming from exactly and from there you should be able to start debugging:

protected function _fetchFactories($reflectionClass, $file)
{
    $factorySuffix = '\\'.ucfirst(FactoryGenerator::ENTITY_TYPE);
    $absentFactories = $this->_findMissingClasses(
        $file,
        $reflectionClass,
        '__construct',
        ucfirst(FactoryGenerator::ENTITY_TYPE)
    );
    foreach ($absentFactories as $key => $absentFactory) {
        if (substr($absentFactory, -strlen($factorySuffix)) == $factorySuffix) {
            $entityName = rtrim(substr($absentFactory, 0, -strlen($factorySuffix)), '\\');
            $this->_log->add(
                Log::CONFIGURATION_ERROR,
                $absentFactory,
                'Invalid Factory declaration for class ' . $entityName . ' in file ' . $file
            );
            unset($absentFactories[$key]);
        }
    }
    return $absentFactories;
}
2

Taking @Raphael's suggestion, I looked through Magento/Setup/Module/Di/Code/Scanner/PhpScanner::_findMissingClasses with the debugger on, the issue arises from this block of code

if (class_exists($missingClassName)) {
    continue;
}

In your case @fschmengler $missingClassName is IntegerNet\SolrSuggest\Implementor\Factory\AppFactory which as you said is an interface not a class.

Revising the core code to

if (interface_exists($missingClassName) || class_exists($missingClassName)) {
    continue;
}

seems to eliminate the problem. Maybe this is a bug worth mentioning to the Magento developers?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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