UpgradePolymorphicExtension   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 71
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 32
c 2
b 0
f 0
dl 0
loc 71
rs 10
wmc 11

1 Method

Rating   Name   Duplication   Size   Complexity  
B requireDefaultRecords() 0 50 11
1
<?php
2
3
namespace SilverStripe\UserForms\Extension;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\Core\Injector\Injector;
7
use SilverStripe\ORM\DataExtension;
8
use SilverStripe\ORM\DataList;
9
use SilverStripe\ORM\DataObject;
10
use SilverStripe\ORM\ValidationException;
11
use SilverStripe\UserForms\Model\EditableFormField;
12
use SilverStripe\UserForms\Model\Recipient\EmailRecipient;
13
use SilverStripe\UserForms\Model\Submission\SubmittedForm;
14
use SilverStripe\UserForms\Model\UserDefinedForm;
15
use SilverStripe\UserForms\UserForm;
16
17
/**
18
 * This extension provides a hook that runs during a dev/build which will check for existing data in various
19
 * polymorphic relationship fields for userforms models, and ensure that the data is correct.
20
 *
21
 * Various `Parent` relationships in silverstripe/userforms for SilverStripe 3 were mapped directly to UserDefinedForm
22
 * instances, and were made polymorphic in SilverStripe 4 (which also requires a class name). This means that a
23
 * certain amount of manual checking is required to ensure that upgrades are performed smoothly.
24
 *
25
 * @internal This API is likely to be removed in later major versions of silverstripe/userforms
26
 */
27
class UpgradePolymorphicExtension extends DataExtension
28
{
29
    /**
30
     * A list of userforms classes that have had polymorphic relationships added in SilverStripe 4, and the fields
31
     * on them that are polymorphic
32
     *
33
     * @var array
34
     */
35
    protected $targets = [
36
        EditableFormField::class => ['ParentClass'],
37
        EmailRecipient::class => ['FormClass'],
38
        SubmittedForm::class => ['ParentClass'],
39
    ];
40
41
    /**
42
     * The default class name that will be used to replace values with
43
     *
44
     * @var string
45
     */
46
    protected $defaultReplacement = UserDefinedForm::class;
47
48
    public function requireDefaultRecords()
49
    {
50
        if (!UserDefinedForm::config()->get('upgrade_on_build')) {
51
            return;
52
        }
53
54
        $updated = 0;
55
        foreach ($this->targets as $className => $fieldNames) {
56
            foreach ($fieldNames as $fieldName) {
57
                /** @var DataList $list */
58
                $list = $className::get();
59
60
                foreach ($list as $entry) {
61
                    /** @var DataObject $relationshipObject */
62
                    $relationshipObject = Injector::inst()->get($entry->$fieldName);
63
                    if (!$relationshipObject) {
64
                        continue;
65
                    }
66
67
                    // If the defined data class doesn't have the UserForm trait applied, it's probably wrong. Re-map
68
                    // it to a default value that does
69
                    $classTraits = class_uses($relationshipObject);
70
                    if (in_array(UserForm::class, $classTraits)) {
71
                        continue;
72
                    }
73
74
                    // Don't rewrite class values when an existing value is set and is an instance of UserDefinedForm
75
                    if ($relationshipObject instanceof UserDefinedForm) {
76
                        continue;
77
                    }
78
79
                    $entry->$fieldName = $this->defaultReplacement;
80
                    try {
81
                        $entry->write();
82
                        $updated++;
83
                    } catch (ValidationException $ex) {
84
                        // no-op, allow the rest of dev/build to continue. There may be an error indicating that the
85
                        // object's class doesn't exist, which can be fixed by {@link DatabaseAdmin::doBuild} and this
86
                        // logic will work the next time dev/build is run.
87
                    }
88
                }
89
            }
90
        }
91
92
        if ($updated) {
93
            $message = "Corrected {$updated} default polymorphic class names to {$this->defaultReplacement}";
94
            if (Director::is_cli()) {
95
                echo sprintf(" * %s\n", $message);
96
            } else {
97
                echo sprintf("<li>%s</li>\n", $message);
98
            }
99
        }
100
    }
101
}
102