Completed
Push — master ( cab21e...ed90cc )
by Daniel
02:43
created

CMSPageHistoryController::getTabIdentifier()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\CMS\Controllers;
4
5
use SilverStripe\Admin\LeftAndMainFormRequestHandler;
6
use SilverStripe\CMS\Model\SiteTree;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Control\HTTPRequest;
9
use SilverStripe\Control\HTTPResponse;
10
use SilverStripe\Forms\CheckboxField;
11
use SilverStripe\Forms\FieldList;
12
use SilverStripe\Forms\Form;
13
use SilverStripe\Forms\FormAction;
14
use SilverStripe\Forms\HiddenField;
15
use SilverStripe\Forms\HTMLReadonlyField;
16
use SilverStripe\Forms\LiteralField;
17
use SilverStripe\Forms\Tab;
18
use SilverStripe\ORM\FieldType\DBField;
19
use SilverStripe\Versioned\Versioned;
20
use SilverStripe\Security\Security;
21
use SilverStripe\View\ArrayData;
22
use SilverStripe\View\ViewableData;
23
24
class CMSPageHistoryController extends CMSMain
25
{
26
27
    private static $url_segment = 'pages/history';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
28
29
    private static $url_rule = '/$Action/$ID/$VersionID/$OtherVersionID';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
30
31
    private static $url_priority = 42;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
32
33
    private static $menu_title = 'History';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
34
35
    private static $required_permission_codes = 'CMS_ACCESS_CMSMain';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
36
37
    private static $allowed_actions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
38
        'EditForm',
39
        'VersionsForm',
40
        'CompareVersionsForm',
41
        'show',
42
        'compare'
43
    );
44
45
    private static $url_handlers = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
46
        '$Action/$ID/$VersionID/$OtherVersionID' => 'handleAction',
47
        'EditForm/$ID/$VersionID' => 'EditForm',
48
    );
49
50
    /**
51
     * Current version ID for this request. Can be 0 for latest version
52
     *
53
     * @var int
54
     */
55
    protected $versionID = null;
56
57
    public function getResponseNegotiator()
58
    {
59
        $negotiator = parent::getResponseNegotiator();
60
        $controller = $this;
61
        $negotiator->setCallback('CurrentForm', function () use (&$controller) {
62
            $form = $controller->getEditForm();
63
            if ($form) {
64
                return $form->forTemplate();
65
            } else {
66
                return $controller->renderWith($controller->getTemplatesWithSuffix('_Content'));
67
            }
68
        });
69
        $negotiator->setCallback('default', function () use (&$controller) {
70
            return $controller->renderWith($controller->getViewer('show'));
71
        });
72
        return $negotiator;
73
    }
74
75
    /**
76
     * @param HTTPRequest $request
77
     * @return HTTPResponse
78
     */
79
    public function show($request)
80
    {
81
        // Record id and version for this request
82
        $id = $request->param('ID');
83
        $this->setCurrentPageID($id);
84
        $versionID = $request->param('VersionID');
85
        $this->setVersionID($versionID);
86
87
        // Show id
88
        $form = $this->getEditForm();
89
90
        $negotiator = $this->getResponseNegotiator();
91
        $controller = $this;
92
        $negotiator->setCallback('CurrentForm', function () use (&$controller, &$form) {
93
            return $form
94
                ? $form->forTemplate()
95
                : $controller->renderWith($controller->getTemplatesWithSuffix('_Content'));
96
        });
97
        $negotiator->setCallback('default', function () use (&$controller, &$form) {
98
            return $controller
99
                ->customise(array('EditForm' => $form))
100
                ->renderWith($controller->getViewer('show'));
101
        });
102
103
        return $negotiator->respond($request);
104
    }
105
106
    /**
107
     * @param HTTPRequest $request
108
     * @return HTTPResponse
109
     */
110
    public function compare($request)
111
    {
112
        $form = $this->CompareVersionsForm(
113
            $request->param('VersionID'),
114
            $request->param('OtherVersionID')
115
        );
116
117
        $negotiator = $this->getResponseNegotiator();
118
        $controller = $this;
119
        $negotiator->setCallback('CurrentForm', function () use (&$controller, &$form) {
120
            return $form ? $form->forTemplate() : $controller->renderWith($controller->getTemplatesWithSuffix('_Content'));
121
        });
122
        $negotiator->setCallback('default', function () use (&$controller, &$form) {
123
            return $controller->customise(array('EditForm' => $form))->renderWith($controller->getViewer('show'));
124
        });
125
126
        return $negotiator->respond($request);
127
    }
