Completed
Push — namespace-template ( 7967f2...367a36 )
by Sam
10:48
created

HierarchyHideTest_Object   A

Complexity

Total Complexity 1

Size/Duplication

Total Lines 14
Duplicated Lines 100 %

Coupling/Cohesion

Components 0
Dependencies 1

Importance

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

1 Method

Rating   Name   Duplication   Size   Complexity  
A cmstreeclasses() 3 3 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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');
0 ignored issues
show
Unused Code introduced by
$obj2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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');
0 ignored issues
show
Unused Code introduced by
$obj1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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 View Code Duplication
	public function testGetChildrenAsULMinNodeCount() {
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...
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 View Code Duplication
	public function testGetChildrenAsULMinNodeCountWithMarkToExpose() {
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...
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 View Code Duplication
	public function testGetChildrenAsULMinNodeCountWithFilters() {
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...
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 View Code Duplication
	public function testGetChildrenAsULHardLimitsNodes() {
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...
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 View Code Duplication
	public function testGetChildrenAsULNodeDeletedOnLive() {
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...
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 View Code Duplication
	public function testGetChildrenAsULNodeDeletedOnStage() {
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...
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 View Code Duplication
	protected function assertTreeContains($html, $nodes, $message = null) {
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...
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 View Code Duplication
	protected function assertTreeNotContains($html, $nodes, $message = null) {
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...
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 View Code Duplication
class HierarchyTest_Object extends DataObject implements TestOnly {
0 ignored issues
show
Duplication introduced by
This class 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...
564
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
565
		'Title' => 'Varchar'
566
	);
567
568
	private static $extensions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
569
		'Hierarchy',
570
		'Versioned',
571
	);
572
573
	public function cmstreeclasses() {
574
		return $this->markingClasses();
575
	}
576
}
577
578 View Code Duplication
class HierarchyHideTest_Object extends DataObject implements TestOnly {
0 ignored issues
show
Duplication introduced by
This class 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...
579
	private static $db = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
580
		'Title' => 'Varchar'
581
	);
582
583
	private static $extensions = array(
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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