PageHierarchyCreator   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 98.33%

Importance

Changes 0
Metric Value
dl 0
loc 137
ccs 59
cts 60
cp 0.9833
rs 10
c 0
b 0
f 0
wmc 20
lcom 1
cbo 2

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getTextForTitle() 0 3 1
A newPageFromText() 0 3 1
A getTitleParts() 0 3 1
A titleTextFromParts() 0 3 1
A getParentTitle() 0 5 1
A createHierarchy() 0 12 2
A addTitle() 0 14 2
A addTopLevelPage() 0 6 2
A addSubPage() 0 6 2
A createParents() 0 24 3
A assertAreTitles() 0 7 3
1
<?php
2
3
namespace SubPageList\Lister;
4
5
use InvalidArgumentException;
6
use SubPageList\TitleFactory;
7
use Title;
8
9
/**
10
 * Turns a flat list of Title objects into a sub page hierarchy of Page objects.
11
 *
12
 * @since 1.2
13
 *
14
 * @licence GNU GPL v2+
15
 * @author Jeroen De Dauw < [email protected] >
16
 */
17
class PageHierarchyCreator {
18
19
	/**
20
	 * Top level pages.
21
	 *
22
	 * @var Page[]
23
	 */
24
	private $pages;
25
26
	/**
27
	 * All pages, indexed by title text.
28
	 *
29
	 * @var Page[]
30
	 */
31
	private $allPages;
32
33
	/**
34
	 * @var TitleFactory
35
	 */
36
	private $titleFactory;
37
38 33
	public function __construct( TitleFactory $titleFactory ) {
39 33
		$this->titleFactory = $titleFactory;
40 33
	}
41
42
	/**
43
	 * @param Title[] $titles
44
	 *
45
	 * @return Page[]
46
	 */
47 27
	public function createHierarchy( array $titles ) {
48 27
		$this->assertAreTitles( $titles );
49
50 26
		$this->pages = [];
51 26
		$this->allPages = [];
52
53 26
		foreach ( $titles as $title ) {
54 25
			$this->addTitle( $title );
55
		}
56
57 26
		return $this->pages;
58
	}
59
60 25
	private function addTitle( Title $title ) {
61 25
		$page = new Page( $title, [] );
62 25
		$titleText = $this->getTextForTitle( $title );
63
64 25
		$parentTitle = $this->getParentTitle( $titleText );
65
66 25
		if ( $parentTitle === '' ) {
67 22
			$this->addTopLevelPage( $titleText, $page );
68
		}
69
		else {
70 16
			$this->createParents( $titleText );
71 16
			$this->addSubPage( $parentTitle, $titleText, $page );
72
		}
73 25
	}
74
75 25
	private function getTextForTitle( Title $title ) {
76 25
		return $title->getFullText();
77
	}
78
79
	/**
80
	 * @param string $titleText
81
	 * @param Page $page Page is expected to not have any subpages
82
	 */
83 25
	private function addTopLevelPage( $titleText, Page $page ) {
84 25
		if ( !array_key_exists( $titleText, $this->allPages ) ) {
85 25
			$this->pages[] = $page;
86 25
			$this->allPages[$titleText] = $page;
87
		}
88 25
	}
89
90
	/**
91
	 * @param string $parentTitle
92
	 * @param string $pageTitle
93
	 * @param Page $page Page is expected to not have any subpages
94
	 */
95 16
	private function addSubPage( $parentTitle, $pageTitle, Page $page ) {
96 16
		if ( !array_key_exists( $pageTitle, $this->allPages ) ) {
97 16
			$this->allPages[$parentTitle]->addSubPage( $page );
98 16
			$this->allPages[$pageTitle] = $page;
99
		}
100 16
	}
101
102 16
	private function createParents( $pageTitle ) {
103 16
		$titleParts = $this->getTitleParts( $pageTitle );
104 16
		array_pop( $titleParts );
105
106 16
		if ( empty( $titleParts ) ) {
107
			return;
108
		}
109
110 16
		$topLevelPage =  array_shift( $titleParts );
111
112 16
		$this->addTopLevelPage( $topLevelPage, $this->newPageFromText( $topLevelPage ) );
113
114 16
		$previousParts = [ $topLevelPage ];
115
116 16
		foreach ( $titleParts as $titlePart ) {
117 5
			$parentTitle = $this->titleTextFromParts( $previousParts );
118
119 5
			$previousParts[] = $titlePart;
120
121 5
			$pageTitle = $this->titleTextFromParts( $previousParts );
122
123 5
			$this->addSubPage( $parentTitle, $pageTitle, $this->newPageFromText( $pageTitle ) );
124
		}
125 16
	}
126
127 16
	private function newPageFromText( $titleText ) {
128 16
		return new Page( $this->titleFactory->newFromText( $titleText ) );
0 ignored issues
show
Bug introduced by
It seems like $this->titleFactory->newFromText($titleText) can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
129
	}
130
131 25
	private function getTitleParts( $titleText ) {
132 25
		return explode( '/', $titleText );
133
	}
134
135 25
	private function titleTextFromParts( array $titleParts ) {
136 25
		return implode( '/', $titleParts );
137
	}
138
139 25
	private function getParentTitle( $titleText ) {
140 25
		$titleParts = $this->getTitleParts($titleText );
141 25
		array_pop( $titleParts );
142 25
		return $this->titleTextFromParts( $titleParts );
143
	}
144
145 27
	private function assertAreTitles( array $titles ) {
146 27
		foreach ( $titles as $title ) {
147 26
			if ( !( $title instanceof Title ) ) {
0 ignored issues
show
Bug introduced by
The class Title does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
148 1
				throw new InvalidArgumentException( 'All elements must be of instance Title' );
149
			}
150
		}
151 26
	}
152
153
}