128
129
    public function getSilverStripeNavigator()
130
    {
131
        $record = $this->getRecord($this->currentPageID(), $this->getRequest()->param('VersionID'));
132
        if ($record) {
133
            $navigator = new SilverStripeNavigator($record);
134
            return $navigator->renderWith($this->getTemplatesWithSuffix('_SilverStripeNavigator'));
135
        } else {
136
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type of the parent method SilverStripe\Admin\LeftA...etSilverStripeNavigator of type SilverStripe\ORM\FieldType\DBHTMLText.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
137
        }
138
    }
139
140
    /**
141
     * @param HTTPRequest $request
142
     * @return Form
143
     */
144
    public function EditForm($request = null)
145
    {
146
        if ($request) {
147
            // Validate VersionID is present
148
            $versionID = $request->param('VersionID');
149
            if (!isset($versionID)) {
150
                $this->httpError(400);
151
                return null;
152
            }
153
            $this->setVersionID($versionID);
154
        }
155
        return parent::EditForm($request);
156
    }
157
158
    /**
159
     * Returns the read only version of the edit form. Detaches all {@link FormAction}
160
     * instances attached since only action relates to revert.
161
     *
162
     * Permission checking is done at the {@link CMSMain::getEditForm()} level.
163
     *
164
     * @param int $id ID of the record to show
165
     * @param array $fields optional
166
     * @param int $versionID
167
     * @param int $compareID Compare mode
168
     *
169
     * @return Form
170
     */
171
    public function getEditForm($id = null, $fields = null, $versionID = null, $compareID = null)
172
    {
173
        if (!$id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
174
            $id = $this->currentPageID();
175
        }
176
        if (!$versionID) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $versionID of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
177
            $versionID = $this->getVersionID();
178
        }
179
180
        $record = $this->getRecord($id, $versionID);
181
        if (!$record) {
182
            return $this->EmptyForm();
183
        }
184
185
        // Refresh version ID
186
        $versionID = $record->Version;
0 ignored issues
show
Bug introduced by
The property Version does not seem to exist. Did you mean versioning?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
187
        $this->setVersionID($versionID);
188
189
        // Get edit form
190
        $form = parent::getEditForm($record, $record->getCMSFields());
0 ignored issues
show
Documentation introduced by
$record is of type object<SilverStripe\CMS\Model\SiteTree>, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
191
        // Respect permission failures from parent implementation
192
        if (!($form instanceof Form)) {
193
            return $form;
194
        }
195
196
        // TODO: move to the SilverStripeNavigator structure so the new preview can pick it up.
197
        //$nav = new SilverStripeNavigatorItem_ArchiveLink($record);
198
199
        $actions = new FieldList(
200
            $revert = FormAction::create(
201
                'doRollback',
202
                _t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')
203
            )->setUseButtonTag(true)
204
        );
205
        $actions->setForm($form);
206
        $form->setActions($actions);
207
208
        $fields = $form->Fields();
209
        $fields->removeByName("Status");
210
        $fields->push(new HiddenField("ID"));
211
        $fields->push(new HiddenField("Version"));
212
213
        $fields = $fields->makeReadonly();
214
215
        if ($compareID) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $compareID of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
216
            $link = Controller::join_links(
217
                $this->Link('show'),
218
                $id
219
            );
220
221
            $view = _t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.VIEW', "view");
222
223
            $message = _t(
224
                'SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.COMPARINGVERSION',
225
                "Comparing versions {version1} and {version2}.",
226
                array(
227
                    'version1' => sprintf('%s (<a href="%s">%s</a>)', $versionID, Controller::join_links($link, $versionID), $view),
228
                    'version2' => sprintf('%s (<a href="%s">%s</a>)', $compareID, Controller::join_links($link, $compareID), $view)
229
                )
230
            );
231
232
            $revert->setReadonly(true);
