Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
92.86% covered (success)
92.86%
13 / 14
CRAP
94.39% covered (success)
94.39%
101 / 107
iaArray
0.00% covered (danger)
0.00%
0 / 1
92.86% covered (success)
92.86%
13 / 14
63.70
94.39% covered (success)
94.39%
101 / 107
 array_key_exists_insensitive
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 get_key_insensitive
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
3 / 3
 array_key_n
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 change_array_keys
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
7 / 7
 in_array_case_insensitive
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 6
 compare
n/a
0 / 0
1
n/a
0 / 0
 array_changes
100.00% covered (success)
100.00%
1 / 1
7
100.00% covered (success)
100.00%
10 / 10
 arrayExtend
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
7 / 7
 expandKeyToArray
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
14 / 14
 tupplesToArrayAssoc
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
13 / 13
 tupplesToArrayPath
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
11 / 11
 arrayGetPath
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
9 / 9
 multiKeyIt
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
13 / 13
 arrayKey2Ul
100.00% covered (success)
100.00%
1 / 1
7
100.00% covered (success)
100.00%
11 / 11
 arrayKey2Ul_echo
n/a
0 / 0
7
n/a
0 / 0
 htmlentities
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
1 / 1
<?php
/**
 * @author Informática Asocaida SA de CV
 * @version 1.0.4
 * @copyright 2015
 *
 * 1.0.4 add array_key_exists_insensitive
 */
namespace ia\Lib;
/**
 * iaArray: Useful function for arrays
 *
 */
