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    /** @var IMenuEntry[] */
31    private array $entries = [];
32    private string $id;
33
34    /**
35     * @param string $id of the menu defaults to null (optional)
36     */
37    public function __construct( $id ) {
38        $this->id = $id;
39    }
40
41    /**
42     * Get the identifier for the group
43     *
44     * @return string
45     */
46    public function getId(): string {
47        return $this->id;
48    }
49
50    /**
51     * Return entries count
52     *
53     * @return bool
54     */
55    public function hasEntries(): bool {
56        return count( $this->entries ) > 0;
57    }
58
59    /**
60     * Get all entries represented as plain old PHP arrays.
61     *
62     * @return array
63     */
64    public function getEntries(): array {
65        $entryPresenter = static function ( IMenuEntry $entry ) {
66            $result = [
67                'name' => $entry->getName(),
68                'components' => $entry->getComponents(),
69            ];
70            $classes = $entry->getCSSClasses();
71            if ( $classes ) {
72                $result[ 'class' ] = implode( ' ', $classes );
73            }
74
75            return $result;
76        };
77
78        return array_map( $entryPresenter, $this->entries );
79    }
80
81    /**
82     * Helper method to verify that the $name of entry is unique (do not exists
83     * in current Group )
84     * @param string $name
85     * @throws DomainException When the entry already exists
86     */
87    private function throwIfNotUnique( string $name ): void {
88        try {
89            $this->search( $name );
90        } catch ( DomainException $exception ) {
91            return;
92        }
93        throw new DomainException( "The \"{$name}\" entry already exists." );
94    }
95
96    /**
97     * Prepend new menu entry
98     * @param IMenuEntry $entry
99     * @throws DomainException When the entry already exists
100     */
101    public function prependEntry( IMenuEntry $entry ): void {
102        $this->throwIfNotUnique( $entry->getName() );
103        array_unshift( $this->entries, $entry );
104    }
105
106    /**
107     * Insert new menu entry
108     * @param IMenuEntry $entry
109     * @throws DomainException When the entry already exists
110     */
111    public function insertEntry( IMenuEntry $entry ): void {
112        $this->throwIfNotUnique( $entry->getName() );
113        $this->entries[] = $entry;
114    }
115
116    /**
117     * Searches for a menu entry by name.
118     *
119     * @param string $name
120     * @return int If the menu entry exists, then the 0-based index of the entry; otherwise, -1
121     * @throws DomainException
122     */
123    private function search( string $name ): int {
124        $count = count( $this->entries );
125
126        for ( $i = 0; $i < $count; ++$i ) {
127            if ( $this->entries[$i]->getName() === $name ) {
128                return $i;
129            }
130        }
131        throw new DomainException( "The \"{$name}\" entry doesn't exist." );
132    }
133
134    /**
135     * @param string $targetName
136     * @return IMenuEntry
137     * @throws DomainException
138     */
139    public function getEntryByName( string $targetName ): IMenuEntry {
140        $index = $this->search( $targetName );
141        return $this->entries[$index];
142    }
143
144    /**
145     * Serialize the group for use in a template
146     * @return array{entries:array,id:string}
147     */
148    public function serialize(): array {
149        return [
150            'entries' => $this->getEntries(),
151            'id' => $this->getId(),
152        ];
153    }
154}