mautic の plugin の reload 処理をみる 02
Published: 2021-08-07 23:26:27

## ReloadFacade#reloadPlugins

reload の実態となるメソッドを見ていきます。

```php
public function reloadPlugins()
{
    $plugins                 = $this->pluginModel->getAllPluginsConfig();
    $pluginMetadata          = $this->pluginModel->getPluginsMetadata();
    $installedPlugins        = $this->pluginModel->getInstalledPlugins();
    $installedPluginTables   = $this->pluginModel->getInstalledPluginTables($pluginMetadata);
    $installedPluginsSchemas = $this->pluginModel->createPluginSchemas($installedPluginTables);
    $disabledPlugins         = $this->reloadHelper->disableMissingPlugins($plugins, $installedPlugins);
    $enabledPlugins          = $this->reloadHelper->enableFoundPlugins($plugins, $installedPlugins);
    $updatedPlugins          = $this->reloadHelper->updatePlugins($plugins, $installedPlugins, $pluginMetadata, $installedPluginsSchemas);
    $installedPlugins        = $this->reloadHelper->installPlugins($plugins, $installedPlugins, $pluginMetadata, $installedPluginsSchemas);
    $persist                 = array_values($disabledPlugins + $enabledPlugins + $updatedPlugins + $installedPlugins);

    if (!empty($persist)) {
        $this->pluginModel->saveEntities($persist);
    }
```

### PluginModel

以降では内部を理解するために細かく実行しているが、 `PluginModel` 自体をpsysh で取得しておけば自由に試せる。

```php
>>> $pluginModel = $container->get('mautic.plugin.model.plugin')
```

### pluginModel->getAllPluginsConfig();

ここは内部的には `BundleHelper` を見ているため、一つ前の記事で見た通りで `%mautic.plugin.bundles%` のパラメータを参照している。

### pluginModel->getPluginsMetadata()

`PluginModel` は以下のようになっている。

```php
public function getPluginsMetadata()
{
    $allMetadata     = $this->em->getMetadataFactory()->getAllMetadata();
    $pluginsMetadata = [];

    foreach ($allMetadata as $meta) {
        $namespace = $meta->namespace;

        if (false !== strpos($namespace, 'MauticPlugin')) {
            $bundleName = preg_replace('/\\\Entity$/', '', $namespace);
            if (!isset($pluginsMetadata[$bundleName])) {
                $pluginsMetadata[$bundleName] = [];
            }
            $pluginsMetadata[$bundleName][$meta->getName()] = $meta;
        }
    }

    return $pluginsMetadata;
}
```

最初に取得している `Metadata` は以下で psysh で取得できる。

```bash
>>> $em = $container->get('doctrine')->getManager();
>>> $em->getMetadataFactory()->getAllMetadata()
   [
     Doctrine\ORM\Mapping\ClassMetadata {#5392
       +name: "Mautic\PluginBundle\Entity\IntegrationEntity",
       +namespace: "Mautic\PluginBundle\Entity",
       +rootEntityName: "Mautic\PluginBundle\Entity\IntegrationEntity",
       +customGeneratorDefinition: null,
       +customRepositoryClassName: "Mautic\PluginBundle\Entity\IntegrationEntityRepository",
       +isMappedSuperclass: false,
       +isEmbeddedClass: false,
```
上記の通りで、`Doctrine\ORM\Mapping\ClassMetadata` の一覧が大量に取得できる。（ `count` したら 101 ありました）

取得した Metadata から namespace に `MauticPlugin` が入っているものだけを取得し、末尾の `\Entity` を除外したものを集めている。

### pluginModel->getInstalledPlugins()

```php
class PluginModel extends FormModel {
    public function getInstalledPlugins()
    {
        return $this->getEntities(
            [
                'index' => 'bundle',
            ]
        );
    }

    public function getRepository()
    {
        return $this->em->getRepository('MauticPluginBundle:Plugin');
    }

// FormModel の親クラスが AbstractCommonModel
abstract class AbstractCommonModel {
    public function getEntities(array $args = [])
    {
        //set the translator
        $repo = $this->getRepository();

        if ($repo instanceof CommonRepository) {
            $repo->setTranslator($this->translator);
            $repo->setCurrentUser($this->userHelper->getUser());

            return $repo->getEntities($args);
        }

        return [];
    }
```

`getEntities` 内で呼ばれる `getRepository` は `PluginModel#getRepository` なので、 `PluginBundle\Entity\PluginRepository` が使われる。これは `CommonRepository` を継承しているので、`instanceof` も問題ない。

実行すると以下のように取得できる。

```php
>>> $em->getRepository('MauticPluginBundle:Plugin')->getEntities(['index' => 'bundle',]);
=> [
     "MauticCitrixBundle" => Mautic\PluginBundle\Entity\Plugin {#4605},
     "MauticClearbitBundle" => Mautic\PluginBundle\Entity\Plugin {#4653},
     "MauticCloudStorageBundle" => Mautic\PluginBundle\Entity\Plugin {#4634},
     "MauticCrmBundle" => Mautic\PluginBundle\Entity\Plugin {#4662},
     "MauticEmailMarketingBundle" => Mautic\PluginBundle\Entity\Plugin {#4657},
     "MauticFullContactBundle" => Mautic\PluginBundle\Entity\Plugin {#4603},
     "MauticGmailBundle" => Mautic\PluginBundle\Entity\Plugin {#4593},
     "GrapesJsBuilderBundle" => Mautic\PluginBundle\Entity\Plugin {#4621},
     "HelloWorldBundle" => Mautic\PluginBundle\Entity\Plugin {#4573},
     "MauticFocusBundle" => Mautic\PluginBundle\Entity\Plugin {#4613},
     "MauticTagManagerBundle" => Mautic\PluginBundle\Entity\Plugin {#4616},
     "MauticOutlookBundle" => Mautic\PluginBundle\Entity\Plugin {#4665},
     "MauticSocialBundle" => Mautic\PluginBundle\Entity\Plugin {#4681},
     "MauticZapierBundle" => Mautic\PluginBundle\Entity\Plugin {#4678},
   ]
>>>
```

