6, Relaties 1:1 en 1:N
DEZE EN VOLGENDE LESSEN WORDEN NOG AANGEPAST
In deze les gaan we bekijken hoe je relaties legt tussen tabellen en hoe je informatie uit andere tabellen kan afdrukken in jouw view.
Een relatie in de view wordt altijd gelegd tussen één regel (row/record) en een andere tabel. Omdat de relatie vanuit de regel wordt gelegd, is er dus altijd sprake van een 1:1 of 1:N relatie. We gaan beide relaties apart bespreken en uittesten met voorbeelden.
Als uitgangspunt nemen onze eigen view die we in de vorigen les hebben gemaakt. We gaan een kolom toevoegen waarin de hoofdstad van el land wordt getoond.
1:1 relatie
Bekijk de World database. In de country tabel staat de kolom Capital, dit is een foreign key die verwijst naar de primary key ID in de city table.
Vanuit de country table kun je via de foreign key Capital verwijzen naar de Name in de gokoppelde tabel city.
$country->hoofdstad->Name;
Met dit statement verwijs je vanuit de country tabel, via de relatie hoofdstad naar de Name (naam) van de hoofdstad.
Nu moet de relatie hoofdstad alleen nog worden geprogrammeerd. Dit doen we in de model file van Country.
// models/Country.php
public function getHoofdstad()
{
return $this->hasOne(City::className(), ['ID' => 'Capital']);
}
De functie getHoofdstad vertel jij Yii hoe de relatie tussen de tabel Country en City in elkaar zit.
Een 1:1 relatie wordt dus op de volgende manier gemaakt:
public function get<RELATIE NAAM>()
{
return $this-><RELATIE SOORT>(<RIGHT TABEL>::className(),
['<PRIMARY KEY RIGHT TABLE>' => '<FOREIGN KEY LEFT TABLE>']);
}
In een query zou de relatie er als volgt uit zien:
SELECT *
FROM Country
LEFT JOIN City
ON Country.Capital = City.ID
De relatie is gemaakt in het Model van Country en is dan ook alleen vanuit Country Beschikbaar. Je kunt in een view van Country dan gegevens uit de relatie afdrukken door:
$country-><relatie_naam>-><kolom naam>
Opdracht 1
Lees de uitleg hierboven goed door en plaats de kolom hoofdstad in het overzicht.
Maak hiervoor twee aanpassingen:
|
We gaan de Hoofdstad clickable maken. Als je naar http://localhost:8080/city gaat dan zie je het overzicht van steden. Klik op een oogje op een van de steden. Let op de URL. Je ziet http://localhost:8080/city/view?id=<NR> als url en <NR> is het ID van de stad.
Dus als je bijvoorbeeld klikt op http://localhost:8080/city/view?id=5 dan zie je informatie over Amsterdam.
Opdracht 2
Maak elke hoofdstad in het overzicht datje bij opdracht 1 hebt gemaakt clickable. Als je op de link klikt dan open je het overzicht van de stad, bijvoorbeeld http://localhost:8080/city/view?id=5.
Tip: je kunt Html:a() gebruiken om een link te maken. Dit is in de vorige les uitgelegd. |
1:N relatie
In de World database staat een tabel countrylanguage. In deze tabel staat per land welke talen er worden gesproken. Per taal wordt ook aangegeven welk percentage van de bevolking deze taal spreekt. De relatie tussen country en countrylanguage is 1:N. Namelijk in een land worden 1 of meer talen gesproken.
We willen een overzicht maken dat er als volgt uitgaat zien:
In dit voorbeeld zien we dat in Indonesië 8 talen worden gesproken. We gaan ons overzicht aanpassen, zodat we per land alle talen die er worden gesproken netjes in de tabel worden weergegeven zoals hierboven in het voorbeeld is te zien.
Hoe werkt dit?
Bij de 1:1 relatie hierboven konden we via $country->hoofdstad->Name
de naam van de hoofdstad uit de gelinkte tabel opvragen. Als dit niet duidelijk is, lees dan het stuk over 1:1 relatie hierboven nog een keer goed door!
Bij een 1:N relatie werkt het hetzelfde als bij de 1:1 relatie. Dus in het model (models/Country.php) s de relatie beschreven:
public function getCountrylanguages()
{
return $this->hasMany(Countrylanguage::className(), ['CountryCode' => 'Code']);
}
We kunnen nu vanuit de view (views/country/overzicht.php) via $country->countryLanguages->Language
de taal opvragen.
Er is alleen één belangrijk verschil, omdat we geen 1:1 relatie hebben, maar een 1:N, krijgen we geen variabele terug maar een array. We moeten het dus met een loop door het array heen lopen.
Dit gaan we demonstreren met behulp van de debug functie die we in les 1 (optioneel) hadden toegevoegd. als je dit nog niet hebt gedaan dan moet je dat nu doen.
Debugging
Ga nu naar je view en voeg bovenaan in de loop waarmee je het overzicht afdrukt, de regel dd($country->hoofdstad->Name) toe. DD staat voor dump & die. Dus DD laat de variabele zien en stopt met het uitvoeren van het programma.
<?php
....
foreach ($countries as $country) {
dd($country->hoofdstad->Name);
echo "<tr>";
...
...
}
...
<?php foreach ($country->language as $language): ?>
<div class="row">
<div class="col-md-8"><?= $language->Language ?></div>
<div class="col-md-4"><?= $language->Percentage ?></div>
</div>
<?php endforeach; ?>
De variabele $language is willekeurig gekozen, dit is de variabele die $country->language[0], $country->language[1], $country->language[2], etc. etc.
Opdracht 3pas de view (views/country/overzicht.php) aan, zodat de talen die in een land worden gesproken worden afgedrukt zoals in het voorbeeld hierboven is aangegeven. |
Hieronder een schematisch overzicht van de belangrijkste onderdelen hoe je van een URL via de controller en model de juisten informatie in de view plaatst.
- Dit is de URL die de gebruiker invoert. Via de routing worden twee items uit de URL gehaald: (a) country en (b) overzicht. Item (a) is de controller-naam en item (b) is functie-naam (methodenaam). De controller zelf is te vinden in de file controllers/Country.php deze file-naam komt ook overeen met de item (a).
- In de methode actionOverzicht, waarvan de naam dus uit item (b) van de URL komt, wordt een $country object gemaakt. Dit object is verbonden met de methode Country en deze is weer beschreven in de models/Country.php en wijst vanuit daar naar de juiste database tabel.
- Vanuit de controller wordt er verwezen naar het model. In het model is beschreven waar de data werkelijk kan worden gevonden. In de methode tableNaam() wordt beschreven in welke tabel de informatie staat. In de methodes getCapital en getCountrylanguages wordt beschreven hoe een andere tabel is gekoppeld aan deze country tabel.
- In de view kunnen we het object $country dat is gemaakt in de controller gebruiken om gegevens uit de tabel af te drukken. Via de methodes getCapital en getCountrylanguages kunnen gegevens uit de andere tabellen die zijn gekoppeld aan $country ook worden afgedrukt. Afhankelijk van de soort relatie 1:1 of 1:N krijg je een waarde of een array met waardes terug.
- De view maakt (rendert) de hele pagina en stuurt deze in zijn geheel naar de browser.
Opmerking: Een methode (NL) of method (EN) is een functie in een class. Zodra je leest public function Abc() {
dan is Abs eigenlijk een methode.
Toelichting Stap 3a
public function getRelatie() {
return $this->hasMany(Relatie::className(), ['key.relatie' => 'key.thismodel']);
}