1 | <?php |
||
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 ) { |
|
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 ) { |
|
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 ) { |
|
130 | |||
131 | 25 | private function getTitleParts( $titleText ) { |
|
134 | |||
135 | 25 | private function titleTextFromParts( array $titleParts ) { |
|
138 | |||
139 | 25 | private function getParentTitle( $titleText ) { |
|
144 | |||
145 | 27 | private function assertAreTitles( array $titles ) { |
|
146 | 27 | foreach ( $titles as $title ) { |
|
147 | 26 | if ( !( $title instanceof Title ) ) { |
|
148 | 1 | throw new InvalidArgumentException( 'All elements must be of instance Title' ); |
|
149 | } |
||
152 | |||
153 | } |
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: