Completed
Push — member-groupset-delete ( a90a9a )
by Loz
11:22
created

HierarchyHideTest_Object   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 14
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 10
c 0
b 0
f 0
wmc 1
lcom 0
cbo 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A cmstreeclasses() 0 3 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 all obj 3 children are returned
65
		$this->assertEquals(array("Obj 3a", "Obj 3b", "Obj 3c", "Obj 3d"),
66
			$obj3->AllHistoricalChildren()->column('Title'));
67
68
		// Check numHistoricalChildren
69
		$this->assertEquals(4, $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(), 4);
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', 'obj3d')->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->publish("Stage", "Live");
155
		$obj2->publish("Stage", "Live");
156
		$obj2a->publish("Stage", "Live");
157
		$obj2b->publish("Stage", "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
	/**
186
	 * @covers Hierarchy::markChildren()
187
	 */
188
	public function testMarkChildrenDoesntUnmarkPreviouslyMarked() {
189
		$obj3 = $this->objFromFixture('HierarchyTest_Object', 'obj3');
190
		$obj3aa = $this->objFromFixture('HierarchyTest_Object', 'obj3aa');
191
		$obj3ba = $this->objFromFixture('HierarchyTest_Object', 'obj3ba');
192
		$obj3ca = $this->objFromFixture('HierarchyTest_Object', 'obj3ca');
193
194
		$obj3->markPartialTree();
195
		$obj3->markToExpose($obj3aa);
196
		$obj3->markToExpose($obj3ba);
197
		$obj3->markToExpose($obj3ca);
198
199
		$expected = <<<EOT
200
<ul>
201
<li>Obj 3a
202
<ul>
203
<li>Obj 3aa
204
</li>
205
<li>Obj 3ab
206
</li>
207
</ul>
208
</li>
209
<li>Obj 3b
210
<ul>
211
<li>Obj 3ba
212
</li>
213
<li>Obj 3bb
214
</li>
215
</ul>
216
</li>
217
<li>Obj 3c
218
<ul>
219
<li>Obj 3c
220
</li>
221
</ul>
222
</li>
223
<li>Obj 3d
224
</li>
225
</ul>
226
227
EOT;
228
229
		$this->assertSame($expected, $obj3->getChildrenAsUL());
230
	}
231
232
	public function testGetChildrenAsUL() {
233
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
234
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
235
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
236
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
237
238
		$nodeCountThreshold = 30;
239
240
		$root = new HierarchyTest_Object();
241
		$root->markPartialTree($nodeCountThreshold);
242
		$html = $root->getChildrenAsUL(
243
			"",
244
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
245
			null,
246
			false,
247
			"AllChildrenIncludingDeleted",
248
			"numChildren",
249
			true,  // rootCall
250
			$nodeCountThreshold
251
		);
252
		$this->assertTreeContains($html, array($obj2),
253
			'Contains root elements'
254
		);
255
		$this->assertTreeContains($html, array($obj2, $obj2a),
256
			'Contains child elements (in correct nesting)'
257
		);
258
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
259
			'Contains grandchild elements (in correct nesting)'
260
		);
261
	}
262
263
	public function testGetChildrenAsULMinNodeCount() {
264
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
265
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
266
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
267
268
		// Set low enough that it should be fulfilled by root only elements
269
		$nodeCountThreshold = 3;
270
271
		$root = new HierarchyTest_Object();
272
		$root->markPartialTree($nodeCountThreshold);
273
		$html = $root->getChildrenAsUL(
274
			"",
275
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
276
			null,
277
			false,
278
			"AllChildrenIncludingDeleted",
279
			"numChildren",
280
			true,
281
			$nodeCountThreshold
282
		);
283
		$this->assertTreeContains($html, array($obj1),
284
			'Contains root elements'
285
		);
286
		$this->assertTreeContains($html, array($obj2),
287
			'Contains root elements'
288
		);
289
		$this->assertTreeNotContains($html, array($obj2, $obj2a),
290
			'Does not contains child elements because they exceed minNodeCount'
291
		);
292
	}