233
        } else {
234
            if ($record->isLatestVersion()) {
0 ignored issues
show
Documentation Bug introduced by
The method isLatestVersion does not exist on object<SilverStripe\CMS\Model\SiteTree>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
235
                $message = _t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.VIEWINGLATEST', 'Currently viewing the latest version.');
236
            } else {
237
                $message = _t(
238
                    'SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.VIEWINGVERSION',
239
                    "Currently viewing version {version}.",
240
                    array('version' => $versionID)
241
                );
242
            }
243
        }
244
245
        /** @var Tab $mainTab */
246
        $mainTab = $fields->fieldByName('Root.Main');
247
        $mainTab->unshift(
248
            new LiteralField('CurrentlyViewingMessage', ArrayData::create(array(
249
                'Content' => DBField::create_field('HTMLFragment', $message),
250
                'Classes' => 'notice'
251
            ))->renderWith($this->getTemplatesWithSuffix('_notice')))
252
        );
253
254
        $form->setFields($fields->makeReadonly());
255
        $form->loadDataFrom(array(
256
            "ID" => $id,
257
            "Version" => $versionID,
258
        ));
259
260
        if ($record->isLatestVersion()) {
0 ignored issues
show
Documentation Bug introduced by
The method isLatestVersion does not exist on object<SilverStripe\CMS\Model\SiteTree>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
261
            $revert->setReadonly(true);
262
        }
263
264
        $form->removeExtraClass('cms-content');
265
266
        // History form has both ID and VersionID as suffixes
267
        $form->setRequestHandler(
268
            LeftAndMainFormRequestHandler::create($form, [$id, $versionID])
269
        );
270
271
        return $form;
272
    }
273
274
275
    /**
276
     * Version select form. Main interface between selecting versions to view
277
     * and comparing multiple versions.
278
     *
279
     * Because we can reload the page directly to a compare view (history/compare/1/2/3)
280
     * this form has to adapt to those parameters as well.
281
     *
282
     * @return Form
283
     */
284
    public function VersionsForm()
