Skip to content

Commit cfead6c

Browse files
committed
Improve Hierarchical mixin
Changed: - Added method `hasMasterObject()`. - Added methods `loadHierarchy()` and `loadSiblings()`. - Fixed type-hints related to `ModelInterface` and `HierarchicalInterface`.
1 parent a3b6653 commit cfead6c

File tree

2 files changed

+76
-45
lines changed

2 files changed

+76
-45
lines changed

src/Charcoal/Object/HierarchicalInterface.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ interface HierarchicalInterface
1414
*/
1515
public function hasMaster();
1616

17+
/**
18+
* Determine if this object's immediate parent exists.
19+
*
20+
* @return boolean
21+
*/
22+
public function hasMasterObject();
23+
1724
/**
1825
* Determine if this object is the head (top-level) of its hierarchy.
1926
*

src/Charcoal/Object/HierarchicalTrait.php

Lines changed: 69 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ trait HierarchicalTrait
1818
*
1919
* @var string|integer|null
2020
*/
21-
protected $master;
21+
protected $master = null;
2222

2323
/**
2424
* Store a copy of the object's ancestry.
@@ -32,21 +32,21 @@ trait HierarchicalTrait
3232
*
3333
* @var HierarchicalInterface[]|null
3434
*/
35-
private $children;
35+
private $children = null;
3636

3737
/**
3838
* Store a copy of the object's siblings.
3939
*
4040
* @var HierarchicalInterface[]|null
4141
*/
42-
private $siblings;
42+
private $siblings = null;
4343

4444
/**
4545
* The object's parent object, if any, in the hierarchy.
4646
*
4747
* @var HierarchicalInterface|null
4848
*/
49-
private $masterObject;
49+
private $masterObject = null;
5050

5151
/**
5252
* A store of cached objects.
@@ -128,14 +128,24 @@ public function getMasterObject()
128128
return $this->masterObject;
129129
}
130130

131+
/**
132+
* Determine if this object's immediate parent exists.
133+
*
134+
* @return boolean
135+
*/
136+
public function hasMasterObject()
137+
{
138+
return (bool)$this->getMasterObject();
139+
}
140+
131141
/**
132142
* Determine if this object has a direct parent.
133143
*
134144
* @return boolean
135145
*/
136146
public function hasMaster()
137147
{
138-
return ($this->getMaster() !== null);
148+
return (bool)$this->getMaster();
139149
}
140150

141151
/**
@@ -147,7 +157,7 @@ public function hasMaster()
147157
*/
148158
public function isTopLevel()
149159
{
150-
return ($this->getMaster() === null);
160+
return !$this->getMaster();
151161
}
152162

153163
/**
@@ -201,34 +211,44 @@ public function toplevelMaster()
201211
*/
202212
public function hasParents()
203213
{
204-
return !!count($this->hierarchy());
214+
return count($this->hierarchy()) > 0;
205215
}
206216

