Zend Framework: relaties tussen je tabellen

Gisteren kreeg ik een vraag op IRC hoe je de naam van een categorie kan selecteren van een nieuwsbericht. Het probleem is dus, hoe leg ik een relatie tussen verschillende models en hoe vraag ik de gegevens ervan op? Laten we veronderstellen dat we een tabel news hebben en een tabel categories. De structuur ziet er als volgende uit.

CREATE TABLE `categories` (
`id` int(11) NOT NULL auto_increment,
`naam` varchar(50) NOT NULL,
PRIMARY KEY  (`id`)
);

CREATE TABLE `news` (
`id` tinyint(4) NOT NULL auto_increment,
`titel` varchar(255) NOT NULL,
`categorie` int(11) NOT NULL,
PRIMARY KEY  (`id`),
KEY `categorie` (`categorie`)
);

ALTER TABLE `news` ADD CONSTRAINT `nieuws_ibfk_1` FOREIGN KEY (`categories`) REFERENCES `categories` (`id`);

Dit is de structuur van je tabel. In PHP ziet ons model er als volgt uit.

class News extends Zend_Db_Table {
protected $_name = ‘news’;
}

class Categories extends Zend_Db_Table {
protected $_name = ‘categories’;
}

Dit ziet er in orde uit maar wat als ik nu een artikel wil weergeven en daaronder de naam van zijn categorie wil plaatsen.  Je kan natuurlijk de twee modellen oproepen en dan twee fetch instructies doen, zoals hieronder staat.

public function indexAction()
{
$nieuws = new News();
$categorie = new Categories();
$artikel = $nieuws->fetchRow(“id=1”);
$categorie = $artikel->fetchRow(“id=” . $artikel->categorie);
}

Je hebt nu wel de correcte informatie maar je relatie tussen je models zit niet goed. Als ik nu alle nieuwsberichten wil van één categorie, kan me dit behoorlijk wat werk geven. Ook zijn er verschillende soorten relaties. Daarom leg een relatie tussen je models. Hoe beginnen we eraan? In het ene model moet de relatie komen en de andere model moet weten welk model er van hem afhangt. De model News heeft een kolom catgorie die wijst naar Categorie en kolom id. Dus de waarde van News.categorie is een referentie/verwijst naar Categorie.id, dus we defineren de relatie in onze model News.  Dit betekent ook dat onze model News afhankelijk is van de model Categories. Onze models code ziet er als volgt uit (mijn excuses voor het gebrek aan tabs, quotes verwijdert die).

class News extends Zend_Db_Table {
protected $_name = ‘news’;

protected $_referenceMap = array(
‘Categorie’ => array(
‘columns’ => ‘categorie’,
‘refTableClass’ => ‘Categories’,
‘refTableColumn’ => ‘id’
)
);

}

class Categories extends Zend_Db_Table {
protected $_name = ‘categories’;

protected $_dependentTables = array(‘News’);

}

In de referenceMap komt een relatie identifier en die wijst naar de relatie tussen de kolommen. De relatie spreekt voor zich. In de dependentTables zet je een array met de model(s) die afhankelijk zijn.

Je kan nu je indexAction je code als volgt schrijven.

public function indexAction()
{
$nieuws = new News();
$artikel = $nieuws->fetchRow(“id=1”);
$categorie = $artikel->findParentRow(‘Categorie’);
}

Niet moeilijk te implementeren en vooral handig als je Zend Framework gebruikt! Meer informatie over relations.

