mautic の import 機能を少しみてみる
Published: 2021-07-07 23:25:05

https://github.com/mautic/mautic/commit/93813f25837ec83783078193f9b6a7fb68f714fb

commits を眺めていると、上記が入っていたので import 機能についてみてみた。

上記の commit 自体は以下の PR にある通りで、ざっくりこんな感じ。
- これまで `companies` と `contacts` の 2 つで利用できていた
- DB Schema 視点でいえば他のデータも対応できるはず
- しかし、いくつかハードコードがあって使えてなかったので変更したよ

[Import events #7308](https://github.com/mautic/mautic/pull/7308)

## import 機能
- https://mautic.ddev.site/s/contacts/import/new
- https://mautic.ddev.site/s/companies/import/new

上記の 2 箇所ですね。ただ、 routing の定義としては以下のように `{object}` をパラメータに取るようになっているので、固定ではないオブジェクトを受け入れられるようになっているようです。
https://github.com/mautic/mautic/blob/7d4b436891b8ca84b34d2b0f5856bbff2a721c3a/app/bundles/LeadBundle/Config/config.php#L110-L117
```php
'mautic_import_index' => [
    'path'       => '/{object}/import/{page}',
    'controller' => 'MauticLeadBundle:Import:index',
],
'mautic_import_action' => [
    'path'       => '/{object}/import/{objectAction}/{objectId}',
    'controller' => 'MauticLeadBundle:Import:execute',
],
```

### new はどこに受け入れられる？
パッと見では上記の routes 定義では `new` 少なくとも `mautic_import_index` にはマッチしそうにないです。一応確認します。

```bash
$ php bin/console router:match /s/companies/import/new

 Route "mautic_import_index" almost matches but requirement for "page" does not match (\d+)


 [OK] Route "mautic_import_action" matches


+--------------+-----------------------------------------------------------------------------------------------+
| Property     | Value                                                                                         |
+--------------+-----------------------------------------------------------------------------------------------+
| Route Name   | mautic_import_action                                                                          |
| Path         | /s/{object}/import/{objectAction}/{objectId}                                                  |
| Path Regex   | #^/s/(?P<object>[^/]++)/import/(?P<objectAction>[^/]++)(?:/(?P<objectId>[a-zA-Z0-9_-]+))?$#sD |
| Host         | ANY                                                                                           |
| Host Regex   |                                                                                               |
| Scheme       | ANY                                                                                           |
| Method       | ANY                                                                                           |
| Requirements | objectId: [a-zA-Z0-9_-]+                                                                      |
| Class        | Symfony\Component\Routing\Route                                                               |
| Defaults     | _controller: Mautic\LeadBundle\Controller\ImportController::executeAction                     |
|              | objectId: 0                                                                                   |
| Options      | compiler_class: Symfony\Component\Routing\RouteCompiler                                       |
+--------------+-----------------------------------------------------------------------------------------------+
```
https://developer.mautic.org/#routes

やはりマッチしたのは、 `mautic_import_action` の方でした。

### execute はどこ？
継承関係をたどっていくと以下に行き着きました。
https://github.com/mautic/mautic/blob/7d4b436891b8ca84b34d2b0f5856bbff2a721c3a/app/bundles/CoreBundle/Controller/CommonController.php#L455-L462

```php
public function executeAction($objectAction, $objectId = 0, $objectSubId = 0, $objectModel = '')
{
    if (method_exists($this, "{$objectAction}Action")) {
        return $this->{"{$objectAction}Action"}($objectId, $objectModel);
    }


    return $this->notFound();
}
```

確かに `Mautic\LeadBundle\Controller\ImportController.php` には、 `newAction` が存在するため、ここにマッチしていることがわかりました。

## Event

PR を見ていて、特に大きな変更になったのは処理を Event に移譲していた部分ではないかと思います。

Event 部分の知識が全然なので順を追ってみていきたいと思います。

### LeadEvents 定数
https://github.com/mautic/mautic/commit/93813f25837ec83783078193f9b6a7fb68f714fb#diff-838ce9c2377d106faf00bf4c65aee930f4c1bf56c0389046c5296cbe214c117eR371-R399

PR 内で 3 つの `LeadEvents` 定数が新たに定義されています。これが Event の key になるものだと思います。

[Debugging Event Listeners](https://symfony.com/doc/4.4/event_dispatcher.html#debugging-event-listeners)

上記のドキュメントから、特定の Event に対する Listeners を取得できるようなので実行してみます。

```bash
$ php bin/console debug:event-dispatcher mautic.lead_import_on_initialize

Registered Listeners for "mautic.lead_import_on_initialize" Event
=================================================================

 ------- ------------------------------------------------------------------------- ----------
  Order   Callable                                                                  Priority
 ------- ------------------------------------------------------------------------- ----------
  #1      Mautic\LeadBundle\EventListener\ImportContactSubscriber::onImportInit()   0
  #2      Mautic\LeadBundle\EventListener\ImportCompanySubscriber::onImportInit()   0
 ------- ------------------------------------------------------------------------- ----------
```

PR にもある 2 つの `EventSubscriberInterface` 継承クラスが表示されました。他の 2 つの Event についても調べると同じクラスがメソッド違いで表示されます。

中を少し除いてみると以下のようになっています。

```php
final class ImportCompanySubscriber implements EventSubscriberInterface {
    public static function getSubscribedEvents(): array
    {
        return [
            LeadEvents::IMPORT_ON_INITIALIZE    => ['onImportInit'],
            LeadEvents::IMPORT_ON_FIELD_MAPPING => ['onFieldMapping'],
            LeadEvents::IMPORT_ON_PROCESS       => ['onImportProcess'],
        ];
    }

// 以下も同じ function を持つ
final class ImportContactSubscriber implements EventSubscriberInterface {
```

Event に関しては、仕組みに関してもさっぱりなので、もう少し理解を深めていきたいところです。