293
294
	public function testGetChildrenAsULMinNodeCountWithMarkToExpose() {
295
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
296
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
297
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
298
299
		// Set low enough that it should be fulfilled by root only elements
300
		$nodeCountThreshold = 3;
301
302
		$root = new HierarchyTest_Object();
303
		$root->markPartialTree($nodeCountThreshold);
304
305
		// Mark certain node which should be included regardless of minNodeCount restrictions
306
		$root->markToExpose($obj2aa);
307
308
		$html = $root->getChildrenAsUL(
309
			"",
310
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
311
			null,
312
			false,
313
			"AllChildrenIncludingDeleted",
314
			"numChildren",
315
			true,
316
			$nodeCountThreshold
317
		);
318
		$this->assertTreeContains($html, array($obj2),
319
			'Contains root elements'
320
		);
321
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
322
			'Does contain marked children nodes regardless of configured threshold'
323
		);
324
	}
325
326
	public function testGetChildrenAsULMinNodeCountWithFilters() {
327
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
328
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
329
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
330
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
331
332
		// Set low enough that it should fit all search matches without lazy loading
333
		$nodeCountThreshold = 3;
334
335
		$root = new HierarchyTest_Object();
336
337
		// Includes nodes by filter regardless of minNodeCount restrictions
338
		$root->setMarkingFilterFunction(function($record) use($obj2, $obj2a, $obj2aa) {
339
			// Results need to include parent hierarchy, even if we just want to
340
			// match the innermost node.
341
			return in_array($record->ID, array($obj2->ID, $obj2a->ID, $obj2aa->ID));
342
		});
343
		$root->markPartialTree($nodeCountThreshold);
344
345
		$html = $root->getChildrenAsUL(
346
			"",
347
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
348
			null,
349
			true, // limit to marked
350
			"AllChildrenIncludingDeleted",
351
			"numChildren",
352
			true,
353
			$nodeCountThreshold
354
		);
355
		$this->assertTreeNotContains($html, array($obj1),
356
			'Does not contain root elements which dont match the filter'
357
		);
358
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
359
			'Contains non-root elements which match the filter'
360
		);
361
	}
362
363
	public function testGetChildrenAsULHardLimitsNodes() {
364
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
365
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
366
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
367
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
368
369
		// Set low enough that it should fit all search matches without lazy loading
370
		$nodeCountThreshold = 3;
371
372
		$root = new HierarchyTest_Object();
373
374
		// Includes nodes by filter regardless of minNodeCount restrictions
375
		$root->setMarkingFilterFunction(function($record) use($obj2, $obj2a, $obj2aa) {
376
			// Results need to include parent hierarchy, even if we just want to
377
			// match the innermost node.
378
			return in_array($record->ID, array($obj2->ID, $obj2a->ID, $obj2aa->ID));
379
		});
380
		$root->markPartialTree($nodeCountThreshold);
381
382
		$html = $root->getChildrenAsUL(
383
			"",
384
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
385
			null,
386
			true, // limit to marked
387
			"AllChildrenIncludingDeleted",
388
			"numChildren",
389
			true,
390
			$nodeCountThreshold
391
		);
392
		$this->assertTreeNotContains($html, array($obj1),
393
			'Does not contain root elements which dont match the filter'
394
		);
395
		$this->assertTreeContains($html, array($obj2, $obj2a, $obj2aa),
396
			'Contains non-root elements which match the filter'
397
		);
398
	}
399
400
	public function testGetChildrenAsULNodeThresholdLeaf() {
401
		$obj1 = $this->objFromFixture('HierarchyTest_Object', 'obj1');
402
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
403
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
404
		$obj3 = $this->objFromFixture('HierarchyTest_Object', 'obj3');
405
		$obj3a = $this->objFromFixture('HierarchyTest_Object', 'obj3a');
406
407
		$nodeCountThreshold = 99;
408
409
		$root = new HierarchyTest_Object();
410
		$root->markPartialTree($nodeCountThreshold);
411
		$nodeCountCallback = function($parent, $numChildren) {
412
			// Set low enough that it the fixture structure should exceed it
413
			if($parent->ID && $numChildren > 2) {
414
				return '<span class="exceeded">Exceeded!</span>';
415
			}
416
		};
417
418
		$html = $root->getChildrenAsUL(
419
			"",
420
			'"<li id=\"" . $child->ID . "\">" . $child->Title',
421
			null,
422
			true, // limit to marked
423
			"AllChildrenIncludingDeleted",
424
			"numChildren",
425
			true,
426
			$nodeCountThreshold,
427
			$nodeCountCallback
428
		);
429
		$this->assertTreeContains($html, array($obj1),
430
			'Does contain root elements regardless of count'
431
		);
432
		$this->assertTreeContains($html, array($obj3),
433
			'Does contain root elements regardless of count'
434
		);
435
		$this->assertTreeContains($html, array($obj2, $obj2a),
436
			'Contains children which do not exceed threshold'
437
		);
438
		$this->assertTreeNotContains($html, array($obj3, $obj3a),
439
			'Does not contain children which exceed threshold'
440
		);
441
	}
