Posts Tagged: code

2007
28
dec

Ajax és a Zend Framework


Szerettem volna egy egyszerű, minimalista kis alkalmazást készíteni a Zend Framework segítségével, Ajax-os hívások kiszolgálására, de nem találtam egyetlen példát sem ami valóban az egyszerűséget és a lényegi működést lett volna hivatott bemutatni. Egészen addig amíg bele nem botlottam William Graham Ajax 101: A Simple Example of Using Ajax with the Zend Framework című írásába. Ezen a példán dolgozgattam, gyurmázgattam egy kicsit az alábbi eredménnyel:

Tényleg csak a lényeg van benne, semmi extra. A kliens oldalon begépelt szöveget megfordítja vagy változatlanul hagyja szerver oldalon, persze oldal újratöltés nélkül. Persze az érdemi munkát a Prototype library végzi, de a Zend_Json osztály is besegít a munkába. A lényegi részek az alábbiak:

index.php

<?php
error_reporting(E_ALL|E_STRICT);
date_default_timezone_set('Europe/Budapest');
 
set_include_path('.' . PATH_SEPARATOR . './library'
	. PATH_SEPARATOR . './application/models/'
	. PATH_SEPARATOR . get_include_path());
 
include "Zend/Loader.php";
 
Zend_Loader::loadClass('Zend_Controller_Front');
 
$frontController = Zend_Controller_Front::getInstance();
$frontController->throwExceptions(true);
$frontController->setControllerDirectory('./application/controllers');
 
$frontController->dispatch();

IndexController.php

<?php
 
class IndexController extends Zend_Controller_Action
{
	function init() {
		$this->view->baseUrl = $this->_request->getBaseUrl();
		Zend_Loader::loadClass('Zend_Debug');
		Zend_Loader::loadClass('Zend_Json');
	}
 
	function indexAction() {
		$this->view->title = "Zend Ajax 101";
	}
 
	function getDataAction() {
		$this->_helper->viewRenderer->setNoRender();
		$state = $this->_request->getParam('state');
		$data = Zend_Json::decode($state);
		sleep(1);
 
		switch ($data['func']) {
			case 'reverse':
				echo "The text reversed: " . strrev($data['intext']) . "!!";
				break;
			default:
				echo "The text received: " . $data['intext'] . "!!";
		}
	}
}

index.phtml

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
	<meta http-equiv="Content-type" content="text/html; charset=utf-8">
	<title><?php echo $this->title; ?></title>
	<link rel="stylesheet" href="public/styles/boxy.css" type="text/css" media="screen" title="no title" charset="utf-8">
	<script type="text/javascript" src="public/scripts/prototype.js"></script>
	<script type="text/javascript" src="public/scripts/ajax_funcs.js"></script>
</head>
<body>
	<p>
		<input type="text" name="intext" value="" id="intext" />
		<input type="button" name="buttonReverse" value="Reverse" id="buttonReverse" OnClick="callAjax('intext', 'reverse')" />
		<input type="button" name="buttonNormal" value="Normal" id="buttonNormal" OnClick="callAjax('intext')" />
	</p>
	<img src="public/images/loader.gif" id="update" style="display: none"/>
	<span id="hello">boring pre-Ajax-call text ...</span>
</body>
</html>

ajax_funcs.js

function callAjax(s, method)
{
	if (method===undefined) method='';
	if (method == 'reverse')
		var data = {func: 'reverse', intext: $F(s)};
	else
		var data = {func: '', intext: $F(s)};
	var myAjax = new Ajax.Updater('hello', 'index/getData',
		{ 
			method: 'post', 
			parameters: {state: Object.toJSON(data)},
			onCreate: function(transport) {
				$('update').show();
				$('hello').innerHTML = "Loading...";
			},
			onComplete: function(transport) {
				$('update').hide();
			} 
		}
	);
}
2007
26
dec

FYI: content:encoded olvasása


Küzdöttem a Zend Framework-kel, hogy beolvassa a ‘content:encoded’ tag-eket egy RSS feedből. Az alábbi kóddal sikerült:

