私はこれを調べるのに多くの時間を費やしましたが、基本的に変更することなくManyManyList
(拡張システムを介して必要なフックを公開しないため)、多くの選択肢はありません。
私はデザートファーストのタイプですが、どうすればそれができますか?
この偉業を達成するための私の唯一の提案は、本質的に多対多のブリッジ オブジェクト (つまり、Page
とImage
を結合する別個のエンティティ)$has_many
ですが、それでもかなりの変更が必要です。
これは、結合テーブルではなく実際のオブジェクトに対してバージョン管理されたアイテムを保存することによって、実際の関係を破壊することに関する解決策がフォーラムで部分的に議論されています。それはうまくいくでしょうが、私たちはまだそれよりもうまくやれると思います.
私は個人的に、関係のバージョンをそれ自体に結びつけることに傾倒してPage
おり、以下の部分的な解決策がこれをカバーしています。への更新としてこれを試してみて、詳細についてはスクロールせずに読むManyManyList
.
このようなものが始まりです:
class PageImageVersion extends DataObject
{
private static $db = array(
'Version' => 'Int'
);
private static $has_one = array(
'Page' => 'Page',
'Image' => 'Image'
);
}
これには双方向の関係が含まれており、さらにバージョン番号が保存されています。必要な適切なフィールドを追加する機能を指定しgetCMSFields
て、既存の画像に関連付けたり、新しい画像をアップロードしたりできます。実際のバージョン処理部分に比べて比較的簡単なはずなので、これをカバーすることは避けています。
これで、次のhas_many
ようPage
になります。
private static $has_many = array(
'Images' => 'PageImageVersion'
);
私のテストでは、次のようにImage
マッチングを追加するための拡張機能も追加しました。$has_many
class ImageExtension extends DataExtension
{
private static $has_many = array(
'Pages' => 'PageImageVersion'
);
}
正直なところ、関係の側にPages
機能を追加する以外にこれが必要かどうかはわかりません. Image
私が見る限り、この特定のユースケースではそれほど重要ではありません。
残念ながら、このバージョン管理方法のために、 を呼び出す標準的な方法を使用することはできませんImages
。少し工夫する必要があります。このようなもの:
public function getVersionedImages($Version = null)
{
if ($Version == null)
{
$Version = $this->Version;
}
else if ($Version < 0)
{
$Version = max($this->Version - $Version, 1);
}
return $this->Images()->filter(array('Version' => $Version));
}
を呼び出すと、現在のページのバージョンに合わせて設定されたgetVersionedImages()
すべての画像が返されます。また、最後のバージョンを介して以前のバージョンを取得したり、任意の位置番号を渡すことでページの特定のバージョンの画像を取得したりVersion
することもサポートしています。getVersionedImages(-1)
OK、ここまでは順調です。ここで、ページの書き込みごとに、この新しいバージョンのページの画像の重複リストを取得していることを確認する必要があります。
onAfterWrite
関数 onを使用するとPage
、次のことができます。
public function onAfterWrite()
{
$lastVersionImages = $this->getVersionedImages(-1);
foreach ($lastVersionImages as $image)
{
$duplicate = $image->duplicate(false);
$duplicate->Version = $this->Version;
$duplicate->write();
}
}
家で遊んでいる人にとって、これは、以前のバージョンの復元がこれにどのように影響するかに関して、少し不安になる場所Page
です.
これを で編集するためGridField
、いくつかの操作を行う必要があります。まず、コードがAdd New
関数を処理できることを確認します。
私の考えはonAfterWrite
オブジェクトPageImageVersion
です:
public function onAfterWrite()
{
//Make sure the version is actually saved
if ($this->Version == 0)
{
$this->Version = $this->Page()->Version;
$this->write();
}
}
バージョン管理されたアイテムを に表示するにはGridField
、次のように設定します。
$gridFieldConfig = GridFieldConfig_RecordEditor::create();
$gridField = new GridField("Images", "Images", $this->getVersionedImages(), $gridFieldConfig);
$fields->addFieldToTab("Root.Images", $gridField);
GridField
ビアから直接画像にリンクしたいかもしれませんが、GridFieldConfig_RelationEditor
これは事態が悪化するときです。
野菜の時間…
大きな困難の 1 つは、GridField
これらのエンティティのリンクとリンク解除の両方です。標準を使用するGridFieldDeleteAction
と、適切なバージョンなしで関係が直接更新されます。
オブジェクトを書き込んで(別のバージョンをトリガーするために) を拡張GridFieldDeleteAction
およびオーバーライドし、バージョン管理されたイメージ オブジェクトのすべてのバージョンを最後のバージョンに複製し、新しいバージョンで不要なものをスキップする必要があります。handleAction
Page
認めますが、この最後のビットは私の当て推量です。私の理解とデバッグから、それはうまくいくはずですが、それを正しくするために多くの手間がかかります。
の拡張子をGridFieldDeleteAction
特定の に追加する必要がありますGridField
。
これは基本的に、このソリューションを機能させるための最後のステップです。追加、削除、複製、バージョン更新の部分がダウンしたら、実際に使用getVersionedImages()
して適切なイメージを取得するだけです。
結論
避ける。あなたがこれをやりたい理由はわかりますmany_many
が、Silverstripe で関係を処理する方法を適切なサイズで更新しないと、これを処理できるクリーンな方法が本当にわかりません。
しかし、私は本当にそれが欲しいですManyManyList
!
必要と思われる変更はManyManyList
、3 ウェイ キー (外部キー、ローカル キー、バージョン キー) と、追加/削除/取得などのさまざまな方法の更新です。
add
and関数にフックがあれば、remove
(Silverstripe の拡張システムを介して) 拡張機能として機能を忍び込ませ、必要なデータをmany_many
関係が許可する余分なフィールドに追加できる可能性があります。
直接拡張してから を介して強制的にカスタム クラスに置き換えることでこれを実現できますが、それはさらに厄介な解決策になります。ManyManyList
ManyManyList
Object::useCustomClass
この段階で純粋なソリューションに対して完全な答えを出すには、あまりにも長すぎて複雑すぎますManyManyList
(ただし、後でこれに戻って試してみるかもしれません)。
免責事項: 私は Silverstripe Core 開発者ではありません。この問題全体に対するより適切な解決策があるかもしれませんが、その方法がわかりません。