php

2009
04
márc

Rowset cache-be pakolása


A Zend Framework egyik igen kedvelt szolgáltatása – amire nap mint nap szoktam támaszkodni és szinte már elkerülhetetlen a használata – a Zend_Cache modul. Ha a szerver erőforrások lehetővé teszik, akkor előszeretettel építkezek memcached backendre, eddig elég jól bevált. Volt már például, hogy egy nagyon nagy látogatottságú portál esetén a memcached segítségével a szerver load-ot kevesebb mint a tizedére sikerült visszavenni.

Visszatérő dolog, hogy a cache-ben egy lekérdezés eredményeként visszakapott Zend_Db_Table_Rowset ovjektumot szeretnék letárolni. Persze általában sokkal praktikusabb és optimálisabb az eredményt tömbként átadni a cache-nek és erre a toArray() metódus egyszerű megoldást kínál, azonban ezzel el is veszítjük a Zend_Db által kínált fantasztikus adatbázis absztrakció nyújtotta kényelmet. Például a tömb használatával el lehet felejteni egy adott adatbázis rekordhoz kapcsolódó rekordok közvetlen elérését a findParentRow() és findDependentRowset() függvényekkel, a rekord módosításáról nem is beszélve. A Zend_Db_Table_Rowset cache-ben történő tárolásával azonban az a baj, hogy a szerializáció alkalmával a rowset un. disconnected állapotba kerül, mivel a szerializált ovjektum stringként tárolódik, ami az adatbázisra nézve komoly biztonsági kockázatokat jelentene (db jelszavakra és hasonlókra). Tehát amikor a cache-ből kiolvassuk az adott rowset-et akkor a rekordok mezői ugyan elérhetőek, de nagyjából ugyanannyit érünk vele mintha tömbről volna szó, mert a disconnected állapotban a módosítás ugyanúgy nem működik és a többi közvetlen adatelérést biztosító funkció is használhatatlan.

A megoldás persze pofon egyszerű, hiszen mindössze annyit kell elérni, hogy a deszerializált rowset adatbázis kapcsolatát “felélesszük”. Erre pedig a setTable() függvény tökéletesen megfelel:

if (!$items = $cache->load('items')) {
	$select = $product->select() /* ... */;
	$items = $product->fetchAll($select);
	$cache->save($items, 'items');
}
$items->setTable($product);

A ZF Programmer’s Reference Guide ide vonatkozó passzusa: Serializing and Unserializing a Rowset .

2009
10
feb

Zend_Paginator bug


A minap komolyan meggyűlt a bajom a Zend_Paginator komponenssel. Egy HAVING utasítással egészítettem ki a Zend_Db_Select-et melyet a paginatornak akartam adni paraméterként, de állandóan arra panaszkodott, hogy ismeretlen oszlopra hivatkozok a having kifejezésben:

SQLSTATE[42S22]: Column not found: 1054 Unknown column ‘c’ in ‘having clause’ 

Lefuttattam a query-t közvetlenül MySQL-ben, de ott nem volt tapasztalható a hiba, így a Zend Framework kódját és a fórumokat kezdtem el bújni, majd rövidesen rá is bukkantam a megoldásra: [Zend_Paginator] Bug when using complex Zend_Db_Select. A rendellenesség a Zend_Paginator_Adapter_DbSelect setRowCount() függvényében keresendő, mivel ez a függvény már “lebutítva” kapja meg a lekérdezést, amely ekkor már csak egy oszlopot tartalmazhat. Ha nem így történik akkor kivételre fut. Megértve, hogy pontosan mi okozza a hibát elég volt annyit alakítani a kódon, hogy a paginatornak nem az eredeti lekérdezést adtam át, hanem egy butítottat:

// $select1-ben van a komplex lekérdezés
$select2 = $company->select()->setIntegrityCheck(false);
$select2->from($select1, array('COUNT(*)'));
$paginator = new Zend_Paginator(new Zend_Paginator_Adapter_DbSelect($select2));

Álljon hát itt ez a bejegyzés, hogy máskor könnyen visszakereshető legyen a megoldás!

2008
06
ápr

String típuskonverzió kérdés


Azt olvastam a Zend PHP 5 Certification Study Guide-ban, hogy egy string típusú változó értékének növelésekor 1-et kapunk vissza eredményül, mert a ++ operátor integer típusúvá konvertálja a string értékét (amely így nulla értéket vesz fel) majd azt növeli egyel.

$a = 'Test';
echo ++$a;

Nálam mégis Tesu szerepel a kimenetben. Miért?