public function indexAction()
{
	$ns = array
	(
	        'content' => 'http://purl.org/rss/1.0/modules/content/',
	        'wfw' => 'http://wellformedweb.org/CommentAPI/',
	        'dc' => 'http://purl.org/dc/elements/1.1/',
	);
 
	Zend_Loader::loadClass('Zend_Feed');
	try {
		$rssFeed = Zend_Feed::import('http://blog.linuxforge.hu/feed');
	} catch (Zend_Feed_Exception $e) {
		echo "Exception caught importing feed: {$e->getMessage()}\n";
		exit;
	}
 
	$channel = array(
		'title'			=> $rssFeed->title(),
		'link'			=> $rssFeed->link(),
		'description'	=> $rssFeed->description(),
		'items'			=> array(),
	);
 
	$i = 0;
	$xml = new SimpleXMLElement($rssFeed->saveXML());
 
	foreach ($rssFeed as $item) {
		$content = $xml->channel->item[$i++]->children($ns['content']);
		$channel['items'][] = array(
			'title'			=> $item->title(),
			'link'			=> $item->link(),
			'description'	=> $item->description(),
			'content'		=> trim($content->encoded),
		);			
	}
	$this->view->channel = $channel;
}
2007
18
okt

Drupal elérési út


Mindenek előtt szeretném pontosítani a félreértések elkerülése végett, hogy elérési út alatt a path-t – vagyis az url-ben a host neve után megadott útvonalat – értem (Clean URL használata mellett). Készítek egy Dupal motorral hajtott honlapot. A template a tartalomnak megfelelő módon változik, vagyis a site egyes aloldalai és a főoldal eltérő layouttal rendelkezik a standard oldalakhoz képest. Az eltérő oldalakon belül azonban vannak azonosak, tehát egyes oldalak A típusú (standard) layoutot használnak, míg más oldalak B típusút. A főoldal pedig egy C típusú. A Drupal lehetőséget biztosít a megfelelő névkonvenciók alkalmazásával, hogy az egyes oldalak más template-et használjanak. Például a page-front.tpl.php a főoldalhoz, a page-node-sorszam.tpl.php pedig a sorszám számú node-hoz biztosítja a megfelelő sablont. (Persze csak ha léteznek ezek az állományok).

Mivel a 4-es és 8-as node-jaim ugyanabból a B típusú oldalsablonból építkeznek ezért nem szerettem volna ismételni a page-node-8.tpl.php állományban lévő sablont a page-node-4.tpl.php-ban is. A legkézenfekvőbb megoldásnak tűnt, hogy készítek egy a-template.tpl.php és egy b-template.tpl.php nevű sablont, majd a megfelelő page-node template-ben egy include() segítségével hivatkozom be a megfelelő állományt. A fentiekre visszautalva a page-node sablonokba a következő tartalom kerülhetett volna:

include('b-template.tpl.php');

Csavartam azonban egyet a dolgon (többnyelvű site-ról lévén szó nem akartam elveszni a node azonosítók rengetegében), és a következő koncepció szerint építettem fel az oldalsablonokat. Van egy page-node.tpl.php controllerem ami ugye minden egyes node típusú tartalom esetén betöltődik. Szándékosan nem sablont írtam, mert ebben az esetben ez az állomány nem sablonként, hanem vezérlőként fog funkcionálni, mégpedig oly módon, hogy az oldal elérési útjának megfelelő sablont tölti be. Tehát a www.example.com/sample1 esetén az A, míg a www.example.com/sample2 és www.example.com/sample3 esetén a B sablonokkal jeleníti meg az oldalt, valahogy így:

<?php 
switch ($node->path) {
	case "sample2":
	case "sample3":
		include_once('b-template.tpl.php');
		break;
	case "frontpage":
		include_once('c-template.tpl.php');
		break;	
	default:
		include_once('a-template.tpl.php');
		break;
}
?>

A dolog szépséghibája, hogy a $node->path csak hitelesített felhasználók esetén ad vissza értéket, anonim látogatók esetén a $node nem is tartalmaz path elemet. Az alábbi trükköt alkalmaztam:

<?php 
$nid = arg(1);
$path = drupal_get_path_alias("node/$nid");
 
switch ($path) {
	case "sample2":
	case "sample3":
		include_once('b-template.tpl.php');
		break;
	case "frontpage":
		include_once('c-template.tpl.php');
		break;	
	default:
		include_once('a-template.tpl.php');
		break;
}
?>

A drupal_get_path_alias() függvény és a node azonosító [arg(1)] segítségével szerencsére kinyerhető az adott oldal elérési útja és a template megfelelően működik. A trükk eredete: Path / Clean URLs not showing up – anonymous users don’t get a path.

2007
04
júl

Mono kompatibilitás


