<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>deadlime &#187; PDO</title>
	<atom:link href="http://deadlime.hu/tag/pdo/feed/" rel="self" type="application/rss+xml" />
	<link>http://deadlime.hu</link>
	<description>unexpected terminator</description>
	<lastBuildDate>Mon, 14 May 2012 20:38:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>PDO móka: l33t SQL</title>
		<link>http://deadlime.hu/2009/09/05/pdo-moka-l33t-sql/</link>
		<comments>http://deadlime.hu/2009/09/05/pdo-moka-l33t-sql/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 19:58:07 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[PDO]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://deadlime.hu/?p=169</guid>
		<description><![CDATA[Már lassan egy éve nem volt új bejegyzés, gondoltam ideje írni valamit. :) Régebben már volt szó a PHP objektum-orientált adatbázis elérési felületéről, a PDO-ról. Mivel utóbb inkább csak a használatára tértem ki, nem lett megemlítve, hogy ezekből az osztályokból származtathatjuk saját osztályainkat is, ami alapvetően egy jó dolog tud lenni. Vegyünk is egy egyszerű [...]]]></description>
			<content:encoded><![CDATA[<p>Már lassan egy éve nem volt új bejegyzés, gondoltam ideje írni valamit. :) Régebben már volt szó <a href="http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/">a PHP objektum-orientált adatbázis elérési felületéről</a>, a PDO-ról. Mivel utóbb inkább csak a használatára tértem ki, nem lett megemlítve, hogy ezekből az osztályokból származtathatjuk saját osztályainkat is, ami alapvetően egy jó dolog tud lenni.</p>

<p>Vegyünk is egy egyszerű példát. Tegyük fel azt, hogy már annyira jók vagyunk, hogy az SQL szerverrel is csak <a href="http://en.wikipedia.org/wiki/Leet">l33t nyelven</a> vagyunk hajlandóak kommunikálni. Persze a mysqld (vagy egyéb tetszőleges daemon) nem ilyen megértő, és folyamatosan panaszkodik, hogy nem ért meg minket. A probléma elsimítása érdekében származtatunk a beépített PDO osztályból egy sajátot:</p>

<pre class="code prettyprint lang-php">class L33tPDO extends PDO {
	private static $from = array(
		's3l3ct', 'fr0m', 'wh3r3', 's3t', '1ns3rt', '1nt0', 'upd4t3', '0rd3r', '4sc', 'd3sc', 'l3ft', 'r1ght', '1nn3r', 'j01n'
	);
	private static $to = array(
		'SELECT', 'FROM', 'WHERE', 'SET', 'INSERT', 'INTO', 'UPDATE', 'ORDER', 'ASC', 'DESC', 'LEFT', 'RIGHT', 'INNER', 'JOIN'
	);
	public function query($statement, $type = false, $param1 = false, $param2 = false) {
		$statement = $this-&gt;convertStatement($statement);
		
		if ($type &amp;&amp; $param1 &amp;&amp; $param2) {
			return parent::query($statement, $type, $param1, $param2);
		}
		if ($type &amp;&amp; $param1) {
			return parent::query($statement, $type, $param1);
		}
		if ($type) {
			return parent::query($statement, $type);
		}
		
		return parent::query($statement);
	}
	public function prepare($statement, $driver_options = array()) {
		$statement = $this-&gt;convertStatement($statement);
		parent::prepare($statement, $driver_options);
	}
	private function convertStatement($statement) {
		return str_ireplace(self::$from, self::$to, $statement);
	}
}</pre>

<p>Hogy takarékoskodjunk a hellyel, a kulcsszavak listája nem teljes. Nézzünk is egy példát a  használatra:</p>

<pre class="code prettyprint lang-php">$conn = new L33tPDO('pgsql:host=localhost port=5432 dbname=test user=test password=test');

$stmt = $conn-&gt;query(&quot;s3l3ct * fr0m users wh3r3 id &gt; 1 0rd3r by login_name 4sc&quot; );

var_dump($stmt-&gt;fetchAll());</pre>

<p>Bár a felhozott példa nem igényli, a PDOStatement osztályból is származtathatunk sajátot, csak meg kell mondanunk a saját PDO osztályunknak, hogy az általunk írt PDOStatement-tet adja vissza a megfelelő függvényei. Ehhez bővítsük ki a L33tPDO osztályunkat egy konstruktorral:</p>

<pre class="code prettyprint lang-php">function __construct($dsn, $username = null, $password = null, $driver_options = array()) {
	parent::__construct($dsn, $username, $password, $driver_options);
	
	$this-&gt;setAttribute(PDO::ATTR_STATEMENT_CLASS, array('L33tPDOStatement', array($this)));
}</pre>

<p>És egy hozzá passzoló statement osztály:</p>

<pre class="code prettyprint lang-php">class L33tPDOStatement extends PDOStatement {
	private $dbh;
	protected function __construct($dbh) {
		$this -&gt; dbh = $dbh;
	}
}</pre>

<p>Ennyit mára. További kellemes kódolást.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2009/09/05/pdo-moka-l33t-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ajax-os tennivalók</title>
		<link>http://deadlime.hu/2006/10/21/ajax-os-tennivalok/</link>
		<comments>http://deadlime.hu/2006/10/21/ajax-os-tennivalok/#comments</comments>
		<pubDate>Sat, 21 Oct 2006 06:20:03 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[Ajax]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PDO]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/10/21/ajax-os-tennivalok/</guid>
		<description><![CDATA[A minap találkoztam össze a twofifty.org oldallal, ahol az ember trendi Ajax-os rendszer segítségével kihuzogathatja az IMDb 250-es listából azokat a filmeket, amiket látott. Meg mellesleg kommenteket is lehet hozzá fűzni, meg vannak statisztikák is nem, kor szerinti bontásban. Amellett, hogy meglepően kevés filmet láttam ebből a listából, eszembe jutott, hogy mekkora jó lenne már [...]]]></description>
			<content:encoded><![CDATA[<p>A minap találkoztam össze a <a href="http://twofifty.org/">twofifty.org</a> oldallal, ahol az ember trendi Ajax-os rendszer segítségével kihuzogathatja az <a href="http://imdb.com/chart/top">IMDb 250-es listából</a> azokat a filmeket, amiket látott. Meg mellesleg kommenteket is lehet hozzá fűzni, meg vannak statisztikák is nem, kor szerinti bontásban. Amellett, hogy meglepően kevés filmet láttam ebből a listából, eszembe jutott, hogy mekkora jó lenne már egy olyan kis alkalmazás, ahol az ember a tennivalóit tudná hasonló módon kihuzogatni. Gyorsan össze is dobtam egy ilyen kis oldalacskát a Prototype és a PDO segítségével.</p>

<p>Először talán kezdjük az adatbázis táblával, ami roppant egyszerű lesz, mivel nem akartam a dolgot túlbonyolítani, csak egyszerűen kedvet éreztem egy ilyen kis rendszer megvalósításához:</p>

<pre class="code prettyprint lang-sql">CREATE TABLE `todo` (
	`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`description` TEXT NOT NULL,
	`status` ENUM('0', '1') NOT NULL DEFAULT '0'
) ENGINE = MYISAM;</pre>

<p>Persze adatok se ártanak bele:</p>

<pre class="code prettyprint lang-sql">INSERT INTO `todo` (`ID`, `description`, `status`) VALUES
(NULL, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.', '0'),
(NULL, 'Suspendisse luctus, sem at pretium interdum, dolor velit pellentesque turpis, eu volutpat velit neque vel nulla.', '0'),
(NULL, 'Praesent ligula dolor, vehicula sed, facilisis ac, gravida et, elit. Morbi id urna.', '0');</pre>

<p>Aztán a HTML-PHP vonallal folytattam a munkát, a következő pár soros kód legenerálja nekünk a listát (aki esetleg nem mozog annyira otthonosan a PDO világában, annak tudom ajánlani <a href="http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/">egy régebbi bevezető jellegű írásomat</a>):</p>

<pre class="code prettyprint lang-php">print '&lt;div id=&quot;error&quot;&gt;&amp;nbsp;&lt;/div&gt;';
print '&lt;ul id=&quot;todo&quot;&gt;';
$db = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
foreach ($db-&gt;query(&quot;SELECT * FROM `todo`&quot;) as $row) {
	print '&lt;li id=&quot;task-'.$row['ID'].'&quot;'.($row['status'] === '1' ? ' class=&quot;done&quot;' : ' class=&quot;not-done&quot;').'&gt;'.htmlspecialchars($row['description']).'&lt;/li&gt;';
}
$db = NULL;
print '&lt;/ul&gt;';</pre>

<p>Ez után már tényleg nincs is más hátra, mint a Prototype segítségével megírni a szükséges JavaScript kódot. Először is az oldal betöltődése után az összes listatagnak elkezdjük figyelni a click eseményét:</p>

<pre class="code prettyprint lang-javascript">Event.observe(window, 'load', function(e) {
	var todos = $('todo').getElementsByTagName('li');

	for (var i = 0; i &lt; todos.length; ++i) {
		Event.observe(todos[i], 'click', listElementClick);
	}
});</pre>

<p>Miután ez megvan, már nincs más dolgunk, mint a listElementClick nevezetű függvény, ami annyit tesz, hogy az adott ID-jű feladat státuszát az adatbázisban megváltoztatja, majd siker esetén a listaelem stílusát az új státuszhoz igazítja (ha 'done' volt akkor 'not-done' lesz, ha 'not-done' volt, akkor pedig 'done').</p>

<pre class="code prettyprint lang-javascript">function listElementClick(e) {
	$('error').innerHTML = '&amp;nbsp;';

	var t;
	if (e.srcElement) t = e.srcElement;
	else t = e.target;

	var tmp = t.id.split('-');
	var ID = tmp[1];
	var status = 0;

	if (t.className == 'not-done') status = 1;
	else status = 0;

	/* ... */
}</pre>

<p>Nos, ezzel így még nem sok mindent csináltunk, csak előkészítettük a terepet a <code>/* ... */</code> helyére kerülő Ajax kérésnek, ami pedig a következő lesz:</p>

<pre class="code prettyprint lang-javascript">var req = new Ajax.Request(
	'process.php',
	{
		method     : 'post',
		parameters : 'ID='+ID+'&amp;status='+status,
		onComplete : function(req) {
			var response_status = req.responseText.split(',');

			if (response_status[0] == '1') {
				$('task-'+response_status[1]).className = response_status[2];
			}
			else {
				$('error').innerHTML = 'Nem sikerült módosítani a tennivaló státuszát!';
			}
		}
	}
);</pre>

<p>Már csak a process.php tartalma van hátra, ami tulajdonképpen elvégzi a szükséges adatbázis műveleteket és visszatér egy <code>[módosítás státusza],[feladat ID-je],[új css osztály neve]</code> formátumú listával.</p>

<pre class="code prettyprint lang-php">header('Content-Type: text/plain');

if (isset($_POST['ID']) &amp;&amp; isset($_POST['status'])) {
	try {
		$db = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
		$db-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

		$db-&gt;query(&quot;UPDATE `todo` SET `status`='&quot;.(int)$_POST['status'].&quot;' WHERE `ID`='&quot;.(int)$_POST['ID'].&quot;'&quot;);

		echo '1,'.$_POST['ID'].','.($_POST['status'] === '1' ? 'done' : 'not-done');
	}
	catch (PDOException $e) {
		echo '0';
	}
}
else {
	echo '0';
}</pre>

<p>És ha minden kis darabkát sikerült a megfelelő helyre illesztenünk, akkor az oldalt betöltve kattintgathatjuk is a feladatokat, ami nagyszerűen látszik is, ha megfelelő CSS-t is csatolunk a dokumentumunkhoz. Valami ilyesmi egyszerű meg is teszi:</p>

<pre class="code prettyprint lang-css">#todo li {
	cursor: pointer;
}
.done {
	color: gray;
	text-decoration: line-through;
}
.not-done {
	color: black;
	text-decoration: none;
}
#error {
	font-size: 14px;
	color: red;
	font-weight: bold;
}</pre>

<p>Ezzel meg is volnánk. Mint azt az elején is említettem, nem bonyolítottam túl a dolgokat semmiféle extrával. A működő <a href="http://kriz.deadlime.hu/todo/">példa megtekinthető itt</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/10/21/ajax-os-tennivalok/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mi is az a PDO?</title>
		<link>http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/</link>
		<comments>http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/#comments</comments>
		<pubDate>Sat, 11 Feb 2006 18:34:42 +0000</pubDate>
		<dc:creator>Nagy Krisztián</dc:creator>
				<category><![CDATA[nincs kategória]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PDO]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/</guid>
		<description><![CDATA[Gondolom sokaknak megfordult a fejében (akik 2 percnél többet töltöttek el a PHP tanulmányozásával és adatbázis kapcsolatot is próbáltak létesíteni), hogy kellene valami egységesebb felület (mondjuk egy adatbázis objektum), ha például a rendszerünket MySQL alapokról PostgreSQL-re akarnánk átvinni, vagy csak egyszerűen szeretnénk, hogy valahogy kinézzen az a kód. Gondolom akadnak olyanok is, akik fogták magukat [...]]]></description>
			<content:encoded><![CDATA[<p>Gondolom sokaknak megfordult a fejében (akik 2 percnél többet töltöttek el a PHP tanulmányozásával és adatbázis kapcsolatot is próbáltak létesíteni), hogy kellene valami egységesebb felület (mondjuk egy adatbázis objektum), ha például a rendszerünket MySQL alapokról PostgreSQL-re akarnánk átvinni, vagy csak egyszerűen szeretnénk, hogy valahogy kinézzen az a kód. Gondolom akadnak olyanok is, akik fogták magukat és megírták ezt a bizonyos objektumot (vagy objektumokat), vagy olyanok, akik a <a href="http://pear.php.net/package/DB"><acronym title="PHP Extension and Application Repository">PEAR</acronym> által kínált megoldást</a> találták megfelelőnek. Viszont a PHP 5.1-es verziójától már beépített megoldás is van erre az égető problémára egy kiterjesztés-csoport személyében.</p>

<p>A <a href="http://php.net/pdo"><acronym title="PHP Data Objects">PDO</acronym></a> nem más mint egy objektum az adatbázis kapcsolatok, lekérdezések, stb. kényelmes, hatékony, átlátható kezelésére. No de lássunk egy "ilyen volt, ilyen lett" példát, csak a mondani valóm nyomatékosítása érdekében (aztán majd rátérünk a PDO mélyrehatóbb elemzésére):</p>

<pre class="code prettyprint lang-php">$conn = mysql_connect('localhost', 'user', 'password');
mysql_select_db('database', $conn);

$query = mysql_query(&quot; SELECT * FROM `table` &quot;, $conn);
while ($row = mysql_fetch_assoc($query)) {
    print_r($row);
}
mysql_close($conn);</pre>

<p>Nézzük csak, mi lett belőle:</p>

<pre class="code prettyprint lang-php">$db = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
foreach ($db-&gt;query(&quot; SELECT * FROM `table` &quot;) as $row) {
    print_r($row);
}
$db = NULL;</pre>

<p>Ízlés kérdése, de nekem az utóbbi jobban tetszik. Talán érdemes lenne az osztályok szerkezetének a vizsgálatával folytatni a dolgokat. A rendszer három osztályból áll, amik a <code>PDO</code>, <code>PDOStatement</code> és a <code>PDOException</code>. Az első fontosabb függvényei a <code>query</code>, <code>prepare</code>, <code>exec</code>, <code>beginTransaction</code>, <code>commit</code>. Míg a másodiké (természetesen mindkét esetben a teljesség igénye nélkül) a <code>fetch</code>, <code>fetchAll</code>, <code>rowCount</code>, <code>bindParam</code>, <code>execute</code>. A harmadik osztály (a nevéből talán nem nehéz rájönni) a kivételkezelést hivatott elősegíteni. Amint az sejthető, a dolog például úgy működik, hogy a <code>PDO</code> osztály <code>query</code> függvénye visszaad egy <code>PDOStatement</code> típusú érétket, aminek függvényeivel megkaphatjuk a kívánt sorokat vagy dob egy PDOException típusú kivételt.</p>

<h3>Tranzakciók</h3>

<p>Aki annak idejé olvasta Polaa PostgreSQL bejegyzés-sorozatát, annak nem lehet annyira ismeretlen ez a fogalom. A dolog lényege dióhéjban annyi, hogy egy blokkban vagy mindegyik SQL utasítás végrehajtódik, vagy pedig egyik sem. Eléggé szemléletes a mindenhol felhozott banki átutalásos példa, ahol az egyik lekérdezés leveszi "A" ügyfél számlájáról a pénzt, a második pedig rárakja "B" számlájára. Ez esetben azt szeretnénk, hogy ha nem sikerül az első lépés, akkor a második se hajtódjon végre. Nézzünk kódot, mert az érdekesebb:</p>

<pre class="code prettyprint lang-php">try {
    $db = new PDO('mysql:host=localhost;dbname=database', 'user', 'password');
    $db-&gt;setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $db-&gt;beginTransaction();
    $db-&gt;exec(&quot; UPDATE `accounts` SET `account_value`=`account_value`-100 WHERE `account_id`='1' &quot;);
    $db-&gt;exec(&quot; UPDATE `accounts` SET `account_value`=`account_value`+100 WHERE `account_id`='2' &quot;);
    $db-&gt;commit();
} catch (PDOException $e) {
    $db-&gt;rollBack();
}</pre>

<dl>
<dt><code>setAttribute</code></dt>
<dd>Az adatbázis kezelő objektum tulajdonságait tudjuk vele beállítani különböző, a PDO objektumban tárolt konstansokkal. Ez esetben az lett beállítva, hogy - az alapértelmezettől eltérően - kivételt dobjon hiba esetén.</dd>
<dt><code>beginTransaction</code></dt>
<dd>Jelzi, a tranzakció kezdetét.</dd>
<dt><code>commit</code></dt>
<dd>A tranzakció lefuttatása.</dd>
<dt><code>rollBack</code></dt>
<dd>A tranzakció visszavonása.</dd>
</dl>

<h3>Előkészített lekérdezések</h3>

<p>Ez egy tipikusan olyan dolog volt, amit annak idején hiányoltam MySQL-ben és, ami miatt sikerült elég gyorsan megkedvelnem a PostgreSQL-t. A dolog már a neve alapján is teljesen egyértelmű, de a kód is önmagáért fog beszélni, tehát csapjunk is a lecsóba:</p>

<pre class="code prettyprint lang-php">$db = new PDO('pgsql:host=localhost;dbname=database;user=user;password=password');
$pre = $db-&gt;prepare(' INSERT INTO &quot;attrs&quot; (&quot;id&quot;, &quot;name&quot;) VALUES (:id, :name) ');
$pre-&gt;execute(array(':id' =&gt; '1', ':name' =&gt; '12'));
$pre-&gt;execute(array(':id' =&gt; '2', ':name' =&gt; '43'));</pre>

<p>A PDO prepare részének az is a nagy előnye, hogy elég sokféleképpen használható. Itt van például egy másik megoldás is, ahol a kérdőjelek sorrendben cserélődnek le a tömb egyes elemeire, ugyanazt elérve mint az előző kódblokkban (az adatbázis kapcsolatot elhagytam):</p>

<pre class="code prettyprint lang-php">$pre = $db-&gt;prepare(' INSERT INTO &quot;attrs&quot; (&quot;id&quot;, &quot;name&quot;) VALUES (?, ?) ');
$pre-&gt;execute(array('1', '12'));
$pre-&gt;execute(array('2', '43'));</pre>

<p>Jöjjön még egy megoldás két variációja, ami mégjobban leegyszerüsíti az előkészített lekérdezések használatát (a végeredmény ugyanaz, mint az előző esetekben).</p>

<pre class="code prettyprint lang-php">$pre = $db-&gt;prepare(' INSERT INTO &quot;attrs&quot; (&quot;id&quot;, &quot;name&quot;) VALUES (:id, :value) ');
$pre-&gt;bindParam(':id', $id);
$pre-&gt;bindParam(':value', $value);

$id = '1';
$value= '12';
$pre-&gt;execute();
$id = '2';
$value= '43';
$pre-&gt;execute();</pre>

<p>Vagy a másik megoldás (ismét kérdőjeleket használva a beillesztések helyeinek meghatározására):</p>

<pre class="code prettyprint lang-php">$pre = $db-&gt;prepare(' INSERT INTO &quot;attrs&quot; (&quot;id&quot;, &quot;name&quot;) VALUES (?, ?) ');
$pre-&gt;bindParam(1, $id);
$pre-&gt;bindParam(2, $value);

$id = '1';
$value = '12';
$pre-&gt;execute();
$id = '2';
$value = '43';
$pre-&gt;execute();</pre>

<p>Azt hiszem ennyi lenne a kis ismertető a PDO kiterjesztéssel kapcsolatban. Kedvcsinálásnak talán megteszi, mindenesetre mégegyszer megjegyezném, hogy az igazi ereje a dolognak abban rejlik (azon felül, hogy a kódot átláthatóbbá teszi, aminek az erejét sosem szabad lebecsülni), hogy akár egy sor átírása elég lehet ahhoz, hogy egy rendszert például MySQL alapúról PostgreSQL alapúvá tegyünk.</p>]]></content:encoded>
			<wfw:commentRss>http://deadlime.hu/2006/02/11/mi-is-az-a-pdo/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

