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

Silverstripe 4升级-ModelAdmin中未版本化的数据对象将丢失其映像对象,silverstripe,silverstripe-4,Silverstripe,Silverstripe 4,一天来我一直在为这件事发愁,我的google foo已经精疲力尽了。我继承了一个Silverstripe 3.4站点,我们已将其升级到4.4。但在运行MigrateFileTask之后,某些图像出现了一些奇怪的情况 我认为这与将文件附加到通过ModelAdmin访问的未版本对象有关。但我还没有找到一个明确的解决办法 下面是此对象的代码。所遇到的问题都在其范围内 <?php use SilverStripe\Assets\Image; use gorriecoe\Link\Models\L

一天来我一直在为这件事发愁,我的google foo已经精疲力尽了。我继承了一个Silverstripe 3.4站点,我们已将其升级到4.4。但在运行MigrateFileTask之后,某些图像出现了一些奇怪的情况

我认为这与将文件附加到通过ModelAdmin访问的未版本对象有关。但我还没有找到一个明确的解决办法

下面是此对象的代码。所遇到的问题都在其范围内

<?php

use SilverStripe\Assets\Image;
use gorriecoe\Link\Models\Link;
use SilverStripe\Security\Member;
use SilverStripe\Control\Controller;
use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\FieldGroup;
use gorriecoe\LinkField\LinkField;
use SilverStripe\TagField\TagField;
use SilverStripe\ORM\DataObject;
use SilverStripe\SelectUpload\SelectUploadField;

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();
  }
}

您应该能够通过将映像添加到DataObejct的
所有者
属性来解决此问题。基本上加上:

    private static $owns = [
        'Image'
    ];
基本上,
owns
告诉
DataObject
保存时要发布哪些对象:

文档中的更多信息:

已找到问题的原因#1。将此保留在此处,以防将来对某人有所帮助:

数据库表文件中的每个文件和文件夹都有一行。此表有一个名为“CanViewType”的列。它存在于Silverstripe 3和4中

对于迁移过程中出现问题的特定文件夹,我发现它是唯一一个将该列设置为“OnlyTheseUsers”的文件夹。其余的设置为“继承”。这是升级前表的状态

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

问题2依然存在,但这里似乎有两个截然不同的问题。

好的。因此,问题2最终得到了解决(参见第1个问题解决方案的其他答案),但它极大地削弱了我们对Silverstripe的信心,并在这里引发了一场会议

未来读者代码:

在未版本化的数据对象中,添加此项。在这种情况下,我的文件对象称为“Image”。如果保存时要发布多个文件,则必须为每个文件添加一个If块

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

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

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


从v2.4开始,我就一直在与SS合作,并且看到了在进入v4时所学到的所有艰苦的经验教训。但这似乎是一个简单的被过度设计的教科书案例

这是我尝试的第一件事。在网上搜索之后,它看起来实际上对未版本化的对象没有任何作用。当然,它对这个类或其他类似的类没有任何作用。图像仍保存为草稿。您可以添加一个扩展-
RecursivePublishable
或类似的功能that@RobbieAverill,根据SS4文档,它已经包含在DataObject中。此处讨论:。两年前有人在这个问题上提出了同样的问题,答案表明当时就有。我认为这是SS4中“一切都是版本化的”推送的一个例子,我认为在某些情况下,未版本化的对象已经推送通过了裂缝。我建议对上面的代码要小心,我在过去使用过类似的代码,由于
isPublished()
报告似乎并不总是准确。我发现只要使用
$object->publishRecursive()工作得更好,你也不需要检查对象是否已经发布。谢谢@Psycholomo。
$object->publishRecursive()
到底会去哪里?尝试交换
$this->Image()->doPublish()$this->Image()->publishRecursive()
进行编码>。然后还应该能够删除If语句。