442
443
	/**
444
	 * This test checks that deleted ('archived') child pages don't set a css class on the parent
445
	 * node that makes it look like it has children
446
	 */
447
	public function testGetChildrenAsULNodeDeletedOnLive() {
448
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
449
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
450
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
451
		$obj2ab = $this->objFromFixture('HierarchyTest_Object', 'obj2b');
452
453
		// delete all children under obj2
454
		$obj2a->delete();
455
		$obj2aa->delete();
456
		$obj2ab->delete();
457
		// Don't pre-load all children
458
		$nodeCountThreshold = 1;
459
460
		$childrenMethod = 'AllChildren';
461
		$numChildrenMethod = 'numChildren';
462
463
		$root = new HierarchyTest_Object();
464
		$root->markPartialTree($nodeCountThreshold, null, $childrenMethod, $numChildrenMethod);
465
466
		// As in LeftAndMain::getSiteTreeFor() but simpler and more to the point for testing purposes
467
		$titleFn = function(&$child, $numChildrenMethod="") {
468
			return '<li class="' . $child->markingClasses($numChildrenMethod).
469
				'" id="' . $child->ID . '">"' . $child->Title;
470
		};
471
472
		$html = $root->getChildrenAsUL(
473
			"",
474
			$titleFn,
475
			null,
476
			true, // limit to marked
477
			$childrenMethod,
478
			$numChildrenMethod,
479
			true,
480
			$nodeCountThreshold
481
		);
482
483
		// Get the class attribute from the $obj2 node in the sitetree, class 'jstree-leaf' means it's a leaf node
484
		$nodeClass = $this->getNodeClassFromTree($html, $obj2);
485
		$this->assertEquals('jstree-leaf closed', $nodeClass, 'object2 should not have children in the sitetree');
486
	}
487
488
	/**
489
	 * This test checks that deleted ('archived') child pages _do_ set a css class on the parent
490
	 * node that makes it look like it has children when getting all children including deleted
491
	 */
492
	public function testGetChildrenAsULNodeDeletedOnStage() {
493
		$obj2 = $this->objFromFixture('HierarchyTest_Object', 'obj2');
494
		$obj2a = $this->objFromFixture('HierarchyTest_Object', 'obj2a');
495
		$obj2aa = $this->objFromFixture('HierarchyTest_Object', 'obj2aa');
496
		$obj2ab = $this->objFromFixture('HierarchyTest_Object', 'obj2b');
497
498
		// delete all children under obj2
499
		$obj2a->delete();
500
		$obj2aa->delete();
501
		$obj2ab->delete();
502
		// Don't pre-load all children
503
		$nodeCountThreshold = 1;
504
505
		$childrenMethod = 'AllChildrenIncludingDeleted';
506
		$numChildrenMethod = 'numHistoricalChildren';
507
508
		$root = new HierarchyTest_Object();
509
		$root->markPartialTree($nodeCountThreshold, null, $childrenMethod, $numChildrenMethod);
510
511
		// As in LeftAndMain::getSiteTreeFor() but simpler and more to the point for testing purposes
512
		$titleFn = function(&$child, $numChildrenMethod="") {
513
			return '<li class="' . $child->markingClasses($numChildrenMethod).
514
				'" id="' . $child->ID . '">"' . $child->Title;
515
		};
516
517
		$html = $root->getChildrenAsUL(
518
			"",
519
			$titleFn,
520
			null,
521
			true, // limit to marked
522
			$childrenMethod,
523
			$numChildrenMethod,
524
			true,
525
			$nodeCountThreshold
526
		);
527
528
		// Get the class attribute from the $obj2 node in the sitetree
529
		$nodeClass = $this->getNodeClassFromTree($html, $obj2);
530
		// Object2 can now be expanded
531
		$this->assertEquals('unexpanded jstree-closed closed', $nodeClass, 'obj2 should have children in the sitetree');
532
	}
