Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.00% covered (success)
96.00%
48 / 50
87.50% covered (warning)
87.50%
14 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
FormSet
96.00% covered (success)
96.00%
48 / 50
87.50% covered (warning)
87.50%
14 / 16
27
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 toArray
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 toArrayUnordered
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sortForms
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 count
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 maxFormIdNumber
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 add
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 remove
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 put
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getById
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 copy
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __clone
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 isEmpty
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 equals
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
3.07
 hasFormWithId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sameForms
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
4.07
1<?php
2
3declare( strict_types = 1 );
4
5namespace Wikibase\Lexeme\Domain\Model;
6
7use Countable;
8use Wikibase\Lexeme\Domain\Model\Exceptions\ConflictException;
9
10/**
11 * Set of Forms in which uniqueness of a Form is controlled by it's ID.
12 * Supposed to be used only inside the Lexeme class
13 *
14 * @license GPL-2.0-or-later
15 */
16class FormSet implements Countable {
17
18    /**
19     * @var Form[] indexed by serialization of FormId
20     */
21    private array $forms = [];
22
23    /**
24     * @param Form[] $forms
25     */
26    public function __construct( array $forms = [] ) {
27        foreach ( $forms as $form ) {
28            if ( !$form instanceof Form ) {
29                throw new \InvalidArgumentException( '$forms must be an array of Forms' );
30            }
31
32            $this->add( $form );
33        }
34    }
35
36    /**
37     * @return Form[]
38     */
39    public function toArray(): array {
40        $forms = $this->sortForms( $this->forms );
41        return array_values( $forms );
42    }
43
44    /**
45     * Return the individual Forms in arbitrary order.
46     *
47     * Only use this method if the order is certainly insignificant,
48     * e.g. because the Forms will be summarized or reduced in some way.
49     * Otherwise, use {@link toArray()}.
50     *
51     * @return Form[]
52     */
53    public function toArrayUnordered(): array {
54        return array_values( $this->forms );
55    }
56
57    /**
58     * @param Form[] $forms
59     * @return Form[] sorted array mapping numeric id to the form
60     */
61    private function sortForms( array $forms ): array {
62        $sortedForms = [];
63        foreach ( $forms as $form ) {
64            $formIdPart = explode( '-', $form->getId()->getSerialization(), 2 )[1];
65            $formIdNumber = (int)substr( $formIdPart, 1 );
66            $sortedForms[$formIdNumber] = $form;
67        }
68        ksort( $sortedForms );
69
70        return $sortedForms;
71    }
72
73    public function count(): int {
74        return count( $this->forms );
75    }
76
77    public function maxFormIdNumber(): int {
78        if ( !$this->forms ) {
79            return 0;
80        }
81
82        $numbers = array_map( static function ( $formId ) {
83            [ , $formId ] = explode( '-', $formId, 2 );
84            return (int)substr( $formId, 1 );
85        }, array_keys( $this->forms ) );
86        return max( $numbers );
87    }
88
89    public function add( Form $form ): void {
90        $formId = $form->getId()->getSerialization();
91        if ( isset( $this->forms[$formId] ) ) {
92            throw new ConflictException(
93                'At least two forms with the same ID were provided: `' . $formId . '`'
94            );
95        }
96
97        $this->forms[$formId] = $form;
98    }
99
100    public function remove( FormId $formId ): void {
101        unset( $this->forms[$formId->getSerialization()] );
102    }
103
104    /**
105     * Replace the form identified by $form->getId() with the given one or add it
106     */
107    public function put( Form $form ): void {
108        $this->remove( $form->getId() );
109        $this->add( $form );
110    }
111
112    public function getById( FormId $formId ): ?Form {
113        return $this->forms[$formId->getSerialization()] ?? null;
114    }
115
116    public function copy(): self {
117        return clone $this;
118    }
119
120    /**
121     * @see http://php.net/manual/en/language.oop5.cloning.php
122     */
123    public function __clone() {
124        $clonedForms = [];
125        foreach ( $this->forms as $key => $form ) {
126            $clonedForms[$key] = clone $form;
127        }
128        $this->forms = $clonedForms;
129    }
130
131    public function isEmpty(): bool {
132        return !$this->forms;
133    }
134
135    public function equals( $other ): bool {
136        if ( $this === $other ) {
137            return true;
138        }
139
140        if ( !( $other instanceof self ) ) {
141            return false;
142        }
143
144        return $this->sameForms( $other );
145    }
146
147    public function hasFormWithId( FormId $formId ): bool {
148        return $this->getById( $formId ) !== null;
149    }
150
151    private function sameForms( FormSet $other ): bool {
152        if ( $this->count() !== $other->count() ) {
153            return false;
154        }
155
156        foreach ( $this->forms as $form ) {
157            if ( !$form->equals( $other->getById( $form->getId() ) ) ) {
158                return false;
159            }
160        }
161
162        return true;
163    }
164
165}