在 SilverStripe 中链接/取消链接多条记录后更新字段

tho*_*son 5 silverstripe

Customer DataObject通过扩展创建了一个Member. 与 aCustomermany_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 代码做了更多的“黑客攻击”,这就是为什么它的可维护性要低得多。它需要更多的修改(在两个类中),如果你想做任何额外的链接/取消链接管理,比如添加自定义管理模块或某些表单,则需要成倍增加。


Oll*_*elä 0

注意:实际上并没有检查模型是否有效,但通过目视检查这应该可以帮助您:

在您提供的链接上,您正在使用

$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));将仅输出对象的类。