533
534
	public function testNoHideFromHeirarchy() {
535
		$obj4 = $this->objFromFixture('HierarchyHideTest_Object', 'obj4');
536
		$obj4->publish("Stage", "Live");
537
538
		foreach($obj4->stageChildren() as $child) {
539
			$child->publish("Stage", "Live");
540
		}
541
		$this->assertEquals($obj4->stageChildren()->Count(), 2);
542
		$this->assertEquals($obj4->liveChildren()->Count(), 2);
543
	}
544
545
	public function testHideFromHeirarchy() {
546
		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...
547
		$obj4 = $this->objFromFixture('HierarchyHideTest_Object', 'obj4');
548
		$obj4->publish("Stage", "Live");
549
550
		// load without using stage children otherwise it'll bbe filtered before it's publish
551
		// we need to publish all of them, and expect liveChildren to return some.
552
		$children = HierarchyHideTest_Object::get()
553
			->filter('ParentID', (int)$obj4->ID)
554
			->exclude('ID', (int)$obj4->ID);
555
556
		foreach($children as $child) {
557
			$child->publish("Stage", "Live");
558
		}
559
		$this->assertEquals($obj4->stageChildren()->Count(), 1);
560
		$this->assertEquals($obj4->liveChildren()->Count(), 1);
561
	}
562
563
	/**
564
	 * @param String $html  [description]
565
	 * @param array $nodes Breadcrumb path as array
566
	 * @param String $message
567
	 */
568
	protected function assertTreeContains($html, $nodes, $message = null) {
569
		$parser = new CSSContentParser($html);
570
		$xpath = '/';
571
		foreach($nodes as $node) $xpath .= '/ul/li[@id="' . $node->ID . '"]';
572
		$match = $parser->getByXpath($xpath);
573
		self::assertThat((bool)$match, self::isTrue(), $message);
574
	}
575
576
	/**
577
	 * @param String $html  [description]
578
	 * @param array $nodes Breadcrumb path as array
579
	 * @param String $message
580
	 */
581
	protected function assertTreeNotContains($html, $nodes, $message = null) {
582
		$parser = new CSSContentParser($html);
583
		$xpath = '/';
584
		foreach($nodes as $node) $xpath .= '/ul/li[@id="' . $node->ID . '"]';
585
		$match = $parser->getByXpath($xpath);
586
		self::assertThat((bool)$match, self::isFalse(), $message);
587
	}
588
589
	/**
590
	 * Get the HTML class attribute from a node in the sitetree
591
	 *
592
	 * @param $html
593
	 * @param $node
594
	 * @return string
595
	 */
596
	protected function getNodeClassFromTree($html, $node) {
597
		$parser = new CSSContentParser($html);
598
		$xpath = '//ul/li[@id="' . $node->ID . '"]';
599
		$object = $parser->getByXpath($xpath);
600
601
		foreach($object[0]->attributes() as $key => $attr) {
602
			if($key == 'class') {
603
				return (string)$attr;
604
			}
605
		}
606
		return '';
607
	}
608
}
609
610
class HierarchyTest_Object extends DataObject implements TestOnly {
611
	private static $db = array(
612
		'Title' => 'Varchar'
613
	);
614
615
	private static $extensions = array(
616
		'Hierarchy',
617
		"Versioned('Stage', 'Live')",
618
	);
619
620
	private static $default_sort = 'Title ASC';
621
622
	public function cmstreeclasses() {
623
		return $this->markingClasses();
624
	}
625
}
626
627
class HierarchyHideTest_Object extends DataObject implements TestOnly {
628
	private static $db = array(
629
		'Title' => 'Varchar'
630
	);
631
632
	private static $extensions = array(
633
		'Hierarchy',
634
		"Versioned('Stage', 'Live')",
635
	);
636
637
	public function cmstreeclasses() {
638
		return $this->markingClasses();
639
	}
640
}
641
642
class HierarchyHideTest_SubObject extends HierarchyHideTest_Object {
643
644
}
645