6 Responses to Zend Framework: relaties tussen je tabellen

  1. devkid zegt:

    Euhm, dit moet je mij toch eens even uitleggen:

    CREATE TABLE news (
    id tinyint(4) ..

    CREATE TABLE categorie (
    id int(11) ..

    max. 255 nieuws items en ongeveer 4 miljard categorieën? :P

    $artikel = $nieuws->fetchRow(”id=1″);

    is hetzelfde als:

    $artikel = $nieuws->find(1)->current();

    maar zou eigenlijk moeten zijn:

    $artikels = $nieuws->find(1);
    if (!sizeof($artikels)) {
    // FrontController::throwExceptions(false);
    // deze exception wordt opgevangen door ErrorController::errorAction()
    // opvragen kan via $exception = $this->_getParam(‘error_handler’)->exception;
    require_once(‘App/Exception/ArticleNotFound.php’);
    throw new App_Exception_ArticleNotFound();
    }

    $artikel = $artikels->current();

    $categorie = $artikel->fetchRow(”id=” . $artikel->categorie);

    is in mijn ogen een bad practice en zou het vorige voorbeeld moeten volgen.

    my 2 cents :D

  2. shibble zegt:

    Heeey,,

    Handig artikel :), alleen nu moet ik er nog achter zien te komen hoe ik ervoor kan zorgen dat die via die news_categories.sql de categorie ophaalt die bij de newspost hoort.

    @devkid
    iedereen zijn manier van programmeren?

  3. devkid zegt:

    @shibble Klopt, de ene heeft last van SQL Injection en de andere niet :D

  4. shibble zegt:

    @devkid
    Dat ben ik toch echt niet met je eens…
    Ik maak gebruik van Zend Framework en die houdt automatisch al rekening met SQL Injections zover ik weet :).

  5. devkid zegt:

    Het tegengaan van sql injection gebeurt door query statement preparation als jij je data rechtstreeks invoert neemt zend framework dit as-is.

    $this->fetchAll(“id = 1”);

    $this->fetchAll(“id = ” . $rowSet->current()->categories_id);

    $this->fetchAll(“id = ?”, 1);

    Op de eerste en tweede manier moet het zend framework raden waar het vandaan wat de input is, wat het een stuk moeilijker maakt om zeker te zijn dat hij geen sql injection uitvoert.

    Voor hetzelfde geld had daar ook kunnen staan $request->getId() Zend_Controller_Request filtert en valideert zijn data, daar heb je volkomen gelijk in.

    Maar is het niet beter om toch nog net dat iets meer aan zekerheid te hebben? Het kost je maar 2 tekens meer om te schrijven..

    En door de $value parameter te gebruiken heeft het zend framework beter weet welke de waarde is en deze filteren en als je een zend_expr object meegeeft kan je ook het type specifieren van wat je meegeeft klopt het type niet met het $value dan geeft die een exception. Die je dan intern via de ErrorController kan afhandelen.

    Trouwens, mij is altijd geleerd er van uit te gaan dat je steeds full defensive moet programmeren je moet er van uit gaan dat zelfs het systeem waarop jouw applicatie draait vijandig is :) En op shared hosting is het dat ook..

    De meeste gebruiken de index.php als bootstrap en als jouw server faalt geeft hij jouw index.php als een download waardoor iedereen jouw code kan nalezen bij mijn staan er maar 2 regels in de bootstrap nl.

    chdir(dirname(__FILE__)); // voor de cli omgeving
    require_once(‘../private_html/includes/bootstrap.php’); // onder de root-map verborgen en niemand die weet dat ik het zend framework gebruik :)

  6. devkid zegt:

    Het laatste was off-topic en voor degene die weten wat er gebeurd is in het verleden met facebook waardoor iedere hacker nu weet op welke manier facebook werkt

    http://www.techcrunch.com/2007/08/11/facebook-source-code-leaked/

Geef een reactie

Vul je gegevens in of klik op een icoon om in te loggen.

WordPress.com logo

Je reageert onder je WordPress.com account. Log uit / Bijwerken )

Twitter-afbeelding

Je reageert onder je Twitter account. Log uit / Bijwerken )

Facebook foto

Je reageert onder je Facebook account. Log uit / Bijwerken )

Google+ photo

Je reageert onder je Google+ account. Log uit / Bijwerken )

Verbinden met %s

%d bloggers op de volgende wijze: