Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
63.64% covered (warning)
63.64%
21 / 33
50.00% covered (danger)
50.00%
5 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
Group
63.64% covered (warning)
63.64%
21 / 33
50.00% covered (danger)
50.00%
5 / 10
23.42
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getId
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 hasEntries
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getEntries
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 throwIfNotUnique
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 prependEntry
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 insertEntry
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 search
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getEntryByName
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 serialize
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\Minerva\Menu;
22
23use DomainException;
24use MediaWiki\Minerva\Menu\Entries\IMenuEntry;
25
26/**
27 * Model for a menu that can be presented in a skin.
28 */
29final class Group {
30    /**
31     * @var IMenuEntry[]
32     */
33    private $entries = [];
34
35    /**
36     * @var string
37     */
38    private $id;
39
40    /**
41     * @param string $id of the menu defaults to null (optional)
42     */
43    public function __construct( $id ) {
44        $this->id = $id;
45    }
46
47    /**
48     * Get the identifier for the group
49     *
50     * @return string
51     */
52    public function getId() {
53        return $this->id;
54    }
55
56    /**
57     * Return entries count
58     *
59     * @return bool
60     */
61    public function hasEntries(): bool {
62        return count( $this->entries ) > 0;
63    }
64
65    /**
66     * Get all entries represented as plain old PHP arrays.
67     *
68     * @return array
69     */
70    public function getEntries(): array {
71        $entryPresenter = static function ( IMenuEntry $entry ) {
72            $result = [
73                'name' => $entry->getName(),
74                'components' => $entry->getComponents(),
75            ];
76            $classes = $entry->getCSSClasses();
77            if ( $classes ) {
78                $result[ 'class' ] = implode( ' ', $classes );
79            }
80
81            return $result;
82        };
83
84        return array_map( $entryPresenter, $this->entries );
85    }
86
87    /**
88     * Helper method to verify that the $name of entry is unique (do not exists
89     * in current Group )
90     * @param string $name
91     * @throws DomainException When the entry already exists
92     */
93    private function throwIfNotUnique( string $name ): void {
94        try {
95            $this->search( $name );
96        } catch ( DomainException $exception ) {
97            return;
98        }
99        throw new DomainException( "The \"{$name}\" entry already exists." );
100    }
101
102    /**
103     * Prepend new menu entry
104     * @param IMenuEntry $entry
105     * @throws DomainException When the entry already exists
106     */
107    public function prependEntry( IMenuEntry $entry ): void {
108        $this->throwIfNotUnique( $entry->getName() );
109        array_unshift( $this->entries, $entry );
110    }
111
112    /**
113     * Insert new menu entry
114     * @param IMenuEntry $entry
115     * @throws DomainException When the entry already exists
116     */
117    public function insertEntry( IMenuEntry $entry ) {
118        $this->throwIfNotUnique( $entry->getName() );
119        $this->entries[] = $entry;
120    }
121
122    /**
123     * Searches for a menu entry by name.
124     *
125     * @param string $name
126     * @return int If the menu entry exists, then the 0-based index of the entry; otherwise, -1
127     * @throws DomainException
128     */
129    private function search( string $name ): int {
130        $count = count( $this->entries );
131
132        for ( $i = 0; $i < $count; ++$i ) {
133            if ( $this->entries[$i]->getName() === $name ) {
134                return $i;
135            }
136        }
137        throw new DomainException( "The \"{$name}\" entry doesn't exist." );
138    }
139
140    /**
141     * @param string $targetName
142     * @return IMenuEntry
143     * @throws DomainException
144     */
145    public function getEntryByName( string $targetName ): IMenuEntry {
146        $index = $this->search( $targetName );
147        return $this->entries[$index];
148    }
149
150    /**
151     * Serialize the group for use in a template
152     * @return array{entries:array,id:string}
153     */
154    public function serialize(): array {
155        return [
156            'entries' => $this->getEntries(),
157            'id' => $this->getId(),
158        ];
159    }
160}