Hallo allemaal,

Na het lezen van de tut van Blache wilde ik een kijken of mijn eigen OOP kunsten een beetje in orde zijn.

Nu heb ik deze 2 classes:

<?php

/**
* CLASS
*/

class Page {
private $_id;
private $_title;
private $_content;
private $_parentId;
private $_isHome;

public function __construct() {
$this->_id = 0;
$this->_title = '';
$this->_content = '';
$this->_parentId = null;
$this->_isHome = 0;
}

public function setId($id) {
if(ctype_digit($id)) {
$this->_id = $id;
} else {
throw new Exception('Id is not a digit.');
}
}

public function setTitle($title) {
if(ctype_alnum($title)) {
$this->_title = $title;
} else {
throw new Exception('Title is not alphanumaric.');
}
}

public function setContent($content) {
$this->_content = $content;
}

public function setParentId($parentId) {
if(ctype_digit($parentId) || $parentId === null) {
$this->_parentId = $parentId;
} else {
throw new Exception('ParentId is neither a digit nor NULL.');
}
}

public function setIsHome($isHome) {
if($isHome == 0 || $isHome == 1) {
$this->_isHome = $isHome;
} else {
throw new Exception('IsHome is not 0 or 1.');
}
}

public function getId() {
return $this->_id;
}

public function getTitle() {
return $this->_title;
}

public function getContent() {
return $this->_content;
}

public function getParentId() {
return $this->_parentId;
}

public function getIsHome() {
return $this->_isHome;
}
}

