Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
100.00% |
1 / 1 |
|
100.00% |
10 / 10 |
CRAP | |
100.00% |
54 / 54 |
| iaReMapKeys | |
100.00% |
1 / 1 |
|
100.00% |
10 / 10 |
32 | |
100.00% |
54 / 54 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| mapHeaderRow | |
100.00% |
1 / 1 |
4 | |
100.00% |
10 / 10 |
|||
| getHeadersDuplicated | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
| getHeaderMap | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
| getHeaderMissing | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
| getHeaderMissingWithoutDefaults | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| row2key | |
100.00% |
1 / 1 |
8 | |
100.00% |
14 / 14 |
|||
| isLastRowEmpty | n/a |
0 / 0 |
1 | n/a |
0 / 0 |
|||||
| getRowKeysMissing | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
| getRowKeysEmpty | |
100.00% |
1 / 1 |
5 | |
100.00% |
5 / 5 |
|||
| prepareInternalData | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
| headerVariants | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| headerStandardize | |
100.00% |
1 / 1 |
3 | |
100.00% |
3 / 3 |
|||
| <?php | |
| namespace ia\Lib; | |
| use ia\Util\Str; | |
| use \URLify; | |
| /** | |
| * iaReMapKeys | |
| * | |
| * Maps rowIn[$inKey] to rowsKeyed[$key] using header row to define the mapping. | |
| * | |
| * @notes | |
| * default fills col if: not in read row, or it in read row ==='' || row === null | |
| * rows and headers read are trimmed | |
| * | |
| * @version 1.0.4 | |
| * | |
| * @example ../ia_examples/iaReMapKeys.php | |
| * | |
| */ | |
| class iaReMapKeys { | |
| protected $headerKeys = []; // ['key1'=>n1, 'key2'=>n2, ...] | |
| protected $headerKeysLen = 0; | |
| protected $defaultByKey = []; // ['key1'=>'default1', 'key3'=>'default3', ...] | |
| protected $rowKey2Key = []; // [ 'key1'=>3, 'Key2'=>1, 'WantHeader'=>'header Row Key', ...] | |
| protected $headerPrepared = []; // ['label1'=>'key1', 'label1_synonym1'=>'key1', ...] | |
| protected $duplicateHeaders = []; | |
| protected $lastRowEmpty = true; // last Data row processed was empty? | |
| /** | |
| * Maps rowIn[$inKey] to rowsKeyed[$key] using header row to define the mapping | |
| * | |
| * @param array $headerKeys ['key1', 'key2', ...] | |
| * @param array $headerSynonyms ['Synonym1_1'=>'key1', 'Synonym1_2'=>'key1', 'Synonym2_1'=>'key2', ...] default [] | |
| * @param array $defaultByKey ['key2'=>defaultValueKey2,...] default [] | |
| * @return void | |
| */ | |
| function __construct(array $headerKeys, $headerSynonyms=[], $defaultByKey=[]) { | |
| $this->headerKeys = array_flip($headerKeys); | |
| $this->headerKeysLen = count($this->headerKeys); | |
| $this->prepareInternalData($headerKeys, $headerSynonyms ); | |
| $this->defaultByKey = $defaultByKey; | |
| } | |
| /** | |
| * | |
| * Sets up mapping rawRow to keyedRow based on $headerRow, fills $this->rowKey2Key | |
| * | |
| * @param array $headerRow | |
| * @return bool has duplicate headers true | |
| */ | |
| public function mapHeaderRow($headerRow) { | |
| $this->duplicateHeaders = []; | |
| $rowKey2Key = []; | |
| foreach($headerRow as $rowKey => $headerLabel) { | |
| $label = $this->headerStandardize($headerLabel); | |
| if(array_key_exists($label, $this->headerPrepared)) { | |
| if(!isset($rowKey2Key[$this->headerPrepared[$label]])) { | |
| $rowKey2Key[$this->headerPrepared[$label]] = $rowKey; | |
| } else { | |
| $this->duplicateHeaders[$rowKey] = $this->headerPrepared[$label]; | |
| } | |
| } | |
| } | |
| $this->rowKey2Key = $rowKey2Key; | |
| return !empty($this->duplicateHeaders); | |
| } | |
| /** | |
| * Return a list of duplicated headers | |
| * | |
| * @return array with duplicated headers ['headerRowKey'=>'label duplicated'] | |
| */ | |
| function getHeadersDuplicated() { return $this->duplicateHeaders; } | |
| /** | |
| * Return array mapping header row's keys to desired (wantHeaders) | |
| * | |
| * @return array ['headerRowKey' => 'want header', ..] | |
| */ | |
| function getHeaderMap() { return $this->rowKey2Key; } | |
| /** | |
| * Returns missing headers in header row, even those with defaults | |
| * | |
| * @return array header keys missing even if the have default values ['missingKeyN',...] | |
| */ | |
| public function getHeaderMissing() { | |
| $headersMapped = $this->rowKey2Key; | |
| $withDefaults = array_diff_key( $this->defaultByKey, $headersMapped) + $headersMapped; | |
| return array_keys(array_diff_key($this->headerKeys, $withDefaults)); | |
| } | |
| /** | |
| * Returns missing headers in header row and without default values | |
| * | |
| * @return array header keys missing and without default values ['missingKeyN',...] | |
| */ | |
| public function getHeaderMissingWithoutDefaults() { | |
| return \array_keys(\array_diff_key($this->headerKeys, $this->rowKey2Key)); | |
| } | |
| /** | |
| * Returns $rowKeyed values in $rawRow mapped to headersKey, missing keys (not set, null, '') are filled with defaults | |
| * | |
| * @param array $rawRow ['valueForKey1','valueForKey2','valueWithOutKey',] | |
| * @return array ['key1'=>'valueForKey1', ...] | |
| */ | |
| public function row2key($rawRow) { | |
| $this->lastRowEmpty = true; | |
| $rowKeyed = []; | |
| foreach($this->rowKey2Key as $key => $rowKey) { | |
| if(isset($rawRow[$rowKey])) { | |
| $rowKeyed[$key] = Str::strim($rawRow[$rowKey]); | |
| if(($rowKeyed[$key] === '' || $rowKeyed[$key] === null)) { | |
| if(isset($this->defaultByKey[$key])) { | |
| $rowKeyed[$key] = $this->defaultByKey[$key]; | |
| } | |
| } else { | |
| $this->lastRowEmpty = false; | |
| } | |
| } elseif(isset($this->defaultByKey[$key])) { | |
| $rowKeyed[$key] = $this->defaultByKey[$key]; | |
| } | |
| } | |
| if(count($rowKeyed) === $this->headerKeysLen) { | |
| return $rowKeyed; | |
| } | |
| return array_diff_key($this->defaultByKey,$rowKeyed) + $rowKeyed; | |
| } | |
| /** | |
| * Returns false if last processed row has Data for headers, else true. Ignores defaults | |
| * | |
| * @return boolean true: last read row has no values for headersMapped ie is empty (not considering default values), | |
| * false has Data for all headers | |
| */ | |
| public function isLastRowEmpty() {return $this->lastRowEmpty;} | |
| /** | |
| * Returns missing keys from $rowKeyed, defaulted keys not considered missing | |
| * | |
| * @param array $rowKeyed | |
| * @return array header keys missing, and without defaults, in $rowKeyed ['missingKey1'=>n1,...] | |
| */ | |
| public function getRowKeysMissing($rowKeyed) { | |
| return array_keys( array_diff_key($this->headerKeys, $rowKeyed) ); | |
| } | |
| /** | |
| * Keys missing, null or '' | |
| * | |
| * @param array $rowKeyed | |
| * @return array keys missing or with null, '' values ie ['a','b'] | |
| */ | |
| public function getRowKeysEmpty($rowKeyed) { | |
| $emptyKeys = []; | |
| foreach($this->headerKeys as $key => $inputKey) { | |
| if(!isset($rowKeyed[$key]) || $rowKeyed[$key] === '' || $rowKeyed[$key] === null) { | |
| $emptyKeys[] = $key; | |
| } | |
| } | |
| return $emptyKeys; | |
| } | |
| /** | |
| * Prepares $this->headerPrepared array to | |
| * | |
| * @param array $header ['key1','key2', ...] | |
| * @param array $headerSynonyms ['Synonym 1_1'=>'key1', 'Synonym1_2'=>'key1', 'Synonym2_1'=>'key2', ...] | |
| * @return void | |
| */ | |
| protected function prepareInternalData($header, $headerSynonyms ) { | |
| $this->headerPrepared = []; | |
| foreach($header as $key) { | |
| $label = Str::strim( str_replace('_', ' ', Str::camel2Words($key) ) ); | |
| $this->headerVariants($key, $label); | |
| } | |
| foreach($headerSynonyms as $label => $key) { | |
| $this->headerVariants($key, $label); | |
| } | |
| } | |
| /** | |
| * Deduce en plural o singular, el opuesto en que esta. | |
| * | |
| * @param string $key | |
| * @param string $label palabra a cambiar de singular a plural y viceversa | |
| * @return void | |
| */ | |
| protected function headerVariants($key, $label) { | |
| $this->headerPrepared[$label] = $key; | |
| $variants = iaPalabra::variants($this->headerStandardize($label)); | |
| foreach($variants as $word) { | |
| $this->headerPrepared[$word] = $key; | |
| } | |
| } | |
| /** | |
| * Makes label header easily comparable | |
| * | |
| * @param string $headerLabel | |
| * @return string $headerLabel in lowercase, unaccented, trimmed, punctuation chars to spaces, only single spaces. | |
| */ | |
| protected function headerStandardize($headerLabel) { | |
| $label = preg_replace("/['\\p{M}]/umS", '', $headerLabel); | |
| // @codeCoverageIgnoreStart | |
| if($label === null) { | |
| $label = str_replace(["'", '"'], '', $headerLabel); | |
| } | |
| // @codeCoverageIgnoreEnd | |
| $label2 = preg_replace("/\\p{P}/umS", ' ', $label); | |
| // @codeCoverageIgnoreStart | |
| if($label2 === null) { | |
| $label2 = str_replace(['.',';',',','!','?','-','_'], ' ', $label); | |
| } | |
| // @codeCoverageIgnoreEnd | |
| return strtolower(URLify::downcode(Str::strim($label2))); | |
| } | |
| } |