Completed
Pull Request — master (#5574)
by Christopher
11:14
created

HierarchyTest::testHideFromHeirarchy()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 11
nc 2
nop 0
dl 0
loc 17
rs 9.4285
c 1
b 0
f 1
1
<?php
2
3
class HierarchyTest extends SapphireTest {
4
5
	protected static $fixture_file = 'HierarchyTest.yml';
6
7
	protected $requiredExtensions = array(
8
		'HierarchyTest_Object' => array('Hierarchy', 'Versioned'),
9
		'HierarchyHideTest_Object' => array('Hierarchy', 'Versioned'),
10
	);
11
12
	protected $extraDataObjects = array(
13
		'HierarchyTest_Object',
14
		'HierarchyHideTest_Object'
15
	);
16
17
	/**
18
	 * Test the Hierarchy prevents infinite loops.
19
	 */
20
	public function testPreventLoop() {
21
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
22
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
23
24
		$obj2->ParentID = $obj2aa->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<DataObject>. 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...
25
		try {
26
			$obj2->write();
27
		}
28
		catch (ValidationException $e) {
29
			$this->assertContains('Infinite loop found within the "HierarchyTest_Object" hierarchy', $e->getMessage());
30
			return;
31
		}
32
33
		$this->fail('Failed to prevent infinite loop in hierarchy.');
34
	}
35
36
	/**
37
	 * Test Hierarchy::AllHistoricalChildren().
38
	 */
39
	public function testAllHistoricalChildren() {
40
		// Delete some objs
41
		$this->objFromFixture('HierarchyTest_Object', 'obj2b')->delete();
42
		$this->objFromFixture('HierarchyTest_Object', 'obj3a')->delete();
43
		$this->objFromFixture('HierarchyTest_Object', 'obj3')->delete();
44
45
		// Check that obj1-3 appear at the top level of the AllHistoricalChildren tree
46
		$this->assertEquals(array("Obj 1", "Obj 2", "Obj 3"),
47
			singleton('HierarchyTest_Object')->AllHistoricalChildren()->column('Title'));
48
49
		// Check numHistoricalChildren
50
		$this->assertEquals(3, singleton('HierarchyTest_Object')->numHistoricalChildren());
51
52
		// Check that both obj 2 children are returned
53
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
54
		$this->assertEquals(array("Obj 2a", "Obj 2b"),
55
			$obj2->AllHistoricalChildren()->column('Title'));
56
57
		// Check numHistoricalChildren
58
		$this->assertEquals(2, $obj2->numHistoricalChildren());
59
60
61
		// Obj 3 has been deleted; let's bring it back from the grave
62
		$obj3 = Versioned::get_including_deleted("HierarchyTest_Object", "\"Title\" = 'Obj 3'")->First();
63
64
		// Check that both obj 3 children are returned
65
		$this->assertEquals(array("Obj 3a", "Obj 3b", "Obj 3c"),
66
			$obj3->AllHistoricalChildren()->column('Title'));
67
68
		// Check numHistoricalChildren
69
		$this->assertEquals(3, $obj3->numHistoricalChildren());
70
71
	}
72
73
	/**
74
	 * Test that you can call Hierarchy::markExpanded/Unexpanded/Open() on a obj, and that
75
	 * calling Hierarchy::isMarked() on a different instance of that object will return true.
76
	 */
77
	public function testItemMarkingIsntRestrictedToSpecificInstance() {
78
		// Mark a few objs
79
		$this->objFromFixture('HierarchyTest_Object', 'obj2')->markExpanded();
80
		$this->objFromFixture('HierarchyTest_Object', 'obj2a')->markExpanded();
81
		$this->objFromFixture('HierarchyTest_Object', 'obj2b')->markExpanded();
82
		$this->objFromFixture('HierarchyTest_Object', 'obj3')->markUnexpanded();
83
84
		// Query some objs in a different context and check their m
85
		$objs = DataObject::get("HierarchyTest_Object", '', '"ID" ASC');
86
		$marked = $expanded = array();
87
		foreach($objs as $obj) {
88
			if($obj->isMarked()) $marked[] = $obj->Title;
89
			if($obj->isExpanded()) $expanded[] = $obj->Title;
90
		}
91
92
		$this->assertEquals(array('Obj 2', 'Obj 3', 'Obj 2a', 'Obj 2b'), $marked);
93
		$this->assertEquals(array('Obj 2', 'Obj 2a', 'Obj 2b'), $expanded);
94
	}
95
96
	public function testNumChildren() {
97
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj1')->numChildren(), 0);
98
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2')->numChildren(), 2);
99
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3')->numChildren(), 3);
100
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2a')->numChildren(), 2);
101
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj2b')->numChildren(), 0);
102
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3a')->numChildren(), 2);
103
		$this->assertEquals($this->objFromFixture('HierarchyTest_Object', 'obj3b')->numChildren(), 0);
104
105
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
106
		$this->assertEquals($obj1->numChildren(), 0);
107
		$obj1Child1 = new HierarchyTest_Object();
108
		$obj1Child1->ParentID = $obj1->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<HierarchyTest_Object>. 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...
109
		$obj1Child1->write();
110
		$this->assertEquals($obj1->numChildren(false), 1,
111
			'numChildren() caching can be disabled through method parameter'
112
		);
113
		$obj1Child2 = new HierarchyTest_Object();
114
		$obj1Child2->ParentID = $obj1->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<HierarchyTest_Object>. 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...
115
		$obj1Child2->write();
116
		$obj1->flushCache();
117
		$this->assertEquals($obj1->numChildren(), 2,
118
			'numChildren() caching can be disabled by flushCache()'
119
		);
120
	}
121
122
	public function testLoadDescendantIDListIntoArray() {
123
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
124
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
125
		$obj2b = $this->objFromFixture('HierarchyTest_Object', 'obj2b');
126
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
127
		$obj2ab = $this->objFromFixture('HierarchyTest_Object', 'obj2ab');
128
129
		$obj2IdList = $obj2->getDescendantIDList();
130
		$obj2aIdList = $obj2a->getDescendantIDList();
131
132
		$this->assertContains($obj2a->ID, $obj2IdList);
133
		$this->assertContains($obj2b->ID, $obj2IdList);
134
		$this->assertContains($obj2aa->ID, $obj2IdList);
135
		$this->assertContains($obj2ab->ID, $obj2IdList);
136
		$this->assertEquals(4, count($obj2IdList));
137
138
		$this->assertContains($obj2aa->ID, $obj2aIdList);
139
		$this->assertContains($obj2ab->ID, $obj2aIdList);
140
		$this->assertEquals(2, count($obj2aIdList));
141
	}
142
143
	/**
144
	 * The "only deleted from stage" argument to liveChildren() should exclude
145
	 * any page that has been moved to another location on the stage site
146
	 */
147
	public function testLiveChildrenOnlyDeletedFromStage() {
148
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
149
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
150
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
151
		$obj2b = $this->objFromFixture('HierarchyTest_Object', 'obj2b');
152
153
		// Get a published set of objects for our fixture
154
		$obj1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
155
		$obj2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
156
		$obj2a->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
157
		$obj2b->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
158
159
		// Then delete 2a from stage and move 2b to a sub-node of 1.
160
		$obj2a->delete();
161
		$obj2b->ParentID = $obj1->ID;
0 ignored issues
show
Documentation introduced by
The property ParentID does not exist on object<DataObject>. 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...
162
		$obj2b->write();
163
164
		// Get live children, excluding pages that have been moved on the stage site
165
		$children = $obj2->liveChildren(true, true)->column("Title");
166
167
		// 2a has been deleted from stage and should be shown
168
		$this->assertContains("Obj 2a", $children);
169
170
		// 2b has merely been moved to a different parent and so shouldn't be shown
171
		$this->assertNotContains("Obj 2b", $children);
172
	}
173
174
	public function testBreadcrumbs() {
175
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
176
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
177
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
178
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
179
180
		$this->assertEquals('Obj 1', $obj1->getBreadcrumbs());
181
		$this->assertEquals('Obj 2 &raquo; Obj 2a', $obj2a->getBreadcrumbs());
182
		$this->assertEquals('Obj 2 &raquo; Obj 2a &raquo; Obj 2aa', $obj2aa->getBreadcrumbs());
183
	}
184
185
	public function testGetChildrenAsUL() {
186
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
187
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
188
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
189
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
190
191
		$nodeCountThreshold = 30;
192
193
		$root = new HierarchyTest_Object();
194
		$root->markPartialTree($nodeCountThreshold);
195
		$html = $root->getChildrenAsUL(
196
			"",
197
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
198
			null,
199
			false,
200
			"AllChildrenIncludingDeleted",
201
			"numChildren",
202
			true,  // rootCall
203
			$nodeCountThreshold
204
		);
205
		$this->assertTreeContains($html, array($obj2),
206
			'Contains root elements'
207
		);
208
		$this->assertTreeContains($html, array($obj2, $obj2a),
209
			'Contains child elements (in correct nesting)'
210
		);
211
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
212
			'Contains grandchild elements (in correct nesting)'
213
		);
214
	}
215
216
	public function testGetChildrenAsULMinNodeCount() {
217
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
218
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
219
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
220
221
		// Set low enough that it should be fulfilled by root only elements
222
		$nodeCountThreshold = 3;
223
224
		$root = new HierarchyTest_Object();
225
		$root->markPartialTree($nodeCountThreshold);
226
		$html = $root->getChildrenAsUL(
227
			"",
228
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
229
			null,
230
			false,
231
			"AllChildrenIncludingDeleted",
232
			"numChildren",
233
			true,
234
			$nodeCountThreshold
235
		);
236
		$this->assertTreeContains($html, array($obj1),
237
			'Contains root elements'
238
		);
239
		$this->assertTreeContains($html, array($obj2),
240
			'Contains root elements'
241
		);
242
		$this->assertTreeNotContains($html, array($obj2, $obj2a),
243
			'Does not contains child elements because they exceed minNodeCount'
244
		);
245
	}
246
247
	public function testGetChildrenAsULMinNodeCountWithMarkToExpose() {
248
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
249
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
250
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
251
252
		// Set low enough that it should be fulfilled by root only elements
253
		$nodeCountThreshold = 3;
254
255
		$root = new HierarchyTest_Object();
256
		$root->markPartialTree($nodeCountThreshold);
257
258
		// Mark certain node which should be included regardless of minNodeCount restrictions
259
		$root->markToExpose($obj2aa);
260
261
		$html = $root->getChildrenAsUL(
262
			"",
263
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
264
			null,
265
			false,
266
			"AllChildrenIncludingDeleted",
267
			"numChildren",
268
			true,
269
			$nodeCountThreshold
270
		);
271
		$this->assertTreeContains($html, array($obj2),
272
			'Contains root elements'
273
		);
274
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
275
			'Does contain marked children nodes regardless of configured threshold'
276
		);
277
	}