Egy újabb Mono-s bugba sikerült belefutnom. A CustomValidator-okat pofátlanul figyelmen kívül hagyja de ami a leginkább bosszant a dologban, hogy ez a korábbi verziókban működött! Az 1.2.3-as verziónál tapasztaltam a jelenséget de először arra gondoltam, hogy én ejtettem valami hibát a programomban. Módosítás nélkül átvittem a kódot egy MS.NET-es gépre és hiba nélkül működött.

  • CustomValidator:
    <asp:CustomValidator
    	Display="Dynamic"
    	ErrorMessage="A ráfordítási idő nem lett kiválasztva"
    	ID="CustomValidator1"
    	OnServerValidate="ValidateDuration"
    	runat="server" />
    <asp:DropDownList ID="ddlDuration" runat="server" />
  • Az eseménykezelő rész:
    protected void ValidateDuration (object sender, ServerValidateEventArgs e)
    {
    	if (ddlDuration.SelectedValue == "0")
    		e.IsValid = false;
    	else
    		e.IsValid = true;
    	}

Gondoltam, hogy akkor gyorsan feldobok a tesztrendszerben egy 1.2.4-es verziót, hátha ott már javították, de ekkor jött az arconcsúszás, mert az új verzióval mégtöbb hiba jött elő. Nem találja – egészen pontosan rossz helyen keresi – a saját kontroljaimat, mert a korábban tökéletesen működő (Windows-on most is kifogástalan) URL kezelő eljárásom hibás URL-t ad vissza és mindig téveszt egy szintet a könyvtárstruktúrában.

Nagyon óvatosan arra következtetek, hogy production környezetbe még mindig nem való a Mono – ASP.NET páros, mert az ilyen bugokat nem lehet tolerálni. Egyébként Gentoo-val teszteltünk, de a kolléga visszajelzése alapján Ubuntu-val is jelentkezett a hiba! Most jöhet a downgrade 1.2.2-re, ahol még minden hibátlan volt (vagy a Mono forráskód túrása, de nem vagyok mazochista ;-) ).

2007
03
júl

Gondolatok keretrendszerekről


Az elmúlt másfél-két évben az ASP.NET-el való foglalatoskodásom eredményeként sikerült kisebb-nagyobb eredményeket felmutatnom a webes fejlesztések területén. Persze egy fejlesztő sosem – vagy csak meglehetősen ritkán kötelezi el magát – egyetlen programozási nyelv, fejlesztőkörnyezet vagy netán platform mellett. Magamból kiindulva mindig keresem az új lehetőségeket és mindig akad valami ami aktuálisan lázba tud hozni. A kezdeti lelkesedés aztán gyakran rövid idő alatt elmúlik de van olyan is, hogy valami végleg vagy legalábbis hosszabb időre belopja magát a szívembe. Kezdetben az ASP.NET és az egész .NET keretrendszer pont ilyen volt számomra. Nem igazán értettem, hogy miért jó nekünk egy újabb “Java szerű” nyelv egy “Java szerű” virtuális géppel stb. Aztán persze a C# nyelv megismerését követően enyhült az ellenszenvem. Az i-re a pontot végül a Mono project tette fel, amikor megteremtette a valódi platformfüggetlen alkalamazásfejlesztés lehetőségét.

Azt hiszem, hogy senkinek sem kell azt bizonygatnom, hogy mennyire szeretem a C#-ot, az ASP.NET-et vagy a Mono keretrendszert. Rengeteg dologra nyitotta rá a szemem ez a trió. Annó úgy gondoltam, hogy a C nyelvnél és a gcc fordítónál jobbra sosem lesz szükségem, hisz ezekkel mindent meg lehet csinálni amiben csak valaha gondolkodni mertem. Persze ez az állítás továbbra is igaz, de tekintve, hogy a fejlesztési idők drasztikusan csökkennek, nekem ma már sem időm, sem kedvem azzal bajlódni, hogy memóriát allokáljak és szabadítsak fel az alkalmazásomnak vagy azon gondolkodjak, hogy egy adatszerkezetet hogyan írok ki lemezre, ne adj isten hogyan továbbítom azt hálózaton keresztül. Nem újkeletű a problémán, a hozzám hasonló cipőben járók tudják, hogy miről beszélek.

Persze most a kliens oldali alkalmazások fejlesztésről beszéltem, de lassan majdcsak oda érek amiről írni szeretnék :-) Úgy négy éve lehetett mikor elkezdtem nyitni a .NET felé. Ez még messze volt attól, hogy komolyan foglalkoztam volna vele, túlságosan új volt számomra az egész technológia ahhoz, hogy átlássam és megértsem. Mindazonáltal érdekelt a dolog és túl voltam már azon, hogy puszta dacból elutasítsam az egészet a Java fejlesztők által azóta is gyakran hangoztatott indokokra hivatkozva.

Nagyjából három éve kezdtem el aktívan foglalkozni a keretrendszerrel és a C# nyelvvel. Akkoriban Linuxos (és/vagy Windowsos) desktop megoldásokkal foglalatoskodtam, úgy mint például a Gnome-RDP és a SharpSzámla, de akadtak szép számmal belső fejlesztések is. Később egyre gyakrabban merült fel az igény webes alkalmazások fejlesztésére. Ekkor kezdtem el kacérkodni az ASP.NET gondolatával. A hagyományos ASP-s oldalak készítésével kapcsolatban volt már tapasztalatom és pont ez volt sokáig a visszatartó erő, de a C# mindezt feledtette velem és szép lassan sikerült elmerülnöm az új technológia nyújtotta előnyökben. Ezzel szemben persze a PHP volt a “konkurencia”, azonban az ASP.NET használatával oly mértékben lerövidült a fejlesztési idő és annyi kész megoldást kaptam a 2.0-ás keretrendszer használatával, hogy már gondolni sem mertem a PHP-s session- és formkezelésre vagy például a felhasználók hitelesítésére. Persze itt még sokáig tudnám folytatni a kellemes és hasznos dolgok taglalását, de szeretnék egy kicsit az dolgok árnyoldalával is foglalkozni és legfőképpen kitérni arra amit mások már megint évekkel előttem észrevettek :-)

A Mono-t az Microsoft .NET frameworkjének a mintájára készítik. Azt nem tudom, hogy milyen módszereket alkalmaznak, őszintén megvallva nem is érdekel, egy dolog biztos: az aktuális Microsoft féle .NET keretrendszerhez képest a Mono-nak mindig kisebb-nagyobb lemaradása van. Ha valaki a legfrissebb újdonságokra épít, biztos lehet benne, hogy a programja nem fog hiba nélkül működni Mono-val. Ez a kisebbik probléma. Sajnos sokszor egy-egy feature máshogy működik az egyik keretrendszerben mint a másikban. Épp csak egy kicsit, de az épp elég ahhoz, hogy rendellenes eredményt produkáljon. Csak, hogy egy példát is hozzak erre:

Az MS féle ASP.NET-et használva a DataGrid-nek az oszlopait futási időben eltüntethetjük vagy megjeleníthetjük, Mono esetén kivételt kapunk, hogy ez a feature még nem került implementálásra. És sok-sok hasonlót lehetne még hozni. Ha jól tudom, akkor a Vistát már a 3.0-ás .NET frameworkkel szállították, Monos oldalról itt igen tekintélyes lemaradás tapasztalható. Mindezek mellett persze a Mono framework egy kiemelkedő és hiánypótló alkotás és nem lehet a fent említett hiányosságokat részére hibaként felróni. Az elmaradások érthetőek és nem szorulnak magyarázatra.

Számomra a legfájóbb hiányosság Monos oldalról a hosting tekintetében tapasztalható. Nem nagyon lehet találni olyan hosting céget aki Linuxos szerveren ASP.NET 2.0-ás szolgáltatást biztosítana. Eddig csupán egy amerikai céget találtam akiknél megfizethető áron lehet Linuxos kiszolgálással ASP.NET-es szolgáltatásra előfizetni, de sajnos csak 1.1-esre. Hát, azt pedig köszi, de inkább már nem! Windowsos persze van, de nem hiszem, hogy magyarázatra szorul az, hogy ettől miért nem jövök lázba.

Ez volt tehát a fekete leves, most pedig jöjjön az amit az imént említettem, ami rányitotta a szemem a saját vakságomra. Ha azt mondom, hogy Ruby On Rails akkor a tapasztalt webes fejlesztők már fel sem kapják a fejüket hiszen teljesen természetes dologról van számukra szó. Nem úgy az olyan maradi, Pascal és C nyelven felnőtt “programozóknak” mint például én. Számomra sokáig nem állt össze a kép a fent említett nyelv – vagy nevezzük inkább keretrendszernek – kapcsán. Félreértés ne essék, nem egy Ruby On Rails áradozás fog következni.

