tiny ‘n’ smart
database layer

Odkazy: dibi | API reference

Oznámení

Omlouváme se, provoz fóra byl ukončen

Formát názvů sloupců pro fetchPairs

před 8 lety

Václav M.
Člen | 34

FetchPairs nesnáší názvy sloupců které jsou ve formátu NázevTabulky.NázevSloupce. Místo toho chce názvy sloupců ve formátu jen NázevSloupce.

A já myslím, že by šlo do kódu této metody přidat mechanismus, který by názvy sloupců do potřebného formátu upravil.

před 8 lety

HosipLan
Moderator | 4693

A to proč?

před 8 lety

Václav M.
Člen | 34

A proč ne?

Představte si, že někdo bude mít třídu (nebo funkci), která bude přijímat sloupce pro select, tabulky pro from atd., ale bude rozhodovat o použití metody fetchAll nebo fetchPairs podle počtu sloupců, které mají být ve výsledku.

Pokud budou 3 sloupce nebo více, tak se použije fetchAll – a pokud budou jen dva sloupce či jeden sloupec, použije se fetchPairs – s tím, že pokud budou sloupce 2, tak jako parametry metodě fetchPairs zadá právě názvy obou sloupců – jenže je zadá pomocí souřadnic v tom poli sloupců pro select, tedy

$this -> Vysledek = $this -> Vysledek -> fetchPairs($Dotaz_Select[0], $Dotaz_Select[1]);

V případě výběru z jedné tabulky je vše OK, ale pokud se vybírá z dvou nebo více tabulek, tak nastává problém. No, ne že by nešlo názvy sloupců upravit u programátora – namísto úrovně dibi, ale …

Tady je moje řešení konverze názvů sloupců – mimo dibi:

$NazvySloupcu = array(  explode(".", $Dotaz_Select[0]), explode(".", $Dotaz_Select[1])  );
for ($Cislo = 0; $Cislo < count($NazvySloupcu); $Cislo++)
{
    $NazvySloupcu[$Cislo] = ( count($NazvySloupcu[$Cislo]) == 1 ) ? $NazvySloupcu[$Cislo] : $NazvySloupcu[$Cislo][1];
}

před 8 lety

HosipLan
Moderator | 4693

Proč ano? Zbytečně by to komplikovalo „tenkou, chytrou knihovnu“? Právě proto, že to jde ošetřit výběrem požadovaných sloupců, to není potřeba.

před 8 lety

paranoiq
Člen | 388

„Představte si, že někdo bude mít třídu…“

nechápu účel takové třídy. o tom jakou podobu bude mít výsledek, se kterým dál pracuji, je snad lepší rozhodovat přímo výběrem té které metody, než na základě počtu sloupců (ty mohou být dva třeba jen náhodou)

btw. třída, která přijímá sloupce pro SELECT a tabulky pro FROM je pokud vím DibiFluent

před 8 lety

Václav M.
Člen | 34

paranoiq napsal(a):

nechápu účel takové třídy. o tom jakou podobu bude mít výsledek, se kterým dál pracuji, je snad lepší rozhodovat přímo výběrem té které metody, než na základě počtu sloupců (ty mohou být dva třeba jen náhodou)

btw. třída, která přijímá sloupce pro SELECT a tabulky pro FROM je pokud vím DibiFluent

Já na základě počtu sloupců v selectu rozhoduji o tom, která metoda pro zpracování se použije – jestli fetchAll – nebo fetchPairs. A pokud jsou v selectu dva sloupce, tak dojde k tomu, že (zvolené) metodě fetchPairs jako parametry zadám názvy sloupců, jak jsou v selectu – protože ne vždy mohu předem určit, jaké ty sloupce v selectu vlastně budou – protože ty jsou zadávány třídě VyberSekci, nikoliv DibiFluent.

Zde je celý kód sestavení objektu třídy DibiFluent a zpracování výsledku.

