Completed
Push — address-as-title ( 9b6eeb...601934 )
by Peter
11:07
created

MapsLayerGroup::__construct()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 3
eloc 5
nc 4
nop 1
1
<?php
2
3
/**
4
 * Class for describing map layer groups, collecdtions of MapsLayer objects
5
 * defined on the same layer page. The fatching of layers from the database
6
 * is also done from within this class.
7
 *
8
 * @since 3.0
9
 * 
10
 * @file Maps_LayerGroup.php
11
 * @ingroup Maps
12
 * 
13
 * @author Daniel Werner
14
 */
15
class MapsLayerGroup {
16
17
	const LAYERS_ALL = 255;
18
	const LAYERS_NAMED = 1;
19
	const LAYERS_NUMERIC = 2;
20
21
	/**
22
	 * Members of this group.
23
	 *
24
	 * @since 3.0
25
	 *
26
	 * @var array
27
	 */
28
	protected $layers = [];
29
30
	/**
31
	 * Constructor.
32
	 *
33
	 * @since 3.0
34
	 *
35
	 * @param MapsLayer[]|MapsLayer $layers MapsLayer objects as members of this group. If any
36
	 *        of these layers have the same name, only one of them will make it into
37
	 *        the group since the name is the ID within the group, though, the name is
38
	 *        just optional.
39
	 */
40
	public function __construct( $layers = [] ) {
41
		if( ! is_array( $layers ) ) {
42
			$layers = [ $layers ];
43
		}
44
		foreach( $layers as $layer ) {
45
			// using the function will prevent having layers with the same name:
46
			$this->addLayer( $layer );
47
		}
48
	}
49
50
	/**
51
	 * Returns the layers which are members of this group. An empty array will be
52
	 * returned in case no layers belong to this group.
53
	 *
54
	 * @since 3.0
55
	 *
56
	 * @param integer $types bitfield defining whether named, numeric or all layers should be returned.
57
	 *        MapsLayerGroup::LAYERS_NAMED, MapsLayerGroup::LAYERS_NUMERIC or MapsLayerGroup::LAYERS_ALL
58
	 *
59
	 * @return MapsLayer[]
60
	 */
61
	public function getLayers( $types = self::LAYERS_ALL ) {
62
		/*
63
		 * For all layers: If given, take the name as key.
64
		 * by not doing this in the constructor we won't have conflicts with layer
65
		 * name changes later on.
66
		 */
67
		$namedLayers = [];
68
		
69
		foreach( $this->layers as $layer ) {
70
			
71
			if( $layer->getName() !== null ) {
72
				
73
				if( $types & self::LAYERS_NAMED ) {					
74
					// name as key:
75
					$namedLayers[ $layer->getName() ] = $layer;
76
				}
77
			}
78
			elseif( $types & self::LAYERS_NUMERIC ) {
79
				// numeric (random) key:
80
				$namedLayers[] = $layer;
81
			}
82
		}
83
		return $namedLayers;
84
	}
85
86
	/**
87
	 * Returns the layer with the given name. If the layer doesn't exist, return null.
88
	 *
89
	 * @since 3.0
90
	 *
91
	 * @param string $name
92
	 *
93
	 * @return MapsLayer|null
94
	 */
95
	public function getLayerByName( $name ) {
96
		// get Layers in array with named index for named layers:
97
		$layers = $this->getLayers();
98
		
99
		if( array_key_exists( $name, $layers ) ) {
100
			return $layers[ $name ];
101
		}		
102
		return null;
103
	}
104
105
	/**
106
	 * Returns whether a specific layer exists within the group.
107
	 *
108
	 * @since 3.0
109
	 *
110
	 * @param MapsLayer $layer 
111
	 *
112
	 * @return boolean
113
	 */
114
	public function hasLayer( MapsLayer $layer ) {
115
		foreach( $this->layers as $groupLayer ) {
116
			if( $layer === $groupLayer ) {
117
				return true;
118
			}
119
		}
120
		return false;
121
	}
122
123
	/**
124
	 * This will add a layer to the collection of layers in this group if it is not a
125
	 * member already.
126
	 * Does NOT automatically store the layer in the database if the group is loaded
127
	 * from a page.
128
	 *
129
	 * @since 3.0
130
	 *
131
	 * @param MapsLayer $layer
132
	 *
133
	 * @return boolean whether a layer with the same name has been overwritten. Also
134
	 *         returns false in case the same layer exists within the group already.
135
	 */
136
	public function addLayer( MapsLayer $layer ) {
137
138
		if( $this->hasLayer( $layer ) ) {
139
			return false; // exact same layer already exists within group
140
		}
141
142
		$overwritten = false;
143
144
		// check for layer with same name in this group
145
		if( $layer->getName() !== null ) {
146
			
147
			// remove all layers with same name (shouldn't be more than one but be paranoid):
148
			do {
149
				$existingLayer = $this->getLayerByName( $layer->getName() );
150
				
151
				if( $existingLayer !== null ) {
152
					$this->removeLayer( $existingLayer );
153
					$overwritten = true;
154
				}
155
			}
156
			while( $existingLayer !== null );
157
		}
158
159
		$this->layers[] = $layer;
160
		return $overwritten; // layer with same name overwritten?
161
	}
162
163
	/**
164
	 * This will remove a layer from the collection of layers in this group.
165
	 * Does NOT automatically store the layer in the database if the group is loaded
166
	 * from a page.
167
	 *
168
	 * @since 3.0
169
	 *
170
	 * @param MapsLayer $layer 
171
	 *
172
	 * @return boolean whether the layer was a member of the group and has been removed.
173
	 */
174
	public function removeLayer ( MapsLayer $layer ) {
175
		foreach( $this->layers as $key => $groupLayer ) {
176
			if( $layer === $groupLayer ) {
177
				unset( $this->layers[ $key ] );
178
				return true;
179
			}
180
		}
181
		return false;
182
	}
183
184
	/**
185
	 * Get a group of layers by the title of the group. If the page doesn't contain
186
	 * any layers, the group will be returned anyway but won't contain any layers.
187
	 *
188
	 * @since 3.0
189
	 *
190
	 * @param Title $title
191
	 *
192
	 * @return MapsLayerGroup
193
	 */
194
	public static function newFromTitle( Title $title ) {
195
		// load all members defined on the page $title:
196
		$db = wfGetDB( DB_SLAVE );
197
		$conditions = [ 'layer_page_id' => $title->getArticleID() ];
198
199
		$layers = self::loadMembersFromConds( $db, $conditions );
200
		if( $layers === false && wfGetLB()->getServerCount() > 1 ) {
201
			$db = wfGetDB( DB_MASTER );
202
			$layers = self::loadMembersFromConds( $db, $conditions );
203
		}
204
		$obj = new MapsLayerGroup( $layers );
0 ignored issues
show
Documentation introduced by
$layers is of type array|false, but the function expects a array<integer,object<Map...yer>>|object<MapsLayer>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
205
		return $obj;
206
	}
207
208
	/**
209
	 * Given a set of conditions, fetch all matching layers from the given database
210
	 * connection and return them in an array
211
	 *
212
	 * @param Database $db
213
	 * @param array $conditions
214
	 *
215
	 * @return array|false
216
	 */
217
	protected static function loadMembersFromConds( $db, $conditions ) {
218
		$results = [];
219
		$res = self::fetchMembersFromConds( $db, $conditions );
220
		if( $res ) {
221
			// load all matching layer objects into the layer group:
222
			foreach( $res  as $row ) {
223
				if( $row ) {
224
					$obj = MapsLayers::newLayerFromRow( $row );
225
					$results[] = $obj;
226
				}
227
			}
228
			$res->free();
229
			return $results;
230
		}
231
		return false;
232
	}
233
234
	/**
235
	 * Given a set of conditions, return a ResultWrapper
236
	 * which will return matching database rows with the
237
	 * fields necessary to build the group.
238
	 *
239
	 * @param Database $db
240
	 * @param array $conditions
241
	 *
242
	 * @return ResultWrapper|false
243
	 */
244
	protected static function fetchMembersFromConds( $db, $conditions ) {
245
		$fields = MapsLayers::databaseFields();
246
		$res = $db->select(
247
			[ 'maps_layers' ],
248
			$fields,
249
			$conditions,
250
			__METHOD__
251
		);
252
		return $res;
253
	}
254
}
255