我Customer DataObject通过扩展创建了一个Member. 与 aCustomer有many_many数据关系Package DataObject。
我想Credits在基于表中的字段通过 CMS 链接/取消链接Customer DataObjecta 时增加/减少一个字段。PackageLimitPackage
顾客
class Customer extends Member {
private static $db = array(
'Gender' => 'Varchar(2)',
'DateOfBirth' => 'Date',
'Featured' => 'Boolean',
'Credits' => 'Int'
);
private static $many_many = array(
'Packages' => 'Package'
);
public function getCMSFields() {
$fields = new FieldList();
$config = GridFieldConfig_RelationEditor::create();
$config->removeComponentsByType('GridFieldAddNewButton');
$packageField = new GridField(
'Packages',
'Package',
$this->Packages(),
$config
);
$fields->addFieldToTab('Root.Package', $packageField);
Session::set('SingleID', $this->ID);
$this->extend('updateCMSFields', $fields);
return $fields;
}
}
Run Code Online (Sandbox Code Playgroud)
包裹
class Package extends DataObject {
private static $db = array(
'Title' => 'Varchar(255)',
'Limit' => 'Int'
);
private static $belongs_many_many = array(
'Customers' => 'Customer'
);
}
Run Code Online (Sandbox Code Playgroud)
小智 6
当您创建或删除多对多关系时,只会修改数据库中的一条记录 - 表中的一条记录连接关系双方的元素。因此,关系所基于的对象都不会更新。这就是为什么像: onBeforeWrite, onAfterWrite, onBeforeDeleteand这样的方法onAfterDelete根本不会被调用,并且您不能使用它们来检测这种变化。
然而,Silverstripe 提供了ManyManyList负责连接到多对多关系的所有操作的类。您感兴趣的方法有两种:添加和删除。您可以覆盖它们并在内部操作以执行您需要的操作。无论对象类型如何,这些方法显然都会在每个链接或取消链接操作上调用,因此您应该对您特别感兴趣的类进行一些过滤。
重写ManyManyList类的正确方法是使用注入器机制,以免修改框架或cms文件夹内的任何内容。下面的示例使用 Silverstripe 中成员和组之间的关系,但您可以轻松地根据需要采用它(客户 -> 成员;包 -> 组)。
应用程序.yml
Injector:
ManyManyList:
class: ManyManyListExtended
Run Code Online (Sandbox Code Playgroud)
ManyManyListExtended.php
Injector:
ManyManyList:
class: ManyManyListExtended
Run Code Online (Sandbox Code Playgroud)
3dgoo 提供的解决方案也应该可以正常工作,但 IMO 代码做了更多的“黑客攻击”,这就是为什么它的可维护性要低得多。它需要更多的修改(在两个类中),如果你想做任何额外的链接/取消链接管理,比如添加自定义管理模块或某些表单,则需要成倍增加。
注意:实际上并没有检查模型是否有效,但通过目视检查这应该可以帮助您:
在您提供的链接上,您正在使用
$customer = Customer::get()->Filter...
Run Code Online (Sandbox Code Playgroud)
它返回一个对象的 DataList,而不是单个对象,除非您指定要从 DataList 中获取的对象是什么。
如果您正在过滤客户,那么您希望从数据列表中获取特定客户,例如本例中的第一个客户。
$customer = Customer::get()->filter(array('ID' => $this->CustomerID))->first();
Run Code Online (Sandbox Code Playgroud)
但是您应该能够通过以下方式获取单个 DataObject:
$customer = $this->Customer();
Run Code Online (Sandbox Code Playgroud)
当您将客户定义为“has_one”时。如果关系是 Has Many,则使用 () 将获得对象的 DataList。
专家提示:
您不需要在 SilverStripe 中编写我们自己的调试文件。它有自己的功能。例如Debug::log("yay");,什么将输出写入文件并Debug::dump("yay")直接转储出来。
提示是您可以检查您正确访问的对象是什么。Debug::dump(get_class($customer));将仅输出对象的类。
| 归档时间: |
|
| 查看次数: |
1069 次 |
| 最近记录: |