class iaArray {
    /**
     * array_key_exists case insensitive
     *
     * @param string $key key to search for case insensitive
     * @param array $array
     * @return bool true key exists, false dosen't exist
     */
    public static function array_key_exists_insensitive($key, $array) {
        return array_key_exists(strtolower($key), array_change_key_case( array_flip(array_keys($array)),CASE_LOWER ) );
    }
    /**
     *  get $array[$case_insensitive_key]
     *
     * @param array $array
     * @param string $key
     * @param mixed $notFoundValue
     * @return mixed the value for $array[$case_insensitive_key]
     */
    public static function get_key_insensitive($key, $array, $notFoundValue = null) {
        $keyLower = strtolower($key);
        $case_insensitive = array_change_key_case($array, CASE_LOWER);
        return array_key_exists($keyLower, $case_insensitive) ? $case_insensitive[$keyLower] : $notFoundValue;
    }
    /**
     * return array's key at position $keyPosition, zero based
     *
     * @param array $array
     * @param int $keyPosition
     * @param string $notFoundKey
     * @return string array's key at position $keyPosition
     */
    public static function array_key_n($array, $keyPosition, $notFoundKey = null) {
        return \array_keys($array)[$keyPosition] ?? $notFoundKey;
    }
    /**
     * Change array keys
     *
     * @param array $data
     * @param array $keyMap ['keyIn $Data' => 'newKey']
     * @param bool $includeNonMappedKeys true keys not in $keyMap are
     * @return array changes de keys in $Data for those in $keyMap, not found are controled by $includeNonMappedKeys
     * @exmpale change_array_keys(['kB'=>'kB val','kA'=>'kA val','other'=>'other val'],['kA'=>'A','kB'=>'B'],true) ['B'=>'kB val','A'=>'kA val','other'=>'other val']
     * @exmpale change_array_keys(['kB'=>'kB val','kA'=>'kA val','other'=>'other val'],['kA'=>'A','kB'=>'B'],false) ['B'=>'kB val','A'=>'kA val']
     */
    public static function change_array_keys($data, $keyMap, $includeNonMappedKeys = true) {
        $ret = [];
        foreach($data as $key => $value) {
            if(\array_key_exists($key, $keyMap)) {
                $ret[$keyMap[$key]] = $data[$key];
            } elseif($includeNonMappedKeys) {
                $ret[$key] = $data[$key];
            }
        }
        return $ret;
    }
    public static function in_array_case_insensitive($needle, $haystack) {
        if(in_array($needle, $haystack)) {
            return true;
        }
        foreach($haystack as $value) {
            if(strcasecmp($needle, $value) === 0) {
                return true;
            }
        }
        return false;
    }
    public static function compare($a,$b){ return $a<=>$b;}
    /**
     * Retrun an array with what changed or added in $after vs $before
     *
     * @param array $after  ['both_no_changed'=>'Error value did not change','both_changed'=>'after_value', 'only_in_after'=>'only_in_after value']
     * @param array $before ['both_no_changed'=>'Error value did not change','both_changed'=>'before_value','only_in_before'=>'only_in_before value']
     * @return array ['both_changed'=>'after_value', 'only_in_after'=>'only_in_after value']
     */
    public static function array_changes($after, $before) {
        $changed = [];
        foreach($after as $k => $v) {
            if(isset($before[$k])) {
                if(is_array($v) && is_array($before[$k])) {
                    if( !empty(self::array_changes($v, $before[$k]))) {
                        $changed[$k] = $v;
                    }
                } elseif($v != $before[$k]) {
                    $changed[$k] = $v;
                }
            } else {
                $changed[$k] = $v;
            }
        }
        return $changed;
    }
    /**
     * Recursevely adds/replaces keys in $base with keys in $extendWith
     *
     * @param array $base ie: ['a'=>'OriA','b'=>'OnlyB','d'=>['d1'=>1]]
     * @param array $extendWith ie: ['c'=>'NewC', 'a'=>'Replaced', 'd'=>['d2'=>2]]
     * @return void $base is modified ie:  [['a'] => 'Replaced', ['b'] => 'OnlyB', ['d'] => [ ['d1'] => 1, ['d2'] => 2 ], [c] => 'NewC']
     */
    public static function arrayExtend(&$base, $extendWith) {
        foreach($extendWith as $key => $val) {
            if(is_array($val)) {
                if(!isset($base[$key])) {
                    $base[$key] =[];
                }
                self::arrayExtend($base[$key], $val);
            } else {
                $base[$key] = $val;
            }
        }
    }
    /**
     *
     *
     * @param array $array
     * @param string $separator
     * @return array (['a.b.c'=>'It', 'a.b.d'=>'is', 'a.b.e'=>'a', 'a.b.f'=>'cat'], '.') => ['a' => [ 'b'=> ['c' => 'It','d'=>'is','e'=>'a','f'=>'cat'] ] ]
     */
    public static function expandKeyToArray($array, $separator) {
        $ret = [];
        foreach($array as $k => $d) {
            $pointer = &$ret;
            $path = explode($separator, $k );
            $len = count($path);
            $i=0;
            foreach($path as $p) {
                ++$i;
                if($i === $len) {
                    $pointer[$p] = $d;
                } else {
                    if(!array_key_exists($p, $pointer)) {
                        $pointer[$p] = [];
                    }
                    $pointer = &$pointer[$p];
                }
            }
        }
        return $ret;
    }
    /**
     * Keys to final value
     *
     * @param array $list ie [ ['vivo','animal','felino','gato', 'domestico','gato info'], ['vivo','animal','felino','gato', 'feral','salvaje'], ['vivo','animal','canino','perro','Perro Frase'] ]
     * @return array ie [ 'vivo' => ['animal' => ['felino' => [ 'gato' => [ 'domestico' => 'gato info' , 'feral' => 'salvaje' ] ], 'canino' => ['perro' => 'Perro Frase' ] ] ]]
     */
    public static function tupplesToArrayAssoc($list) {
        $ret = [];
        foreach($list as $rec) {
            $dPointer = &$ret;
            $numKeys = count($rec) - 1;
            $i = 0;
            foreach($rec as $d) {
                if($i++ >= $numKeys) {
                    $dPointer = $d;
                    break;
                }
                if(!array_key_exists($d, $dPointer)) {
                    $dPointer[$d] = [];
                }
                $dPointer = &$dPointer[$d];
            }
        }
        return $ret;
    }
    /**
     *
     *
     * @param array $array ie: [ ['vivo','animal','felino','gato','gato info'], ['vivo','animal','canino','perro','Perro Frase'] ]
     * @param string $pathSeparator ie: '.'
     * @return array ie: [ 'vivo.animal.felino.gato' => 'gato info', 'vivo.animal.canino.perro' => 'Perro Frase' ]
     */
    public static function tupplesToArrayPath($array, $pathSeparator = "\t") {
        $ret = [];
        foreach($array as $rec) {
            $path = '';
            $numKeys = count($rec) - 1;
            $i = 0;
            foreach($rec as $key => $d) {
                if($i++ >= $numKeys) {
                    break;
                }
                $path .= $d . $pathSeparator;
            }
            $ret[substr($path, 0, -1)] = $d;
        }
        return $ret;
    }
    /**
     * regresa el valor del ultimo key en el path
     *
     * @param array $array ie: ['vivo' => ['animal' =>['felino' => ['gato' => ['Gato Info'] ] ] ] ]
     * @param string $path ie: 'vivo.animal.felino.gato'
     * @param string $pathSeparator ie: '.'
     * @return mixed ie: ['Gato Info'], null on not found
     */
    public static function arrayGetPath($array, $path, $pathSeparator = "\t") {
        $dPointer = &$array;
        foreach(explode($pathSeparator, $path) as $p) {
            if(array_key_exists($p, $dPointer)) {
                $dPointer = &$dPointer[$p];
            } else {
                $key = trim($p);
                if(array_key_exists($key, $dPointer)) {
                    $dPointer = &$dPointer[$key];
                } else {
                    return null;
                }
            }
        }
        return $dPointer;
    }
    /**
     * @param array $array
     * @param int $numKeys
     * @return array
     */
    public static function multiKeyIt($array, $numKeys) {
        $multiKeyed = [];
        foreach($array as $row) {
            if(!isset($countFields)) {
                $countFields = count($row);
            }
            $arrRef = &$multiKeyed;
            $theKey = reset($row);
            for($k = 0; $k < $numKeys; $k++) {
                if(!isset($arrRef[$theKey])) {
                    $arrRef[$theKey] = array();
                }
                $arrRef = &$arrRef[$theKey];
                $theKey = next($row);
            }
            $arrRef = array_merge($arrRef, array_slice($row,$numKeys));
        }
        return $multiKeyed;
    }
    /**
     * Returns a string of indented ul/ol representing the array
     *
     * keys inside span class='key2UlKey' values inside span class='key2UlValue'
     *
     * @param array $array
     * @param string $ul html tag to use 'ul' or 'ol', default 'ul'
     * @param bool $displayValue on true display value on false only keys. default true
     * @param bool $displayKey on true display the key
     * @param bool $skipHtmlentities true no htmlentites on output, false output using htmlentities
     * @param bool $displayKeyNumeric
     * @return string '<ul><li><span class='key2UlKey'>key1</span><ul><li>key1.1'
     */
   public static function arrayKey2Ul($array, $ul='ul', $displayValue = true, $displayKey = false,
                                      $skipHtmlentities=false, $displayKeyNumeric = false ) {
        $ret =  "<$ul class='key2Ul'>";
        foreach ( $array as $key => $item ) {
            $ret .=  "<li>";
            if($displayKey && ($displayKeyNumeric || !is_numeric($key)  )) {
                $ret .= "<span class='key2UlKey'>".self::htmlentities($key, $skipHtmlentities)."</span>";
            }
            if ( is_array($item) ) {
                $ret .=  self::arrayKey2Ul( $item, $ul, $displayValue, $displayKey, $skipHtmlentities, $displayKeyNumeric );
            } elseif($displayValue) {
                $ret .= " <span class='key2UlValue'>".self::htmlentities($item, $skipHtmlentities)."</span>";
            }
            $ret .= '</li>';
        }
        return "$ret</$ul>";
    }
    /**
     * echos indented ul/ol representing the array
     *
     * @param array $array
     * @param string $ul html tag to use 'ul' or 'ol', default 'ul'
     * @param bool $displayValue on true display value on false only keys. default true
     * @param bool $displayKey on true display the key
     * @param bool $skipHtmlentities true no htmlentites on output, false output using htmlentities
     * @param bool $displayKeyNumeric
     * @return void
     *
     * @codeCoverageIgnore
     */
   public static function arrayKey2Ul_echo($array, $ul='ul', $displayValue = true, $displayKey = false,
                                           bool $skipHtmlentities = false, $displayKeyNumeric = false
   ) {
        echo "<$ul class='key2Ul'>";
        foreach ( $array as $key => $item ) {
            echo "<li>";
            if($displayKey && ($displayKeyNumeric || !is_numeric($key)  )) {
                echo "<span class='key2UlKey'>".self::htmlentities($key, $skipHtmlentities)."</span>";
            }
            if ( is_array($item) ) {
                self::arrayKey2Ul_echo( $item, $ul, $displayValue, $displayKey, $skipHtmlentities, $displayKeyNumeric );
            } elseif($displayValue) {
                echo " <span class='key2UlValue'>" .self::htmlentities($item, $skipHtmlentities)."</span>";
            }
        }
        echo "</$ul>";
    }
    /**
     * Protects or not a string with htmlentities
     *
     * @param $str string to otuput
     * @param bool $skipHtmlentities true no htmlentites on output, false output using htmlentities
     * @return string
     */
    private static function htmlentities($str, bool $skipHtmlentities = false) {
        return $skipHtmlentities == true ? $str : htmlentities($str,0,'UTF-8',false );
    }
}