285
    {
286
        $id = $this->currentPageID();
287
        $page = $this->getRecord($id);
288
        $versionsHtml = '';
289
290
        $action = $this->getRequest()->param('Action');
291
        $versionID = $this->getRequest()->param('VersionID');
292
        $otherVersionID = $this->getRequest()->param('OtherVersionID');
293
294
        $showUnpublishedChecked = 0;
295
        $compareModeChecked = ($action == "compare");
296
297
        if ($page) {
298
            $versions = $page->allVersions();
0 ignored issues
show
Documentation Bug introduced by
The method allVersions does not exist on object<SilverStripe\CMS\Model\SiteTree>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
299
            $versionID = (!$versionID) ? $page->Version : $versionID;
0 ignored issues
show
Bug introduced by
The property Version does not seem to exist. Did you mean versioning?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
300
301
            if ($versions) {
302
                foreach ($versions as $k => $version) {
303
                    $active = false;
304
305
                    if ($version->Version == $versionID || $version->Version == $otherVersionID) {
306
                        $active = true;
307
308
                        if (!$version->WasPublished) {
309
                            $showUnpublishedChecked = 1;
310
                        }
311
                    }
312
313
                    $version->Active = ($active);
314
                }
315
            }
316
317
            $vd = new ViewableData();
318
319
            $versionsHtml = $vd->customise(array(
320
                'Versions' => $versions
321
            ))->renderWith($this->getTemplatesWithSuffix('_versions'));
322
        }
323
324
        $fields = new FieldList(
325
            new CheckboxField(
326
                'ShowUnpublished',
327
                _t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.SHOWUNPUBLISHED', 'Show unpublished versions'),
328
                $showUnpublishedChecked
329
            ),
330
            new CheckboxField(
331
                'CompareMode',
332
                _t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.COMPAREMODE', 'Compare mode (select two)'),
333
                $compareModeChecked
334
            ),
335
            new LiteralField('VersionsHtml', $versionsHtml),
0 ignored issues
show
Bug introduced by
It seems like $versionsHtml defined by $vd->customise(array('Ve...ithSuffix('_versions')) on line 319 can also be of type object<SilverStripe\ORM\FieldType\DBHTMLText>; however, SilverStripe\Forms\LiteralField::__construct() does only seem to accept string|object<SilverStripe\Forms\FormField>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
336
            $hiddenID = new HiddenField('ID', false, "")
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a null|string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
337
        );
338
339
        $form = Form::create(
340
            $this,
341
            'VersionsForm',
342
            $fields,
343
            new FieldList()
344
        )->setHTMLID('Form_VersionsForm');
345
        $form->loadDataFrom($this->getRequest()->requestVars());
346
        $hiddenID->setValue($id);
347
        $form->unsetValidator();
348
349
        $form
350
            ->addExtraClass('cms-versions-form') // placeholder, necessary for $.metadata() to work
351
            ->setAttribute('data-link-tmpl-compare', Controller::join_links($this->Link('compare'), '%s', '%s', '%s'))
352
            ->setAttribute('data-link-tmpl-show', Controller::join_links($this->Link('show'), '%s', '%s'));
353
354
        return $form;
355
    }
356
357
    /**
358
     * @param int $versionID
359
     * @param int $otherVersionID
360
     * @return mixed
361
     */
362
    public function CompareVersionsForm($versionID, $otherVersionID)
363
    {
364
        if ($versionID > $otherVersionID) {
365
            $toVersion = $versionID;
366
            $fromVersion = $otherVersionID;
367
        } else {
368
            $toVersion = $otherVersionID;
369
            $fromVersion = $versionID;
370
        }
371
372
        if (!$toVersion || !$fromVersion) {
373
            return null;
374
        }
375
376
        $id = $this->currentPageID();
377
        /** @var SiteTree $page */
378
        $page = SiteTree::get()->byID($id);
379
380
        $record = null;
381
        if ($page && $page->exists()) {
382
            if (!$page->canView()) {
383
                return Security::permissionFailure($this);
384
            }
385
386
            $record = $page->compareVersions($fromVersion, $toVersion);
0 ignored issues
show
Documentation Bug introduced by
The method compareVersions does not exist on object<SilverStripe\CMS\Model\SiteTree>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
387
        }
388
389
        $fromVersionRecord = Versioned::get_version(SiteTree::class, $id, $fromVersion);
390
        $toVersionRecord = Versioned::get_version(SiteTree::class, $id, $toVersion);
391
392
        if (!$fromVersionRecord) {
393
            user_error("Can't find version $fromVersion of page $id", E_USER_ERROR);
394
        }
395
396
        if (!$toVersionRecord) {
397
            user_error("Can't find version $toVersion of page $id", E_USER_ERROR);
398
        }
399
400
        if (!$record) {
401
            return null;
402
        }
403
        $form = $this->getEditForm($id, null, $fromVersion, $toVersion);
404
        $form->setActions(new FieldList());
405
        $form->addExtraClass('compare');
406
407
        $form->loadDataFrom($record);
408
        $form->loadDataFrom(array(
409
            "ID" => $id,
410
            "Version" => $fromVersion,
411
        ));
412
413
        // Comparison views shouldn't be editable.
414
        // As the comparison output is HTML and not valid values for the various field types
415
        $readonlyFields = $this->transformReadonly($form->Fields());
416
        $form->setFields($readonlyFields);
417
418
        return $form;
419
    }
420
421
    public function Breadcrumbs($unlinked = false)
422
    {
423
        $crumbs = parent::Breadcrumbs($unlinked);
424
        $crumbs[0]->Title = _t('SilverStripe\\CMS\\Controllers\\CMSPagesController.MENUTITLE', 'Pages');
425
        return $crumbs;
426
    }
427
428
    /**
429
     * Replace all data fields with HTML readonly fields to display diff
430
     *
431
     * @param FieldList $fields
432
     * @return FieldList
433
     */
434
    public function transformReadonly(FieldList $fields)
435
    {
436
        foreach ($fields->dataFields() as $field) {
437
            if ($field instanceof HiddenField) {
438
                continue;
439
            }
440
            $newField = $field->castedCopy(HTMLReadonlyField::class);
441
            $fields->replaceField($field->getName(), $newField);
442
        }
443
        return $fields;
444
    }
445
446
    /**
447
     * Set current version ID
448
     *
449
     * @param int $versionID
450
     * @return $this
451
     */
452
    public function setVersionID($versionID)
453
    {
454
        $this->versionID = $versionID;
455
        return $this;
456
    }
457
458
    /**
459
     * Get current version ID
460
     *
461
     * @return int
462
     */
463
    public function getVersionID()
464
    {
465
        return $this->versionID;
466
    }
467
468
    public function getTabIdentifier()
469
    {
470
        return 'history';
471
    }
472
}
473