278
279
	public function testGetChildrenAsULMinNodeCountWithFilters() {
280
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
281
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
282
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
283
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
284
285
		// Set low enough that it should fit all search matches without lazy loading
286
		$nodeCountThreshold = 3;
287
288
		$root = new HierarchyTest_Object();
289
290
		// Includes nodes by filter regardless of minNodeCount restrictions
291
		$root->setMarkingFilterFunction(function($record) use($obj2, $obj2a, $obj2aa) {
292
			// Results need to include parent hierarchy, even if we just want to
293
			// match the innermost node.
294
			return in_array($record->ID, array($obj2->ID, $obj2a->ID, $obj2aa->ID));
295
		});
296
		$root->markPartialTree($nodeCountThreshold);
297
298
		$html = $root->getChildrenAsUL(
299
			"",
300
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
301
			null,
302
			true, // limit to marked
303
			"AllChildrenIncludingDeleted",
304
			"numChildren",
305
			true,
306
			$nodeCountThreshold
307
		);
308
		$this->assertTreeNotContains($html, array($obj1),
309
			'Does not contain root elements which dont match the filter'
310
		);
311
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
312
			'Contains non-root elements which match the filter'
313
		);
314
	}
315
316
	public function testGetChildrenAsULHardLimitsNodes() {
317
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
318
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
319
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
320
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
321
322
		// Set low enough that it should fit all search matches without lazy loading
323
		$nodeCountThreshold = 3;
324
325
		$root = new HierarchyTest_Object();
326
327
		// Includes nodes by filter regardless of minNodeCount restrictions
328
		$root->setMarkingFilterFunction(function($record) use($obj2, $obj2a, $obj2aa) {
329
			// Results need to include parent hierarchy, even if we just want to
330
			// match the innermost node.
331
			return in_array($record->ID, array($obj2->ID, $obj2a->ID, $obj2aa->ID));
332
		});
333
		$root->markPartialTree($nodeCountThreshold);
334
335
		$html = $root->getChildrenAsUL(
336
			"",
337
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
338
			null,
339
			true, // limit to marked
340
			"AllChildrenIncludingDeleted",
341
			"numChildren",
342
			true,
343
			$nodeCountThreshold
344
		);
345
		$this->assertTreeNotContains($html, array($obj1),
346
			'Does not contain root elements which dont match the filter'
347
		);
348
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
349
			'Contains non-root elements which match the filter'
350
		);
