0

Symfony2 にソフト削除機能を実装しようとしています。ほとんどの場合、希望どおりに機能していますが、関連するエンティティに少し問題があります。重要ではないデータについては、関連するエンティティを論理的に削除できるようにしたいと考えていますが、すべてのデータはそのままにしておきます。

たとえば、次のテーブル構造を持つ Account エンティティと City エンティティがあるとします。

table: account
---------------------------
id | account_name | city_id
---------------------------
1  | Jane Doe     | 1
2  | John Smith   | 1
3  | Dave Jones   | 2


table: city
---------------------------
id | city_name | deleted
---------------------------
1  | Phoenix   | 1
2  | New York  | 0

したがって、この場合、「Phoenix」はソフト削除されており、アカウント テーブルの 2 つの行はそのリンクを保持しています。このようにして、Phoenix の削除を取り消すことができ、データが失われることはありません。

もちろん、Phoenix が論理的に削除されている場合、アカウントを表示するときにそのデータを表示したくありません。行を除外する Doctrine フィルターを作成しましたdeleted = 1。ただし、Account テーブルのリンクされた列はまだ存在するため、本質的に存在しない関連オブジェクト (Phoenix) を指しているため、EntityNotFoundException がスローされます。

これは私の問題です。2 つのオブジェクト間のリンクを保持しながら、都市がソフト削除されたアカウントのリストを表示するにはどうすればよいですか?

私の考えでは、アカウントのリストを表示すると、次のようになります。

Account Name | City
---------------------------
Jane Doe     | -
John Smith   | -
Dave Jones   | New York

簡単な実験として、EntityNotFoundException をキャッチして、とにかくデータを返すことを試みました。これは意図したとおりに機能するように見えましたが、かなり醜いハックであり、あちこちで繰り返す必要があります (私が気付いていない別の方法がない限り)。以下は、私がテストした SonataAdmin CRUDController の例です。

try {
    return $this->render($this->admin->getTemplate('list'), array(
        'action'   => 'list',
        'form'     => $formView,
        'datagrid' => $datagrid
    ));
} catch (\Twig_Error_Runtime $e) {
    if (strpos($e->getMessage(), 'Entity was not found')) {
        return $this->render($this->admin->getTemplate('list'), array(
            'action'   => 'list',
            'form'     => $formView,
            'datagrid' => $datagrid
        ));
    }
}

私はその解決策に満足していません。私が見逃しているもっと良い方法があると感じています。

記録のために、これは私のフィルターです:

class SoftDeleteFilter extends SQLFilter
{
    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        if (!$targetEntity->hasField('deleted')) {
            return '';
        }

        return $targetTableAlias . '.deleted = false';
    }
}

前もって感謝します!

4

1 に答える 1