class Page_Controller {
private function $_page;

public function __construct(Page $page) {
$this->_page = $page;
}

public function new() {
mysql_query("
INSERT INTO
pages
(
title,
content,
parent_id,
is_home
)
VALUES
(
'" . $this->_page->getTitle() . "',
'" . mysql_real_escape_string($this->_page->getContent()) . "',
'" . $this->_page->getParentId() . "',
'" . $this->_page->getIsHome() . "'
)
");
}

public function edit() {
mysql_query("
UPDATE
pages
SET
title = '" . $this->_page->getTitle() . "',
content = '" . mysql_real_escape_string($this->_page->getContent()) . "',
parent_id = '" . $this->_page->getParentId() . "',
is_home = '" . $this->_page->getIsHome() . "'
WHERE
id = '" . $this->_page->getId() . "'
");
}

public function delete() {
mysql_query("DELETE FROM pages WHERE id = '" . $this->_page->getId() . "'");
}

public function getData() {
$result = mysql_query("SELECT * FROM pages WHERE id = '" . $this->_page->getId() . "'");
return mysql_fetch_assoc($result);
}
}

/**
* USAGE
*/

try {
/* create a page */
$page = new Page();
$page->setTitle('Sub pagina');
$page->setContent('Lorum ipsum..');
$page->setParentId(1);
$page->setIsHome(0);

$pageController = new Page_Controller($page);
$pageController->new();

/* edit a page */
$page = new Page();
$page->setId(1);
$page->setTitle('Hoofd pagina');
$page->setContent('Lipsum lorum pipsum..');
$page->setParentId(null);
$page->setIsHome(1);

$pageController = new Page_Controller($page);
$pageController->edit();

/* delete a page */
$page = new Page();
$page->setId(1);

$pageController = new Page_Controller($page);
$pageController->delete();

/* get data of a page */
$page = new Page();
$page->setId(1);

$pageController = new Page_Controller($page);
print_r($pageController->getData());

} catch (Exception $e) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}

?>

Ik heb er voor gekozen om verschillende "set" functies te maken, en niet alles via de constructor mee te geven.
Dit heb ik gedaan omdat je bij het verwijderen van een pagina alleen het id nodig hebt, bij het bewerken echter ook de titel, inhoud etc..

Ik hoor graag jullie mening.

Groetjes,
Boris

ps: ik zou idd een PDO achtig iets moeten gebruiken voor m'n database werk, maar dit heb ik net ff snel in elkaar geflanst had geen zin om dat uit te gaan zoeken. Misschien dat ik dat na jullie reviews nog ff doe.. ;)
In de Page_Controller:
<?php
private function $_page;
?>
Dit klopt niet, je moet 'function' daar even weghalen.

Verder zijn die mysql_query()'s daar niet erg gelukkig. In principe zou je nu een query uit proberen te voeren zonder dat er een verbinding met de database opgezet is. Dat zul jij dus altijd nog moeten doen voordat je deze class gebruikt en dat is niet gewenst. (Maar dat zei je zelf ook al :))

Dit heb ik gedaan omdat je bij het verwijderen van een pagina alleen het id nodig hebt, bij het bewerken echter ook de titel, inhoud etc..
Bij het verwijderen heb je dan ook niet per se een Page object nodig. Je zou ervoor kunnen kiezen om je Page_Controller te voorzien van een method deletePageById($pageId). In de constructor van je Page_Controller moet je dan ook geen Page object vragen, je kunt het Page object ook meegeven op het moment dat je de actie uitvoert. Wat je wél aan die constructor mee zou moeten geven, is een Database object dat de communicatie met de database verzorgt.

Blanche,
Dat was idd een typo, en ik heb er nu ook een database klasse bij gebouwd (of eigenlijk gekopieerd van php.net)

Resultaat:
<?php

/**
* CLASS
*/

class DB {
protected static $_host = 'localhost';
protected static $_user = 'root';
protected static $_pass = '***';
protected static $_dbname = 'site_db';

private static $objInstance;

private function __construct() {}
private function __clone() {}

public static function getInstance( ) {
if(!self::$objInstance){
self::$objInstance = new PDO('mysql:host=' . self::$_host . ';dbname=' . self::$_dbname, self::$_user, self::$_pass);
self::$objInstance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$objInstance;
}

final public static function __callStatic( $chrMethod, $arrArguments ) {
$objInstance = self::getInstance();
return call_user_func_array(array($objInstance, $chrMethod), $arrArguments);
}
}

class Page {
private $_id;
private $_title;
private $_content;
private $_parentId;
private $_isHome;

public function __construct() {
$this->_id = 0;
$this->_title = '';
$this->_content = '';
$this->_parentId = null;
$this->_isHome = 0;
}

public function setId($id) {
if(ctype_digit($id)) {
$this->_id = $id;
} else {
throw new Exception('Id is not a digit.');
}
}

public function setTitle($title) {
if(ctype_alnum($title)) {
$this->_title = $title;
} else {
throw new Exception('Title is not alphanumaric.');
}
}

public function setContent($content) {
$this->_content = $content;
}

public function setParentId($parentId) {
if(ctype_digit($parentId) || $parentId === null) {
$this->_parentId = $parentId;
} else {
throw new Exception('ParentId is neither a digit nor NULL.');
}
}

public function setIsHome($isHome) {
if($isHome == 0 || $isHome == 1) {
$this->_isHome = $isHome;
} else {
throw new Exception('IsHome is not 0 or 1.');
}
}

public function getId() {
return $this->_id;
}

public function getTitle() {
return $this->_title;
}

public function getContent() {
return $this->_content;
}

public function getParentId() {
return $this->_parentId;
}

public function getIsHome() {
return $this->_isHome;
}
}

class Page_Controller {
private $_page;

public function __construct(Page $page) {
$this->_page = $page;
$this->_db = new Database();
}

public function new() {
$query = "
INSERT INTO
pages
(
title,
content,
parent_id,
is_home
)
VALUES
(
:title,
:content,
:parentId,
:isHome
)
";
$stmt = DB::prepare($query);
$stmt->bindParam(':title', $this->_page->getTitle(), PDO::PARAM_STR);
$stmt->bindParam(':content', $this->_page->getContent(), PDO::PARAM_STR);
$stmt->bindParam(':parentId', $this->_page->getParentId(), PDO::PARAM_STR);
$stmt->bindParam(':isHome', $this->_page->getIsHome(), PDO::PARAM_STR);
$stmt->execute();
}

public function edit() {
$query = "
UPDATE
pages
SET
title = :title
content = :content
parent_id = :parentId
is_home = :isHome
WHERE
id = :id
";
$stmt = DB::prepare($query);
$stmt->bindParam(':title', $this->_page->getTitle(), PDO::PARAM_STR);
$stmt->bindParam(':content', $this->_page->getContent(), PDO::PARAM_STR);
$stmt->bindParam(':parentId', $this->_page->getParentId(), PDO::PARAM_STR);
$stmt->bindParam(':isHome', $this->_page->getIsHome(), PDO::PARAM_STR);
$stmt->bindParam(':id', $this->_page->getId(), PDO::PARAM_STR);
$stmt->execute();
}

public function delete() {
DB::exec("DELETE FROM pages WHERE id = '" . $this->_page->getId() . "'");
}

public function getData() {
return DB:query("SELECT * FROM pages WHERE id = '" . $this->_page->getId() . "'");
}
}

/**
* USAGE
*/

try {
/* create a page */
$page = new Page();
$page->setTitle('Sub pagina');
$page->setContent('Lorum ipsum..');
$page->setParentId(1);
$page->setIsHome(0);

$pageController = new Page_Controller($page);
$pageController->new();

/* edit a page */
$page = new Page();
$page->setId(1);
$page->setTitle('Hoofd pagina');
$page->setContent('Lipsum lorum pipsum..');
$page->setParentId(null);
$page->setIsHome(1);

$pageController = new Page_Controller($page);
$pageController->edit();

/* delete a page */
$page = new Page();
$page->setId(1);

$pageController = new Page_Controller($page);
$pageController->delete();

/* get data of a page */
$page = new Page();
$page->setId(1);

$pageController = new Page_Controller($page);
print_r($pageController->getData());

} catch (Exception $e) {
echo 'Caught exception: '. $e->getMessage() ."\n";
}

?>
En zou jij misschien een voorbeeld (in de vorm van code (A)) kunnen geven van hoe jij dat ziet met dat deletePageById() verhaal icm de Page klasse?

Groet en bij voorbaat dank,
Boris

edit: prepared statements toegevoegd
Waarom is de page_controller gebonden aan één enkele page?

Waarom gebruik je DB::prepare? Wat is dan het verschil met mysql_query, en welk punt van Blanche mis je hier nu? edit: ooh, ik zie dat Blanche een ander punt maakt. In ieder geval: het is vaak onhandig om één databaseverbinding in je hele applicatie te hebben. Soms is het zo dat je gebruikers uit een andere database wilt hebben dan pagina's, en dan heb je met zo'n static DB::prepare() aanroep een probleem. Andere situaties zouden kunnen zijn dat je naar een andere db schrijft dan dat je leest, of dat je een verbinding in een transactie hebt zitten en toch andere dingen direct wilt opslaan, en dus een tweede verbinding nodig hebt. En natuurlijk het principe. Een static aanroep is niets anders dan een functie-aanroep, en is niet een goed voorbeeld van Object Georiënteerd programmeren.

Ik zou het meer zoeken in de richting van
<?php
class Page_Controller
{
protected $db;

public function __construct(PDO $pdo)
{
$this->db = $pdo;
}

public function insert(Page $page)
{
$stmt = $this->db->prepare("UPDATE pages ....");
}

public function delete(Page $page)
{
$stmt = $this->db->prepare("UPDATE pages ....");
}
}

$controller = new Page_Controller(new PDO('...'));

$home = new Page();
$controller->insert($home);

$about = new Page();
$controller->insert($about);
?>
Beste Jelmer,

Bedankt voor je reactie!
Inderdaad een goeie opmerking over die Database en Page!
Heb het aangepast.

Code staat nu hier:
http://www.codedump.be/code/482/
Werd een beetje te lang voor op het forum vond ik..

Ik heb nu een klasse Database die PDO extend, ik weet dat dit niet helemaal juist is, maar het biedt wel vele mogelijkheden. (bijvoorbeeld de functies insert, update etc..)

Groetjes,
Boris
PDO extenden is prima hoor :)

Volgens mij is je code nu prima. Niets meer op aan te merken :D

(werkt dat trouwens? new als functienaam? Volgens mij krijg je dan iets met unexpected keyword parse error)
Mooi ! :D

Of het werkt weet ik niet, heb nog helemaal niks ervan getest ;)
Was gewoon om ff te kijken hoe en wat ;)

Nog ff een vraagje, gebruiken jullie vaak "get" methods bijv:
$page->getId();
of doe je gewoon:
$page->id;

Groet,
Omdat ik het toch wel erg handig vind om functies te hebben bij het uitlezen van variabelen gebruik ik wel getters, maar omdat ze zo gewoon zijn maak ik ze niet gebiedende-wijs. Dus $page->id().

De logica erachter is alles wat gebiedende wijs is past $page aan, alles wat meer alleen een naam is, of als een vraag gelezen kan worden, verandert niets aan m'n $page object. Bijvoorbeeld if($page->id() == 24) en if($page->isHidden()) is duidelijk read-only. $page->makeDefault(), $page->setId(), $page->validate() zijn methods die $page aan kunnen passen. ($page->isValid() weer niet, en zo is er voor iedere gebiedende wijs ook wel een vragende vorm te verzinnen)

Reageren