351
	}
352
353
	public function testGetChildrenAsULNodeThresholdLeaf() {
354
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
355
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
356
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
357
		$obj3 = $this->objFromFixture('HierarchyTest_Object', 'obj3');
358
		$obj3a = $this->objFromFixture('HierarchyTest_Object', 'obj3a');
359
360
		$nodeCountThreshold = 99;
361
362
		$root = new HierarchyTest_Object();
363
		$root->markPartialTree($nodeCountThreshold);
364
		$nodeCountCallback = function($parent, $numChildren) {
365
			// Set low enough that it the fixture structure should exceed it
366
			if($parent->ID && $numChildren > 2) {
367
				return '<span class="exceeded">Exceeded!</span>';
368
			}
369
		};
370
371
		$html = $root->getChildrenAsUL(
372
			"",
373
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
374
			null,
375
			true, // limit to marked
376
			"AllChildrenIncludingDeleted",
377
			"numChildren",
378
			true,
379
			$nodeCountThreshold,
380
			$nodeCountCallback
381
		);
382
		$this->assertTreeContains($html, array($obj1),
383
			'Does contain root elements regardless of count'
384
		);
385
		$this->assertTreeContains($html, array($obj3),
386
			'Does contain root elements regardless of count'
387
		);
388
		$this->assertTreeContains($html, array($obj2, $obj2a),
389
			'Contains children which do not exceed threshold'
390
		);
391
		$this->assertTreeNotContains($html, array($obj3, $obj3a),
392
			'Does not contain children which exceed threshold'
393
		);
394
	}
