Databázové závislosti a vytiahnutie udajov

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
StanlieK
Člen | 28
+
0
-

Ahojte,
potrebujem pomôcť s databázovou závislosťou. Mám 3 tabuľky – znacky, modely, auta. Znacky obsahuju nazvy tabuliek id a znacka. Potrebujem zistiť, ako nastaviť kľúč v tabuľke auta na znacka_id, aby som mohol z tejto tabuľky ťahať aj znacky, na základe toho znacka_id v tabuľke auta.

Týmto spôsobom {$auto->znacky->znacka}.

Moje SQL na vytvorenie tabuliek:

DROP TABLE IF EXISTS `znacky`;
CREATE TABLE `znacky` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `znacka` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id` (`id`,`znacka`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `modely`;
CREATE TABLE `modely` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `model` varchar(100) NOT NULL,
  `znacka_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_znacka` (`znacka_id`),
  KEY `id` (`id`,`model`),
  CONSTRAINT `fk_znacka` FOREIGN KEY (`znacka_id`) REFERENCES `znacky` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `auta`;
CREATE TABLE `auta` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `znacka_id` int(10) unsigned NOT NULL,
  `model_id` int(10) unsigned NOT NULL,
  `motor` varchar(50) NOT NULL,
  `karoseria` varchar(50) NOT NULL,
  `prevodovka` int(1) NOT NULL,
  `palivo` int(1) NOT NULL,
  `rok_vyroby` varchar(50) NOT NULL,
  `km` varchar(50) NOT NULL,
  `popis` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_znacky` (`znacka_id`),
  KEY `fk_modely` (`model_id`),
  CONSTRAINT `fk_znacky` FOREIGN KEY (`znacka_id`) REFERENCES `znacky` (`id`),
  CONSTRAINT `fk_modely` FOREIGN KEY (`model_id`) REFERENCES `modely` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

A môj kód v AutaRepository a HomepagePresente:

//AutaRepository

class AutaRepository extends Repository
{
    public function findCars(){
        return $this->findAll()->where('znacka_id LIKE ?', '%%')->order('id ASC');
    }
}

//HomepagePresenter
public function renderDefault() {
        $this->template->auta = $this->autaRepository->findCars();
    }

Ako to mám prosím upraviť aby som neťahal len z tabuľky autá takto {$auto->znacka_id}, ale aby som mohol potiahnuť namiesto znacka_id, názov tejto značky. Predpokladám, že to bude nejaká chyba v mojom SQL a tých kľúčoch a indexoch. Ako to mám upraviť prosím.

Editoval StanlieK (7. 4. 2013 15:05)

Šaman
Člen | 2666
+
0
-

$auto->znacka->znacka

Není důležitý název tabulek (i když pro jistotu doporučuji používat jednotné číslo – odpadnou některé starosti), důležité je pole znacka_id.

Offtopic:

  1. Název metody findCars() nijak neinvokuje, že se hledají podle značky, doporučuji upravit na jednoznačnější název. Třeba findByZnacka(), protože to, že hledáš mezi auty je jasné z toho, že to voláš na AutaRepository.
  2. Doporučuji taky používat anglické názvy i pro tabulky a proměnné, jink ti pak vznikají takové názvy, jako findAutaByZnacka() a to je trochu fuj.
StanlieK
Člen | 28
+
0
-

Hej, názvy tabuliek nie je problém upraviť, ale ja mám skôr ťažkú hlavu z toho, ako nastaviť tie kľúče medzi tabuľkami v DB, aby keď použijem.

class AutaRepository extends Repository
{
    public function findByCars(){
        return $this->findAll()->order('id ASC');
    }
}

a

//HomepagePresenter
public function renderDefault() {
        $this->template->auta = $this->autaRepository->findByCars();
}

Aby som v HomePage/deafult.latte vedel použiť {$auto->znacka->znacka} na vytiahnutie názvu z tabuľky znacka, podľa hodnoty znacka_id z tabuľky auta.

Šaman
Člen | 2666
+
0
-

A to $auto->znacka->znacka ti teď nefunguje? (Já v klíčích problém nevidím.)
Aha, už vidím druhý problém, ta find metoda ti vrací kolekci, nikoliv jeden záznam. Musíš si to v šabloně foreachnout. Jestli je problém jinde, tak ho líp popiš, protože jinak nevím, kde hledat brouka.

Výpis modelu ti funguje? Jestli jo a značka ne, tak pošli kód šablony.

Opět offtopic – osvědčilo se mi mít get metody které vrací jediný záznam a find metody pro kolekce. Pak vím, že výsledek find metody musím fetchovat,get nemusím.