Pole selectu, from a where jsou předem sestavena podle zadání uživatele. A k tomu třídě VyberSekci slouží metody, které podle účelu přijímají sloupce pro select, tabulky pro from atd. – a podle dalších instrukcí k nim přidá další. Právě proto je nemožné při použití metody fetchPairs zadat přesné sloupce.

$this -> Vysledek = PripravnaSQL("select", $Dotaz_Select);
$this -> Vysledek -> from($Dotaz_From);
$this -> Vysledek -> where($Dotaz_Where);

if( !empty($Dotaz_Order) && $this -> Razeni != FALSE )
{
    $this -> Vysledek -> orderBy($Dotaz_Order);
}

switch ( count($Dotaz_Select) )
{
    case "1":
        $this -> Vysledek = $this -> Vysledek -> fetchPairs();
        break;
    case "2":
        $NazvySloupcu = array(  explode(".", $Dotaz_Select[0]), explode(".", $Dotaz_Select[1])  );
        for ($Cislo = 0; $Cislo < count($NazvySloupcu); $Cislo++)
        {
            $NazvySloupcu[$Cislo] = ( count($NazvySloupcu[$Cislo]) == 1 ) ? $NazvySloupcu[$Cislo] : $NazvySloupcu[$Cislo][1];
        }

        $this -> Vysledek = $this -> Vysledek -> fetchPairs($NazvySloupcu[0], $NazvySloupcu[1]);
        break;
    default:
        $this -> Vysledek = $this -> Vysledek -> fetchAll();
        $Seznam = array();

        foreach ($this -> Vysledek as $Radek)
        {
            settype($Radek, "array");
            $NazvySloupcu = array_keys($Radek);
            $PocetSloupcu = count($Radek);

            for($Cislo = 0; $Cislo < $PocetSloupcu; $Cislo++)
            {
                $Seznam[$Radek[$NazvySloupcu[0]]][$NazvySloupcu[$Cislo]] = $Radek[$NazvySloupcu[$Cislo]];
            }
        }

        $this -> Vysledek = $Seznam;
        $Seznam = array();
        break;
    }
    return $this -> Vysledek;

Jinak původní řešení zpracování výsledku (získaného výhradně metodou fetchAll) bylo takové:

foreach($Vysledek as $Radek)
{
    settype($Radek, "array");
    $NazvySloupcu = array_keys($Radek);
    $PocetSloupcu = count($Radek);

    switch($PocetSloupcu)
    {
        case "1":
            $Seznam[] = $Radek[$NazvySloupcu[0]];
            break;
        case "2":
            $Seznam[$Radek[$NazvySloupcu[0]]] = $Radek[$NazvySloupcu[1]];
            break;
        default:
            for($Cislo = 0; $Cislo < $PocetSloupcu; $Cislo++)
            {
                $Seznam[$Radek[$NazvySloupcu[0]]][$NazvySloupcu[$Cislo]] = $Radek[$NazvySloupcu[$Cislo]];
            }
    }
}

… a forma výsledného pole byla shodná.

před 8 lety

HosipLan
Moderator | 4693

To co jsi tady ukázal je hromada naprosto nepřehledných anti-patternů s odporným coding-style. „Builder“ na „query builder“, kterým je DibiFluent, je sám o sobě bruální anti-pattern :)

Né každý má tvé potřeby. Abych byl přesný, nikoho dalšího neznám. To co jsi vymyslel v dibi vidět určitě nechci.

Nevím jak ti to říct slušněji, nechci tě odradit od programování, každý nějak začínal, ale opravdu bych ti doporučil si nastudovat základy programování, OOP a knihoven, které používáš, předtím, než budeš navrhovat nějaké změny. Děkuji.

před 8 lety

Václav M.
Člen | 34

Že používám postupy, z kterých někoho může klepnout, připouštím, ale s tím coding-style …

Mou literaturou, pokud jde o PHP byly a jsou:
PHP Progragumeje profesionálně (ComputerPress)
PHP a MySQL Názorný průvodce tvorbou dynamických WWW stránek (ComputerPress)
PHP a MySQL Vytváříme webové databázové aplikace (ComputerPress)
Velká kniha PHP & MySQL 5 (ZonerPress)