395
396
	/**
397
	 * This test checks that deleted ('archived') child pages don't set a css class on the parent
398
	 * node that makes it look like it has children
399
	 */
400
	public function testGetChildrenAsULNodeDeletedOnLive() {
401
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
402
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
403
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
404
		$obj2ab = $this->objFromFixture('HierarchyTest_Object', 'obj2b');
405
406
		// delete all children under obj2
407
		$obj2a->delete();
408
		$obj2aa->delete();
409
		$obj2ab->delete();
410
		// Don't pre-load all children
411
		$nodeCountThreshold = 1;
412
413
		$childrenMethod = 'AllChildren';
414
		$numChildrenMethod = 'numChildren';
415
416
		$root = new HierarchyTest_Object();
417
		$root->markPartialTree($nodeCountThreshold, null, $childrenMethod, $numChildrenMethod);
418
419
		// As in LeftAndMain::getSiteTreeFor() but simpler and more to the point for testing purposes
420
		$titleFn = function(&$child, $numChildrenMethod="") {
421
			return '<li class="' . $child->markingClasses($numChildrenMethod).
422
				'" id="' . $child->ID . '">"' . $child->Title;
423
		};
424
425
		$html = $root->getChildrenAsUL(
426
			"",
427
			$titleFn,
428
			null,
429
			true, // limit to marked
430
			$childrenMethod,
431
			$numChildrenMethod,
432
			true,
433
			$nodeCountThreshold
434
		);
435
436
		// Get the class attribute from the $obj2 node in the sitetree, class 'jstree-leaf' means it's a leaf node
437
		$nodeClass = $this->getNodeClassFromTree($html, $obj2);
438
		$this->assertEquals('jstree-leaf closed', $nodeClass, 'object2 should not have children in the sitetree');
439
	}
440
441
	/**
442
	 * This test checks that deleted ('archived') child pages _do_ set a css class on the parent
443
	 * node that makes it look like it has children when getting all children including deleted
444
	 */
445
	public function testGetChildrenAsULNodeDeletedOnStage() {
446
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
447
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
448
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
449
		$obj2ab = $this->objFromFixture('HierarchyTest_Object', 'obj2b');
450
451
		// delete all children under obj2
452
		$obj2a->delete();
453
		$obj2aa->delete();
454
		$obj2ab->delete();
455
		// Don't pre-load all children
456
		$nodeCountThreshold = 1;
457
458
		$childrenMethod = 'AllChildrenIncludingDeleted';
459
		$numChildrenMethod = 'numHistoricalChildren';
460
461
		$root = new HierarchyTest_Object();
462
		$root->markPartialTree($nodeCountThreshold, null, $childrenMethod, $numChildrenMethod);
463
464
		// As in LeftAndMain::getSiteTreeFor() but simpler and more to the point for testing purposes
465
		$titleFn = function(&$child, $numChildrenMethod="") {
466
			return '<li class="' . $child->markingClasses($numChildrenMethod).
467
				'" id="' . $child->ID . '">"' . $child->Title;
468
		};
469
470
		$html = $root->getChildrenAsUL(
471
			"",
472
			$titleFn,
473
			null,
474
			true, // limit to marked
475
			$childrenMethod,
476
			$numChildrenMethod,
477
			true,
478
			$nodeCountThreshold
479
		);
480
481
		// Get the class attribute from the $obj2 node in the sitetree
482
		$nodeClass = $this->getNodeClassFromTree($html, $obj2);
483
		// Object2 can now be expanded
484
		$this->assertEquals('unexpanded jstree-closed closed', $nodeClass, 'obj2 should have children in the sitetree');
485
	}
