Rev 1086 | Rev 1121 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1086 | Rev 1116 | ||
---|---|---|---|
Line 24... | Line 24... | ||
24 | // phpcs:enable PSR1.Files.SideEffects |
24 | // phpcs:enable PSR1.Files.SideEffects |
25 | 25 | ||
26 | class OIDplusGs1 extends OIDplusObject { |
26 | class OIDplusGs1 extends OIDplusObject { |
27 | private $number; |
27 | private $number; |
28 | 28 | ||
- | 29 | /** |
|
- | 30 | * @param $number |
|
- | 31 | */ |
|
29 | public function __construct($number) { |
32 | public function __construct($number) { |
30 | // TODO: syntax checks |
33 | // TODO: syntax checks |
31 | $this->number = $number; |
34 | $this->number = $number; |
32 | } |
35 | } |
33 | 36 | ||
- | 37 | /** |
|
- | 38 | * @param string $node_id |
|
- | 39 | * @return OIDplusGs1|null |
|
- | 40 | */ |
|
34 | public static function parse($node_id) { |
41 | public static function parse(string $node_id)/*: ?OIDplusGs1*/ { |
35 | @list($namespace, $number) = explode(':', $node_id, 2); |
42 | @list($namespace, $number) = explode(':', $node_id, 2); |
36 | if ($namespace !== self::ns()) return false; |
43 | if ($namespace !== self::ns()) return null; |
37 | return new self($number); |
44 | return new self($number); |
38 | } |
45 | } |
39 | 46 | ||
- | 47 | /** |
|
- | 48 | * @return string |
|
- | 49 | */ |
|
40 | public static function objectTypeTitle() { |
50 | public static function objectTypeTitle(): string { |
41 | return _L('GS1 Based IDs (GLN/GTIN/SSCC/...)'); |
51 | return _L('GS1 Based IDs (GLN/GTIN/SSCC/...)'); |
42 | } |
52 | } |
43 | 53 | ||
- | 54 | /** |
|
- | 55 | * @return string |
|
- | 56 | */ |
|
44 | public static function objectTypeTitleShort() { |
57 | public static function objectTypeTitleShort(): string { |
45 | return _L('GS1'); |
58 | return _L('GS1'); |
46 | } |
59 | } |
47 | 60 | ||
- | 61 | /** |
|
- | 62 | * @return string |
|
- | 63 | */ |
|
48 | public static function ns() { |
64 | public static function ns(): string { |
49 | return 'gs1'; |
65 | return 'gs1'; |
50 | } |
66 | } |
51 | 67 | ||
- | 68 | /** |
|
- | 69 | * @return string |
|
- | 70 | */ |
|
52 | public static function root() { |
71 | public static function root(): string { |
53 | return self::ns().':'; |
72 | return self::ns().':'; |
54 | } |
73 | } |
55 | 74 | ||
- | 75 | /** |
|
- | 76 | * @return bool |
|
- | 77 | */ |
|
56 | public function isRoot() { |
78 | public function isRoot(): bool { |
57 | return $this->number == ''; |
79 | return $this->number == ''; |
58 | } |
80 | } |
59 | 81 | ||
- | 82 | /** |
|
- | 83 | * @param bool $with_ns |
|
- | 84 | * @return string |
|
- | 85 | */ |
|
60 | public function nodeId($with_ns=true) { |
86 | public function nodeId(bool $with_ns=true): string { |
61 | return $with_ns ? self::root().$this->number : $this->number; |
87 | return $with_ns ? self::root().$this->number : $this->number; |
62 | } |
88 | } |
63 | 89 | ||
- | 90 | /** |
|
- | 91 | * @param string $str |
|
- | 92 | * @return string |
|
- | 93 | * @throws OIDplusException |
|
- | 94 | */ |
|
64 | public function addString($str) { |
95 | public function addString(string $str): string { |
65 | $m = array(); |
96 | $m = array(); |
66 | if (!preg_match('@^\\d+$@', $str, $m)) { |
97 | if (!preg_match('@^\\d+$@', $str, $m)) { |
67 | throw new OIDplusException(_L('GS1 value needs to be numeric')); |
98 | throw new OIDplusException(_L('GS1 value needs to be numeric')); |
68 | } |
99 | } |
69 | 100 | ||
70 | return $this->nodeId() . $str; |
101 | return $this->nodeId() . $str; |
71 | } |
102 | } |
72 | 103 | ||
- | 104 | /** |
|
- | 105 | * @param OIDplusObject $parent |
|
- | 106 | * @return string |
|
- | 107 | */ |
|
73 | public function crudShowId(OIDplusObject $parent) { |
108 | public function crudShowId(OIDplusObject $parent): string { |
74 | return $this->chunkedNotation(false); |
109 | return $this->chunkedNotation(false); |
75 | } |
110 | } |
76 | 111 | ||
- | 112 | /** |
|
- | 113 | * @return string |
|
- | 114 | */ |
|
77 | public function crudInsertPrefix() { |
115 | public function crudInsertPrefix(): string { |
78 | return $this->isRoot() ? '' : $this->chunkedNotation(false); |
116 | return $this->isRoot() ? '' : $this->chunkedNotation(false); |
79 | } |
117 | } |
80 | 118 | ||
- | 119 | /** |
|
- | 120 | * @param OIDplusObject|null $parent |
|
- | 121 | * @return string |
|
- | 122 | */ |
|
81 | public function jsTreeNodeName(OIDplusObject $parent = null) { |
123 | public function jsTreeNodeName(OIDplusObject $parent = null): string { |
82 | if ($parent == null) return $this->objectTypeTitle(); |
124 | if ($parent == null) return $this->objectTypeTitle(); |
83 | return substr($this->nodeId(), strlen($parent->nodeId())); |
125 | return substr($this->nodeId(), strlen($parent->nodeId())); |
84 | } |
126 | } |
85 | 127 | ||
- | 128 | /** |
|
- | 129 | * @return string |
|
- | 130 | */ |
|
86 | public function defaultTitle() { |
131 | public function defaultTitle(): string { |
87 | return $this->number; |
132 | return $this->number; |
88 | } |
133 | } |
89 | 134 | ||
- | 135 | /** |
|
- | 136 | * @return bool |
|
- | 137 | */ |
|
90 | public function isLeafNode() { |
138 | public function isLeafNode(): bool { |
91 | return !$this->isBaseOnly(); |
139 | return !$this->isBaseOnly(); |
92 | } |
140 | } |
93 | 141 | ||
- | 142 | /** |
|
- | 143 | * @param string $title |
|
- | 144 | * @param string $content |
|
- | 145 | * @param string $icon |
|
- | 146 | * @return void |
|
- | 147 | * @throws OIDplusException |
|
- | 148 | */ |
|
94 | public function getContentPage(&$title, &$content, &$icon) { |
149 | public function getContentPage(string &$title, string &$content, string &$icon) { |
95 | $icon = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : ''; |
150 | $icon = file_exists(__DIR__.'/img/main_icon.png') ? OIDplus::webpath(__DIR__,OIDplus::PATH_RELATIVE).'img/main_icon.png' : ''; |
96 | 151 | ||
97 | if ($this->isRoot()) { |
152 | if ($this->isRoot()) { |
98 | $title = OIDplusGs1::objectTypeTitle(); |
153 | $title = OIDplusGs1::objectTypeTitle(); |
99 | 154 | ||
Line 136... | Line 191... | ||
136 | } |
191 | } |
137 | } |
192 | } |
138 | 193 | ||
139 | # --- |
194 | # --- |
140 | 195 | ||
- | 196 | /** |
|
- | 197 | * @return bool |
|
- | 198 | */ |
|
141 | public function isBaseOnly() { |
199 | public function isBaseOnly(): bool { |
142 | return strlen($this->number) <= 7; |
200 | return strlen($this->number) <= 7; |
143 | } |
201 | } |
144 | 202 | ||
- | 203 | /** |
|
- | 204 | * @param bool $withAbbr |
|
- | 205 | * @return string |
|
- | 206 | * @throws OIDplusException |
|
- | 207 | */ |
|
145 | public function chunkedNotation($withAbbr=true) { |
208 | public function chunkedNotation(bool $withAbbr=true): string { |
146 | $curid = self::root().$this->number; |
209 | $curid = self::root().$this->number; |
147 | 210 | ||
148 | $obj = OIDplusObject::findFitting($curid); |
211 | $obj = OIDplusObject::findFitting($curid); |
149 | if (!$obj) return $this->number; |
212 | if (!$obj) return $this->number; |
150 | 213 | ||
Line 176... | Line 239... | ||
176 | $full[] = $withAbbr && ($hint !== '') ? '<abbr title="'.htmlentities($hint).'">'.$c.'</abbr>' : $c; |
239 | $full[] = $withAbbr && ($hint !== '') ? '<abbr title="'.htmlentities($hint).'">'.$c.'</abbr>' : $c; |
177 | } |
240 | } |
178 | return implode(' ', $full); |
241 | return implode(' ', $full); |
179 | } |
242 | } |
180 | 243 | ||
- | 244 | /** |
|
- | 245 | * @return string |
|
- | 246 | */ |
|
181 | public function fullNumber() { |
247 | public function fullNumber(): string { |
182 | return $this->number . $this->checkDigit(); |
248 | return $this->number . $this->checkDigit(); |
183 | } |
249 | } |
184 | 250 | ||
- | 251 | /** |
|
- | 252 | * @return int |
|
- | 253 | */ |
|
185 | public function checkDigit() { |
254 | public function checkDigit(): int { |
186 | $mul = 3; |
255 | $mul = 3; |
187 | $sum = 0; |
256 | $sum = 0; |
188 | for ($i=strlen($this->number)-1; $i>=0; $i--) { |
257 | for ($i=strlen($this->number)-1; $i>=0; $i--) { |
189 | $sum += $this->number[$i] * $mul; |
258 | $sum += $this->number[$i] * $mul; |
190 | $mul = $mul == 3 ? 1 : 3; |
259 | $mul = $mul == 3 ? 1 : 3; |
191 | } |
260 | } |
192 | return 10 - ($sum % 10); |
261 | return 10 - ($sum % 10); |
193 | } |
262 | } |
194 | 263 | ||
- | 264 | /** |
|
- | 265 | * @return OIDplusGs1|null |
|
- | 266 | */ |
|
195 | public function one_up() { |
267 | public function one_up()/*: ?OIDplusGs1*/ { |
196 | return OIDplusObject::parse($this->ns().':'.substr($this->number,0,strlen($this->number)-1)); |
268 | return self::parse($this->ns().':'.substr($this->number,0,strlen($this->number)-1)); |
197 | } |
269 | } |
198 | 270 | ||
- | 271 | /** |
|
- | 272 | * @param string $a |
|
- | 273 | * @param string $b |
|
- | 274 | * @return false|int |
|
- | 275 | */ |
|
199 | private static function distance_($a, $b) { |
276 | private static function distance_(string $a, string $b) { |
200 | $min_len = min(strlen($a), strlen($b)); |
277 | $min_len = min(strlen($a), strlen($b)); |
201 | 278 | ||
202 | for ($i=0; $i<$min_len; $i++) { |
279 | for ($i=0; $i<$min_len; $i++) { |
203 | if ($a[$i] != $b[$i]) return false; |
280 | if ($a[$i] != $b[$i]) return false; |
204 | } |
281 | } |
205 | 282 | ||
206 | return strlen($a) - strlen($b); |
283 | return strlen($a) - strlen($b); |
207 | } |
284 | } |
208 | 285 | ||
- | 286 | /** |
|
- | 287 | * @param $to |
|
- | 288 | * @return int|null |
|
- | 289 | */ |
|
209 | public function distance($to) { |
290 | public function distance($to) { |
210 | if (!is_object($to)) $to = OIDplusObject::parse($to); |
291 | if (!is_object($to)) $to = OIDplusObject::parse($to); |
211 | if (!($to instanceof $this)) return false; |
292 | if (!($to instanceof $this)) return null; |
212 | 293 | ||
213 | // This is pretty tricky, because the whois service should accept GS1 numbers with and without checksum |
294 | // This is pretty tricky, because the whois service should accept GS1 numbers with and without checksum |
214 | if ($this->number == $to->number) return 0; |
295 | if ($this->number == $to->number) return 0; |
215 | if ($this->number.$this->checkDigit() == $to->number) return 0; |
296 | if ($this->number.$this->checkDigit() == $to->number) return 0; |
216 | if ($this->number == $to->number.$to->checkDigit()) return 0; |
297 | if ($this->number == $to->number.$to->checkDigit()) return 0; |
217 | 298 | ||
218 | $b = $this->number; |
299 | $b = $this->number; |
219 | $a = $to->number; |
300 | $a = $to->number; |
220 | $tmp = self::distance_($a, $b); |
301 | $tmp = self::distance_($a, $b); |
221 | if ($tmp != false) return $tmp; |
302 | if ($tmp !== false) return $tmp; |
222 | 303 | ||
223 | $b = $this->number.$this->checkDigit(); |
304 | $b = $this->number.$this->checkDigit(); |
224 | $a = $to->number; |
305 | $a = $to->number; |
225 | $tmp = self::distance_($a, $b); |
306 | $tmp = self::distance_($a, $b); |
226 | if ($tmp != false) return $tmp; |
307 | if ($tmp !== false) return $tmp; |
227 | 308 | ||
228 | $b = $this->number; |
309 | $b = $this->number; |
229 | $a = $to->number.$to->checkDigit(); |
310 | $a = $to->number.$to->checkDigit(); |
230 | $tmp = self::distance_($a, $b); |
311 | $tmp = self::distance_($a, $b); |
231 | if ($tmp != false) return $tmp; |
312 | if ($tmp !== false) return $tmp; |
232 | 313 | ||
233 | return null; |
314 | return null; |
234 | } |
315 | } |
235 | 316 | ||
- | 317 | /** |
|
- | 318 | * @return array|OIDplusAltId[] |
|
- | 319 | * @throws OIDplusException |
|
- | 320 | */ |
|
236 | public function getAltIds() { |
321 | public function getAltIds(): array { |
237 | if ($this->isRoot()) return array(); |
322 | if ($this->isRoot()) return array(); |
238 | $ids = parent::getAltIds(); |
323 | $ids = parent::getAltIds(); |
239 | 324 | ||
240 | // (VTS F5) GS1 to AID (PIX allowed) |
325 | // (VTS F5) GS1 to AID (PIX allowed) |
241 | $gs1 = $this->nodeId(false); |
326 | $gs1 = $this->nodeId(false); |
Line 245... | Line 330... | ||
245 | if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, with "FF" prefix').')'); |
330 | if ($aid_is_ok) $ids[] = new OIDplusAltId('aid', $aid, _L('Application Identifier (ISO/IEC 7816)'), ' ('._L('Optional PIX allowed, with "FF" prefix').')'); |
246 | 331 | ||
247 | return $ids; |
332 | return $ids; |
248 | } |
333 | } |
249 | 334 | ||
- | 335 | /** |
|
- | 336 | * @return string |
|
- | 337 | */ |
|
250 | public function getDirectoryName() { |
338 | public function getDirectoryName(): string { |
251 | if ($this->isRoot()) return $this->ns(); |
339 | if ($this->isRoot()) return $this->ns(); |
252 | return $this->ns().'_'.$this->nodeId(false); // safe, because there are only numbers |
340 | return $this->ns().'_'.$this->nodeId(false); // safe, because there are only numbers |
253 | } |
341 | } |
254 | 342 | ||
- | 343 | /** |
|
- | 344 | * @param string $mode |
|
- | 345 | * @return string |
|
- | 346 | */ |
|
255 | public static function treeIconFilename($mode) { |
347 | public static function treeIconFilename(string $mode): string { |
256 | return 'img/'.$mode.'_icon16.png'; |
348 | return 'img/'.$mode.'_icon16.png'; |
257 | } |
349 | } |
258 | } |
350 | } |