MVC begin
Pagina: « vorige 1 2 3 volgende »
Roy B op 27/05/2014 16:21:22:
Oke duidelijk!
De DataMapper is dus een laag tussen de Controller en het Model?
Dan mijn volgende vraag:
Ik wil een database gaan koppelen, maar is dit een beetje de juiste manier?
De DataMapper is dus een laag tussen de Controller en het Model?
Dan mijn volgende vraag:
Ik wil een database gaan koppelen, maar is dit een beetje de juiste manier?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
// newsitem.model.php
class NewsitemModel
{
private $_database;
public function __construct($database)
{
$this->_database = $database;
}
}
// config.php
$host = "localhost";
$database = "";
$username = "";
$password = "";
$pdo = new PDO("mysql: host='.$localhost.'; dbname='.$database.'", "'.$username.'", "'.$password.'");
// news.php
include "config.php";
$model = new NewsitemModel($pdo);
$controller = new NewsitemController($model);
$controller->getAll();
?>
// newsitem.model.php
class NewsitemModel
{
private $_database;
public function __construct($database)
{
$this->_database = $database;
}
}
// config.php
$host = "localhost";
$database = "";
$username = "";
$password = "";
$pdo = new PDO("mysql: host='.$localhost.'; dbname='.$database.'", "'.$username.'", "'.$password.'");
// news.php
include "config.php";
$model = new NewsitemModel($pdo);
$controller = new NewsitemController($model);
$controller->getAll();
?>
Je zou gewoon een BaseModel class kunnen maken die voorziet in de database connectie. Daarna extend je ieder Model van de BaseModel.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
// base.model.php
class BaseModel
{
private $db; // lekker kort :p
public function __construct($database)
{
$this->db= $database;
}
}
// newsitem.model.php
class NewsitemModel extends baseModel
{
public function indexAction()
{
$newsitems = $this->db->getAll('newsitems');
//...
}
}
// blog.model.php
class BlogModel extends baseModel
{
public function indexAction()
{
$blogs = $this->db->getAll('blogs');
//...
}
}
?>
// base.model.php
class BaseModel
{
private $db; // lekker kort :p
public function __construct($database)
{
$this->db= $database;
}
}
// newsitem.model.php
class NewsitemModel extends baseModel
{
public function indexAction()
{
$newsitems = $this->db->getAll('newsitems');
//...
}
}
// blog.model.php
class BlogModel extends baseModel
{
public function indexAction()
{
$blogs = $this->db->getAll('blogs');
//...
}
}
?>
Roy B op 27/05/2014 15:29:34:
@Frank Nietbelangrijk,
Kun je een voorbeeldje geven van hoe de methode load_view eruit ziet?
Waar wordt de locatie van de view meegegeven?
Kun je een voorbeeldje geven van hoe de methode load_view eruit ziet?
Waar wordt de locatie van de view meegegeven?
Dit is een héél erg eenvoudige loader. In werkelijkheid zijn er nog wel wat zaken om rekening mee te houden.
Code (php)
Gewijzigd op 27/05/2014 21:51:30 door Frank Nietbelangrijk
Frank Nietbelangrijk op 27/05/2014 21:39:40:
Roy heb je al ervaring met het extenden van een class?
Je zou gewoon een BaseModel class kunnen maken die voorziet in de database connectie. Daarna extend je ieder Model van de BaseModel.
Je zou gewoon een BaseModel class kunnen maken die voorziet in de database connectie. Daarna extend je ieder Model van de BaseModel.
Nee, maar ik begin het wel te begrijpen.
Ik maak dus de verbinding met de database in mijn BaseModel? Moet ik deze dan ook iedere keer dat ik een Model gebruik de BaseModel aanroepen om een database verbinding te creëren?
Gewijzigd op 28/05/2014 09:23:51 door Roy B
Roy B op 27/05/2014 16:21:22:
Dan mijn volgende vraag:
Ik wil een database gaan koppelen, maar is dit een beetje de juiste manier?
Ik wil een database gaan koppelen, maar is dit een beetje de juiste manier?
Nee dat is het niet. Door je gegevens van de connectie hardcoded in een php bestand te zetten mis je alle flexibiliteit. Als je morgen dezelfde code wilt gaan gebruiken op een andere site (of zelfs maar test en productie omgevingen wilt hebben), dan heb je al een probleem. Configuratie gegevens horen in een configuratie bestand (ini, xml, yaml) en niet in een php script bestand.
Maak van de connectie ook een class en zorg dat je zelfs die class nog eens zou kunnen vervangen. Bijvoorbeeld als je niet van een mysql database, maar van een db2 database gebruik gaat maken, om maar iets te noemen.
Gewijzigd op 28/05/2014 09:18:03 door Erwin H
Roy B op 28/05/2014 09:02:57:
Nee, maar ik begin het wel te begrijpen.
Ik maak dus de verbinding met de database in mijn BaseModel? Moet ik deze dan ook iedere keer dat ik een Model gebruik de BaseModel aanroepen om een database verbinding te creëren of roep ik deze eenmalig ergens aan?
Frank Nietbelangrijk op 27/05/2014 21:39:40:
Roy heb je al ervaring met het extenden van een class?
Je zou gewoon een BaseModel class kunnen maken die voorziet in de database connectie. Daarna extend je ieder Model van de BaseModel.
Je zou gewoon een BaseModel class kunnen maken die voorziet in de database connectie. Daarna extend je ieder Model van de BaseModel.
Nee, maar ik begin het wel te begrijpen.
Ik maak dus de verbinding met de database in mijn BaseModel? Moet ik deze dan ook iedere keer dat ik een Model gebruik de BaseModel aanroepen om een database verbinding te creëren of roep ik deze eenmalig ergens aan?
Iemand nog tips?
Gewijzigd op 03/06/2014 15:12:42 door Roy B
Laat eens zien hoe ver je ondertussen bent?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
// config.php
$host = "localhost";
$database = "";
$username = "";
$password = "";
$pdo = new PDO("mysql:host=".$hostname."; dbname=".$database."", $username, $password);
// newsitem.controller.php
class NewsitemController
{
private $_model;
public function __construct($model)
{
$this->_model = $model;
}
public function getAll()
{
return $this->_model->getAll();
}
}
// model.php
class BaseModel
{
private $_database;
public function __construct($database)
{
$this->_database = $database;
}
}
// newsitem.model.php
class NewsitemModel extends BaseModel
{
public function getAll()
{
$select = "SELECT * FROM newsitems";
$query = $this->_database->query($select);
if($query->rowCount() > 0)
{
return $query->fetchAll();
}
}
}
// news.php
include "config.php";
$model = new NewsitemModel($pdo);
$controller = new NewsitemController($model);
$newsitems = $controller->getAll();
foreach($newsitems AS $newsitem)
{
echo "<h2>".$newsitem["title"]."</h2>";
}
?>
// config.php
$host = "localhost";
$database = "";
$username = "";
$password = "";
$pdo = new PDO("mysql:host=".$hostname."; dbname=".$database."", $username, $password);
// newsitem.controller.php
class NewsitemController
{
private $_model;
public function __construct($model)
{
$this->_model = $model;
}
public function getAll()
{
return $this->_model->getAll();
}
}
// model.php
class BaseModel
{
private $_database;
public function __construct($database)
{
$this->_database = $database;
}
}
// newsitem.model.php
class NewsitemModel extends BaseModel
{
public function getAll()
{
$select = "SELECT * FROM newsitems";
$query = $this->_database->query($select);
if($query->rowCount() > 0)
{
return $query->fetchAll();
}
}
}
// news.php
include "config.php";
$model = new NewsitemModel($pdo);
$controller = new NewsitemController($model);
$newsitems = $controller->getAll();
foreach($newsitems AS $newsitem)
{
echo "<h2>".$newsitem["title"]."</h2>";
}
?>
Gewijzigd op 03/06/2014 15:55:48 door Roy B
Je kunt verschillende dingen anders/beter doen, maar heb je zelf ergens specifieke vragen of twijfels over?
Ward van der Put op 03/06/2014 15:58:32:
Helemaal geen slecht begin, hoor!
Je kunt verschillende dingen anders/beter doen, maar heb je zelf ergens specifieke vragen of twijfels over?
Je kunt verschillende dingen anders/beter doen, maar heb je zelf ergens specifieke vragen of twijfels over?
Thanks! :)
Sowieso zijn tips voor verbeteringen altijd welkom, dus als je tips hebt, graag!
Ik heb nog wel een vraag over het volgende..
Stel ik wil een newsitem ophalen a.d.v. de titel in de URL.
Bijvoorbeeld: ../nieuws/Eerste-nieuwsitem
Wat ik dan terug krijg is $newsitem["title"] etc.
In mijn view gebruik ik liever $titel i.p.v. $newsitem["title"]. Kan dat?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
// newsitem.php
include "../includes/config.php";
$model = new NewsitemModel($pdo);
$controller = new NewsitemController($model);
if(isset($_GET["title"]) AND trim($_GET["title"]) != "")
{
// Select Newsitem by title
$newsitem = $controller->getByTitle($_GET["title"]);
}
// newsitem.controller.php
class NewsitemController
{
private $_model;
public function __construct($model)
{
$this->_model = $model;
}
public function getByTitle($title)
{
$title = str_replace("-", " ", $title);
return $this->_model->getByTitle($title);
}
}
// newsitem.model.php
class NewsitemModel extends BaseModel
{
public function getByTitle($title)
{
$title = str_replace("-", " ", $title);
$select = "SELECT * FROM newsitems WHERE title = :title";
$prepare = $this->_database->prepare($select);
$prepare->bindParam(":title", $title, PDO::PARAM_STR);
$prepare->execute();
if($prepare->rowCount() > 0)
{
return $prepare->fetch();
}
}
}
?>
// newsitem.php
include "../includes/config.php";
$model = new NewsitemModel($pdo);
$controller = new NewsitemController($model);
if(isset($_GET["title"]) AND trim($_GET["title"]) != "")
{
// Select Newsitem by title
$newsitem = $controller->getByTitle($_GET["title"]);
}
// newsitem.controller.php
class NewsitemController
{
private $_model;
public function __construct($model)
{
$this->_model = $model;
}
public function getByTitle($title)
{
$title = str_replace("-", " ", $title);
return $this->_model->getByTitle($title);
}
}
// newsitem.model.php
class NewsitemModel extends BaseModel
{
public function getByTitle($title)
{
$title = str_replace("-", " ", $title);
$select = "SELECT * FROM newsitems WHERE title = :title";
$prepare = $this->_database->prepare($select);
$prepare->bindParam(":title", $title, PDO::PARAM_STR);
$prepare->execute();
if($prepare->rowCount() > 0)
{
return $prepare->fetch();
}
}
}
?>
Gewijzigd op 03/06/2014 16:32:05 door Roy B
http://nl3.php.net/extract
Daar was die extract functie voor. Gewijzigd op 03/06/2014 16:32:41 door jan terhuijzen
1. Je hebt nu een config.php die een PDO-object $pdo definieert.
2. Die $pdo injecteer je in een BaseModel en alle Model-klassen die dit BaseModel extenden.
3. Tot slot gebruik je bijvoorbeeld binnen een class NewsitemModel extends BaseModel code die alleen werkt bij PDO.
Die basisopzet schaalt niet lekker:
• Je opent per request altijd een databaseverbinding, zelfs als je die helemaal niet nodig hebt. Daarmee verbrand je bij een populaire site resources die je hard nodig hebt.
• Je kunt PDO niet soepel vervangen door iets anders, omdat je daarvoor meerdere klassen moet aanpassen.
• Je kunt de databaseverbinding (ongeacht of dat PDO of iets anders is) niet gemakkelijk vervangen, waardoor de applicatie zich bijvoorbeeld niet laat cachen. Je applicaties leunen nu altijd op de database terwijl dat misschien helemaal niet hoeft.
• Je zeult nu één PDO-object $pdo achter je aan door de hele applicatie. Dat kan zowel een voordeel als een nadeel zijn. Je weet het verschil echter pas als je het overdenkt of test.
Dit is, kortom, het eerste onderdeel dat ik nog eens zou overdenken.
Klopt! De connectie met de database is een uitdaging voor later.
Hiervoor wil ik een klasse maken, maar voor nu is dat nog even niet nodig.
Heb je misschien nog tips over de vraag die ik stelde?
Ik wil mijn templates compleet afhankelijk maken van de Controller met enkel variabelen daarin. Dat is nu nog niet. Ik denk dat ik dan moet gaan werken met een Router.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?
// newsitems.php
includes "../includes/config.php";
$model = new Model($pdo);
$controller = new Controller($model);
if(isset($_GET["title"]) AND trim($_GET["title"]) != "")
{
$newsitems = $controller->getByTitle($_GET["title"]);
}
?>
<!DOCTYPE html>
<head>
<title><?php echo $newsitem["title"]; ?></title>
...
// newsitems.php
includes "../includes/config.php";
$model = new Model($pdo);
$controller = new Controller($model);
if(isset($_GET["title"]) AND trim($_GET["title"]) != "")
{
$newsitems = $controller->getByTitle($_GET["title"]);
}
?>
<!DOCTYPE html>
<head>
<title><?php echo $newsitem["title"]; ?></title>
...
Gewijzigd op 03/06/2014 20:05:17 door Roy B
Dat lost in je huidige opzet meteen twee problemen op: de $pdo die je achter je aansleept en controllers die via/via aan het model hangen.
Ward van der Put op 03/06/2014 20:09:29:
Dat lost in je huidige opzet meteen twee problemen op: de $pdo die je achter je aansleept en controllers die via/via aan het model hangen.
Hoe bedoel je via/via?
Roy B op 03/06/2014 20:18:37:
Hoe bedoel je via/via?
Je hebt een te lange aaneenschakeling van onderling afhankelijke objecten. Moeilijk te verwoorden, maar je hebt te veel objecten "in" elkaar zitten; die zou je ze meer "naast" elkaar moeten zetten.
Je opent al in config.php met PDO een databaseverbinding $pdo. Die injecteer je vervolgens in het model NewsitemModel($pdo). Dat model injecteer je tot slot in de controller NewsitemController($model), waarmee je eigenlijk dus NewsitemController(NewsitemModel($pdo)) doet.
Die $pdo hoort daar niet in thuis. Alleen het model weet waar Abraham de mosterd haalt. De NewsitemController is nu nog geen controller, maar meer een "wrapper", een extra en overbodige schil rondom het model:
Code (php)
Al in de constructor maak je zo van de controller een container van het $model. Vervolgens is de methode getByTitle() van de controller slechts een herhaling van getByTitle() van het model. Kortom: deze controller is een kopie van het model.
Heb je tips/voorbeelden voor verbeteringen?
Een database klasse is een begin? En verder?
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
/* Configuratie in bijvoorbeeld config.php */
define('DB_HOST', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'test');
/* Abstract Data Access Object (DAO) */
abstract class AbstractBaseDAO
{
private $Connection;
public function __construct()
{
$this->connect();
}
private function connect()
{
$this->Connection = new \MySQLi(DB_HOST, DB_USERNAME, DB_PASSWORD);
$this->Connection->select_db(DB_NAME);
}
/**
* @param void
* @return array|null
*/
public function fetchAll()
{
$query = 'SELECT * FROM ' . $this->TableName;
if ($result = $this->Connection->query($query)) {
if ($result->num_rows == 0) {
return null;
} else {
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
return $rows;
}
} else {
return null;
}
}
}
?>
/* Configuratie in bijvoorbeeld config.php */
define('DB_HOST', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'test');
/* Abstract Data Access Object (DAO) */
abstract class AbstractBaseDAO
{
private $Connection;
public function __construct()
{
$this->connect();
}
private function connect()
{
$this->Connection = new \MySQLi(DB_HOST, DB_USERNAME, DB_PASSWORD);
$this->Connection->select_db(DB_NAME);
}
/**
* @param void
* @return array|null
*/
public function fetchAll()
{
$query = 'SELECT * FROM ' . $this->TableName;
if ($result = $this->Connection->query($query)) {
if ($result->num_rows == 0) {
return null;
} else {
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
return $rows;
}
} else {
return null;
}
}
}
?>
Nu zeul je geen $pdo met geopende databaseverbinding achter je aan in alle modelklassen. Wil je de database-opzet veranderen, dan hoef je slechts op één plaats de code te herschrijven, hier in de methode connect().
Zoals gezegd, weet alleen het model waar Abraham de mosterd haalt. En die models kunnen we nu ook sterk vereenvoudigen, want daaruit verdwijnt alle PDO-specifieke PHP-code. Je kunt met deze eerste opzet bijvoorbeeld al alle nieuwsberichten ophalen via fetchAll(). Het enige model dat je daarvoor nodig hebt, is:
Code (php)
That's it. De abstract class AbstractBaseDAO is er voor de database en de class NewsitemModel extends AbstractBaseDAO voor een specifieke databasetabel.
Er zijn meer design patterns; dit is slechts een voorbeeld. Je kunt het op verschillende manieren aanpakken, bijvoorbeeld ook met een data mapper pattern of met een active record pattern.
Ik ga hier mee aan de slag :)
Dan nog even heel iets anders tussendoor..
Alle URL's worden doorgestuurd naar mijn index.php d.m.v. htaccess.
In mijn index.php haal ik de URL op met $_SERVER["REQUEST_URI"].
Stel dat mijn URL /nieuws/dit-is-een-nieuwsitem is. Dan moet de NewsitemController worden aangeroepen en vervolgens de actie $controller->getByTitle($title) worden uitgevoerd. Maar is mijn URL /nieuws moet de actie $controller->getAll() worden uitgevoerd.
Heb je hier nog tips voor?
Gewijzigd op 04/06/2014 11:51:30 door Roy B
Maar waarschijnlijk handelt index.php in de root als de "front controller" meer af dan alleen /nieuws/ en dan kun je het beste een apart object voor MVC-routing gebruiken dat beslist welke controllers worden aangesproken.
In plaats van $_SERVER['REQUEST_URI'] zou ik zelf een aparte variabele gebruiken, bijvoorbeeld $_GET['route'] met:
Mijn index.php handelt inderdaad meer af dan alleen /nieuws. Alle URL's worden hier afgehandeld, zoals dat hoort bij een MVC heb ik gelezen. Ik heb ook iets gelezen over een Router. Kun je mij op weg helpen hiermee?
Gewijzigd op 04/06/2014 12:33:24 door Roy B