CommentsTest::testGetCMSFieldsWithParentComment()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 28
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 22
c 2
b 0
f 0
nc 2
nop 0
dl 0
loc 28
rs 9.568
1
<?php
2
3
namespace SilverStripe\Comments\Tests;
4
5
use HTMLPurifier;
0 ignored issues
show
Bug introduced by
The type HTMLPurifier was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use HTMLPurifier_Config;
0 ignored issues
show
Bug introduced by
The type HTMLPurifier_Config was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use ReflectionClass;
8
use SilverStripe\Comments\Extensions\CommentsExtension;
9
use SilverStripe\Comments\Model\Comment;
10
use SilverStripe\Comments\Tests\Stubs\CommentableItem;
11
use SilverStripe\Comments\Tests\Stubs\CommentableItemDisabled;
12
use SilverStripe\Comments\Tests\Stubs\CommentableItemEnabled;
13
use SilverStripe\Core\Config\Config;
14
use SilverStripe\Dev\FunctionalTest;
15
use SilverStripe\ORM\DataObject;
16
use SilverStripe\Security\Member;
17
use SilverStripe\Security\Security;
18
19
class CommentsTest extends FunctionalTest
20
{
21
    protected static $fixture_file = 'CommentsTest.yml';
22
23
    protected static $extra_dataobjects = [
24
        CommentableItem::class,
25
        CommentableItemEnabled::class,
26
        CommentableItemDisabled::class,
27
    ];
28
29
    protected function setUp()
30
    {
31
        parent::setUp();
32
33
        // Set good default values
34
        Config::modify()->merge(CommentsExtension::class, 'comments', [
35
            'enabled' => true,
36
            'comment_permalink_prefix' => 'comment-',
37
        ]);
38
    }
39
40
    public function testCommentsList()
41
    {
42
        // comments don't require moderation so unmoderated comments can be
43
        // shown but not spam posts
44
        Config::modify()->merge(CommentableItem::class, 'comments', [
45
            'require_moderation_nonmembers' => false,
46
            'require_moderation' => false,
47
            'require_moderation_cms' => false,
48
        ]);
49
50
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
51
52
        $this->assertListEquals([
53
            ['Name' => 'Comment 1'],
54
            ['Name' => 'Comment 3']
55
        ], $item->Comments(), 'Only 2 non spam posts should be shown');
56
57
        // when moderated, only moderated, non spam posts should be shown.
58
        Config::modify()->merge(CommentableItem::class, 'comments', ['require_moderation_nonmembers' => true]);
59
60
        // Check that require_moderation overrides this option
61
        Config::modify()->merge(CommentableItem::class, 'comments', ['require_moderation' => true]);
62
63
        $this->assertListEquals(array(
64
            array('Name' => 'Comment 3')
65
        ), $item->Comments(), 'Only 1 non spam, moderated post should be shown');
66
        $this->assertEquals(1, $item->Comments()->Count());
67
68
        // require_moderation_nonmembers still filters out unmoderated comments
69
        Config::modify()->merge(CommentableItem::class, 'comments', ['require_moderation' => false]);
70
        $this->assertEquals(1, $item->Comments()->Count());
71
72
        Config::modify()->merge(CommentableItem::class, 'comments', ['require_moderation_nonmembers' => false]);
73
        $this->assertEquals(2, $item->Comments()->Count());
74
75
        // With unmoderated comments set to display in frontend
76
        Config::modify()->merge(CommentableItem::class, 'comments', [
77
            'require_moderation' => true,
78
            'frontend_moderation' => true,
79
        ]);
80
        $this->assertEquals(1, $item->Comments()->Count());
81
82
        $this->logInWithPermission('ADMIN');
83
        $this->assertEquals(2, $item->Comments()->Count());
84
85
        // With spam comments set to display in frontend
86
        Config::modify()->merge(CommentableItem::class, 'comments', [
87
            'require_moderation' => true,
88
            'frontend_moderation' => false,
89
            'frontend_spam' => true,
90
        ]);
91
92
        $this->logOut();
93
        $this->assertEquals(1, $item->Comments()->Count());
94
95
        $this->logInWithPermission('ADMIN');
96
        $this->assertEquals(2, $item->Comments()->Count());
97
98
99
        // With spam and unmoderated comments set to display in frontend
100
        Config::modify()->merge(CommentableItem::class, 'comments', [
101
            'require_moderation' => true,
102
            'frontend_moderation' => true,
103
            'frontend_spam' => true,
104
        ]);
105
106
        $this->logOut();
107
        $this->assertEquals(1, $item->Comments()->Count());
108
109
        $this->logInWithPermission('ADMIN');
110
        $this->assertEquals(4, $item->Comments()->Count());
111
    }
112
113
    /**
114
     * Test moderation options configured via the CMS
115
     */
116
    public function testCommentCMSModerationList()
117
    {
118
        Config::modify()->merge(CommentableItem::class, 'comments', [
119
            'require_moderation' => true,
120
            'require_moderation_cms' => true,
121
        ]);
122
123
        $item = $this->objFromFixture(CommentableItem::class, 'spammed');
124
125
        $this->assertEquals('None', $item->getModerationRequired());
126
127
        $this->assertListEquals([
128
            ['Name' => 'Comment 1'],
129
            ['Name' => 'Comment 3']
130
        ], $item->Comments(), 'Only 2 non spam posts should be shown');
131
132
        // when moderated, only moderated, non spam posts should be shown.
133
        $item->ModerationRequired = 'NonMembersOnly';
134
        $item->write();
135
136
        $this->assertEquals('NonMembersOnly', $item->getModerationRequired());
137
138
        // Check that require_moderation overrides this option
139
        $item->ModerationRequired = 'Required';
140
        $item->write();
141
        $this->assertEquals('Required', $item->getModerationRequired());
142
143
        $this->assertListEquals([
144
            ['Name' => 'Comment 3']
145
        ], $item->Comments(), 'Only 1 non spam, moderated post should be shown');
146
        $this->assertEquals(1, $item->Comments()->Count());
147
148
        // require_moderation_nonmembers still filters out unmoderated comments
149
        $item->ModerationRequired = 'NonMembersOnly';
150
        $item->write();
151
        $this->assertEquals(1, $item->Comments()->Count());
152
153
        $item->ModerationRequired = 'None';
154
        $item->write();
155
        $this->assertEquals(2, $item->Comments()->Count());
156
    }
157
158
    public function testCanPostComment()
159
    {
160
        Config::modify()->merge(CommentableItem::class, 'comments', [
161
            'require_login' => false,
162
            'require_login_cms' => false,
163
            'required_permission' => false,
164
        ]);
165
        /** @var CommentableItem&CommentsExtension $item */
166
        $item = $this->objFromFixture(CommentableItem::class, 'first');
167
        /** @var CommentableItem&CommentsExtension $item2 */
168
        $item2 = $this->objFromFixture(CommentableItem::class, 'second');
169
170
        // Test restriction free commenting
171
        $this->logOut();
172
        $this->assertFalse($item->CommentsRequireLogin);
0 ignored issues
show
Bug Best Practice introduced by
The property CommentsRequireLogin does not exist on SilverStripe\Comments\Tests\Stubs\CommentableItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
173
        $this->assertTrue($item->canPostComment());
0 ignored issues
show
Bug introduced by
The method canPostComment() does not exist on SilverStripe\Comments\Tests\Stubs\CommentableItem. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

173
        $this->assertTrue($item->/** @scrutinizer ignore-call */ canPostComment());
Loading history...
174
175
        // Test permission required to post
176
        Config::modify()->merge(CommentableItem::class, 'comments', [
177
            'require_login' => true,
178
            'required_permission' => 'POSTING_PERMISSION',
179
        ]);
180
        $this->assertTrue($item->CommentsRequireLogin);
181
        $this->assertFalse($item->canPostComment());
182
        $this->logInWithPermission('WRONG_ONE');
183
        $this->assertFalse($item->canPostComment());
184
        $this->logInWithPermission('POSTING_PERMISSION');
185
        $this->assertTrue($item->canPostComment());
186
        $this->logInWithPermission('ADMIN');
187
        $this->assertTrue($item->canPostComment());
188
189
        // Test require login to post, but not any permissions
190
        Config::modify()->merge(CommentableItem::class, 'comments', [
191
            'required_permission' => false,
192
        ]);
193
        $this->assertTrue($item->CommentsRequireLogin);
194
195
        $this->logOut();
196
        $this->assertFalse($item->canPostComment());
197
        $this->logInWithPermission('ANY_PERMISSION');
198
        $this->assertTrue($item->canPostComment());
199
200
        // Test options set via CMS
201
        Config::modify()->merge(CommentableItem::class, 'comments', [
202
            'require_login' => true,
203
            'require_login_cms' => true,
204
        ]);
205
        $this->assertFalse($item->CommentsRequireLogin);
206
        $this->assertTrue($item2->CommentsRequireLogin);
207
208
        $this->logOut();
209
        $this->assertTrue($item->canPostComment());
210
        $this->assertFalse($item2->canPostComment());
211
212
        // Login grants permission to post
213
        $this->logInWithPermission('ANY_PERMISSION');
214
        $this->assertTrue($item->canPostComment());
215
        $this->assertTrue($item2->canPostComment());
216
    }
217
    public function testDeleteComment()
218
    {
219
        // Test anonymous user
220
        $this->logOut();
221
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
222
        $commentID = $comment->ID;
223
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
224
        $delete = $this->get('comments/delete/' . $comment->ID . '?ajax=1');
225
        $this->assertEquals(403, $delete->getStatusCode());
226
        $check = DataObject::get_by_id(Comment::class, $commentID);
227
        $this->assertTrue($check && $check->exists());
228
229
        // Test non-authenticated user
230
        $this->logInAs('visitor');
231
        $this->assertNull($comment->DeleteLink(), 'No permission to see delete link');
232
233
        // Test authenticated user
234
        $this->logInAs('commentadmin');
235
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
236
        $commentID = $comment->ID;
237
        $adminComment1Link = $comment->DeleteLink();
238
        $this->assertContains('comments/delete/' . $commentID . '?t=', $adminComment1Link);
239
240
        // Test that this link can't be shared / XSS exploited
241
        $this->logInAs('commentadmin2');
242
        $delete = $this->get($adminComment1Link);
243
        $this->assertEquals(400, $delete->getStatusCode());
244
        $check = DataObject::get_by_id(Comment::class, $commentID);
245
        $this->assertTrue($check && $check->exists());
246
247
        // Test that this other admin can delete the comment with their own link
248
        $adminComment2Link = $comment->DeleteLink();
249
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
250
        $this->autoFollowRedirection = false;
251
        $delete = $this->get($adminComment2Link);
252
        $this->assertEquals(302, $delete->getStatusCode());
253
        $check = DataObject::get_by_id(Comment::class, $commentID);
254
        $this->assertFalse($check && $check->exists());
255
    }
256
257
    public function testSpamComment()
258
    {
259
        // Test anonymous user
260
        $this->logOut();
261
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
262
        $commentID = $comment->ID;
263
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
264
        $spam = $this->get('comments/spam/' . $comment->ID . '?ajax=1');
265
        $this->assertEquals(403, $spam->getStatusCode());
266
        $check = DataObject::get_by_id(Comment::class, $commentID);
267
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
268
269
        // Test non-authenticated user
270
        $this->logInAs('visitor');
271
        $this->assertNull($comment->SpamLink(), 'No permission to see mark as spam link');
272
273
        // Test authenticated user
274
        $this->logInAs('commentadmin');
275
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
276
        $commentID = $comment->ID;
277
        $adminComment1Link = $comment->SpamLink();
278
        $this->assertContains('comments/spam/' . $commentID . '?t=', $adminComment1Link);
279
280
        // Test that this link can't be shared / XSS exploited
281
        $this->logInAs('commentadmin2');
282
        $spam = $this->get($adminComment1Link);
283
        $this->assertEquals(400, $spam->getStatusCode());
284
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
285
        $this->assertEquals(0, $check->IsSpam, 'No permission to mark as spam');
286
287
        // Test that this other admin can spam the comment with their own link
288
        $adminComment2Link = $comment->SpamLink();
289
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
290
        $this->autoFollowRedirection = false;
291
        $spam = $this->get($adminComment2Link);
292
        $this->assertEquals(302, $spam->getStatusCode());
293
        $check = DataObject::get_by_id(Comment::class, $commentID);
294
        $this->assertEquals(1, $check->IsSpam);
295
296
        // Cannot re-spam spammed comment
297
        $this->assertNull($check->SpamLink());
298
    }
299
300
    public function testHamComment()
301
    {
302
        // Test anonymous user
303
        $this->logOut();
304
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
305
        $commentID = $comment->ID;
306
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
307
        $ham = $this->get('comments/ham/' . $comment->ID . '?ajax=1');
308
        $this->assertEquals(403, $ham->getStatusCode());
309
        $check = DataObject::get_by_id(Comment::class, $commentID);
310
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
311
312
        // Test non-authenticated user
313
        $this->logInAs('visitor');
314
        $this->assertNull($comment->HamLink(), 'No permission to see mark as ham link');
315
316
        // Test authenticated user
317
        $this->logInAs('commentadmin');
318
        $comment = $this->objFromFixture(Comment::class, 'secondComC');
319
        $commentID = $comment->ID;
320
        $adminComment1Link = $comment->HamLink();
321
        $this->assertContains('comments/ham/' . $commentID . '?t=', $adminComment1Link);
322
323
        // Test that this link can't be shared / XSS exploited
324
        $this->logInAs('commentadmin2');
325
        $ham = $this->get($adminComment1Link);
326
        $this->assertEquals(400, $ham->getStatusCode());
327
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
328
        $this->assertEquals(1, $check->IsSpam, 'No permission to mark as ham');
329
330
        // Test that this other admin can ham the comment with their own link
331
        $adminComment2Link = $comment->HamLink();
332
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
333
        $this->autoFollowRedirection = false;
334
        $ham = $this->get($adminComment2Link);
335
        $this->assertEquals(302, $ham->getStatusCode());
336
        $check = DataObject::get_by_id(Comment::class, $commentID);
337
        $this->assertEquals(0, $check->IsSpam);
338
339
        // Cannot re-ham hammed comment
340
        $this->assertNull($check->HamLink());
341
    }
342
343
    public function testApproveComment()
344
    {
345
        // Test anonymous user
346
        $this->logOut();
347
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
348
        $commentID = $comment->ID;
349
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
350
        $approve = $this->get('comments/approve/' . $comment->ID . '?ajax=1');
351
        $this->assertEquals(403, $approve->getStatusCode());
352
        $check = DataObject::get_by_id(Comment::class, $commentID);
353
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
354
355
        // Test non-authenticated user
356
        $this->logInAs('visitor');
357
        $this->assertNull($comment->ApproveLink(), 'No permission to see approve link');
358
359
        // Test authenticated user
360
        $this->logInAs('commentadmin');
361
        $comment = $this->objFromFixture(Comment::class, 'secondComB');
362
        $commentID = $comment->ID;
363
        $adminComment1Link = $comment->ApproveLink();
364
        $this->assertContains('comments/approve/' . $commentID . '?t=', $adminComment1Link);
365
366
        // Test that this link can't be shared / XSS exploited
367
        $this->logInAs('commentadmin2');
368
        $approve = $this->get($adminComment1Link);
369
        $this->assertEquals(400, $approve->getStatusCode());
370
        $check = DataObject::get_by_id(Comment::class, $comment->ID);
371
        $this->assertEquals(0, $check->Moderated, 'No permission to approve');
372
373
        // Test that this other admin can approve the comment with their own link
374
        $adminComment2Link = $comment->ApproveLink();
375
        $this->assertNotEquals($adminComment2Link, $adminComment1Link);
376
        $this->autoFollowRedirection = false;
377
        $approve = $this->get($adminComment2Link);
378
        $this->assertEquals(302, $approve->getStatusCode());
379
        $check = DataObject::get_by_id(Comment::class, $commentID);
380
        $this->assertEquals(1, $check->Moderated);
381
382
        // Cannot re-approve approved comment
383
        $this->assertNull($check->ApproveLink());
384
    }
385
386
    public function testCommenterURLWrite()
387
    {
388
        $comment = new Comment();
389
        // We only care about the CommenterURL, so only set that
390
        // Check a http and https URL. Add more test urls here as needed.
391
        $protocols = [
392
            'Http',
393
            'Https',
394
        ];
395
        $url = '://example.com';
396
397
        foreach ($protocols as $protocol) {
398
            $comment->CommenterURL = $protocol . $url;
0 ignored issues
show
Bug Best Practice introduced by
The property CommenterURL does not exist on SilverStripe\Comments\Model\Comment. Since you implemented __set, consider adding a @property annotation.
Loading history...
399
            // The protocol should stay as if, assuming it is valid
400
            $comment->write();
401
            $this->assertEquals($comment->CommenterURL, $protocol . $url, $protocol . ':// is a valid protocol');
0 ignored issues
show
Bug Best Practice introduced by
The property CommenterURL does not exist on SilverStripe\Comments\Model\Comment. Since you implemented __get, consider adding a @property annotation.
Loading history...
402
        }
403
    }
404
405
    public function testSanitizesWithAllowHtml()
406
    {
407
        if (!class_exists('\\HTMLPurifier')) {
408
            $this->markTestSkipped('HTMLPurifier class not found');
409
        }
410
411
        // Add p for paragraph
412
        // NOTE: The config method appears to append to the existing array
413
        Config::modify()->merge(CommentableItem::class, 'comments', [
414
            'html_allowed_elements' => ['p'],
415
        ]);
416
417
        // Without HTML allowed
418
        $comment1 = new Comment();
419
        $comment1->AllowHtml = false;
420
        $comment1->ParentClass = CommentableItem::class;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentClass does not exist on SilverStripe\Comments\Model\Comment. Since you implemented __set, consider adding a @property annotation.
Loading history...
421
        $comment1->Comment = '<p><script>alert("w00t")</script>my comment</p>';
422
        $comment1->write();
423
        $this->assertEquals(
424
            '<p><script>alert("w00t")</script>my comment</p>',
425
            $comment1->Comment,
426
            'Does not remove HTML tags with html_allowed=false, ' .
427
            'which is correct behaviour because the HTML will be escaped'
428
        );
429
430
        // With HTML allowed
431
        $comment2 = new Comment();
432
        $comment2->AllowHtml = true;
433
        $comment2->ParentClass = CommentableItem::class;
434
        $comment2->Comment = '<p><script>alert("w00t")</script>my comment</p>';
435
        $comment2->write();
436
        $this->assertEquals(
437
            '<p>my comment</p>',
438
            $comment2->Comment,
439
            'Removes HTML tags which are not on the whitelist'
440
        );
441
    }
442
443
    public function testDefaultTemplateRendersHtmlWithAllowHtml()
444
    {
445
        if (!class_exists('\\HTMLPurifier')) {
446
            $this->markTestSkipped('HTMLPurifier class not found');
447
        }
448
449
        Config::modify()->merge(CommentableItem::class, 'comments', [
450
            'html_allowed_elements' => ['p'],
451
        ]);
452
453
        $item = new CommentableItem();
454
        $item->write();
455
456
        // Without HTML allowed
457
        $comment = new Comment();
458
        $comment->Comment = '<p>my comment</p>';
459
        $comment->AllowHtml = false;
460
        $comment->ParentID = $item->ID;
461
        $comment->ParentClass = CommentableItem::class;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentClass does not exist on SilverStripe\Comments\Model\Comment. Since you implemented __set, consider adding a @property annotation.
Loading history...
462
        $comment->write();
463
464
        $html = $item->customise(['CommentsEnabled' => true])->renderWith('CommentsInterface');
465
        $this->assertContains(
466
            '&lt;p&gt;my comment&lt;/p&gt;',
467
            $html
468
        );
469
470
        $comment->AllowHtml = true;
471
        $comment->write();
472
        $html = $item->customise(['CommentsEnabled' => true])->renderWith('CommentsInterface');
473
        $this->assertContains(
474
            '<p>my comment</p>',
475
            $html
476
        );
477
    }
478
479
480
    /**
481
     * Tests whether comments are enabled or disabled by default
482
     */
483
    public function testDefaultEnabled()
484
    {
485
        Config::modify()->merge(CommentableItem::class, 'comments', [
486
            'enabled_cms' => true,
487
            'require_moderation_cms' => true,
488
            'require_login_cms' => true,
489
        ]);
490
491
        // With default = true
492
        $obj = new CommentableItem();
493
        $this->assertTrue((bool)$obj->getCommentsOption('enabled'), "Default setting is enabled");
0 ignored issues
show
Bug introduced by
The method getCommentsOption() does not exist on SilverStripe\Comments\Tests\Stubs\CommentableItem. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

493
        $this->assertTrue((bool)$obj->/** @scrutinizer ignore-call */ getCommentsOption('enabled'), "Default setting is enabled");
Loading history...
494
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
Bug Best Practice introduced by
The property ProvideComments does not exist on SilverStripe\Comments\Tests\Stubs\CommentableItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
495
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
Bug Best Practice introduced by
The property ModerationRequired does not exist on SilverStripe\Comments\Tests\Stubs\CommentableItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
496
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Bug Best Practice introduced by
The property CommentsRequireLogin does not exist on SilverStripe\Comments\Tests\Stubs\CommentableItem. Since you implemented __get, consider adding a @property annotation.
Loading history...
497
498
        $obj = new CommentableItemEnabled();
499
        $this->assertTrue((bool)$obj->ProvideComments);
0 ignored issues
show
Bug Best Practice introduced by
The property ProvideComments does not exist on SilverStripe\Comments\Te...\CommentableItemEnabled. Since you implemented __get, consider adding a @property annotation.
Loading history...
500
        $this->assertEquals('Required', $obj->ModerationRequired);
0 ignored issues
show
Bug Best Practice introduced by
The property ModerationRequired does not exist on SilverStripe\Comments\Te...\CommentableItemEnabled. Since you implemented __get, consider adding a @property annotation.
Loading history...
501
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Bug Best Practice introduced by
The property CommentsRequireLogin does not exist on SilverStripe\Comments\Te...\CommentableItemEnabled. Since you implemented __get, consider adding a @property annotation.
Loading history...
502
503
        $obj = new CommentableItemDisabled();
504
        $this->assertFalse((bool)$obj->ProvideComments);
0 ignored issues
show
Bug Best Practice introduced by
The property ProvideComments does not exist on SilverStripe\Comments\Te...CommentableItemDisabled. Since you implemented __get, consider adding a @property annotation.
Loading history...
505
        $this->assertEquals('None', $obj->ModerationRequired);
0 ignored issues
show
Bug Best Practice introduced by
The property ModerationRequired does not exist on SilverStripe\Comments\Te...CommentableItemDisabled. Since you implemented __get, consider adding a @property annotation.
Loading history...
506
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
0 ignored issues
show
Bug Best Practice introduced by
The property CommentsRequireLogin does not exist on SilverStripe\Comments\Te...CommentableItemDisabled. Since you implemented __get, consider adding a @property annotation.
Loading history...
507
508
        // With default = false
509
        // Because of config rules about falsey values, apply config to object directly
510
        Config::modify()->merge(CommentableItem::class, 'comments', [
511
            'enabled' => false,
512
            'require_login' => true,
513
            'require_moderation' => true,
514
        ]);
515
516
        $obj = new CommentableItem();
517
518
        $this->assertFalse((bool)$obj->getCommentsOption('enabled'), 'Default setting is disabled');
519
        $this->assertFalse((bool)$obj->ProvideComments);
520
        $this->assertEquals('Required', $obj->ModerationRequired);
521
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
522
523
        $obj = new CommentableItemEnabled();
524
525
        $this->assertTrue((bool)$obj->ProvideComments);
526
        $this->assertEquals('Required', $obj->ModerationRequired);
527
        $this->assertTrue((bool)$obj->CommentsRequireLogin);
528
529
        $obj = new CommentableItemDisabled();
530
531
        $this->assertFalse((bool)$obj->ProvideComments);
532
        $this->assertEquals('None', $obj->ModerationRequired);
533
        $this->assertFalse((bool)$obj->CommentsRequireLogin);
534
    }
535
536
    public function testOnBeforeDelete()
537
    {
538
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
539
540
        $child = new Comment();
541
        $child->Name = 'Fred Bloggs';
542
        $child->Comment = 'Child of firstComA';
543
        $child->write();
544
        $comment->ChildComments()->add($child);
545
        $this->assertEquals(4, $comment->ChildComments()->count());
546
547
        $commentID = $comment->ID;
548
        $childCommentID = $child->ID;
549
550
        $comment->delete();
551
552
        // assert that the new child been deleted
553
        $this->assertNull(DataObject::get_by_id(Comment::class, $commentID));
554
        $this->assertNull(DataObject::get_by_id(Comment::class, $childCommentID));
555
    }
556
557
    public function testRequireDefaultRecords()
558
    {
559
        $this->markTestSkipped('TODO');
560
    }
561
562
    public function testLink()
563
    {
564
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
565
        $this->assertEquals(
566
            'CommentableItemController#comment-' . $comment->ID,
567
            $comment->Link()
568
        );
569
        $this->assertEquals($comment->ID, $comment->ID);
570
571
        // An orphan comment has no link
572
        $comment->ParentID = 0;
573
        $comment->ParentClass = null;
574
        $comment->write();
575
        $this->assertEquals('', $comment->Link());
576
    }
577
578
    public function testPermalink()
579
    {
580
        $comment = $this->objFromFixture(Comment::class, 'thirdComD');
581
        $this->assertEquals('comment-' . $comment->ID, $comment->Permalink());
582
    }
583
584
    /**
585
     * Test field labels are defined
586
     */
587
    public function testFieldLabels()
588
    {
589
        /** @var Comment $comment */
590
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
591
592
        $labels = $comment->FieldLabels();
593
        $expected = [
594
            'Name',
595
            'Comment',
596
            'Email',
597
            'URL',
598
            'IsSpam',
599
            'Moderated',
600
            'ParentTitle',
601
            'Created',
602
        ];
603
        foreach ($expected as $key) {
604
            $this->assertArrayHasKey($key, $labels);
605
        }
606
    }
607
608
    public function testGetParent()
609
    {
610
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
611
        $item = $this->objFromFixture(CommentableItem::class, 'first');
612
        $parent = $comment->Parent();
613
        $this->assertSame($item->getClassName(), $parent->getClassName());
614
        $this->assertSame($item->ID, $parent->ID);
615
    }
616
617
    public function testGetParentTitle()
618
    {
619
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
620
        $title = $comment->getParentTitle();
621
        $this->assertEquals('First', $title);
622
623
        // Title from a comment with no parent is blank
624
        $comment->ParentID = 0;
625
        $comment->ParentClass = null;
626
        $comment->write();
627
        $this->assertEquals('', $comment->getParentTitle());
628
    }
629
630
    public function testGetParentClassName()
631
    {
632
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
633
        $className = $comment->getParentClassName();
634
        $this->assertEquals(CommentableItem::class, $className);
635
    }
636
637
    public function testCastingHelper()
638
    {
639
        $this->markTestSkipped('TODO');
640
    }
641
642
    public function testGetEscapedComment()
643
    {
644
        $this->markTestSkipped('TODO');
645
    }
646
647
    public function testIsPreview()
648
    {
649
        $comment = new Comment();
650
        $comment->Name = 'Fred Bloggs';
651
        $comment->Comment = 'this is a test comment';
652
        $this->assertTrue($comment->isPreview());
653
        $comment->write();
654
        $this->assertFalse($comment->isPreview());
655
    }
656
657
    public function testCanCreate()
658
    {
659
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
660
661
        // admin can create - this is always false
662
        $this->logInAs('commentadmin');
663
        $this->assertFalse($comment->canCreate());
664
665
        // visitor can view
666
        $this->logInAs('visitor');
667
        $this->assertFalse($comment->canCreate());
668
    }
669
670
    public function testCanView()
671
    {
672
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
673
674
        // admin can view
675
        $this->logInAs('commentadmin');
676
        $this->assertTrue($comment->canView());
677
678
        // visitor can view
679
        $this->logInAs('visitor');
680
        $this->assertTrue($comment->canView());
681
682
        $comment->ParentID = 0;
683
        $comment->write();
684
        $this->assertFalse($comment->canView());
685
    }
686
687
    public function testCanEdit()
688
    {
689
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
690
691
        // admin can edit
692
        $this->logInAs('commentadmin');
693
        $this->assertTrue($comment->canEdit());
694
695
        // visitor cannot
696
        $this->logInAs('visitor');
697
        $this->assertFalse($comment->canEdit());
698
699
        $comment->ParentID = 0;
700
        $comment->write();
701
        $this->assertFalse($comment->canEdit());
702
    }
703
704
    public function testCanDelete()
705
    {
706
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
707
708
        // admin can delete
709
        $this->logInAs('commentadmin');
710
        $this->assertTrue($comment->canDelete());
711
712
        // visitor cannot
713
        $this->logInAs('visitor');
714
        $this->assertFalse($comment->canDelete());
715
716
        $comment->ParentID = 0;
717
        $comment->write();
718
        $this->assertFalse($comment->canDelete());
719
    }
720
721
    public function testGetMember()
722
    {
723
        $this->logInAs('visitor');
724
        $current = Security::getCurrentUser();
725
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
726
        $method = $this->getMethod('getMember');
727
728
        // null case
729
        $member = $method->invokeArgs($comment, array());
730
        $this->assertEquals($current->ID, $member->ID);
731
732
        // numeric ID case
733
        $member = $method->invokeArgs($comment, array($current->ID));
734
        $this->assertEquals($current->ID, $member->ID);
735
736
        // identity case
737
        $member = $method->invokeArgs($comment, array($current));
738
        $this->assertEquals($current->ID, $member->ID);
739
    }
740
741
    public function testGetAuthorName()
742
    {
743
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
744
        $this->assertEquals(
745
            'FA',
746
            $comment->getAuthorName()
747
        );
748
749
        $comment->Name = '';
750
        $this->assertEquals(
751
            '',
752
            $comment->getAuthorName()
753
        );
754
755
        $author = $this->objFromFixture(Member::class, 'visitor');
756
        $comment->AuthorID = $author->ID;
757
        $comment->write();
758
        $this->assertEquals(
759
            'visitor',
760
            $comment->getAuthorName()
761
        );
762
763
        // null the names, expect null back
764
        $comment->Name = null;
765
        $comment->AuthorID = 0;
766
        $this->assertNull($comment->getAuthorName());
767
    }
768
769
770
    public function testLinks()
771
    {
772
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
773
        $this->logInAs('commentadmin');
774
775
        $method = $this->getMethod('ActionLink');
776
777
        // test with starts of strings and tokens and salts change each time
778
        $this->assertContains(
779
            '/comments/theaction/' . $comment->ID,
780
            $method->invokeArgs($comment, array('theaction'))
781
        );
782
783
        $this->assertContains(
784
            '/comments/delete/' . $comment->ID,
785
            $comment->DeleteLink()
786
        );
787
788
        $this->assertContains(
789
            '/comments/spam/' . $comment->ID,
790
            $comment->SpamLink()
791
        );
792
793
        $comment->markSpam();
794
        $this->assertContains(
795
            '/comments/ham/' . $comment->ID,
796
            $comment->HamLink()
797
        );
798
799
        //markApproved
800
        $comment->markUnapproved();
801
        $this->assertContains(
802
            '/comments/approve/' . $comment->ID,
803
            $comment->ApproveLink()
804
        );
805
    }
806
807
    public function testMarkSpam()
808
    {
809
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
810
        $comment->markSpam();
811
        $this->assertTrue($comment->Moderated);
812
        $this->assertTrue($comment->IsSpam);
813
    }
814
815
    public function testMarkApproved()
816
    {
817
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
818
        $comment->markApproved();
819
        $this->assertTrue($comment->Moderated);
820
        $this->assertFalse($comment->IsSpam);
821
    }
822
823
    public function testMarkUnapproved()
824
    {
825
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
826
        $comment->markApproved();
827
        $this->assertTrue($comment->Moderated);
828
    }
829
830
    public function testSpamClass()
831
    {
832
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
833
        $this->assertEquals('notspam', $comment->spamClass());
834
        $comment->Moderated = false;
835
        $this->assertEquals('unmoderated', $comment->spamClass());
836
        $comment->IsSpam = true;
837
        $this->assertEquals('spam', $comment->spamClass());
838
    }
839
840
    public function testGetTitle()
841
    {
842
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
843
        $this->assertEquals(
844
            'Comment by FA on First',
845
            $comment->getTitle()
846
        );
847
    }
848
849
    public function testGetCMSFields()
850
    {
851
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
852
        $fields = $comment->getCMSFields();
853
        $names = [];
854
        foreach ($fields as $field) {
855
            $names[] = $field->getName();
856
        }
857
        $expected = [
858
            'Created',
859
            'Name',
860
            'Comment',
861
            'Email',
862
            'URL',
863
            'Options',
864
        ];
865
        $this->assertEquals($expected, $names);
866
    }
867
868
    public function testGetCMSFieldsCommentHasAuthor()
869
    {
870
        $member = Member::get()->filter('FirstName', 'visitor')->first();
871
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
872
        $comment->AuthorID = $member->ID;
873
        $comment->write();
874
875
        $fields = $comment->getCMSFields();
876
        $names = [];
877
        foreach ($fields as $field) {
878
            $names[] = $field->getName();
879
        }
880
        $expected = [
881
            'Created',
882
            'Name',
883
            'AuthorMember',
884
            'Comment',
885
            'Email',
886
            'URL',
887
            'Options',
888
        ];
889
        $this->assertEquals($expected, $names);
890
    }
891
892
    public function testGetCMSFieldsWithParentComment()
893
    {
894
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
895
896
        $child = new Comment();
897
        $child->Name = 'John Smith';
898
        $child->Comment = 'This is yet another test commnent';
899
        $child->ParentCommentID = $comment->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentCommentID does not exist on SilverStripe\Comments\Model\Comment. Since you implemented __set, consider adding a @property annotation.
Loading history...
900
        $child->write();
901
902
        $fields = $child->getCMSFields();
903
        $names = [];
904
        foreach ($fields as $field) {
905
            $names[] = $field->getName();
906
        }
907
        $expected = [
908
            'Created',
909
            'Name',
910
            'Comment',
911
            'Email',
912
            'URL',
913
            'Options',
914
            'ParentComment_Title',
915
            'ParentComment_Created',
916
            'ParentComment_AuthorName',
917
            'ParentComment_EscapedComment',
918
        ];
919
        $this->assertEquals($expected, $names);
920
    }
921
922
    public function testPurifyHtml()
923
    {
924
        if (!class_exists(HTMLPurifier_Config::class)) {
925
            $this->markTestSkipped('HTMLPurifier class not found');
926
        }
927
928
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
929
930
        $dirtyHTML = '<p><script>alert("w00t")</script>my comment</p>';
931
        $this->assertEquals(
932
            'my comment',
933
            $comment->purifyHtml($dirtyHTML)
934
        );
935
    }
936
937
    public function testGravatar()
938
    {
939
        // Turn gravatars on
940
        Config::modify()->merge(CommentableItem::class, 'comments', [
941
            'use_gravatar' => true,
942
            'gravatar_size' => 80,
943
            'gravatar_default' => 'identicon',
944
            'gravatar_rating' => 'g',
945
        ]);
946
947
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
948
949
        $this->assertEquals(
950
            'https://www.gravatar.com/avatar/d41d8cd98f00b204e9800998ecf8427e?s'
951
            . '=80&d=identicon&r=g',
952
            $comment->Gravatar()
953
        );
954
955
        // Turn gravatars off
956
        Config::modify()->merge(CommentableItem::class, 'comments', [
957
            'use_gravatar' => false,
958
        ]);
959
960
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
961
962
        $this->assertEquals(
963
            '',
964
            $comment->Gravatar()
965
        );
966
    }
967
968
    public function testGetRepliesEnabled()
969
    {
970
        Config::modify()->merge(CommentableItem::class, 'comments', [
971
            'nested_comments' => false,
972
        ]);
973
974
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
975
        $this->assertFalse($comment->getRepliesEnabled());
976
977
        Config::modify()->merge(CommentableItem::class, 'comments', [
978
            'nested_comments' => true,
979
            'nested_depth' => 4,
980
        ]);
981
982
        $this->assertTrue($comment->getRepliesEnabled());
983
984
        $comment->Depth = 4;
985
        $this->assertFalse($comment->getRepliesEnabled());
986
987
988
        // 0 indicates no limit for nested_depth
989
        Config::modify()->merge(CommentableItem::class, 'comments', [
990
            'nested_comments' => true,
991
            'nested_depth' => 0,
992
        ]);
993
994
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
995
        $comment->Depth = 234;
996
997
        $comment->markUnapproved();
998
        $this->assertFalse($comment->getRepliesEnabled());
999
1000
        $comment->markSpam();
1001
        $this->assertFalse($comment->getRepliesEnabled());
1002
1003
        $comment->markApproved();
1004
        $this->assertTrue($comment->getRepliesEnabled());
1005
    }
1006
1007
    public function testAllReplies()
1008
    {
1009
        Config::modify()->merge(CommentableItem::class, 'comments', [
1010
            'nested_comments' => true,
1011
            'nested_depth' => 4,
1012
        ]);
1013
1014
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1015
1016
        $this->assertEquals(
1017
            3,
1018
            $comment->allReplies()->count()
1019
        );
1020
1021
        $child = new Comment();
1022
        $child->Name = 'Fred Smith';
1023
        $child->Comment = 'This is a child comment';
1024
        $child->ParentCommentID = $comment->ID;
0 ignored issues
show
Bug Best Practice introduced by
The property ParentCommentID does not exist on SilverStripe\Comments\Model\Comment. Since you implemented __set, consider adding a @property annotation.
Loading history...
1025
1026
        // spam should be returned by this method
1027
        $child->markSpam();
1028
        $child->write();
1029
        $replies = $comment->allReplies();
0 ignored issues
show
Unused Code introduced by
The assignment to $replies is dead and can be removed.
Loading history...
1030
        $this->assertEquals(
1031
            4,
1032
            $comment->allReplies()->count()
1033
        );
1034
1035
        Config::modify()->merge(CommentableItem::class, 'comments', [
1036
            'nested_comments' => false,
1037
        ]);
1038
1039
        $this->assertEquals(0, $comment->allReplies()->count());
1040
    }
1041
1042
    public function testReplies()
1043
    {
1044
        CommentableItem::add_extension(CommentsExtension::class);
1045
        $this->logInWithPermission('ADMIN');
1046
        Config::modify()->merge(CommentableItem::class, 'comments', [
1047
            'nested_comments' => true,
1048
            'nested_depth' => 4,
1049
        ]);
1050
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1051
        $this->assertEquals(
1052
            3,
1053
            $comment->Replies()->count()
1054
        );
1055
1056
        // Test that spam comments are not returned
1057
        $childComment = $comment->Replies()->first();
1058
        $childComment->IsSpam = 1;
1059
        $childComment->write();
1060
        $this->assertEquals(
1061
            2,
1062
            $comment->Replies()->count()
1063
        );
1064
1065
        // Test that unmoderated comments are not returned
1066
        //
1067
        $childComment = $comment->Replies()->first();
1068
1069
        // FIXME - moderation settings scenarios need checked here
1070
        $childComment->Moderated = 0;
1071
        $childComment->IsSpam = 0;
1072
        $childComment->write();
1073
        $this->assertEquals(
1074
            2,
1075
            $comment->Replies()->count()
1076
        );
1077
1078
1079
        // Test moderation required on the front end
1080
        $item = $this->objFromFixture(CommentableItem::class, 'first');
1081
        $item->ModerationRequired = 'Required';
1082
        $item->write();
1083
1084
        Config::modify()->merge(CommentableItemDisabled::class, 'comments', [
1085
            'nested_comments' => true,
1086
            'nested_depth' => 4,
1087
            'frontend_moderation' => true,
1088
        ]);
1089
1090
        $comment = DataObject::get_by_id(Comment::class, $comment->ID);
1091
1092
        $this->assertEquals(
1093
            2,
1094
            $comment->Replies()->count()
1095
        );
1096
1097
        // Turn off nesting, empty array should be returned
1098
        Config::modify()->merge(CommentableItem::class, 'comments', [
1099
            'nested_comments' => false,
1100
        ]);
1101
1102
        $this->assertEquals(
1103
            0,
1104
            $comment->Replies()->count()
1105
        );
1106
1107
        CommentableItem::remove_extension(CommentsExtension::class);
1108
    }
1109
1110
    public function testPagedReplies()
1111
    {
1112
        Config::modify()->merge(CommentableItem::class, 'comments', [
1113
            'nested_comments' => true,
1114
            'nested_depth' => 4,
1115
            'comments_per_page' => 2,
1116
        ]);
1117
1118
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1119
        $pagedList = $comment->pagedReplies();
1120
1121
        $this->assertEquals(
1122
            2,
1123
            $pagedList->TotalPages()
1124
        );
1125
1126
        $this->assertEquals(
1127
            3,
1128
            $pagedList->getTotalItems()
1129
        );
1130
1131
        Config::modify()->merge(CommentableItem::class, 'comments', [
1132
            'nested_comments' => false,
1133
        ]);
1134
1135
        $this->assertEquals(0, $comment->PagedReplies()->count());
1136
    }
1137
1138
    public function testReplyForm()
1139
    {
1140
        Config::modify()->merge(CommentableItem::class, 'comments', [
1141
            'nested_comments' => false,
1142
            'nested_depth' => 4,
1143
        ]);
1144
1145
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1146
1147
        // No nesting, no reply form
1148
        $form = $comment->replyForm();
1149
        $this->assertNull($form);
1150
1151
        // parent item so show form
1152
        Config::modify()->merge(CommentableItem::class, 'comments', [
1153
            'nested_comments' => true,
1154
            'nested_depth' => 4,
1155
        ]);
1156
        $form = $comment->ReplyForm();
1157
        $this->assertNotNull($form);
1158
        $names = [];
1159
1160
        foreach ($form->Fields() as $field) {
1161
            array_push($names, $field->getName());
1162
        }
1163
1164
        $this->assertContains('NameEmailURLComment', $names, 'The CompositeField name');
1165
        $this->assertContains('ParentID', $names);
1166
        $this->assertContains('ParentClassName', $names);
1167
        $this->assertContains('ReturnURL', $names);
1168
        $this->assertContains('ParentCommentID', $names);
1169
1170
        // no parent, no reply form
1171
1172
        $comment->ParentID = 0;
1173
        $comment->ParentClass = null;
1174
        $comment->write();
1175
        $form = $comment->replyForm();
1176
        $this->assertNull($form);
1177
    }
1178
1179
    public function testUpdateDepth()
1180
    {
1181
        Config::modify()->merge(CommentableItem::class, 'comments', [
1182
            'nested_comments' => true,
1183
            'nested_depth' => 4,
1184
        ]);
1185
1186
        $comment = $this->objFromFixture(Comment::class, 'firstComA');
1187
        $children = $comment->allReplies()->toArray();
1188
        // Make the second child a child of the first
1189
        // Make the third child a child of the second
1190
        $reply1 = $children[0];
1191
        $reply2 = $children[1];
1192
        $reply3 = $children[2];
1193
        $reply2->ParentCommentID = $reply1->ID;
1194
        $reply2->write();
1195
        $this->assertEquals(3, $reply2->Depth);
1196
        $reply3->ParentCommentID = $reply2->ID;
1197
        $reply3->write();
1198
        $this->assertEquals(4, $reply3->Depth);
1199
    }
1200
1201
    public function testGetToken()
1202
    {
1203
        $this->markTestSkipped('TODO');
1204
    }
1205
1206
    public function testMemberSalt()
1207
    {
1208
        $this->markTestSkipped('TODO');
1209
    }
1210
1211
    public function testAddToUrl()
1212
    {
1213
        $this->markTestSkipped('TODO');
1214
    }
1215
1216
    public function testCheckRequest()
1217
    {
1218
        $this->markTestSkipped('TODO');
1219
    }
1220
1221
    public function testGenerate()
1222
    {
1223
        $this->markTestSkipped('TODO');
1224
    }
1225
1226
    protected static function getMethod($name)
1227
    {
1228
        $class = new ReflectionClass(Comment::class);
1229
        $method = $class->getMethod($name);
1230
        $method->setAccessible(true);
1231
        return $method;
1232
    }
1233
}
1234