Takže nic moc, protože OOP se věnuje jen poslední z nich … a ještě ne moc.

… a smyslem třídy VyberSekci, tedy toho horního builderu je především oddělit zpracování výsledku SQL dotazu od dalšího kódu.

Editoval Václav M. (21. 11. 2011 22:21)

před 8 lety

paranoiq
Člen | 388

@CáclavM: vysvětlil jsi sice co děláš, ale nikoliv proč. nevysvětlil jsi účel té třídy. proč potřebuješ aby výsledek byl jednou takový a podruhé makový? tahle třída se jen snaží vyřešit nesmyslné zadání. hlavní chyba je podle mě v předpokladech kódu, který ji používá

k hlavním zásadám psaní kódu patří to, že každá metoda má právě jeden návratový typ (to patří k těm základům programování, o kterých HosipLan mluví. zkoušel jsi nějaký jazyk se statickým typováním?). je to proto, aby ses mohl spolehnout, že výsledek bude vždy přesně takový, jaký očekáváš. ty tohle elementární pravidlo záměrně porušuješ, tím že chceš, aby se výstupní formát měnil v závislosti na vstupních datech. ale k ničemu dobrému to nepovede

také se zamysli nad tím jak se tvůj „query-builder builder“ popere s tím, až budeš potřebovat něco složitějšího než jen pouhý „from“ z jedné tabulky

@HosipLan: a s tím coding stylem bych to tak černě neviděl. alespoň je to čitelné. ono mu snad časem dojde, že se s těmi shifty a mezerami obtěžuje zbytečně. prvňáčci taky ze začátku nemají nejhezčí rukopis. hlavně aby se to nezvrtlo na druhou stranu. já měl kdysi dávno období, kdy jsem veškerý white space (krom odsazení, naštěstí!) považoval za zbytečnost :P

Editoval paranoiq (22. 11. 2011 9:44)

před 8 lety

Milo
Nette Core | 1119

Václav M. napsal(a):

FetchPairs nesnáší názvy sloupců které jsou ve formátu NázevTabulky.NázevSloupce. Místo toho chce názvy sloupců ve formátu jen NázevSloupce.

To je ale správné chování. Výsledkem dotazu:

SELECT
    tab.id,
    tab.name
FROM
    tab

je také result set, který obsahuje pouze názvy sloupců.

Když to „oaliasuješ“:

-- Postgres syntax
SELECT
    tab.id    AS "tab.id",
    tab.name  AS "tab.name"
FROM
    tab

tak můžeš tab.id a tab.name používat ve fetchAssoc() i fetchPairs().

před 8 lety

Václav M.
Člen | 34

paranoiq napsal(a):

@VáclavM: vysvětlil jsi sice co děláš, ale nikoliv proč. nevysvětlil jsi účel té třídy. proč potřebuješ aby výsledek byl jednou takový a podruhé makový? tahle třída se jen snaží vyřešit nesmyslné zadání. hlavní chyba je podle mě v předpokladech kódu, který ji používá

k hlavním zásadám psaní kódu patří to, že každá metoda má právě jeden návratový typ (to patří k těm základům programování, o kterých HosipLan mluví. zkoušel jsi nějaký jazyk se statickým typováním?). je to proto, aby ses mohl spolehnout, že výsledek bude vždy přesně takový, jaký očekáváš. ty tohle elementární pravidlo záměrně porušuješ, tím že chceš, aby se výstupní formát měnil v závislosti na vstupních datech. ale k ničemu dobrému to nepovede

také se zamysli nad tím jak se tvůj „query-builder builder“ popere s tím, až budeš potřebovat něco složitějšího než jen pouhý „from“ z jedné tabulky

