Completed
Push — master ( 3f1f9d...ab54c8 )
by Ingo
08:52
created

HierarchyTest::testHideFromHeirarchy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 0
dl 0
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\ORM\Tests;
4
5
use SilverStripe\ORM\ValidationException;
6
use SilverStripe\Versioned\Versioned;
7
use SilverStripe\Dev\SapphireTest;
8
9
class HierarchyTest extends SapphireTest
10
{
11
    protected static $fixture_file = 'HierarchyTest.yml';
12
13
    protected static $extra_dataobjects = array(
14
        HierarchyTest\TestObject::class,
15
        HierarchyTest\HideTestObject::class,
16
        HierarchyTest\HideTestSubObject::class,
17
    );
18
19
    protected static function getExtraDataObjects()
20
    {
21
        // Prevent setup breaking if versioned module absent
22
        if (class_exists(Versioned::class)) {
23
            return parent::getExtraDataObjects();
24
        }
25
        return [];
26
    }
27
28
    public function setUp()
29
    {
30
        parent::setUp();
31
32
        // Note: Soft support for versioned module optionality
33
        if (!class_exists(Versioned::class)) {
34
            $this->markTestSkipped('HierarchyTest requires the Versioned extension');
35
        }
36
    }
37
38
    /**
39
     * Test the Hierarchy prevents infinite loops.
40
     */
41
    public function testPreventLoop()
42
    {
43
        $this->expectException(ValidationException::class);
44
        $this->expectExceptionMessage(sprintf(
45
            'Infinite loop found within the "%s" hierarchy',
46
            HierarchyTest\TestObject::class
47
        ));
48
49
        /** @var HierarchyTest\TestObject $obj2 */
50
        $obj2 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2');
51
        $obj2aa = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2aa');
52
53
        $obj2->ParentID = $obj2aa->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\ORM\...erarchyTest\TestObject>. 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...
54
        $obj2->write();
55
    }
56
57
    /**
58
     * Test Hierarchy::AllHistoricalChildren().
59
     */
60
    public function testAllHistoricalChildren()
61
    {
62
        // Delete some objs
63
        $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2b')->delete();
64
        $this->objFromFixture(HierarchyTest\TestObject::class, 'obj3a')->delete();
65
        $this->objFromFixture(HierarchyTest\TestObject::class, 'obj3')->delete();
66
67
        // Check that obj1-3 appear at the top level of the AllHistoricalChildren tree
68
        $this->assertEquals(
69
            array("Obj 1", "Obj 2", "Obj 3"),
70
            HierarchyTest\TestObject::singleton()->AllHistoricalChildren()->column('Title')
71
        );
72
73
        // Check numHistoricalChildren
74
        $this->assertEquals(3, HierarchyTest\TestObject::singleton()->numHistoricalChildren());
75
76
        // Check that both obj 2 children are returned
77
        /** @var HierarchyTest\TestObject $obj2 */
78
        $obj2 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2');
79
        $this->assertEquals(
80
            array("Obj 2a", "Obj 2b"),
81
            $obj2->AllHistoricalChildren()->column('Title')
82
        );
83
84
        // Check numHistoricalChildren
85
        $this->assertEquals(2, $obj2->numHistoricalChildren());
86
87
88
        // Obj 3 has been deleted; let's bring it back from the grave
89
        /** @var HierarchyTest\TestObject $obj3 */
90
        $obj3 = Versioned::get_including_deleted(
91
            HierarchyTest\TestObject::class,
92
            "\"Title\" = 'Obj 3'"
93
        )->First();
94
95
        // Check that all obj 3 children are returned
96
        $this->assertEquals(
97
            array("Obj 3a", "Obj 3b", "Obj 3c", "Obj 3d"),
98
            $obj3->AllHistoricalChildren()->column('Title')
99
        );
100
101
        // Check numHistoricalChildren
102
        $this->assertEquals(4, $obj3->numHistoricalChildren());
103
    }
104
105
    public function testNumChildren()
106
    {
107
        /** @var HierarchyTest\TestObject $obj1 */
108
        $obj1 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj1');
109
        /** @var HierarchyTest\TestObject $obj2 */
110
        $obj2 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2');
111
        /** @var HierarchyTest\TestObject $obj3 */
112
        $obj3 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj3');
113
        /** @var HierarchyTest\TestObject $obj2a */
114
        $obj2a = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2a');
115
        /** @var HierarchyTest\TestObject $obj2b */
116
        $obj2b = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2b');
117
        /** @var HierarchyTest\TestObject $obj3a */
118
        $obj3a = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj3a');
119
        /** @var HierarchyTest\TestObject $obj3b */
120
        $obj3b = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj3d');
121
122
        $this->assertEquals(0, $obj1->numChildren());
123
        $this->assertEquals(2, $obj2->numChildren());
124
        $this->assertEquals(4, $obj3->numChildren());
125
        $this->assertEquals(2, $obj2a->numChildren());
126
        $this->assertEquals(0, $obj2b->numChildren());
127
        $this->assertEquals(2, $obj3a->numChildren());
128
        $this->assertEquals(0, $obj3b->numChildren());
129
        $obj1Child1 = new HierarchyTest\TestObject();
130
        $obj1Child1->ParentID = $obj1->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\ORM\...erarchyTest\TestObject>. 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...
131
        $obj1Child1->write();
132
        $this->assertEquals(
133
            $obj1->numChildren(false),
134
            1,
135
            'numChildren() caching can be disabled through method parameter'
136
        );
137
        $obj1Child2 = new HierarchyTest\TestObject();
138
        $obj1Child2->ParentID = $obj1->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\ORM\...erarchyTest\TestObject>. 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...
139
        $obj1Child2->write();
140
        $obj1->flushCache();
141
        $this->assertEquals(
142
            $obj1->numChildren(),
143
            2,
144
            'numChildren() caching can be disabled by flushCache()'
145
        );
146
    }
147
148
    public function testLoadDescendantIDListIntoArray()
149
    {
150
        /** @var HierarchyTest\TestObject $obj2 */
151
        $obj2 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2');
152
        /** @var HierarchyTest\TestObject $obj2a */
153
        $obj2a = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2a');
154
        $obj2b = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2b');
155
        $obj2aa = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2aa');
156
        $obj2ab = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2ab');
157
158
        $obj2IdList = $obj2->getDescendantIDList();
159
        $obj2aIdList = $obj2a->getDescendantIDList();
160
161
        $this->assertContains($obj2a->ID, $obj2IdList);
162
        $this->assertContains($obj2b->ID, $obj2IdList);
163
        $this->assertContains($obj2aa->ID, $obj2IdList);
164
        $this->assertContains($obj2ab->ID, $obj2IdList);
165
        $this->assertEquals(4, count($obj2IdList));
166
167
        $this->assertContains($obj2aa->ID, $obj2aIdList);
168
        $this->assertContains($obj2ab->ID, $obj2aIdList);
169
        $this->assertEquals(2, count($obj2aIdList));
170
    }
171
172
    /**
173
     * The "only deleted from stage" argument to liveChildren() should exclude
174
     * any page that has been moved to another location on the stage site
175
     */
176
    public function testLiveChildrenOnlyDeletedFromStage()
177
    {
178
        /** @var HierarchyTest\TestObject $obj1 */
179
        $obj1 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj1');
180
        /** @var HierarchyTest\TestObject $obj2 */
181
        $obj2 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2');
182
        /** @var HierarchyTest\TestObject $obj2a */
183
        $obj2a = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2a');
184
        /** @var HierarchyTest\TestObject $obj2b */
185
        $obj2b = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2b');
186
187
        // Get a published set of objects for our fixture
188
        $obj1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
189
        $obj2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
190
        $obj2a->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
191
        $obj2b->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
192
193
        // Then delete 2a from stage and move 2b to a sub-node of 1.
194
        $obj2a->delete();
195
        $obj2b->ParentID = $obj1->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<SilverStripe\ORM\...erarchyTest\TestObject>. 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...
196
        $obj2b->write();
197
198
        // Get live children, excluding pages that have been moved on the stage site
199
        $children = $obj2->liveChildren(true, true)->column("Title");
200
201
        // 2a has been deleted from stage and should be shown
202
        $this->assertContains("Obj 2a", $children);
203
204
        // 2b has merely been moved to a different parent and so shouldn't be shown
205
        $this->assertNotContains("Obj 2b", $children);
206
    }
207
208
    public function testBreadcrumbs()
209
    {
210
        /** @var HierarchyTest\TestObject $obj1 */
211
        $obj1 = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj1');
212
        /** @var HierarchyTest\TestObject $obj2a */
213
        $obj2a = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2a');
214
        /** @var HierarchyTest\TestObject $obj2aa */
215
        $obj2aa = $this->objFromFixture(HierarchyTest\TestObject::class, 'obj2aa');
216
217
        $this->assertEquals('Obj 1', $obj1->getBreadcrumbs());
218
        $this->assertEquals('Obj 2 &raquo; Obj 2a', $obj2a->getBreadcrumbs());
219
        $this->assertEquals('Obj 2 &raquo; Obj 2a &raquo; Obj 2aa', $obj2aa->getBreadcrumbs());
220
    }
221
222
    public function testNoHideFromHeirarchy()
223
    {
224
        /** @var HierarchyTest\HideTestObject $obj4 */
225
        $obj4 = $this->objFromFixture(HierarchyTest\HideTestObject::class, 'obj4');
226
        $obj4->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
227
228
        foreach ($obj4->stageChildren() as $child) {
229
            $child->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
230
        }
231
        $this->assertEquals($obj4->stageChildren()->Count(), 2);
232
        $this->assertEquals($obj4->liveChildren()->Count(), 2);
233
    }
234
235
    public function testHideFromHeirarchy()
236
    {
237
        HierarchyTest\HideTestObject::config()->update(
238
            'hide_from_hierarchy',
239
            [ HierarchyTest\HideTestSubObject::class ]
240
        );
241
        /** @var HierarchyTest\HideTestObject $obj4 */
242
        $obj4 = $this->objFromFixture(HierarchyTest\HideTestObject::class, 'obj4');
243
        $obj4->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
244
245
        // load without using stage children otherwise it'll bbe filtered before it's publish
246
        // we need to publish all of them, and expect liveChildren to return some.
247
        $children = HierarchyTest\HideTestObject::get()
248
            ->filter('ParentID', (int)$obj4->ID)
249
            ->exclude('ID', (int)$obj4->ID);
250
251
        /** @var HierarchyTest\HideTestObject $child */
252
        foreach ($children as $child) {
253
            $child->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
254
        }
255
        $this->assertEquals($obj4->stageChildren()->Count(), 1);
256
        $this->assertEquals($obj4->liveChildren()->Count(), 1);
257
    }
258
}
259