Silverstripe 4 升级 - ModelAdmin 中的未版本化数据对象会丢失其图像对象



为此拔头发一天,耗尽了我的谷歌foo。我继承了一个 Silverstripe 3.4 网站,我们已经升级到 4.4。但是在运行MigrateFilesTask之后,某些图像发生了一些奇怪的事情。

我认为这与附加到通过 ModelAdmin 访问的未版本化对象的文件有关。但我未能找到明确的解决方案。

此对象的代码如下。遇到的问题就在它之下。

<?php
use SilverStripeAssetsImage;
use gorriecoeLinkModelsLink;
use SilverStripeSecurityMember;
use SilverStripeControlController;
use SilverStripeViewParsersURLSegmentFilter;
use SilverStripeFormsTextField;
use SilverStripeFormsFieldGroup;
use gorriecoeLinkFieldLinkField;
use SilverStripeTagFieldTagField;
use SilverStripeORMDataObject;
use SilverStripeSelectUploadSelectUploadField;
class Person extends DataObject
{
private static $db = array(
'FirstName'        => 'Varchar(128)',
'LastName'         => 'Varchar(128)',
'Role'             => 'Varchar(128)',
'DirectDialNumber' => 'Varchar(128)',
'Email'            => 'Varchar(128)',
'CellphoneNumber'  => 'Varchar(30)',
'DirectDial'       => 'Varchar(30)',
'UrlSegment'       => 'Varchar(255)',
'Blurb'            => 'HTMLText',
'SortOrder'        => 'Int'
);
private static $has_one = array(
'Image' => Image::class,
'Office' => 'Office',
'LinkedIn' => Link::class,
'Member' => Member::class
);
private static $many_many = array(
'Interests' => 'Section'
);
private static $belongs_many_many = array(
'ElementCollection' => 'ElementCollection'
);
static $sort_fields = array(
'FirstName' => 'First name',
'LastName' => 'Last name',
'Role' => 'Role'
);
private static $summary_fields = array(
'Name' => 'Name',
'Role' => 'Role',
'Office.Name' => 'Office'
);
private static $searchable_fields = array(
'FirstName',
'LastName',
'Role'
);
// For use with the ElementCollection
public static $templates = array(
'ElementPeople' => 'Default',
'ElementPeopleAlternative' => 'Alternative'
);

public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->removeByName( ['SortOrder', 'ElementCollection', 'FirstName', 'LastName', 'Interests'] );
$firstname = TextField::create('FirstName', 'First name');
$lastname = TextField::create('LastName', 'Last name');
$fields->addFieldsToTab('Root.Main', FieldGroup::create($firstname, $lastname)->setTitle('Name')->setName('Name'), 'Role');
$image = UploadField::create('Image', 'Photo');
$image->setFolderName('Uploads/People');
$image->setCanSelectFolder(false);
$fields->addFieldToTab('Root.Main', $image);
$linkedin = LinkField::create('LinkedIn', 'LinkedIn', $this);
$fields->addFieldToTab('Root.Main', $linkedin);
$interests = TagField::create(
'Interests',
'Interests Tags',
Section::get(),
$this->Interests()
)->setShouldLazyLoad(true)
->setCanCreate(false);
$fields->addFieldToTab('Root.Main', $interests);
return $fields;
}
public function onBeforeWrite()
{
$count = 1;
$this->UrlSegment = $this->generateURLSegment();
while (!$this->validURLSegment()) {
$this->UrlSegment = preg_replace('/-[0-9]+$/', null, $this->UrlSegment) . '-' . $count;
$count++;
}
parent::onBeforeWrite();
}
}

问题 #1是在运行 MigrateFileTask 后,附加到此类实例的所有现有图像都将从/assets/Uploads/People 移动到/assets/.protected/Uploads/People。这里令人困惑的部分是,还有一个名为 Company 的类在结构上几乎相同,但其图像仍按预期保留在/assets/Uploads/Companies 中。

问题 #2是,如果我创建一个新的 Person 对象并附加一个图像,该图像位于草稿中,位于/assets/.protected/Uploads/People 中,没有实际发布它的方法。同时,如果我对公司对象执行相同的操作,图像仍在草稿中,但我可以在 CMS 中看到它。

有人可以就上述内容提供一些指导吗?在这一点上,我很高兴能够在DO时发布图像,我将手动浏览每个Person记录并点击保存自己,以便通过该行进行此升级。

您应该能够通过将图像添加到 DataObbejct 的owns属性来解决此问题。基本上添加这个:

private static $owns = [
'Image'
];

基本上owns告诉DataObject在保存时要发布哪些对象:

文档中的详细信息:https://docs.silverstripe.org/en/4/developer_guides/model/versioning/#defining-ownership-between-related-versioned-dataobjects

找到了问题 #1 的原因。把它留在这里以防将来对某人有帮助:

数据库表文件对系统中的每个文件和文件夹都有一行。此表有一个名为"CanViewType"的列。它存在于银条3和4中。

对于在迁移过程中引起问题的特定文件夹,我发现它是唯一将该列设置为"仅这些用户"的文件夹。其余的设置为"继承"。这是升级前表的状态。

我不确定如何或通过什么机制更改该行,但问题 #1 的解决方案是在运行 FileMigrationTask 之前手动将该字段更改为"继承"。

问题#2仍然存在,但看起来这里有两个非常不同的问题。

好的。所以最终解决了问题 #2(有关 #1 的解决方案,请参阅其他答案(,但它极大地削弱了我们对 Silverstripe 的信心,并引发了这里的会议。

面向未来读者的代码:

在未受版本控制的数据对象中,添加此项。在这种情况下,我的文件对象称为"图像"。如果要在保存时发布多个文件,则必须为每个文件添加其中一个 IF 块。

public function onAfterWrite()
{
if ($this->Image()->exists() && !$this->Image()->isPublished()) {
$this->Image()->doPublish();
}
parent::onAfterWrite();
}

旁注:

这种对象/文件关系确实是一个奇怪的设计选择。实际上是否存在任何您希望将文件或图像附加到数据对象而不是在保存/发布对象/页面的同时发布该文件的情况?开发人员甚至需要使用$owns在版本化对象上显式定义它 - 我很高兴打赌,大多数开发人员必须添加更多次而不是不添加。这应该真正告诉我们有些事情是错误的。

将图像添加到CMS系统应该不难。最多应该需要阅读基本文档。不是谷歌搜索,深入的API文档潜水(回答不多(或在StackOverlfow上发布(没有人真正知道答案(超过三天。这是一个图像。产品的核心功能。

自 v2.4 以来,我一直在使用 SS,并看到了进入 v4 的所有惨痛教训。但这似乎是简单被过度设计的教科书案例。

最新更新