#### getAllPluginsConfig と getInstalledPlugins 
名前の通りではあるが、`getAllPluginsConfig` はあくまで設定情報として取得しているものであって、実際に mautic にインストールされているかは分からないものも含まれている。

逆に `getInstalledPlugins` はインストールされているかを DB から抽出している。

### pluginModel->getInstalledPluginTables

```php
public function getInstalledPluginTables(array $pluginsMetadata)
{
    $currentSchema          = $this->em->getConnection()->getSchemaManager()->createSchema();
    $installedPluginsTables = [];

    foreach ($pluginsMetadata as $bundleName => $pluginMetadata) {
        foreach ($pluginMetadata as $meta) {
            $table = $meta->getTableName();

            if (!isset($installedPluginsTables[$bundleName])) {
                $installedPluginsTables[$bundleName] = [];
            }

            if ($currentSchema->hasTable($table)) {
                $installedPluginsTables[$bundleName][] = $currentSchema->getTable($table);
            }
        }
    }

    return $installedPluginsTables;
}
```

`$pluginsMetadata` はすでに取得しているが、一つ例をあげておくと以下のようになる。

```php
>>> $pluginModel->getPluginsMetadata();
>>> array_key_first($pluginMetadata)
=> "MauticPlugin\HelloWorldBundle"
>>> $metadata = $pluginMetadata["MauticPlugin\HelloWorldBundle"]
=> [
     "MauticPlugin\HelloWorldBundle\Entity\World" => Doctrine\ORM\Mapping\ClassMetadata {#5750
       +name: "MauticPlugin\HelloWorldBundle\Entity\World",
       +namespace: "MauticPlugin\HelloWorldBundle\Entity",
...
>>> array_key_first($metadata)
=> "MauticPlugin\HelloWorldBundle\Entity\World"
>>> $meta = $metadata["MauticPlugin\HelloWorldBundle\Entity\World"]
=> Doctrine\ORM\Mapping\ClassMetadata {#5658
     +name: "MauticPlugin\HelloWorldBundle\Entity\World",
     +namespace: "MauticPlugin\HelloWorldBundle\Entity",
     +rootEntityName: "MauticPlugin\HelloWorldBundle\Entity\World",
...
>>> $meta->getTableName();
=> "hello_world"
```

後は `$currentSchema` に入っている情報と突き合わせて、テーブル情報を収集している。

インストール直後とかだとそれほど数は多くない。 (HelloWorldBundle は追加で入れているもの）
テーブルを複数使っているプラグインがあることも分かる。

```php
>>> $installedPluginTables = $pluginModel->getInstalledPluginTables($pluginMetadata)
=> [
     "MauticPlugin\HelloWorldBundle" => [
       Doctrine\DBAL\Schema\Table {#11257},
     ],
     "MauticPlugin\MauticTagManagerBundle" => [
       Doctrine\DBAL\Schema\Table {#11724},
     ],
     "MauticPlugin\MauticCitrixBundle" => [
       Doctrine\DBAL\Schema\Table {#12562},
     ],
     "MauticPlugin\MauticSocialBundle" => [
       Doctrine\DBAL\Schema\Table {#12089},
       Doctrine\DBAL\Schema\Table {#12032},
       Doctrine\DBAL\Schema\Table {#13314},
       Doctrine\DBAL\Schema\Table {#13260},
       Doctrine\DBAL\Schema\Table {#12066},
     ],
     "MauticPlugin\MauticCrmBundle" => [
       Doctrine\DBAL\Schema\Table {#12576},
     ],
     "MauticPlugin\GrapesJsBuilderBundle" => [
       Doctrine\DBAL\Schema\Table {#6726},
     ],
     "MauticPlugin\MauticFocusBundle" => [
       Doctrine\DBAL\Schema\Table {#11069},
       Doctrine\DBAL\Schema\Table {#11101},
     ],
   ]
```

### pluginModel->createPluginSchemas

`PluginModel` はこれが最後。

```php
public function createPluginSchemas(array $installedPluginsTables)
{
    $installedPluginsSchemas = [];
    foreach ($installedPluginsTables as $bundleName => $tables) {
        $installedPluginsSchemas[$bundleName] = new Schema($tables);
    }

    return $installedPluginsSchemas;
}
```

メソッド名が `create` になっているが、このメソッドで DB にデータを作成する訳ではない。
単純に `$installedPluginsTables` のマッピングを変えているだけで値を `Schema` のオブジェクトに変更している。

ここまでで `PluginModel` を使ったプラグイン情報の収集部分を見た。
次回は `ReloadHelper` でのプラグインの更新処理を確認していく。