Editoval Šaman (7. 4. 2013 17:10)

StanlieK
Člen | 28
+
0
-

OK, takže ten výpis za pomoci $auto->znacka->znacka som rozchodil, pretože to bola čisto moja chyba a v šablóne som písal $auto->znacky->znacka …

A teraz potrebujem pomôcť ešte s jedným problémom. Potrebujem, aby po odoslaní formulára sa upravil sql dotaz tak, aby to hľadalo podľa hodnôt z formulára. Resp. ako tieto hodnoty z formulára predať tomuto dotazu. Povedzme, že mám v AutaRepository toto:

public function findCars() {
        return $this->findAll()->where('znacka_id LIKE ?','%%')->where('model_id LIKE ?','%%')->where('palivo LIKE ?','%%')->where('prevodovka LIKE ?','%%')->order('id ASC');
    }

Ako spraviť aby miesto ‚%%‘, boli premenné z formulára, ktorý je v HomepagePresenter spravený takto. Alebo kam mám ten dotaz umiestniť, aby mi to vypísalo na úvodnej stránke hľadané záznamy na základe odoslaného formuláru?

Formulár:

<?php

/**
 * Homepage presenter.
 */
class HomepagePresenter extends BasePresenter
{
    public $znackyRepository;
    public $modelyRepository;
    public $autaRepository;

    protected function startup() {
        parent::startup();
        $this->znackyRepository = $this->context->znackyRepository;
        $this->modelyRepository = $this->context->modelyRepository;
        $this->autaRepository = $this->context->autaRepository;
        \DependentSelectBox\DependentSelectBox::register('addDSelect');
        \DependentSelectBox\JsonDependentSelectBox::register('addJSelect');
    }

    protected function beforeRender() {
        DependentSelectBox\JsonDependentSelectBox::tryJsonResponse($this);
    }

    public function renderDefault() {
        $this->template->auta = $this->autaRepository->findCars();
    }

    protected function createComponentForm() {
        $form = new Nette\Application\UI\Form;
        $form->setMethod('GET');

        $znackyPairs = $this->znackyRepository->findAll()->order('znacka ASC')->fetchPairs('id', 'znacka');

        $form->addSelect('znacka', 'Značka', $znacka = array('0' => 'Nezáleží', $znackyPairs));
        $self = $this;
        $form->addDSelect('model', 'Model', $form['znacka'], function($form) use ($self) {
            $v = $form['znacka']->getValue();
            $modelsPairs = $self->modelyRepository->findBy(array('znacka_id' => $v))->order('model ASC')->fetchPairs('id', 'model');
            if ($v == '0'){
                $modelyPairs = $self->modelyRepository->findAll()->order('model ASC')->fetchPairs('id', 'model');
                return array ('0' => 'Nezáleží', $modelyPairs);
            }
            else {
                return array('0' => 'Nezáleží', $modelsPairs);
            }
        });
        $form->addSelect('palivo', 'Palivo', $palivo = array(
                '' => 'Nezáleží',
                '1' => 'Diesel',
                '2' => 'Benzín',
                '3' => 'LPG',
                '4' => 'Hybrid',
            )
        );
        $form->addSelect('prevodovka', 'Prevodovka', $prevodovka = array(
                '' => 'Nezáleží',
                '1' => 'Manuálna',
                '2' => 'Automatická',
            )
        );

        //$presenter = $this;
        if($this->isAjax()) {
            $form['model']->addOnSubmitCallback(function() use($self) {
                $self->invalidateControl('formSnippet');
            });
        }

        $form->addSubmit('vyhladat', 'Vyhľadať');

        return $form;
    }
}

Ako to mám upraviť, aby to predalo premenné scriptu v AutaRepository. Alebo ako to riešiť, aby mi po odoslaní formulára na Homepage zobrazilo výsledky?

Ďakujem za pomoc.

Šaman
Člen | 2666
+
0
-

Na znacky vs. znacka jsem upozorňoval v prvním přispěvku, ale asi jsem to písmenko málo zdůraznil. Vysvětlení je v něm, nejde o název tabulky, ale jméno sloupce.

Předání proměnné řeš normálně přes parametry funkce, tedy třeba $cars->findCar('skoda', 'fabia');. To není věc Nette, stejně jako problém pokud na daném kritériu nezáleží.

Ve findCar($znacka, $model) budeš volat normálně ->where("znacka LIKE ?","%$znacka%");

Editoval Šaman (7. 4. 2013 19:27)