Lekce 6 - Knihovna ArrayUtils pro práci s poli v PHP
V předešlém cvičení, Řešené úlohy k 4.-5. lekci knihovny v PHP, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Důležitou datovou strukturou v PHP jsou pole. Asi vás nepřekvapí, že i
pro pole se najde několik užitečných funkcí, které si dnes zabalíme do
třídy ArrayUtils
.
ArrayUtils
Nejprve si založíme naši třídu:
class ArrayUtils
{
}
Filtrování pole podle klíčů
Často se nám stává, že potřebujeme profiltrovat pole tak, aby
obsahovalo jen některé klíče. Pokud používáte místní databázový
wrapper nad PDO, jistě víte, že pomocí něj můžeme např. jednoduše
vložit nový řádek do tabulky uzivatel
tímto způsobem:
$uzivatel = array( 'jmeno' => 'Jan', 'prijmeni' => 'Novak', 'email' => '[email protected]', ); Db::insert('uzivatel', $uzivatel);
Kód výše by se mohl využít např. pro nějakou registraci. Pokud
předáme data z formuláře, bude sice fungovat, ale vystavujeme se
nebezpečnému riziku a to sice, že uživatel si může nějaká formulářová
pole přidat a ta se poté vloží do dotazu (např.
"admin" = 1
):
// Tento kód není bezpečný Db::insert('uzivatel', $_POST);
Hodilo by se nám pole $_POST
profiltrovat tak, aby obsahovalo
jen určitý výčet klíčů. Uvedený postup se samozřejmě neváže jen na
pole $_POST
, ale využijeme ho i v dalších případech.
Do třídy přidáme následující metodu:
public static function filterKeys(array $input, array $keys): array { return array_intersect_key($input, array_flip($keys)); }
Metoda filterKeys()
přijímá v argumentech vstupní pole a
dále pole klíčů, které chceme ponechat. Co se týče kódu, pomocí funkce
array_flip()
získáme pole, které má jako klíče ty klíče,
které chceme ponechat. Pomocí funkce array_intersect_key()
následně provedeme průnik klíčů dvou polí a vrátíme výsledek.
Ukažme si využití v původním příkladu, kde zabezpečíme získání
dat z pole $_POST
:
$klice = array('jmeno', 'prijmeni', 'email'); Db::insert('uzivatel', ArrayUtils::filterKeys($_POST, $klice));
Když je klíčů více, je výhodné dát jim nějaký prefix (předponu) a filtrovat podle něj:
public static function filterKeysPrefix(string $prefix, array $input): array { $output = array(); foreach ($input as $key => $value) { if (mb_strpos($key, $prefix) === 0) $output[$key] = $value; } return $output; }
Funkce filterKeysPrefix()
přijímá prefix a vstupní pole. Ve
výsledném poli zůstanou jen ty klíče, které začínají řetězcem
$prefix
. Kód by měl být srozumitelný.
Mapování párů klíč-hodnota a hodnot
Když vybíráme data z databáze, přijdou nám vždy jako pole polí, např. takto:
Array ( [0] => Array ( [uzivatel_id] => 1 [jmeno] => Jan Novák [email] => [email protected] ) [1] => Array ( [uzivatel_id] => 2 [jmeno] => Jana Nováková [email] => [email protected] ) [2] => Array ( [uzivatel_id] => 3 [jmeno] => Josef Nový [email] => [email protected] ) )
Mapování párů
Nyní si představte, že budeme v aplikaci chtít přidat formulář s výběrem uživatele pomocí HTML selectu (popisek bude jméno uživatele a hodnota odesílaná na server bude jeho ID). Pokud pro to použijeme nějaký formulářový framework, je velmi pravděpodobné, že bude chtít data ve formátu klíč-hodnota:
Array ( [Jan Novák] => 1 [Jana Nováková] => 2 [Josef Nový] => 3 )
Pro mapování výsledku databázového dotazu na takovéto asociativní pole
přidejme do naší třídy metodu mapPairs()
:
public static function mapPairs(array $rows, string $keyKey, string $valueKey): array { $pairs = array(); foreach ($rows as $row) { $key = $row[$keyKey]; // Kontrola kolizí klíče if (isset($pairs[$key])) { $i = 1; while (isset($pairs[$key . ' (' . $i . ')'])) { $i++; } $key .= ' (' . $i . ')'; } $pairs[$key] = $row[$valueKey]; } return $pairs; }
Metodě předáme pole a poté 2 názvy klíčů. První klíč se stane ve výsledném poli klíčem a druhý hodnotou.
Výše zmíněné pole tedy získáme tímto způsobem:
$uzivatele = Db::queryAll('SELECT jmeno, uzivatel_id FROM uzivatel'); $polozky = ArrayUtils::mapPairs($uzivatele, 'jmeno', 'uzivatel_id');
Všimněte si, že metoda řeší i případ, když se dva uživatelé jmenují stejně. V takovém případě začne položky číslovat.
Mapování hodnot
Podobně budeme občas potřebovat získat pole nějakých hodnot, např. emailů všech uživatelů, kterým pošleme newsletter. Budeme chtít získat následující pole:
Array ( [0] => [email protected] [1] => [email protected] [2] => [email protected] )
Metoda mapSingles()
není nijak složitá:
public static function mapSingles(array $rows, array $singleKey): array { $singles = array(); foreach ($rows as $row) { $singles[] = $row[$singleKey]; } return $singles; }
A použití:
$emaily = ArrayUtils::mapSingles(Db::queryAll('SELECT email FROM uzivatel'), 'email');
V příští lekci, Dokončení knihovny ArrayUtils v PHP, se zaměříme na práci s prefixy, konverzi notací a převod pole do XML a naopak.