Egy-két posttal ezelőtt elkezdtem ismételt áradozásomat a Drupal CMS-ről. Akkor is említettem, hogy mennyire jó a Drupal modul fejlesztőknek szóló dokumentációja. Ekkor indultam el azon az úton, hogy hosszú idő után ismét PHP-t kezdtem idomítani. Erre alapvetően három okom volt:

  1. az előbb említett ASP.NET-es hosting hiányosság,
  2. a Drupal CMS kellemes programozhatósága,
  3. Mac OS X-en is fejleszthető, nem kell virtuális gépen kódolnom vagy másik rendszert bootolnom.

A Drupal kapcsán aztán rájöttem, hogy több régóta érlelt projektötlet is van amit szeretnék megvalósítani vagy akár migrálni a szélesebb körben való elterjedés érdekében PHP-s alapokon. Mindaddig amíg egy egyszerű Drupal modul megvalósításáról beszélünk könnyű dolga van a programozónak, – de a saját véleményem szerint – egy komplexebb projekt megvalósítása már komoly tervezési és megvalósítási nehézségekbe ütközhet ha elrugaszkodunk a Drupal alapverő mivoltától, attól, hogy ez egy tartalomkezelő rendszer.

Így találtam rá véletlenül valamelyik nap a Prado-ra. A Prado, hogy egészen pontos legyek egy PHP 5-ös komponens keretrendszer (component framework for PHP 5), amely az ASP.NET szolgáltatásaival elég komoly hasonlóságot mutat. Csak, hogy néhány fontosabbat említsek a teljesség igénye nélkül:

  • Eseményvezérelt programozási keretrendszer
  • Felhasználókezelés
  • “CodeBehind” alkalmazása, az oldal és az azt vezérlő kód elszeparálása
  • MVC (Model-View-Controller) architektúra
  • DAO (MySQL, PSQL, MS-SQL és Sqlite), Active Record, SQL táblák osztályokhoz rendelése (SqlMap Data Mapper)
  • Integrált AJAX-os vezérlők
  • XML alapú konfigurációs állományok
  • SOAP szolgáltatások
  • Mester és tartalmi oldalak
  • Kivételkezelés

Adódik a kérdés, hogy mindezekhez mire van szükség? Mindössze egy webszerverre, amely rendelkezik legalább PHP 5.1.0 támogatással. Valljuk be ez nem túl nagy igény :-) A Prado oldalán lévő dokumentáció és a példaprogramok elég komolyan rávilágítanak arra, hogy mi mindent lehet megvalósítani a keretrendszerrel és mindezt mennyi idő alatt, mekkora befektetéssel. Valamint arról sem szabad elfeledkeznünk, hogy mennyire marad áttekinthető és módosítható a későbbiek során a kódunk. Lássuk a HelloWorld példát:

  • Home.page:
  • <html>
      <body>
        <com:TForm>
          <com:TButton Text="Click me" OnClick="buttonClicked" />
        </com:TForm>
      </body>
    </html>
  • Home.php:
  • class Home extends TPage
    {
        public function buttonClicked($sender,$param)
        {
            // $sender refers to the button component
            $sender->Text="Hello World!";
        }
    }

    Prado-t leginkább a Ruby On Rails-hez tudnám hasonlítani koncepcióban valamint az ASP.NET-hez szintaktikában és filozófiában. Mindezt PHP-s megvalósítással. Elég érdekes, ugyanakkor ütőképesnek tűnő egyvelege ez a különböző nyelveknek és technológiáknak. Nekem nagyon felkeltette az érdeklődésemet és tekintve, hogy 2004 óta fejlesztik, elég kiforrottnak is tűnik. Ami pedig a dolog apropója, hogy pont a napokban jelent meg – egy év fejlesztést követően – a 3.1.0-ás verzió ami számos nagyon hasznos újítást hozott magával.

    Egy gondolat és egy kérdés maradt a végére:

    • Nem tudtam róla, hogy ilyen sok jó PHP-s framework létezik: Prado, Symfony vagy CakePHP. Nyitottabb szemmel kellene járnom.
    • A kérdés: hogyan lehet védeni a PHP-s forráskódot. Létezik erre valami technika, hogy a PHP-ben írt alkalmazás kódja védhető legyen a külső módosításoktól? Nem a webszerver felőli védelemre gondolok, hanem a tényleges PHP állományok védelmére.