Completed
Push — authenticator-refactor ( 16f104...61b037 )
by Simon
06:52
created

InheritedPermissionsTest::testEditPermissions()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 37
Code Lines 18

Duplication

Lines 37
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
eloc 18
nc 1
nop 0
dl 37
loc 37
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Security\Tests;
4
5
use SilverStripe\Core\Injector\Injector;
6
use SilverStripe\Dev\SapphireTest;
7
use SilverStripe\Security\Group;
8
use SilverStripe\Security\InheritedPermissions;
9
use SilverStripe\Security\Member;
10
use SilverStripe\Security\PermissionChecker;
11
use SilverStripe\Security\Test\InheritedPermissionsTest\TestPermissionNode;
12
use SilverStripe\Security\Test\InheritedPermissionsTest\TestDefaultPermissionChecker;
13
use SilverStripe\Versioned\Versioned;
14
15
class InheritedPermissionsTest extends SapphireTest
16
{
17
    protected static $fixture_file = 'InheritedPermissionsTest.yml';
18
19
    protected static $extra_dataobjects = [
20
        TestPermissionNode::class,
21
    ];
22
23
    /**
24
     * @var TestDefaultPermissionChecker
25
     */
26
    protected $rootPermissions = null;
27
28
    protected function setUp()
29
    {
30
        parent::setUp();
31
32
        // Register root permissions
33
        $permission = InheritedPermissions::create(TestPermissionNode::class)
34
            ->setGlobalEditPermissions(['TEST_NODE_ACCESS'])
35
            ->setDefaultPermissions($this->rootPermissions = new TestDefaultPermissionChecker());
36
        Injector::inst()->registerService(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Container\ContainerInterface as the method registerService() does only exist in the following implementations of said interface: SilverStripe\Core\Injector\Injector.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
37
            $permission,
38
            PermissionChecker::class.'.testpermissions'
39
        );
40
41
        // Reset root permission
42
    }
43
44 View Code Duplication
    public function testEditPermissions()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
45
    {
46
        $editor = $this->objFromFixture(Member::class, 'editor');
47
48
        $about = $this->objFromFixture(TestPermissionNode::class, 'about');
49
        $aboutStaff = $this->objFromFixture(TestPermissionNode::class, 'about-staff');
50
        $history = $this->objFromFixture(TestPermissionNode::class, 'history');
51
        $products = $this->objFromFixture(TestPermissionNode::class, 'products');
52
        $product1 = $this->objFromFixture(TestPermissionNode::class, 'products-product1');
53
        $product4 = $this->objFromFixture(TestPermissionNode::class, 'products-product4');
54
55
        // Test logged out users cannot edit
56
        Member::actAs(null, function () use ($aboutStaff) {
57
            $this->assertFalse($aboutStaff->canEdit());
58
        });
59
60
        // Can't edit a page that is locked to admins
61
        $this->assertFalse($about->canEdit($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 46 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canEdit() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
62
63
        // Can edit a page that is locked to editors
64
        $this->assertTrue($products->canEdit($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 46 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canEdit() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
65
66
        // Can edit a child of that page that inherits
67
        $this->assertTrue($product1->canEdit($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 46 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canEdit() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
68
69
        // Can't edit a child of that page that has its permissions overridden
70
        $this->assertFalse($product4->canEdit($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 46 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canEdit() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
71
72
        // Test that root node respects root permissions
73
        $this->assertTrue($history->canEdit($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 46 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canEdit() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
74
75
        TestPermissionNode::getInheritedPermissions()->clearCache();
76
        $this->rootPermissions->setCanEdit(false);
77
78
        // With root edit false, permissions are now denied for CanEditType = Inherit
79
        $this->assertFalse($history->canEdit($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 46 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canEdit() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
80
    }
81
82 View Code Duplication
    public function testDeletePermissions()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
83
    {
84
        $editor = $this->objFromFixture(Member::class, 'editor');
85
86
        $about = $this->objFromFixture(TestPermissionNode::class, 'about');
87
        $aboutStaff = $this->objFromFixture(TestPermissionNode::class, 'about-staff');
88
        $history = $this->objFromFixture(TestPermissionNode::class, 'history');
89
        $products = $this->objFromFixture(TestPermissionNode::class, 'products');
90
        $product1 = $this->objFromFixture(TestPermissionNode::class, 'products-product1');
91
        $product4 = $this->objFromFixture(TestPermissionNode::class, 'products-product4');
92
93
        // Test logged out users cannot edit
94
        Member::actAs(null, function () use ($aboutStaff) {
95
            $this->assertFalse($aboutStaff->canDelete());
96
        });
97
98
        // Can't edit a page that is locked to admins
99
        $this->assertFalse($about->canDelete($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 84 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canDelete() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
100
101
        // Can't delete a page if a child (product4) is un-deletable
102
        $this->assertFalse($products->canDelete($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 84 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canDelete() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
103
104
        // Can edit a child of that page that inherits
105
        $this->assertTrue($product1->canDelete($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 84 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canDelete() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
106
107
        // Can't edit a child of that page that has its permissions overridden
108
        $this->assertFalse($product4->canDelete($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 84 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canDelete() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
109
110
        // Test that root node respects root permissions
111
        $this->assertTrue($history->canDelete($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 84 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canDelete() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
112
113
        TestPermissionNode::getInheritedPermissions()->clearCache();
114
        $this->rootPermissions->setCanEdit(false);
115
116
        // With root edit false, permissions are now denied for CanEditType = Inherit
117
        $this->assertFalse($history->canDelete($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 84 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canDelete() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
118
    }
119
120
    public function testViewPermissions()
121
    {
122
        $history = $this->objFromFixture(TestPermissionNode::class, 'history');
123
        $contact = $this->objFromFixture(TestPermissionNode::class, 'contact');
124
        $contactForm = $this->objFromFixture(TestPermissionNode::class, 'contact-form');
125
        $secret = $this->objFromFixture(TestPermissionNode::class, 'secret');
126
        $secretNested = $this->objFromFixture(TestPermissionNode::class, 'secret-nested');
127
        $protected = $this->objFromFixture(TestPermissionNode::class, 'protected');
128
        $protectedChild = $this->objFromFixture(TestPermissionNode::class, 'protected-child');
129
        $editor = $this->objFromFixture(Member::class, 'editor');
130
131
        // Not logged in user can only access Inherit or Anyone pages
132
        Member::actAs(
133
            null,
134
            function () use ($protectedChild, $secretNested, $protected, $secret, $history, $contact, $contactForm) {
135
                $this->assertTrue($history->canView());
136
                $this->assertTrue($contact->canView());
137
                $this->assertTrue($contactForm->canView());
138
                // Protected
139
                $this->assertFalse($secret->canView());
140
                $this->assertFalse($secretNested->canView());
141
                $this->assertFalse($protected->canView());
142
                $this->assertFalse($protectedChild->canView());
143
            }
144
        );
145
146
        // Editor can view pages restricted to logged in users
147
        $this->assertTrue($secret->canView($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 129 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canView() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
148
        $this->assertTrue($secretNested->canView($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 129 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canView() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
149
150
        // Cannot read admin-only pages
151
        $this->assertFalse($protected->canView($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 129 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canView() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
152
        $this->assertFalse($protectedChild->canView($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 129 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canView() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
153
154
        // Check root permissions
155
        $this->assertTrue($history->canView($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 129 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canView() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
156
157
        TestPermissionNode::getInheritedPermissions()->clearCache();
158
        $this->rootPermissions->setCanView(false);
159
160
        $this->assertFalse($history->canView($editor));
0 ignored issues
show
Bug introduced by
It seems like $editor defined by $this->objFromFixture(\S...ember::class, 'editor') on line 129 can also be of type object<SilverStripe\ORM\DataObject>; however, SilverStripe\ORM\DataObject::canView() does only seem to accept object<SilverStripe\Security\Member>|null, 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...
161
    }
162
163
    /**
164
     * Test that draft permissions deny unrestricted live permissions
165
     */
166
    public function testRestrictedDraftUnrestrictedLive()
167
    {
168
        Versioned::set_stage(Versioned::DRAFT);
169
170
        // Should be editable by non-admin editor
171
        /** @var TestPermissionNode $products */
172
        $products = $this->objFromFixture(TestPermissionNode::class, 'products');
173
        /** @var TestPermissionNode $products1 */
174
        $products1 = $this->objFromFixture(TestPermissionNode::class, 'products-product1');
175
        $editor = $this->objFromFixture(Member::class, 'editor');
176
177
        // Ensure the editor can edit
178
        $this->assertTrue($products->canEdit($editor));
179
        $this->assertTrue($products1->canEdit($editor));
180
181
        // Write current version to live
182
        $products->writeToStage(Versioned::LIVE);
183
        $products1->writeToStage(Versioned::LIVE);
184
185
        // Draft version restrict to admins
186
        $products->EditorGroups()->setByIDList([
187
            $this->idFromFixture(Group::class, 'admins')
188
        ]);
189
        $products->write();
190
191
        // Ensure editor can no longer edit
192
        TestPermissionNode::getInheritedPermissions()->clearCache();
193
        $this->assertFalse($products->canEdit($editor));
194
        $this->assertFalse($products1->canEdit($editor));
195
    }
196
197
    /**
198
     * Test that draft permissions permit access over live permissions
199
     */
200
    public function testUnrestrictedDraftOverridesLive()
201
    {
202
        Versioned::set_stage(Versioned::DRAFT);
203
204
        // Should be editable by non-admin editor
205
        /** @var TestPermissionNode $about */
206
        $about = $this->objFromFixture(TestPermissionNode::class, 'about');
207
        /** @var TestPermissionNode $aboutStaff */
208
        $aboutStaff = $this->objFromFixture(TestPermissionNode::class, 'about-staff');
209
        $editor = $this->objFromFixture(Member::class, 'editor');
210
211
        // Ensure the editor can't edit
212
        $this->assertFalse($about->canEdit($editor));
213
        $this->assertFalse($aboutStaff->canEdit($editor));
214
215
        // Write current version to live
216
        $about->writeToStage(Versioned::LIVE);
217
        $aboutStaff->writeToStage(Versioned::LIVE);
218
219
        // Unrestrict draft
220
        $about->CanEditType = InheritedPermissions::LOGGED_IN_USERS;
0 ignored issues
show
Documentation introduced by
The property CanEditType does not exist on object<SilverStripe\Secu...est\TestPermissionNode>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
221
        $about->write();
222
223
        // Ensure editor can no longer edit
224
        TestPermissionNode::getInheritedPermissions()->clearCache();
225
        $this->assertTrue($about->canEdit($editor));
226
        $this->assertTrue($aboutStaff->canEdit($editor));
227
    }
228
229
    /**
230
     * Ensure that flipping parent / child relationship on live doesn't
231
     * cause infinite loop
232
     */
233
    public function testMobiusHierarchy()
234
    {
235
        Versioned::set_stage(Versioned::DRAFT);
236
237
        /** @var TestPermissionNode $history */
238
        $history = $this->objFromFixture(TestPermissionNode::class, 'history');
239
        /** @var TestPermissionNode $historyGallery */
240
        $historyGallery = $this->objFromFixture(TestPermissionNode::class, 'history-gallery');
241
242
        // Publish current state to live
243
        $history->writeToStage(Versioned::LIVE);
244
        $historyGallery->writeToStage(Versioned::LIVE);
245
246
        // Flip relation
247
        $historyGallery->ParentID = 0;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\Secu...est\TestPermissionNode>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
248
        $historyGallery->write();
249
        $history->ParentID = $historyGallery->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\Secu...est\TestPermissionNode>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
250
        $history->write();
251
252
        // Test viewability (not logged in users)
253
        Member::actAs(null, function () use ($history, $historyGallery) {
254
            $this->assertTrue($history->canView());
255
            $this->assertTrue($historyGallery->canView());
256
        });
257
258
        // Change permission on draft root and ensure it affects both
259
        $historyGallery->CanViewType = InheritedPermissions::LOGGED_IN_USERS;
0 ignored issues
show
Documentation introduced by
The property CanViewType does not exist on object<SilverStripe\Secu...est\TestPermissionNode>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
260
        $historyGallery->write();
261
        TestPermissionNode::getInheritedPermissions()->clearCache();
262
263
        // Test viewability (not logged in users)
264
        Member::actAs(null, function () use ($history, $historyGallery) {
265
            $this->assertFalse($historyGallery->canView());
266
            $this->assertFalse($history->canView());
267
        });
268
    }
269
}
270