silverstripe-userforms/code/Extension/UpgradePolymorphicExtension.php
2022-04-13 13:52:56 +12:00

102 lines
3.9 KiB
PHP

<?php
namespace SilverStripe\UserForms\Extension;
use SilverStripe\Control\Director;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ValidationException;
use SilverStripe\UserForms\Model\EditableFormField;
use SilverStripe\UserForms\Model\Recipient\EmailRecipient;
use SilverStripe\UserForms\Model\Submission\SubmittedForm;
use SilverStripe\UserForms\Model\UserDefinedForm;
use SilverStripe\UserForms\UserForm;
/**
* This extension provides a hook that runs during a dev/build which will check for existing data in various
* polymorphic relationship fields for userforms models, and ensure that the data is correct.
*
* Various `Parent` relationships in silverstripe/userforms for SilverStripe 3 were mapped directly to UserDefinedForm
* instances, and were made polymorphic in SilverStripe 4 (which also requires a class name). This means that a
* certain amount of manual checking is required to ensure that upgrades are performed smoothly.
*
* @internal This API is likely to be removed in later major versions of silverstripe/userforms
*/
class UpgradePolymorphicExtension extends DataExtension
{
/**
* A list of userforms classes that have had polymorphic relationships added in SilverStripe 4, and the fields
* on them that are polymorphic
*
* @var array
*/
protected $targets = [
EditableFormField::class => ['ParentClass'],
EmailRecipient::class => ['FormClass'],
SubmittedForm::class => ['ParentClass'],
];
/**
* The default class name that will be used to replace values with
*
* @var string
*/
protected $defaultReplacement = UserDefinedForm::class;
public function requireDefaultRecords()
{
if (!UserDefinedForm::config()->get('upgrade_on_build')) {
return;
}
$updated = 0;
foreach ($this->targets as $className => $fieldNames) {
foreach ($fieldNames as $fieldName) {
/** @var DataList $list */
$list = $className::get();
foreach ($list as $entry) {
/** @var DataObject $relationshipObject */
$relationshipObject = Injector::inst()->get($entry->$fieldName);
if (!$relationshipObject) {
continue;
}
// If the defined data class doesn't have the UserForm trait applied, it's probably wrong. Re-map
// it to a default value that does
$classTraits = class_uses($relationshipObject);
if (in_array(UserForm::class, $classTraits ?? [])) {
continue;
}
// Don't rewrite class values when an existing value is set and is an instance of UserDefinedForm
if ($relationshipObject instanceof UserDefinedForm) {
continue;
}
$entry->$fieldName = $this->defaultReplacement;
try {
$entry->write();
$updated++;
} catch (ValidationException $ex) {
// no-op, allow the rest of dev/build to continue. There may be an error indicating that the
// object's class doesn't exist, which can be fixed by {@link DatabaseAdmin::doBuild} and this
// logic will work the next time dev/build is run.
}
}
}
}
if ($updated) {
$message = "Corrected {$updated} default polymorphic class names to {$this->defaultReplacement}";
if (Director::is_cli()) {
echo sprintf(" * %s\n", $message);
} else {
echo sprintf("<li>%s</li>\n", $message);
}
}
}
}