Composer-Plugin wird nach Aufruf "Meine Erweiterungen" im Backend wieder gelöscht

Ich habe ein komisches Verhalten mit einem eigenen Composer-Plugin. Das Plugin liegt korrekt im Ordner „static-plugins“ und wurde mit folgenden Befehlen installiert

composer require areanet/test
bin/console plugin:refresh
bin/console plugin:install AreanetTest
=> Plugin "AreanetTest" has been installed successfully.
bin/console cache:clear

Das Plugin liegt im Ordner „vendor/areanet/test“ - in der Datenbank wird es nach der Installation in der Tabelle plugin aufgeführt (manages_by_composed = 1 / active = 0). Über CLI-Befehl „plugin:list“ wird es ebenfalls korrekt angezeigt.

Sobald ich im Admin „Meine Erweiterungen“ aufrufe, verschwindet das Plugin aber wieder - bzw. wird aus der Plugin-DB-Tabelle wieder rausgelöscht.

Scheint wohl an der Methode Shopware\Core\Framework\Plugin\PluginService->refreshPlugins() zu liegen. Irgendwie findet er das Plugin im Dateisystem nicht und löscht es daher wieder.

Das Plugin ist wie gesagt im Ordner „vendor/areanet/test“ vorhanden - ebenso wie im Ordner „static-Plugins“. In der composer.json steht in „shopware-plugin-class“ das gleiche wie in der plugin-Tabelle im Feld base_class. Also müsste er in der folgenden Zeile auch was finden
$currentPluginEntity = $installedPlugins->filterByProperty('baseClass', $baseClass)->first();
und das Plugin vom Löschen ausschließen.

Irgendwie scheint die Methode das Plugin gar nicht im Filesystem zu finden? Cache-Problematik?

public function refreshPlugins(Context $shopwareContext, IOInterface $composerIO): ExceptionCollection
    {
        $errors = new ExceptionCollection();
        $pluginsFromFileSystem = $this->pluginFinder->findPlugins($this->pluginDir, $this->projectDir, $errors, $composerIO);

        $installedPlugins = $this->getPlugins(new Criteria(), $shopwareContext);

        $plugins = [];
        foreach ($pluginsFromFileSystem as $pluginFromFileSystem) {
            $baseClass = $pluginFromFileSystem->getBaseClass();
            $pluginPath = $pluginFromFileSystem->getPath();
            $info = $pluginFromFileSystem->getComposerPackage();

            $autoload = $info->getAutoload();
            if (empty($autoload) || (empty($autoload['psr-4']) && empty($autoload['psr-0']))) {
                $errors->add(new PluginComposerJsonInvalidException(
                    $pluginPath . '/composer.json',
                    ['Neither a PSR-4 nor PSR-0 autoload information is given.']
                ));

                continue;
            }

            $pluginVersion = $this->versionSanitizer->sanitizePluginVersion($info->getVersion());
            $extra = $info->getExtra();
            $authors = $this->getAuthors($info);
            $license = $info->getLicense();
            $pluginIconPath = $extra['plugin-icon'] ?? 'src/Resources/config/plugin.png';

            $pluginData = [
                'name' => $pluginFromFileSystem->getName(),
                'baseClass' => $baseClass,
                'composerName' => $info->getName(),
                'path' => str_replace($this->projectDir . '/', '', $pluginPath),
                'author' => $authors,
                'copyright' => $extra['copyright'] ?? null,
                'license' => implode(', ', $license),
                'version' => $pluginVersion,
                'iconRaw' => $this->getPluginIconRaw($pluginPath . '/' . $pluginIconPath),
                'autoload' => $info->getAutoload(),
                'managedByComposer' => $pluginFromFileSystem->getManagedByComposer(),
            ];

            $pluginData['translations'] = $this->getTranslations($shopwareContext, $extra);

            if ($changelogFiles = $this->changelogService->getChangelogFiles($pluginPath)) {
                foreach ($changelogFiles as $file) {
                    $languageId = $this->getLanguageIdForLocale(
                        $this->changelogService->getLocaleFromChangelogFile($file),
                        $shopwareContext
                    );
                    if ($languageId === '') {
                        continue;
                    }

                    try {
                        $pluginData['translations'][$languageId]['changelog'] = $this->changelogService->parseChangelog($file);
                    } catch (PluginChangelogInvalidException $changelogInvalidException) {
                        $errors->add($changelogInvalidException);
                    }
                }
            }

            /** @var PluginEntity $currentPluginEntity */
            $currentPluginEntity = $installedPlugins->filterByProperty('baseClass', $baseClass)->first();
            if ($currentPluginEntity !== null) {
                $currentPluginId = $currentPluginEntity->getId();
                $pluginData['id'] = $currentPluginId;

                $currentPluginVersion = $currentPluginEntity->getVersion();
                if (!$currentPluginEntity->getInstalledAt()) {
                    $pluginData['version'] = $pluginVersion;
                    $pluginData['upgradeVersion'] = null;
                } elseif ($this->hasPluginUpdate($pluginVersion, $currentPluginVersion)) {
                    $pluginData['version'] = $currentPluginVersion;
                    $pluginData['upgradeVersion'] = $pluginVersion;
                } else {
                    $pluginData['upgradeVersion'] = null;
                }

                $installedPlugins->remove($currentPluginId);
            }

            $plugins[] = $pluginData;
        }

        if ($plugins !== []) {
            foreach ($plugins as $plugin) {
                try {
                    $this->pluginRepo->upsert([$plugin], $shopwareContext);
                } catch (ShopwareHttpException $exception) {
                    $errors->set($plugin['name'], $exception);
                }
            }
        }

        // delete plugins, which are in storage but not in filesystem anymore
        $deletePluginIds = $installedPlugins->getIds();
        if (\count($deletePluginIds) !== 0) {
            $deletePlugins = [];
            foreach ($deletePluginIds as $deletePluginId) {
                $deletePlugins[] = ['id' => $deletePluginId];
            }
            $this->pluginRepo->delete($deletePlugins, $shopwareContext);
        }

        return $errors;
    }

Problem war der OPcache - muss geleert werden, dann passt es:

opcache_reset()