207217
/**
208218
* Retrieve this object's ancestors (from immediate parent to top-level).
209219
*
210-
* @return array
220+
* @return HierarchicalInterface[]
211221
*/
212222
public function hierarchy()
213223
{
214-
if (!isset($this->hierarchy)) {
215-
$hierarchy = [];
216-
$master = $this->getMasterObject();
217-
while ($master) {
218-
$hierarchy[] = $master;
219-
$master = $master->getMasterObject();
220-
}
221-
222-
$this->hierarchy = $hierarchy;
224+
if ($this->hierarchy === null) {
225+
$this->hierarchy = $this->loadHierarchy();
223226
}
224227

225228
return $this->hierarchy;
226229
}
227230

231+
/**
232+
* Build this object's ancestors (from immediate parent to top-level).
233+
*
234+
* @return HierarchicalInterface[]
235+
*/
236+
public function loadHierarchy()
237+
{
238+
$hierarchy = [];
239+
$master = $this->getMasterObject();
240+
while ($master) {
241+
$hierarchy[] = $master;
242+
$master = $master->getMasterObject();
243+
}
244+
245+
return $hierarchy;
246+
}
247+
228248
/**
229249
* Retrieve this object's ancestors, inverted from top-level to immediate.
230250
*
231-
* @return array
251+
* @return HierarchicalInterface[]
232252
*/
233253
public function invertedHierarchy()
234254
{
@@ -290,15 +310,15 @@ public function numChildren()
290310
* Get the total number of children in the entire hierarchy.
291311
* This method counts all children and sub-children, unlike `numChildren()` which only count 1 level.
292312
* @return integer
313+
* @todo Implementation needed.
293314
*/
294315
public function recursiveNumChildren()
295316
{
296-
// TODO
297317
return 0;
298318
}
299319

300320
/**
301-
* @param array $children The children to set.
321+
* @param mixed[] $children The children to set.
302322
* @return HierarchicalInterface Chainable
303323
*/
304324
public function setChildren(array $children)
@@ -336,7 +356,7 @@ public function addChild($child)
336356

337357
/**
338358
* Get the children directly under this object.
339-
* @return array
359+
* @return ModelInterface[]
340360
*/
341361
public function children()
342362
{
@@ -361,11 +381,8 @@ abstract public function loadChildren();
361381
public function isChildOf($master)
362382
{
363383
$master = $this->objFromIdent($master);
364-
if ($master === null) {
365-
return false;
366-
}
367384

368-
return ($master->id() === $this->getMaster());
385+
return ($master && $master->id() === $this->getMaster());
369386
}
370387

371388
/**
@@ -378,8 +395,8 @@ public function recursiveIsChildOf($master)
378395
return true;
379396
}
380397

381-
if ($this->hasParents() && $this->getMasterObject()->recursiveIsChildOf($master)) {
382-
return true;
398+
if ($this->hasParents() && $this->hasMasterObject()) {
399+
return $this->getMasterObject()->recursiveIsChildOf($master);
383400
}
384401

385402
return false;
@@ -407,24 +424,32 @@ public function numSiblings()
407424

408425
/**
409426
* Get all the objects on the same level as this one.
410-
* @return array
427+
* @return ModelInterface[]
411428
*/
412429
public function siblings()
413430
{
414-
if ($this->siblings !== null) {
415-
return $this->siblings;
431+
if ($this->siblings === null) {
432+
$this->siblings = $this->loadSiblings();
416433
}
434+
435+
return $this->siblings;
436+
}
437+
438+
/**
439+
* Get all the objects on the same level as this one.
440+
* @return ModelInterface[]
441+
* @todo Implementation needed.
442+
*/
443+
public function loadSiblings()
444+
{
417445
$master = $this->getMasterObject();
418-
if ($master === null) {
419-
// Todo: return all top-level objects.
420-
$siblings = [];
421-
} else {
446+
if ($master) {
422447
// Todo: Remove "current" object from siblings
423-
$siblings = $master->children();
448+
return $master->children();
424449
}
425-
$this->siblings = $siblings;
426450

427-
return $this->siblings;
451+
// TODO: return all top-level objects.
452+
return [];
428453
}
429454

430455
/**
@@ -440,7 +465,7 @@ public function isSiblingOf($sibling)
440465

441466
/**
442467
* @param mixed $ident The ident.
443-
* @return HierarchicalInterface|null
468+
* @return (HierarchicalInterface&ModelInterface)|null
444469
* @throws InvalidArgumentException If the identifier is not a scalar value.
445470
*/
446471
private function objFromIdent($ident)
@@ -472,7 +497,6 @@ private function objFromIdent($ident)
472497
}
473498

474499
$obj = $this->loadObjectFromSource($ident);
475-
476500
if ($obj !== null) {
477501
$this->addObjectToCache($obj);
478502
}
@@ -484,7 +508,7 @@ private function objFromIdent($ident)
484508
* Retrieve an object from the storage source by its ID.
485509
*
486510
* @param mixed $id The object id.
487-
* @return null|HierarchicalInterface
511+
* @return (HierarchicalInterface&ModelInterface)|null
488512
*/
489513
private function loadObjectFromSource($id)
490514
{
@@ -493,25 +517,25 @@ private function loadObjectFromSource($id)
493517

494518
if ($obj->id()) {
495519
return $obj;
496-
} else {
497-
return null;
498520
}
521+
522+
return null;
499523
}
500524

501525
/**
502526
* Retrieve an object from the cache store by its ID.
503527
*
504528
* @param mixed $id The object id.
505-
* @return null|HierarchicalInterface
529+
* @return (HierarchicalInterface&ModelInterface)|null
506530
*/
507531
private function loadObjectFromCache($id)
508532
{
509533
$objType = $this->objType();
510534
if (isset(static::$objectCache[$objType][$id])) {
511535
return static::$objectCache[$objType][$id];
512-
} else {
513-
return null;
514536
}
537+
538+
return null;
515539
}
516540

517541
/**

0 commit comments

Comments
 (0)