486
487
	public function testNoHideFromHeirarchy() {
488
		$obj4 = $this->objFromFixture('HierarchyHideTest_Object', 'obj4');
489
		$obj4->publish("Stage", "Live");
490
491
		foreach($obj4->stageChildren() as $child) {
492
			$child->publish("Stage", "Live");
493
		}
494
		$this->assertEquals($obj4->stageChildren()->Count(), 2);
495
		$this->assertEquals($obj4->liveChildren()->Count(), 2);
496
	}
497
498
	public function testHideFromHeirarchy() {
499
		HierarchyHideTest_Object::config()->hide_from_hierarchy = array('HierarchyHideTest_SubObject');
0 ignored issues
show
Documentation introduced by
The property hide_from_hierarchy does not exist on object<Config_ForClass>. 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...
500
		$obj4 = $this->objFromFixture('HierarchyHideTest_Object', 'obj4');
501
		$obj4->publish("Stage", "Live");
502
503
		// load without using stage children otherwise it'll bbe filtered before it's publish
504
		// we need to publish all of them, and expect liveChildren to return some.
505
		$children = HierarchyHideTest_Object::get()
506
			->filter('ParentID', (int)$obj4->ID)
507
			->exclude('ID', (int)$obj4->ID);
508
509
		foreach($children as $child) {
510
			$child->publish("Stage", "Live");
511
		}
512
		$this->assertEquals($obj4->stageChildren()->Count(), 1);
513
		$this->assertEquals($obj4->liveChildren()->Count(), 1);
514
	}
515
516
	/**
517
	 * @param String $html  [description]
518
	 * @param array $nodes Breadcrumb path as array
519
	 * @param String $message
520
	 */
521
	protected function assertTreeContains($html, $nodes, $message = null) {
522
		$parser = new CSSContentParser($html);
523
		$xpath = '/';
524
		foreach($nodes as $node) $xpath .= '/ul/li[@id="' . $node->ID . '"]';
525
		$match = $parser->getByXpath($xpath);
526
		self::assertThat((bool)$match, self::isTrue(), $message);
527
	}
528
529
	/**
530
	 * @param String $html  [description]
531
	 * @param array $nodes Breadcrumb path as array
532
	 * @param String $message
533
	 */
534
	protected function assertTreeNotContains($html, $nodes, $message = null) {
535
		$parser = new CSSContentParser($html);
536
		$xpath = '/';
537
		foreach($nodes as $node) $xpath .= '/ul/li[@id="' . $node->ID . '"]';
538
		$match = $parser->getByXpath($xpath);
539
		self::assertThat((bool)$match, self::isFalse(), $message);
540
	}
541
542
	/**
543
	 * Get the HTML class attribute from a node in the sitetree
544
	 *
545
	 * @param $html
546
	 * @param $node
547
	 * @return string
548
	 */
549
	protected function getNodeClassFromTree($html, $node) {
550
		$parser = new CSSContentParser($html);
551
		$xpath = '//ul/li[@id="' . $node->ID . '"]';
552
		$object = $parser->getByXpath($xpath);
553
554
		foreach($object[0]->attributes() as $key => $attr) {
555
			if($key == 'class') {
556
				return (string)$attr;
557
			}
558
		}
559
		return '';
560
	}
561
}
562
563
class HierarchyTest_Object extends DataObject implements TestOnly {
564
	private static $db = array(
565
		'Title' => 'Varchar'
566
	);
567
568
	private static $extensions = array(
569
		'Hierarchy',
570
		'Versioned',
571
	);
572
573
	public function cmstreeclasses() {
574
		return $this->markingClasses();
575
	}
576
}
577
578
class HierarchyHideTest_Object extends DataObject implements TestOnly {
579
	private static $db = array(
580
		'Title' => 'Varchar'
581
	);
582
583
	private static $extensions = array(
584
		'Hierarchy',
585
		"Versioned('Stage', 'Live')",
586
	);
587
588
	public function cmstreeclasses() {
589
		return $this->markingClasses();
590
	}
591
}
592
593
class HierarchyHideTest_SubObject extends HierarchyHideTest_Object {
594
595
}
596