@HosipLan: a s tím coding stylem bych to tak černě neviděl. alespoň je to čitelné. ono mu snad časem dojde, že se s těmi shifty a mezerami obtěžuje zbytečně. prvňáčci taky ze začátku nemají nejhezčí rukopis. hlavně aby se to nezvrtlo na druhou stranu. já měl kdysi dávno období, kdy jsem veškerý white space (krom odsazení, naštěstí!) považoval za zbytečnost :P

1. Účel třídy VyberSekci je výběr sekcí přístupných uživateli

Ten builder tedy není něco extra obecného, ale je velmi specializovaný pro svůj úkol. Z více tabulek je vybíráno, ale … Zatím nic složitějšího nehrozí, protože zatím neplánuji další změny v uživatelském systému.

2. Účel diferenciace výsledku (podle situace):

  1. několik různých situací podle nasazení potřebuje různou formu výsledku:
  2. rozbalovací seznam (select) potřebuje jen asociativní pole (ve tvaru ID sekce ⇒ název sekce)
  3. menu potřebuje mnohem více informací (a jiné), které je nutné sestavit z pole získaného pomocí fetchAll.
  4. a v jiném místě naopak stačí úplně jednoduché pole

Ale všechny výběry spojuje jediná (byť dvojitá) podmínka

Sekce_Prava.Akce = $this -> VolbaPravaSekce
Sekce_Prava.Opravneni = $this -> Uzivatel_AO

kde $this -> VolbaPravaSekce obsahuje obecné povolení s sekcí pracovat či název sekce určené k manipulaci s jinými sekcemi – a $this -> Uzivatel_AO obsahuje kód uživatelova oprávnění k zacházení s tím, co je uloženo v proměnné $this -> VolbaPravaSekce.

  • Shifty? To jako že používám malá a velká písmena? Na tom snad není nic špatného.
  • A mezery navíc? Které? Mezi názvem objektu, šipkou a názvem metody? Nebo ty v cyklu foreach? Možná zbytečné, ale mně to pomáhá.
  • Odsazení není prostými mezerami.

Jediný návratový typ pro jednu metodu? VyberSekci je první a zatím jediná třída, kde jsem toto porušil. I když ne tak úplně – návratovým typem je stále pole – pouze jeho podoba se mění. V jiných mých třídách je jedinečnost formy výsledku zachována.

před 8 lety

paranoiq
Člen | 388

pokud se týká VyberSekci, přesvědčovat tě nebudu

k tvému coding style žádné zásadní výhrady nemám. psal jsem, že je alespoň čitelný – a to je hlavní

Odsazení není prostými mezerami

to je ta poslední věc na které záleží. mimochodem, sám je používám. měl jsem na mysli mezery okolo ->

Editoval paranoiq (23. 11. 2011 10:01)

před 8 lety

Václav M.
Člen | 34

paranoiq napsal(a):

pokud se týká VyberSekci, přesvědčovat tě nebudu

k tvému coding style žádné zásadní výhrady nemám. psal jsem, že je alespoň čitelný – a to je hlavní

měl jsem na mysli mezery okolo ->

  1. O čem? O nesmyslnosti konstrukce?
  2. Dík za podporu.
  3. Jsou zbytečné – ale mě pomáhají – hlavně v těchto případech
$Sablona = new Radkovac_Table();
$Sablona -> ZadaniObsahuSloupce($VkladanyText6);
$Sablona -> ZadaniVlastnostiSloupce(">", "colspan", "2");
$Sablona -> ZadaniVzhleduSloupce("#", "text-align", "right");
$TextRadku .= $Sablona -> Spustit();

(což je jedno z mnoha možných použití třídy pro vytvoření jednoho řádku tabulky vytvořené značnou table)


A jedna menší poznámka k třídě VyberSekci – v rámci sestavování veškerých parametrů, které jsou dále použity na výsledný dotaz, dochází k několika dalším databázovým dotazovacím procesům. Proto není možné použít rovnou DibiFluent. Navíc je tam ta podmínka vložení řazení, které možná uniklo pozornosti. Především kvůli tomu je nutno použít tu funkci PripravnaSQL pro složení celého dotazu.

Editoval Václav M. (24. 11. 2011 17:06)