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