Completed
Push — master ( 14d2bd...06e609 )
by mw
81:37 queued 59:24
created

includes/datavalues/SMW_DV_Quantity.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
use SMW\ApplicationFactory;
4
use SMW\NumberFormatter;
5
use SMW\Message;
6
use SMW\DataValues\UnitConversionFetcher;
7
8
/**
9
 * @ingroup SMWDataValues
10
 */
11
12
/**
13
 * This datavalue implements unit support custom units, for which users have
14
 * provided linear conversion factors within the wiki. Those user settings
15
 * are retrieved from a property page associated with this object.
16
 *
17
 * @author Markus Krötzsch
18
 * @ingroup SMWDataValues
19
 */
20
class SMWQuantityValue extends SMWNumberValue {
21
22
	/**
23
	 * Array with format (canonical unit ID string) => (conversion factor)
24
	 * @var float[]|bool
25
	 */
26
	protected $m_unitfactors = false;
27
28
	/**
29
	 * Array with format (normalised unit string) => (canonical unit ID string)
30
	 * @var string[]|bool
31
	 */
32
	protected $m_unitids = false;
33
34
	/**
35
	 * Ordered array of (normalized) units that should be displayed in tooltips, etc.
36
	 * @var string[]|bool
37
	 */
38
	protected $m_displayunits = false;
39
40
	/**
41
	 * Main unit in canonical form (recognised by the conversion factor 1)
42
	 * @var string|bool
43
	 */
44
	protected $m_mainunit = false;
45
46 20
	protected function convertToMainUnit( $number, $unit ) {
47 20
		$this->initConversionData();
48
49 20
		if ( array_key_exists( $unit, $this->m_unitids ) ) {
50 19
			$this->m_unitin = $this->m_unitids[$unit];
51 19
			assert( '$this->m_unitfactors[$this->m_unitin] != 0 /* Should be filtered by initConversionData() */' );
52 19
			$this->m_dataitem = new SMWDINumber( $number / $this->m_unitfactors[$this->m_unitin], $this->m_typeid );
53 19
			return true;
54
		} else { // unsupported unit
55 7
			return false;
56
		}
57
	}
58
59 11
	protected function makeConversionValues() {
60 11
		if ( $this->m_unitvalues !== false ) {
61
			return; // do this only once
62
		}
63
64 11
		$this->m_unitvalues = array();
65
66 11
		if ( !$this->isValid() ) {
67
			return;
68
		}
69
70 11
		$this->initDisplayData();
71
72 11
		if ( count( $this->m_displayunits ) == 0 ) { // no display units, just show all
73 9
			foreach ( $this->m_unitfactors as $unit => $factor ) {
74 9
				if ( $unit !== '' ) { // filter out the empty fallback unit that is always there
75 9
					$this->m_unitvalues[$unit] = $this->m_dataitem->getNumber() * $factor;
76
				}
77
			}
78
		} else {
79 3
			foreach ( $this->m_displayunits as $unit ) {
80
				/// NOTE We keep non-ID units unless the input unit is used, so display units can be used to pick
81
				/// the preferred form of a unit. Doing this requires us to recompute the conversion values whenever
82
				/// the m_unitin changes.
83 3
				$unitkey = ( $this->m_unitids[$unit] == $this->m_unitin ) ? $this->m_unitids[$unit] : $unit;
84 3
				$this->m_unitvalues[$unitkey] = $this->m_dataitem->getNumber() * $this->m_unitfactors[$this->m_unitids[$unit]];
85
			}
86
		}
87 11
	}
88
89 6
	protected function makeUserValue() {
90 6
		$printunit = false; // the normalised string of a known unit to use for printouts
91
92
		// Check if a known unit is given as outputformat:
93 6
		if ( ( $this->m_outformat ) && ( $this->m_outformat != '-' ) &&
94 6
		     ( $this->m_outformat != '-n' ) && ( $this->m_outformat != '-u' ) ) { // first try given output unit
95 2
			$wantedunit = $this->normalizeUnit( $this->m_outformat );
96 2
			if ( array_key_exists( $wantedunit, $this->m_unitids ) ) {
97 2
				$printunit = $wantedunit;
98
			}
99
		}
100
101
		// Alternatively, try to use the main display unit as a default:
102 6
		if ( $printunit === false ) {
103 6
			$this->initDisplayData();
104 6
			if ( count( $this->m_displayunits ) > 0 ) {
105 3
				$printunit = reset( $this->m_displayunits );
106
			}
107
		}
108
		// Finally, fall back to main unit:
109 6
		if ( $printunit === false ) {
110 4
			$printunit = $this->getUnit();
111
		}
112
113 6
		$asPrefix = isset( $this->prefixalUnitPreference[$printunit] ) && $this->prefixalUnitPreference[$printunit];
114
115 6
		$this->m_unitin = $this->m_unitids[$printunit];
116 6
		$this->m_unitvalues = false; // this array depends on m_unitin if displayunits were used, better invalidate it here
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type array of property $m_unitvalues.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
117
118 6
		$value = $this->m_dataitem->getNumber() * $this->m_unitfactors[$this->m_unitin];
119
120 6
		$this->m_caption = '';
121
122 6
		if ( $this->m_outformat != '-u' ) { // -u is the format for displaying the unit only
123 6
			$this->m_caption .= ( ( $this->m_outformat != '-' ) && ( $this->m_outformat != '-n' ) ? $this->getLocalizedFormattedNumber( $value ) : $this->getNormalizedFormattedNumber( $value ) );
124
		}
125
126 6
		if ( ( $printunit !== '' ) && ( $this->m_outformat != '-n' ) ) { // -n is the format for displaying the number only
127
128 6
			$sep = '';
129
130 6
			if ( $this->m_outformat != '-u' ) {
131 6
				$sep =  ( $this->m_outformat != '-' ? '&#160;' : ' ' );
132
			}
133
134 6
			$this->m_caption = $asPrefix ? $printunit . $sep . $this->m_caption : $this->m_caption . $sep . $printunit;
135
		}
136 6
	}
137
138
	public function getUnitList() {
139
		$this->initConversionData();
140
		return array_keys( $this->m_unitfactors );
141
	}
142
143 5
	public function getUnit() {
144 5
		$this->initConversionData();
145 5
		return $this->m_mainunit;
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->m_mainunit; of type string|boolean adds the type boolean to the return on line 145 which is incompatible with the return type of the parent method SMWNumberValue::getUnit of type string.
Loading history...
146
	}
147
148
/// The remaining functions are relatively "private" but are kept protected since
149
/// subclasses might exploit this to, e.g., "fake" conversion factors instead of
150
/// getting them from the database. A cheap way of making built-in types.
151
152
	/**
153
	 * This method initializes $m_unitfactors, $m_unitids, and $m_mainunit.
154
	 */
155 20
	protected function initConversionData() {
156 20
		if ( $this->m_unitids !== false ) {
157 12
			return; // do the below only once
158
		}
159
160 20
		$unitConversionFetcher = new UnitConversionFetcher( $this );
161 20
		$unitConversionFetcher->fetchCachedConversionData( $this->m_property );
162
163 20
		if ( $unitConversionFetcher->getErrors() !== array() ) {
164 7
			foreach ( $unitConversionFetcher->getErrors() as $error ) {
165 7
				$this->addErrorMsg(
166
					$error,
167 7
					Message::TEXT,
168 7
					Message::USER_LANGUAGE
169
				);
170
			}
171
		}
172
173 20
		$this->m_unitids = $unitConversionFetcher->getUnitIds();
174 20
		$this->m_unitfactors = $unitConversionFetcher->getUnitFactors();
175 20
		$this->m_mainunit = $unitConversionFetcher->getMainUnit();
176 20
		$this->prefixalUnitPreference = $unitConversionFetcher->getPrefixalUnitPreference();
177 20
	}
178
179
	/**
180
	 * This method initializes $m_displayunits.
181
	 */
182 12
	protected function initDisplayData() {
183 12
		if ( $this->m_displayunits !== false ) {
184 4
			return; // do the below only once
185
		}
186 12
		$this->initConversionData(); // needed to normalise unit strings
187 12
		$this->m_displayunits = array();
188
189 12
		if ( is_null( $this->m_property ) || is_null( $this->m_property->getDIWikiPage() ) ) {
190
			return;
191
		}
192
193 12
		$units = $this->getPropertySpecificationLookup()->getDisplayUnitsFor(
194 12
			$this->getProperty()
195
		);
196
197 12
		foreach ( $units as $unit ) {
198 4
			$unit = $this->normalizeUnit( $unit );
199 4
			if ( array_key_exists( $unit, $this->m_unitids ) ) {
200 4
				$this->m_displayunits[] = $unit; // do not avoid duplicates, users can handle this
201
			} // note: we ignore unsuppported units -- no way to display them
202
		}
203 12
	}
204
}
205