Edwin V. http://edwinv.nl Most recent posts at Edwin V. posterous.com Sun, 20 Aug 2006 18:13:14 -0700 De perfecte opbouw van een webapplicatie http://edwinv.nl/webdevelopment/de-perfecte-opbouw-van-een-webapplicatie http://edwinv.nl/webdevelopment/de-perfecte-opbouw-van-een-webapplicatie

Begin dit jaar schreef Tri Pham een interessant artikel op Scriptorama over de perfecte webdeveloper. Zijn conclusie was simpel maar doeltreffend:

De perfecte web developer bestaat misschien niet, maar er naar streven doet geen vlieg kwaad.

Een manier om hier naar te streven is voor mij een goede opbouw van een applicatie. De laatste tijd heb ik verschillende verzoeken ontvangen om te adviseren bij het ontwikkelen van een webapplicatie. Omdat het hier niet om kleine websites gaat, is de opbouw van groot belang. In dit artikel ga ik proberen de perfecte web developer uit te hangen en mijn mening geven over de perfecte opbouw van een webapplicatie.

A key thing about patterns is that you can never just apply the solution blindly, which is why pattern tools have been such miserable failures. I like to say that patterns are “half baked,” meaning that you always have to finish them off in the oven of your own project. Every time I use a pattern I tweak it a little here and a little there. You see the same solution many times over, but it’s never exactly the same.

De bovenstaande uitspraak komt uit het boek Patterns of Enterprise Application Architecture van Martin Fowler. In dit artikel zullen veel design patterns aan bod komen, patterns die ik zelf handig vind om te gebruiken. Luister naar Fowler, blijf altijd nadenken over de opbouw van je eigen applicatie!

De opbouw van webapplicaties is meestal in grote lijnen met elkaar te vergelijken. Je hebt te maken met de weergave van de applicatie in een webbrowser. Daarnaast zal er een bepaalde gegevensbron zijn, bijvoorbeeld in de vorm van een database. Het laatste element is de koppeling tussen de weergave en de database. Dit element zal de aanvraag van een client omzetten naar een weergave van gegevens uit de database.

De drie bovenstaande elementen zijn beter bekend als Model, View en Controller. Het MVC pattern is in mijn ogen daarom een goede basis voor een webapplicatie.

Model

Het model van een webapplicatie bestaat uit de koppeling tussen de applicatie en een gegevensbron. In veel gevallen hebben hier te maken met een database. De gegevens in een database bestaan uit verschillende entiteiten die inhoud kunnen bevatten. In verschillende projecten in het verleden heb ik ervoor gekozen om voor elke tabel een klasse aan te maken die er globaal als volgt uit ziet:

<?php
class PageModel extends Model {

public function getPages(){
return $this->query("SELECT * FROM pages");
}

public function getPage($iId){
return $this->query("SELECT * FROM pages WHERE id = ".$iId);
}

public function addPage($sName, $sLocation, $bPublished){
return $this->query("INSERT INTO ...");
}

public function editPage($iId, $sName, $sLocation, $bPublished){
return $this->query("UPDATE pages SET ...");
}

public function deletePage($iId){
return $this->query("DELETE FROM ...");
}

}
?>

De methoden werden meestal aangevuld met controles op de gegeven parameters. De Model klasse bevatte alle functionaliteit voor de koppeling met de database. Vaak gaf de methode ‘query’ al associatieve arrays terug met gegevens zodat het in de applicatie verder niet nodig was om te werken met mysql_* functies. Het voordeel hiervan was ook de uitwisselbaarheid met andere database typen, zoals PostgreSQL.

De bovenstaande opzet van een model klasse werkt, alleen doe je regelmatig dubbel werk. De queries in de verschillende klassen zullen voor het grootste gedeelte gelijk zijn. Daarnaast mis je veel flexibiliteit. Zodra je in een controller of view een andere sortering van de gegevens wilt dien je gelijk aanpassingen te maken in de model klasse. Er is dus nog veel ruimte voor automatisering van een model klasse.

Dat laatste is iets waar ik veel belang aan ben gaan hechten. Dubbel werk moet niet nodig zijn als je een goede opbouw van je applicatie hebt, DRY dus. Helemaal als je gebruik gaat maken van object-georiënteerd programmeren. Versie 5 van PHP biedt de hiervoor voldoende mogelijkheden, al ben ik zelf meer een Ruby aanhanger aan het worden. Ruby is zelf een native OOP taal waardoor er veel meer mogelijk is op dat gebied.

Een goed design pattern voor het model is in mijn ogen ActiveRecord. Binnen verschillende frameworks wordt dit pattern toegepast en mijn ervaring is dat het geweldig werkt. Het biedt alle mogelijkheden om DRY te werken, maar je kunt altijd nog zelf je queries gaan schrijven als het nodig is.

Een simpel voorbeeld:
<?php
class Person extends ActiveRecord {

}

// SELECT * FROM persons WHERE id = 1
$person = Person::find(1);
echo $person->name;

// UPDATE persons SET name = 'Edwin V.' WHERE id = 1
$person->name = "Edwin V.";
$person->save;
?>

Zoals je ziet is het overbodig om queries te schrijven, ActiveRecord stelt zelf de queries samen. Het hangt van de implementatie van ActiveRecord af wat allemaal mogelijk is. De implementatie binnen Ruby on Rails biedt bijvoorbeeld functionaliteit voor associaties en gegevens validatie. Het Zend Framework biedt helaas geen implementatie van ActiveRecord aan, maar wel andere handige database klassen.

Een interessant overzicht van object-relational mapping implementaties in PHP is te vinden op de PHP wiki.

View

Een net zo belangrijk onderdeel van een applicatie is de weergave richting de gebruiker. Bij een webapplicatie gebeurd dat meestal in een browser, dus de weergave bestaat uit HTML en de bijbehorende afbeeldingen, JavaScripts en stylesheets. Daarnaast is het natuurlijk mogelijk om XML als weergave te hebben, voor bijvoorbeeld gebruik in een andere applicatie of als RSS feed.
Een laatste – redelijk nieuwe – techniek is JavaScript. In dat geval zal als reactie op een Ajax request vanuit de browser een stukje JavaScript terug gezonden worden om uitgevoerd te worden in de browser. Deze manier van werken wordt de laatste tijd meer toegepast door de introductie van RJS templates in Rails. Een korte introductie van RJS is te vinden op de weblog van Cody Fauser.

De belangrijkste taak van de view is dus de gegevens uit de controller omzetten naar een passend formaat. Hiervoor kan je vaak gebruik maken van een template engine zoals Smarty of Yapter. Mijn ervaring is dat template engines meestal overbodig zijn omdat PHP zelf al een perfecte template engine is.

<ul>
[LOOP $items]
<li>[$item]</li>
[ENDLOOP]
</ul>

<ul>
<? foreach($this->items as $item): ?>
<li><?= $item ?></li>
<? end; ?>
</ul>

Het bovenste voorbeeld zou uit een template engine kunnen komen. Het doet precies wat je wilt, maar absoluut niet meer. Het onderste voorbeeld is dezelfde code in PHP. Als nadeel kan je het aantal tekens noemen, maar dat weegt zeker op tegen de voordelen. Je kunt namelijk gewoon alle functionaliteit gebruiken die PHP te bieden heeft.

Een goede implementatie van een View is die van het Zend Framework. Hierbij ken je in de controller waarden toe aan variabelen in het view object. Deze variabelen kan je vervolgens weer gebruiken in je template.

Binnen templates kan het handig zijn om met helpers te werken. Dit principe kennen we onder andere van Rails en zit wederom in het Zend Framework. Helpers bevatten functies die veel gebruikte HTML tags genereren. Ze kunnen bijvoorbeeld helpen bij het samenstellen van een formulier voor een bepaald object.

Controller

De taak van de controller klassen is een request van een gebruiker omzetten naar een bepaalde weergave van de staat van het systeem. Een request van een gebruiker bestaat meestal uit een URL met daarin bepaalde informatie over de op te vragen gegevens. Een veel gebruikte opzet bestaat uit:
* Controller: De entiteit die opgevraagd wordt, bijvoorbeeld ‘person’
* Actie: De actie die uitgevoerd wordt op de entiteit, bijvoorbeeld ‘show’
* ID: De unieke identifier naar de entiteit, bijvoorbeeld ’1′.

Een aanvraag kan er dus uit zien als ‘index.php?controller=person&action=show&id=1′, maar vaak wordt gebruik gemaakt van nette URL’s en ziet de URL er zo uit: ‘/person/show/1′. Voor elke entiteit bestaat vervolgens een controller:

<?php
class PersonController extends ApplicationController {

public function showAction(){
// Show Person with given ID
}
}
?>

Een controller bevat voor elke mogelijke actie een methode. In het verleden heb ik wel gewerkt met speciale klassen voor elke actie, maar mijn ervaring is dat dit erg onoverzichtelijk is. Het is aan te raden om voor elke actie een methode te gebruiken.

Het omzetten van de URL naar een aanroep van een methode in een controller gaat meestal via routing. De implementatie van controllers in het Zend Framework bevat een RewriteRouter waarmee dit makkelijk te realiseren is. Zodra het routing gedaan is kan de methode de benodigde acties uitvoeren. Een voorbeeld van een controller met twee acties is:
<?php
class PersonController extends ApplicationController {

public function showAction(){
$view = new View();
$view->person = Person::find($this->params['id']);
return $view->parse('person/show.tpl');
}

public function editAction(){
if($this->request->isPostMethod()){
$person = Person::find($this->params['id']);
$person->name = $this->params['person']['name'];
$person->save();
return $this->redirect('person', 'show', $person->id);
} else {
$view = new View();
$view->person = Person::find($this->params['id']);
return $view->parse('person/edit.tpl');
}
}

}
?>

Conclusie

Zoals uit het artikel blijkt ben ik zelf een grote fan van Ruby on Rails en het Zend Framework. Het Rails framework geeft webdevelopers een kant-en-klare oplossing voor de opbouw van een webapplicatie. Zowel het MVC pattern als ActiveRecords is hierin terug te vinden, beide met een zeer goede implementatie.

Het Zend Framework is helaas nog in een beta status en dwingt niet de opbouw van een applicatie af. Ze geven echter wel een goede basis met verschillende klassen ter ondersteuning van MVC en object-relation mapping. Hoewel ik de laatste tijd veel werk met Ruby, zou ik het framework zeker gebruiken als basis voor een PHP applicatie.

De genoemde opbouw van een applicatie is in mijn ogen een manier om DRY te werken en toch voldoende flexibiliteit te hebben. De methode heeft al meerdere keren goede dienst bewezen bij mij. En om net zo’n pakkende conclusie als Tri Pham te geven:

Een perfecte opbouw van een webapplicatie bestaat niet, maar er naar streven doet geen vlieg kwaad.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Sat, 19 Aug 2006 14:54:36 -0700 Script.aculo.us update: versie 1.6.2 http://edwinv.nl/webdevelopment/scriptaculous-update-versie-162 http://edwinv.nl/webdevelopment/scriptaculous-update-versie-162

Afgelopen week is er een update uitgekomen van de JavaScript library script.aculo.us. Script.aculo.us wordt standaard meegeleverd met Ruby on Rails en biedt functionaliteit voor visuele effecten, drag-and-drop en verschillende controls.

In de vorige versie van de bibliotheek was het onder andere mogelijk gemaakt om geneste lijsten te sorteren, de zogenaamde sortable trees. Helaas zat er een bug in de serialisatie van de lijsten waardoor ze in applicaties onbruikbaar waren. In de nieuwe versie is onder andere dit probleem opgelost.

Een uitgebreide changelog en download links zijn te vinden op de website van script.aculo.us.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Thu, 20 Apr 2006 21:41:31 -0700 Vitamin: voeding voor de webontwikkelaar http://edwinv.nl/webdevelopment/vitamin-voeding-voor-de-webontwikkelaar http://edwinv.nl/webdevelopment/vitamin-voeding-voor-de-webontwikkelaar

Vitamin is een nieuw online magazine met interessante artikelen voor webontwikkelaars. De artikelen zijn veel gericht op Web 2.0 aspecten zoals AJAX en Ruby on Rails. Een voorbeeld hiervan is het artikel van Thomas Fuchs over het maken van AJAX effecten in je web applicaties.

Een ander interessant artikel is ‘Making Popular Layout Decisions’ van Eric Meyer. Op een luchtige wijze laat hij precies zien waar het tijdens webdesign altijd om gaat: het maken van keuzes.

De magazine wordt elke week geüpdate, een aanrader voor in de RSS reader dus.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Tue, 18 Apr 2006 20:31:07 -0700 Zend Framework: preview versie 0.1.3 http://edwinv.nl/webdevelopment/zend-framework-preview-versie-013 http://edwinv.nl/webdevelopment/zend-framework-preview-versie-013

Zend heeft net een nieuwe preview van hun framework openbaar gemaakt. Na een herstyle van de framework website afgelopen week, is er nu dus ook weer wat aan de code gedaan. Overigens is het ook mogelijk om rechtstreeks in de SVN repository een checkout te doen, zodat je de allerlaatste preview hebt.

De changelog van de nieuwe versie ziet er als volgt uit:

RELEASE 0.1.3 / 18-Apr-2006

  • Zend_Filter is* methods return strictly TRUE or FALSE. (Chris)
  • Zend_InputFilter has test* methods for retrieving valid data. (Chris)
  • Fixed bug in Zend_View_Abstract::__isset(). Reported by James Simmons. (Mike)
  • Zend_Db_Adapter_Pdo_Mysql::limit() now compatible with MySQL versions prior to 4.0. Reported by Greg Neustaetter (Mike)
  • Fixed bug in Zend_Controller_Dispatcher_Token::setParams(). Reported by Rob Allen. (Chris)
  • Fixed bug in Zend_Log::log(). Reported by Mislav. (Mike)
  • Updated Zend_Filter::isFloat() and Zend_Filter::isInt() to respect locale. (Chris)
  • Improved Zend_Db_Adapter_Pdo_Mssql contributed by Rob Allen. (Mike)
  • Fixed bug in Zend_Controller_Dispatcher::_formatName. Reported by Arpad Ray. (Chris)
  • Zend::dump() now works from CLI (Rob Allen)
  • Improved support for XML-RPC namespaces (Mike, Chuck)
  • Registry can now be tested with Zend::isRegistered (Shekar C. Reddy, Mike)
  • Zend_Search_Lucene promoted from incubator (Alex)
  • Zend_Cache has been accepted to the incubator (Fabien, Mislav)
  • Zend_Json testing expanded; covers all major cases (Matthew)
  • Fixed Zend_Json encoding of empty values (Matthew, Davey)
  • Fixed Zend_Json encoding of associative arrays (Matthew, Davey)
  • Fixed Zend_Json encoding of numeric indices in associative arrays (Matthew)
  • Removed formatting (newlines, tabs) from Zend_Json encoding methods (Matthew)
  • Fixed escaping in Zend_Json_Encoder (Matthew)
  • Zend_HttpClient moved to Zend_Http_Client (Mike)
  • Zend_Console_Args in the incubator but not yet refactored (Jason Garber)
  • Zend_Mail enhancements in the incubator by Austria Telekom (Nico, Clez)
  • Zend_Service classes no longer subclass Zend_Service_Rest (Davey, Andi, et al)
  • Zend_Service classes now use new Zend_InputFilter (Davey)
  • Fixed bug in Zend_Service_Amazon::itemLookup() (Davey)
  • Fixed bug in Zend_Service_Flickr::userSearch() (Davey)
  • Fixed bug in Zend_Uri_Http::__construct(). Reported by Adrian Gheorghe. (Mike)
  • Improved some not well-formed PDF processing with Zend_Pdf. (Alexander)
  • Minor Zend_Pdf documentation fixes. (Alexander)
  • Fixed Zend_Pdf processing of inherited page attributes. (Alexander)
  • Fixed Zend_Pdf umlauts support for standard fonts. (Alexander)

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Mon, 17 Apr 2006 16:01:49 -0700 Ruby on Rails: Web development that doesn't hurt http://edwinv.nl/webdevelopment/ruby-on-rails-web-development-that-doesnt-hurt http://edwinv.nl/webdevelopment/ruby-on-rails-web-development-that-doesnt-hurt

Al lange tijd zit ik te wachten op een goed framework om webapplicaties in te bouwen. Gezien mijn ruime ervaring met PHP, leek het nieuwe Zend Framework een uitkomst te bieden. Helaas staat dit framework nog teveel in de kinderschoenen en wordt mijn drang naar iets goeds met de dag groter. De andere PHP frameworks zijn vaak afgeleid van Ruby on Rails. Reden genoeg om eens naar dit geweldige framework te kijken.

Door enkele wijzigingen in de nieuwe versie van Ruby on Rails, is het mij deze keer wel gelukt om het framework op een linux server te installeren. In plaats van het bekende – maar weinig zeggende – witte scherm, kreeg ik nu een keurige foutmelding, waardoor mijn fouten met FastCGI zo opgelost waren.

Natuurlijk valt er nog veel te leren op het gebied van Ruby en Rails, maar mijn eerste kennismaking is positief. Ruby heeft een aparte syntax, maar na het doorspitten van enkele hoofdstukken uit Programming Ruby – The Pragmatic Programmer’s Guide werd de opbouw al snel duidelijk. Volledig werken met OOP heb ik goede ervaringen mee vanuit Java. In PHP heb ik al enkele pogingen gedaan om netjes OOP te werken, maar daar helpen ze niet echt mee. Binnen Ruby kunnen ze niet anders, dus dat zit wel goed.

De documentatie van Ruby bestaat uit een Class and Library Reference, die overigens ook in een ander formaat te verkrijgen is. Het is een genot om bijvoorbeeld naar de String klasse te kijken en het te vergelijken met PHP. Moest je in PHP nog de manual openen om te zoeken of voor een string functie ‘str’, ‘str_’ of niets stond, hier heet het gewoon ‘capitalize’ of ‘include?’.

De API van Rails is duidelijk en bevat voldoende informatie over de verschillende onderdelen. Het kost echter wat tijd voordat je door hebt in welke klasse iets te vinden is (al is dat achteraf wel logisch). Verder is de Wiki een goede aanvulling op de API.

Ik ben van plan om de komende tijd regelmatig wat over mijn bevindingen met Ruby on Rails te schrijven.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Fri, 07 Apr 2006 20:48:39 -0700 RTFM: de grote resource voor de webdeveloper http://edwinv.nl/webdevelopment/rtfm-de-grote-resource-voor-de-webdeveloper http://edwinv.nl/webdevelopment/rtfm-de-grote-resource-voor-de-webdeveloper

Veel webdeveloper weten handige informatiebronnen voor het programmeren niet te vinden. Onder het mom van Read The F*cking Manual zal ik in dit artikel een overzicht geven van de resources die ik regelmatig raadpleeg tijdens m’n ontwikkel werk.

  1. PHP.net
    De officiële PHP handleiding, grotendeels vertaald naar het Nederlands. De handleiding bevat een slimme zoekmachine, als je achter ‘php.net’ een term typt zal hij proberen de goede handleiding pagina voor te schotelen. Een voorbeeld http://php.net/array_search
  2. MySQL Reference Manual
    De officiële MySQL handleiding, helaas helemaal in het Engels, maar dat is voor de echte webdeveloper geen punt. Naast de goede SQL syntax en handige functies, staan hier ook veel zaken voor database beheerders in. Minder interessant tijdens het programmeer werk dus. Nuttige hoofdstukken zijn:
  3. Data Types
  4. Functions And Operators
  5. SQL Statement Syntax
  6. PostgreSQL Documentation
    Wederom een officiële handleiding, ditmaal van PostgreSQL. Vooral het hoofdstuk SQL Syntax moet je doorgelezen hebben voordat je aan de slag gaat met PostgreSQL (maar veel hiervan kan je ook toepassing bij MySQL).
  7. CSS level 2
    De definitie van CSS volgens het W3C. Heel handig om te kijken wat de syntax van CSS is en om te kijken welke argumenten een property kan krijgen.
  8. URL Rewriting Guide
    Een hele duidelijke uitleg over de toepassing van mod_rewrite in je scripts. Samen met de syntax specificatie zou je hiermee al je rewrite rules op moeten kunnen stellen.

Scriptorama wees mij afgelopen week op een handige verzameling van deze verschillende handleidingen. Via gotAPI kan je via een simpele interface snel zoeken in de handleidingen.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Sat, 11 Mar 2006 17:05:36 -0800 Zend Framework: Scaffolding http://edwinv.nl/webdevelopment/zend-framework-scaffolding http://edwinv.nl/webdevelopment/zend-framework-scaffolding

The current version of Zend Framework doesn’t include a way to use scaffolding in a script-in-development. Because I wanted to play with the framework, I’ve extended the Zend_Controller_Action class to make scaffolding possible. In this article I shall explain the code and give some feedback for the developers of the framework.

The main purpose for scaffolding is creating very basic pages for viewing and editing content in the database. In an early stage of implementation, scaffolding gives the developer a way to test certain functionality, without the need to work directly in the database. Besides that, scaffolding is used as a basis for the final implementation.

In this example, I’m using the Action and Router class from Akra’s DevNotes to create a simple application. In fact, de Scaffold class will extend the Akrabat_Action class, which hopefully in the future will be part of the framework itself.


h3. Creating the model

First of all, we need to create a new data object to apply our Scaffold class to. Create a new table in your favorite database and create a new model class for the database:

<?php
class tableName extends Zend_Db_Table { }
?>

‘tableName’ matches the name of the table you just created, in this case ‘table_name’. Make sure the column name which contains the primary id of the table is ‘id’ or define another primary column.

Creating the controller class

To manage the data inside the table, we want to create a controller class like this:

class tableNameController extends Fly_Scaffolding { }

The controller ‘tableName’ should give us the possibility to:
* Show a list of rows in the table
* Show a single row in the table
* Edit a row
* Delete a row
* Add a row

The Scaffolding class

The code for the Fly_Scaffolding class is:

<?php

/**
* This file contains the scaffolding class
*
*
* @copyright 2006 Edwin V.
* @license http://www.zend.com/license/3_0.txt PHP License 3.0
* @version CVS: $Id:$
* @link
*/

require_once 'Zend/Db/Inflector.php';

/**
* Scaffolding class, extends the Akrabat_Action class
* Provides the developer a simple CRUD interface for a table
*
* @copyright 2006 Edwin V.
* @license http://www.zend.com/license/3_0.txt PHP License 3.0
* version Release: @package_version
* @link
*/
class Fly_Scaffolding extends Akrabat_Controller_Action {

/**
* For name inflections.
*
* @var Zend_Db_Inflector
*/
static protected $_inflector;

/**
* The name of this controller
*
* @var string
*/
protected $_name;

/**
* The name of this entity, this is the table name without the given prefix
*
* @var string
*/
protected $_entityName;

/**
* The table to scaffold
*
* @var Zend_Db_Table
*/
private $_table;

/**
* The information about the table
*
* @var array
*/
private $_tableInfo;


/**
* Construct a new scaffolding object
*/
public function __construct($tableName = ""){
parent::__construct();

// Use the db inflector
self::$_inflector = new Zend_Db_Inflector();

if(empty($tableName)){
$this->_name = str_replace("Controller", "", get_class($this));
} else {
$this->_name = self::$_inflector->camelize($tableName);
}

// Replace fly with some kind of table prefix
$this->_entityName = $this->_name;

require_once("../application/models/".ucfirst($this->_name).".php");

$this->_table = new $this->_name();

$this->_tableInfo = $this->_table->info();

// Define the singular and plural name for use in the views
$this->nameSingular = self::$_inflector->singular($this->_entityName);
$this->namePlural = self::$_inflector->plural($this->_entityName);

$info = $this->_table->info();
$this->primary = strtolower($this->_tableInfo['primary']);

}

public function indexAction(){
$this->_redirect('list');
}

/**
* The list action shows a list of all rows in the table
*/
public function listAction(){
$info = $this->_table->info();
$this->columns = $info['cols'];
$this->items = $this->_table->fetchAll();
}

/**
* The show action shows a single row in the table
*/
public function showAction(){
$this->item = $this->_table->find($this->_getParam('id'));

// Create array because of bug
$data = $this->item->toArray();
$this->id = $data[$this->primary];
}

/**
* The edit action shows a form for editing a row in the table
*/
public function editAction(){
$this->item = $this->_table->find($this->_getParam('id'));
}

/**
* The update action updates the table with information from the edit form
*/
public function updateAction(){
// Add some kind of post method check
// check if post variables are available

$id = $_POST[$this->primary];

// We don't want to update the primary column
unset($_POST[$this->primary], $_POST['submit']);

$where = $this->_table->getAdapter()->quoteInto($this->primary." = ?", $id);
$this->_table->update($_POST, $where);

$this->_redirect('show/id/'.$id);
}

/**
* The add action displays a form for adding a new row to the table
*/
public function newAction(){
$this->columns = $this->_tableInfo['cols'];
}

/**
* The create action adds a new row to the table
*/
public function createAction(){
unset($_POST['submit']);

$id = $this->_table->insert($_POST);
$this->_redirect('show/id/'.$id);
}

/**
* The delete action deletes a row from the table
*/
public function destroyAction(){
$where = $this->_table->getAdapter()->quoteInto($this->primary." = ?", $this->_getParam('id'));
$this->_table->delete($where);
$this->_redirect('../../list');
}


}

This class extends the action class and defines eight new actions for the controller. For the list, show, edit and new action we create views to display the information delivered by this controller. The view files can be found in the zip file, together with an application to test the scaffolding class.

Suggestions for improvement of the Scaffold class

The given implementation of the Scaffold class is just an example of how it can be implemented. There are a lot of improvement points and possible security problems.

Some suggestions for improvement:

  • Move the view files to the Zend Framework path, so users don’t have to copy it to their application path.
  • Check if a view is available, if not, use the framework default view for the action (but therefor the above point should be solved first)
  • Display form elements according to the column type
  • Check if the request method of the update and create actions is post

Feedback

Things I’m missing in the current version of the framework and bugs I’ve found:

  • There is no possibility to get the current url of the page. If you want to create a link to a different action in the same controller, you should always read the current url and do some tricky actions. Maybe a function like this can be interesting:
    // Returns the value of the controller part and the action part of the url,
    // in case of requesting 'tableNameController/edit/id/1' this would return 'tableNameController/edit'
    $this->getUrl("controller/action");
  • In the form helper functions, it is possible to define html tag arguments in the array. In case of the ‘disabled’ argument of a form element, giving a boolean always puts the disabled argument in the tag. Actually, you only want to add the disabled argument when the argument is true. In case of false, the output would be ‘disabled=”"‘, which still means that the element is disabled.
  • A new function in the inflector class for creating human readable column names: ‘site_id’ should become ‘Site id’. Maybe make the inflector class available as a helper in a view?
  • A way to detect if a request is post or get and if there are certain post variables available. For example in the update method in my class this can be useful. The update method should only be parsed succesful when the method is post and the post variables that existed in the edit form are available.
  • With the Zend_Db_Table::update method, it is possible to update some rows in the table. The method doesn’t check if the given keys are valid columns in the table.
  • “Notice: Undefined index: ID in e:public_htmlZFlibraryZendDbTableRow.php on line 95″ When using ID as a primary column, ZF sometimes makes the column lowercase. In this case, the column exists, but the value is stored in ‘id’, so this error is thrown.
  • Create a special Zend_Db_Row property which contains the value of the primary key:
    echo $this->item->_primary;
    // instead of
    $data = $this->item->toArray();
    $info = $this->_table->info();
    echo $data[$info['primary']];
  • Make it possible to have table prefixes that do not need to be in the classname of the class that extends Zend_Db_Table or Fly_Scaffolding
  • Improve the table classes to:
    • Define validations for table contents which can easily be read to use in add/edit forms.
    • Define relations between tables
    • Make is possible to read the column types of the table to use appropriate form elements

I really hope that there will be some kind of scaffolding in the stable version of the Zend Framework. With one small class and a few views, the work of many developers can be made a lot easier.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Wed, 08 Mar 2006 11:31:55 -0800 AJAX & byFly.net [Deel 1] http://edwinv.nl/webdevelopment/ajax-byflynet-deel-1 http://edwinv.nl/webdevelopment/ajax-byflynet-deel-1

byFly.net is al tijden mijn virtuele kindje. Nu hij zijn eerste stapjes in de grote mensen wereld gezet heeft, denk ik dat het tijd wordt om hem eens te leren voetballen zodat hij later misschien wat kan gaan doen bij AJAX.

Een van de trends binnen Web 2.0 is Rich User Experience. Door middel van alom bekende technieken is het nu plots mogelijk om de mooiste dingen te doen en de gebruiker een rijkere ervaring te geven. Verschillende JavaScript libraries maken je het op dit punt makkelijk, ze bieden je een uitbreiding van de standaard functies van JavaScript (Prototype), mooie effecten (Script.aculo.us) en AJAX functionaliteit (Prototype).

De opbouw van een pagina binnen byFly.net bestaat uit enkele containers die zijn vastgelegd in de sjabloon van de pagina. Binnen het systeem bepaal je welke inhoud deze containers moet hebben door er gegevensblokken aan toe te voegen. De inhoud van deze gegevensblokken is afkomstig van de verschillende modules en kunnen dus allerlei soorten inhoud bevatten.

Wanneer 2 pagina’s dezelfde sjablonen hebben, is het dus mogelijk om alleen de inhoud van de containers te vervangen met de nieuwe inhoud. We kunnen zelfs nog een stapje verder gaan: blokken die in beide pagina’s aanwezig zijn hoeven ook niet meer van de server gehaalt te worden. Via een simpele AJAX request halen we dus alleen de nieuwe blokken op en plaatsen die in de juiste containers in de pagina.

Een nadeel van deze manier van werken is de gebruiksvriendelijkheid voor minder validen. Daarbij denk ik voornamelijk aan de bezoekers die met een screenreader de website bekijken en soms geen JavaScript ondersteuning hebben. Een belangrijke eis is dus dat de pagina’s ook zonder JavaScript normaal hun werk doen. Daarnaast moet het systeem niet de handige features van de browser onbruikbaar maken, zoals de bookmark functie en de history knoppen.

De eerste eis is redelijk simpel te bereiken: zorg ervoor dat het systeem altijd een normaal bruikbare pagina oplevert en vervang in de browser pas de links naar pagina’s door links naar AJAX requests.

De tweede eis had wat meer voeten in de aarde. Bronnen die ik hiervoor gebruikt heb zijn:
* AJAX Tutorial: A Tale of Two IFrames
* Developing Ajax Applications That Preserve Standard Browser Functionality
* Fixing the Back Button and Enabling Bookmarking for AJAX Apps
* AJAX: How to Handle Bookmarks and Back Buttons

De oplossing ligt in het gebruiken van het hash element in een url. Door deze aan te passen zal er geen nieuwe request naar de server gaan, maar wordt in Firefox wel de history aangeroepen en is het mogelijk om een link op te slaan als bookmark.

De werking van het systeem zal globaal het volgende zijn:
# Na het laden van de pagina alle links op de pagina aanpassen en in plaats van ‘index.php?page=_pagename_’ de link te laten verwijzen naar ‘index.php#_pagename_’.
# Een inventarisatie maken van de huidige inhoud van de containers.
# Een observer aanmaken die door middel van polling kijkt of de hash in de url aangepast is doordat er op een link in de pagina geklikt is.
# Indien dit het geval is, de huidige toestand van de pagina opsturen naar een serverside script
# Dit script zal de structuur van de weer te geven pagina opsturen en alleen de gegevens die nog niet beschikbaar zijn in de browser meesturen
# De response van de AJAX request wordt verwerkt tot een aanpassing van de containers op de pagina met de nieuwe gegevens. Dit kan eventueel gebeuren met een mooi effectje.

Een eerste versie van dit systeem is hier te vinden.

De volgende punten moeten nog opgelost worden:
* Wat als een gebruiker zonder JavaScript van een gebruiker met JavaScript een url met een hash erin krijgt? Op dit moment wordt in JavaScript die hash uitgelezen en de pagina aangepast. Dit is zoiezo onzinnig, want dan wordt eerst een paginainhoud geladen die de gebruiker niet nodig heeft, om vervolgens deze direct te vervangen met de inhoud van de pagina van de hash.
* Zou niet van tevoren bekend moeten zijn of achter een link een pagina met een andere sjabloon zit? Hierdoor kan sneller ingespeelt worden op requests van pagina’s met een andere sjabloon door gelijk de complete pagina te verversen. Is dit de verantwoordelijkheid van het serverside script of kan dit ook opgelost worden met een AJAX request gelijk na het laden van de pagina?
* In Internet Explorer moet de history functie nog geïmplementeerd worden. Hiervoor moet gebruik gemaakt worden van een iframe.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Wed, 08 Mar 2006 10:17:00 -0800 Zend Framework 0.1.2 http://edwinv.nl/webdevelopment/zend-framework-012 http://edwinv.nl/webdevelopment/zend-framework-012

Vandaag is een nieuwe preview van het Zend Framework uitgekomen.

Mike Naberezny:
“Also, we are hoping to roll out a new preview release today that will include additional documentation, the unit test suite, and fixes for all bugs that have been reported to date. We hope new preview releases will be a very frequent event. “

De bijbehorende changelog is:
* Fixed default charset in Zend_Mail constructor. Reported by Jakob Buchgraber. (Mike)
* Fixed several Zend_Filter methods. (Chris)
* Fixed JSON datum encoding. Reported by Edwin V. (Mike)
* Fixed FormRadio Helper. Reported by AJ Tarachanowicz. (Chris)
* Fixed Zend_Uri_Http to work with new Zend_Filter. (Chris, Mike)
* Docs for the Zend_Db::factory() method were incorrect. Reported by Dinh. (Chris)
* Zend::loadClass() now works inside __autoload(). Reported by Rob Allen. (Mike)
* Fixed notices from Zend_Pdf_Element_Dictionary. Reported by Ralf Eggert. (Alex)
* Fixed notices from Zend_Search_Lucene_Index_SegmentWriter. Reported by Jared Williams. (Alex)
* Removed defunct Zend_Db_DataObject docs. (Mike)
* Added NEWS.txt file (Andi)

De nieuwe versie is te downloaden vanaf hier.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Mon, 06 Mar 2006 18:35:06 -0800 Zend Framework http://edwinv.nl/webdevelopment/zend-framework http://edwinv.nl/webdevelopment/zend-framework

Na veel onduidelijkheid over het uitkomen van een nieuw framework, is de eerste preview eindelijk beschikbaar. Het Zend Framework is een product van het PHP Collaboration Project dat is opgestart door Zend. Met medewerking van onder andere IBM, Intel en MySQL wil Zend de taal PHP een nieuw leven in blazen.

De drie producten die het resultaat zijn van deze samenwerking zijn:
* Het Zend Framework
* De Zend Developer Zone
* Een Eclipse-based IDE (Op dit moment nog een proposal)

Het Het Zend Framework biedt een degelijke basis voor het werken met PHP. Gebaseerd op de nieuwe technieken in PHP 5 krijg je een volledig OOP framework met een database abstractie layer, MVC pattern en Lucene search. Alles is grondig gedocumenteerd, al staan er op dit moment nog zaken in de manual die nog niet in het framework zitten.
In het framework zelf zitten helaas nog veel bugs, maar we mogen natuurlijk niet te hoge eisen stellen van een preview versie. De ontwikkelaars gaan zeer netjes om met bug reports en we mogen binnenkort een nieuwe preview verwachten/

Enkele nuttige artikelen over het framework zijn hier te vinden:
* Zend Controller
* Zend Framework Front Controller
* Zend Framework Views and the Front Controller
* Zend Framework review-internals en werking

Op de De Zend Developer Zone kan je interessante artikelen vinden over PHP. Een reeks over patterns is er nu al te vinden en belooft veel goeds voor de toekomst.

De Eclipse-based IDE is op dit moment nog een proposal, maar zal in de toekomst een gratis alternatief voor Zend Studio gaan worden. Ook dit is weer een zeer nobel initiatief!

Conclusie: al staat dit project nog in de kinderschoenen, het belooft veel goeds voor de toekomst.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Thu, 01 Dec 2005 10:18:21 -0800 FCKeditor - The text editor for Internet http://edwinv.nl/webdevelopment/fckeditor-the-text-editor-for-internet http://edwinv.nl/webdevelopment/fckeditor-the-text-editor-for-internet

Om je gebruikers van je PHP scripts die geen kennis van html hebben, toch HTML te laten gebruiken, kan je een WYSIWYG editor gebruiken. Vaak hebben deze editors een interface die lijkt op die van MS Word.
Sinds enige tijd bestaat er een hele goede WYSIWYG editor, namelijk FCKeditor. Deze editor is gemaakt door Frederico Caldeira Knabben en bevat zeer veel functies. De editor is volledig aan te passen aan je eigen wensen door de uitgebreide instellingen en de mogelijkheid om plugins te maken.

In dit artikel wil ik jullie kennis laten maken met de mogelijkheden die FCKeditor te bieden heeft.

Wat is FCKeditor?

Zoals gezegd is het met FCKeditor mogelijk om gebruikers van je programma’s html te laten produceren. De interface van de editor is te vergelijken met bijvoorbeeld Word. De drempel voor gebruikers is dus erg laag.

De mogelijkheden van FCKeditor lopen sterk uiteen. Zo zijn de meeste basis functies voor het opmaken van tekst aanwezig, maar ook het weergeven van plaatjes en tabellen is opgenomen. Om te kijken welke mogelijkheden FCKeditor te bieden heeft raad ik jullie aan om de demo op de website te bekijken.

Wat FCKeditor eigenlijk doet, is het vertalen van de menu acties in bruikbare html code. Bijvoorbeeld, door te klikken op de knop ‘B’, komen er bold tags om de geselecteerde tekst te staan. Bij het toevoegen van tags, bijvoorbeeld een table tag, zal de editor netjes een dialoogscherm weergeven en bepaalde gegevens vragen. Nog een stapje verder zijn de img tags. Deze kan je in de editor resizen, waarbij de editor automatisch de hoogte en breedte in de tag aanpast. Via het img dialoog scherm is het weer mogelijk om nieuwe afbeeldingen te uploaden of te zoeken op de server via een bestandsverkenner.

Naast al de geweldige functies, heeft FCKeditor nog een belangrijk voordeel, namelijk dat de editor crossbrowser is. De website van FCK claimt het volgende: “FCKeditor is compatible with most internet browsers which include: IE 5.5+ (Windows), Firefox 1.0+, Mozilla 1.3+ and Netscape 7+.”

h4. Installatie

FCKeditor is eigenlijk een vervanging van een textarea in een html formulier. Het verwerken van de gegevens uit de editor gaat hetzelfde als met een textarea. In PHP zal er in je POST of GET array een element bestaan die als naam de waarde heeft die je opgegeven hebt bij het aanmaken van de editor.
Om FCKeditor compatible te maken met allerlei technieken op het internet, kan je FCKeditor op verschillende manieren invoegen in je website. In dit artikel zal ik kort het aanmaken van een editor via JavaScript en PHP behandelen.
In de onderstaande voorbeelden ga ik er vanuit dat je de source code van FCKeditor in de map FCKeditor hebt staan. Mocht je de source code van de editor ergens anders geplaatst hebben, dien je de locaties van de bestanden aan te passen.
JavaScript toepassing

Als je de editor via JavaScript toe wilt voegen aan je HTML code, moet je 2 dingen doen. Om te beginnen include je de JavaScript source in je html bestand:

<script type="text/javascript" src="FCKeditor/fckeditor.js"></script>

Vervolgens voeg je op de plaats waar je de editor in je formulier wilt zetten nog een stukje JavaScript in:

<script type="text/javascript">
var oFCKeditor = new FCKeditor( 'FCKeditor1' ) ;
oFCKeditor.Create() ;
</script>

PHP toepassing

Ook via PHP kan je de editor heel simpel toevoegen aan een formulier. Het is natuurlijk mogelijk om de bovenstaande JavaScript methode te echoën, maar er zit ook een hele handige
PHP klasse bij de editor. De onderstaande code kan je gebruiken om via PHP een editor aan te maken.
<?php
include("FCKeditor/fckeditor.php") ;
$oFCKeditor = new FCKeditor('FCKeditor1') ;
$oFCKeditor->Create() ;
?>

Instellingen van de instantie

FCKeditor is op verschillende manieren aan te passen aan je eisen. Zo heb je de globale configuratie in het fckconfig.js bestand, maar sommige instellingen verschillen per instantie van de editor. Denk hierbij bijvoorbeeld aan de inhoud van de editor. Om dit in te stellen heb je enkele configuratie opties die je bij het aanmaken van een editor kunt opgeven.
Standaard geef je al de naam van het formulier element mee, in de bovenstaande voorbeelden is dat dus ‘FCKeditor1′. Na het versturen van het formulier zijn de gegevens uit de editor via PHP dus te bereiken via $_POST['FCKeditor1'] of $_GET['FCKeditor1'].
Instellingen beschikbaar bij het aanmaken van de editor

Naam Omschrijving
Value De beginwaarde die de editor heeft
BasePath De map waarin de editor zijn source kan vinden
Width De breedte van de editor, deze kan zowel opgegeven worden in pixels ( “150″ ) als in procenten ( “100%” )
Height De hoogte van de editor, deze kan zowel opgegeven worden in pixels ( “150″ ) als in procenten ( “100%” )
ToolbarSet De menu balk die gebruikt moet worden. Dit moet een waarde van een menu balk zijn zoals deze bestaat in fckconfig.js
Config Dit is een array waarin je alle configuratie opties kunt aanpassen die ook in het fckconfig.js bestand staan. Meer informatie over deze opties kan je vinden in hoofdstuk 2 van dit artikel.

Door de bovenstaande variabelen een waarde te geven pas je de editor dus aan, een voorbeeld in PHP hoe dit zou kunnen staat hieronder.
<?php
include("FCKeditor/fckeditor.php") ;
$oFCKeditor = new FCKeditor('FCKeditor1') ;
$oFCKeditor->Value = "Dit is de inhoud van de editor";
$oFCKeditor->Height = 150; // Dus 150 pixels
$oFCKeditor->Width = "100%";
$oFCKeditor->ToolbarSet = "MijnToolbar"; // 'MijnToolbar' moet in dit geval bestaan in de fckconfig.js
$oFCKeditor->Config['DefaultLanguage'] = "nl";
$oFCKeditor->Create() ;
?>

Informatie over het installeren van FCKeditor via andere programmeertalen is te vinden op de Wiki van FCKeditor.

Instellingen

In het bestand fckconfig.js kan je allerlei instellingen van FCKeditor aanpassen aan je eigen wensen. Op deze manier kan je de editor op verschillende manieren gebruiken. In dit hoofdstuk zal ik verschillende onderdelen van het configuratie bestand behandelen. De items die niet in de onderstaande tabel staan zal je in het begin niet of nauwelijks hoeven aan te passen.

Configuratie instellingen in fckconfig.js

Naam Omschrijving
EditorAreaCSS Hoofdstuk 4: CSS stylesheets
DocType Het document type dat gebruikt moet worden.
BaseHref De basis url waar de editor alle bestanden kan vinden.
FullPage De gebruiker kan een volledige html pagina bewerken (inclusief headers/title)
SkinPath De map naar de skin die je wilt gebruiken. Standaard zijn beschikbaar: ‘default’, ‘silver’ en ‘office2003′.
AutoDetectLanguage Moet FCKeditor automatisch de taal van de gebruiker proberen te achterhalen?
DefaultLanguage De standaard taal als FCKeditor de taal niet automatisch heeft gevonden.
StartupFocus Moet de editor bij het starten de focus krijgen.
UseBROnCarriageReturn Indien true zal de editor een <br/> invoegen bij geven van een Enter, anders zal hij een nieuwe alinea starten met een

tag.

ToolbarSets Hoofdstuk 6: Menu balken
FontColors Welke letter kleuren moeten er in het menu staan.
FontNames Welke letter typen moeten in het menu staan.
FontSizes Welke letter groottes moeten in het menu staan.
FontFormats Welke letter formaten moeten in het menu staan.
StylesXmlPath Hoofdstuk 4: CSS stylesheets
TemplatesXmlPath Hoofdstuk 5: Document sjablonen
Link⁄Image⁄Flash Browse Hoofdstuk 7: Bestands beheer & Uploaden
Link⁄Image⁄Flash Upload Hoofdstuk 7: Bestands beheer & Uploaden
SmileyPath Met deze opties kan je aangeven in welke map de editor de smilies voor het menu kan vinden.
SmileyImages Hiermee kan je de bestanden opgeven die in het menu moeten komen te staan.


h4. CSS stylesheets

In FCKeditor is het mogelijk om de stijl van de inhoud van de editor aan te passen via een css stylesheet. Hiervoor heb je in fckconfig.js twee configuratie opties:

  • EditorAreaCSS: De locatie van het css bestand waarin de stijl staat die toegepast moet worden op de inhoud
  • StylesXmlPath: De locatie van een xml bestand met daarin de inhoud van het stijl menu in de menu balk

Het css bestand heeft verder weinig uitleg nodig. Je kunt gebruik maken van standaard css en in de editor kan je via een class of id de opmaak toepassen op een element.
Het xml bestand moet wel voldoen aan bepaalde eisen. Een voorbeeld van een xml document staat hieronder.

<?xml version="1.0" encoding="utf-8" ?>
<Styles>
<Style name="Custom Italic" element="em" />
<Style name="Title" element="span">
<Attribute name="class" value="Title" />
</Style>

<Style name="Image Width" element="img">
<Attribute name="width" value="100" />
</Style>
</Styles>

Zoals je kunt zien zijn er drie verschillende tags die je kunt opnemen:

  • Styles: Hierin zitten alle definities
  • Style: Bevat een stijl definitie
    • name: De naam van de definitie zoals deze in het menu komt te staan
    • element: Op wat voor type element kan deze stijl toegepast worden.
  • Attribute: Een attribuut van een tag
    • name: De naam van het attribuut dat toegevoegd moet worden aan het huidige element
    • value: De waarde van dit attribuut

Aan de hand van deze gegevens kunnen we het bovenstaande xml voorbeeld eens doorlopen. Allereerst maak je een definitie met de naam ‘Custom Italic’, deze zal <em> tags toevoegen om de geselecteerde tekst. Er zijn geen attributen gedefinieerd, dus zullen alleen de tags toegevoegd worden.
De tweede definitie heeft de naam ‘Title’ en voegt om de geselecteerde tekst een span tag toe met als attribuut class=”Title”.
De laatste definitie zorgt ervoor dat een img tag een breedte van 100 pixels krijgt.

Binnen de definities kan je twee verschillende soorten onderscheiden. Zo bestaan er inline of text definities die aan een stukje tekst een stijl geven. De geselecteerde tekst krijgt nieuwe tags om zich heen met de gedefinieerde attributen. Als de tags al bestaan om de tekst zullen alleen de attributen toegevoegd worden.
Het tweede soort zijn object definities, hiermee kan je aan een object een stijl geven. Objecten zijn elementen met één van de volgende html tags: img, table, tr, td, input, select, textarea, hr en object. De stijl definities voor dit soort objecten zijn pas zichtbaar in het menu op het moment dat je een element van dit type selecteert in de editor.


h4. Document sjablonen

De feature voor document sjablonen is nog niet zo lang aanwezig in FCKeditor. Via de configuratie optie TemplatesXmlPath geef je de locatie van een xml bestand op. In dit xml bestand kan je sjablonen opgeven voor de inhoud van de editor. Een sjabloon bestaat uit een stukje html code dat in de editor geplaatst wordt. Binnen het xml bestand kunnen de volgende elementen opgenomen worden:

  • Templates: Het basis element van de xml definitie
    • imagesBasePath: Het basis pad voor de afbeeldingen van de sjablonen
  • Template: De definitie van een sjabloon
    • title: De titel van dit sjabloon
    • image: De afbeelding die weergegeven wordt in het sjabloon keuze menu in de editor.
  • Description: De optionele omschrijving van een sjabloon
  • Html: De html inhoud van het sjabloon. Denk er om dat de html code moet staan tussen <![CDATA[ en ]]> om het xml bestand valide te houden.

Een voorbeeld van een definitie van een sjabloon zal er dan zo uit zien:

<?xml version="1.0" encoding="utf-8" ?>
<Templates imagesBasePath="/images/templates/">
<Template title="My Template 1" image="template1.gif">
<Description>Description of my template 1.</Description>

<Html>
<![CDATA[
Template 1 HTML
]]>
</Html>
</Template>

<Template title="My Template 2">
<Html>
<![CDATA[
Template 2 HTML
]]>
</Html>

</Template>
</Templates>


h4. 6. Menubalken

Om je de mogelijkheid te bieden om de editor op verschillende fronten in te zetten, heeft Frederico het mogelijk gemaakt om zelf de menu balken in te stellen. Je kan verschillende verzamelingen aanmaken en bij het aanmaken van een instantie op een pagina aangeven welke balken je wilt gebruiken. Ook de items die in het context menu staan kan je op deze manier aanpassen.
In fckconfig.js vind je de verzameling ToolbarSets waarin de arrays met toolbars zitten. Een voorbeeld van een menubalk verzameling staat hieronder:

FCKConfig.ToolbarSets["Basic"] = [
['Bold','Italic','','OrderedList','UnorderedList','','Link','Unlink','-','About'],
['TextColor','BGColor']
] ;

Deze menubalk heeft de naam ‘Basic’ en bevat negen knoppen. De ‘-’ items zijn verticale lijnen. Door een nieuwe array te beginnen maak je een nieuwe balk aan. De items ‘TextColor’ en ‘BgColor’ staan dus in een aparte ruimte.
Als je de menubalken wilt aanpassen is het verstandig om van de ‘Default’ verzameling uit te gaan, vervolgens de opbouw op het scherm te bekijken en dan te bepalen wat je anders wilt. Dit zal ik hier niet verder behandelen.

Wat nog wel belangrijk is om te weten, is dat er geen verschil is tussen een knop en een selectie menu in de configuratie. Zo staat ‘Bold’ voor de bold knop, ‘TextColor’ voor een kleuren menu en ‘FontName’ voor de lettertype selectie box. In de configuratie bestaat hierin geen verschil.

Bestands beheer & Uploaden

In je html wil je soms ook plaatjes en link opnemen. De editor heeft hiervoor keurige dialoog vensters om een link naar een bestand of locatie van een plaatje op te geven. In deze vensters kan je de gebruiker de mogelijkheid geven om een bestand te uploaden. Om dit mogelijk te maken kan je de volgende configuratie opties gebruiken:

Naam Omschrijving
TypeUpload True indien de upload optie beschikbaar is voor dit type
TypeUploadURL De locatie van het upload script (bijvoorbeeld geschreven in PHP)
TypeUploadAllowedExtensions Welke bestandsextensies zijn toegestaan om te uploaden (dit is een regular expression)
TypeUploadDeniedExtensions Welke bestandsextensies zijn niet toegestaan om te uploaden (dit is een regular expression)

In de bovenstaande tabel kan je Type vervangen voor 3 voorkomende type bestanden: Link, Image en Flash.

Indien voor een bepaald bestandstype het uploaden actief is, zal in het dialoog een extra tabblad aangemaakt worden. In dit tabblad zal een upload formulier element te zien zijn. Na het versturen van het formulier zal het script aangeroepen worden dat is opgegeven bij de UploadURL. In de uploader die standaard bij de editor zit is duidelijk te zien op welke manier dit verwerkt wordt.

De volgende stap is het bladeren door bestanden. In de onderstaande tabel kan je de configuratie opties voor de bestandsbrowser vinden.

Naam Omschrijving
TypeBrowser True indien de gebruiker de mogelijkheid heeft om de bestanden op de server te verkennen
TypeBrowserURL De locatie van de bestandsbrowser. Standaard wordt voor PHP een simpele browser en de uitgebreidere mcpuk browser meegeleverd.
TypeBrowserWindowHeight De hoogte van het browser scherm
TypeBrowserWindowWidth De breedte van het browser scherm

Wederom kan je voor Type de drie voorkomende bestandstypen invullen: Link, Image en Flash.

De BrowserURL bestaat standaard altijd uit 2 delen, namelijk een basis locatie van het browser bestand en de locatie van een connctor. In het browser bestand staat de html opbouw van de browser. De connector is een server-side script dat de inhoud van de mappen uitleest. Door de standaard browser default/browser.html te gebruiken in combinatie met de php connector connectors/php/connector.php kan je gebruik maken van de browser en de bestanden via php uitlezen.

In de meeste gevallen zullen de standaard scripts voldoen aan je eisen, maar je kunt natuurlijk ook zelf een bestandsbrowser schrijven. Laat de URL verwijzen naar je php script waarmee je de inhoud van een directory weergeeft. In de html van je bestand kan je de volgende javascript opnemen om de url van het geselecteerde bestand in te voegen in het dialoog venster in FCKeditor.

function selectFile(sUrl){
window.top.opener.SetUrl(sUrl);
window.top.close();
window.top.opener.focus();
}

Door deze functie aan te roepen met de url die je wilt meegeven wordt hij ingevoegd in het dialoog venster.


h4. Plugins

Het is mogelijk om plugins toe te voegen aan FCKeditor om de functionaliteit uit te breiden. Op dit moment zijn er nog maar een beperkt aantal plugins beschikbaar, maar dit zal in de toekomst zeker beter worden.
Een plugin toevoegen aan de editor bestaat uit drie stappen:

  1. Plaats de inhoud van de plugin in de plugin map. Je krijgt dus nu een submap die als naam de naam van de plugin heeft. Hierin zitten alle bestanden voor de plugin.
  2. Wijzig fckconfig.js door een regel toe te voegen waarin je de plugin toevoegd. Dit ziet er bijvoorbeeld zo uit:
    FCKConfig.Plugins.Add( 'FullWindow' ) ;
    Op deze manier geef je aan dat je de plugin ‘FullWindow’ wilt gebruiken in je editor.
  3. Lees eventuele documentatie bij de plugin ook door. Soms is het nodig om een menu item toe te voegen aan een menu om de plugin goed te kunnen gebruiken.

Hoe je zelf een plugin kunt maken voor FCKeditor zal ik in dit artikel niet behandelen. Op de Wiki is voldoende informatie hierover te vinden. Goede kennis van JavaScript is in ieder geval nodig!

In de onderstaande tabel staan enkele plugins die op dit moment handig kunnen zijn. Op de plugin pagina op Sourceforge.net kan je meer plugins vinden.

Naam Omschrijving
FullWindow Een plugin waarmee je de editor in een popup kunt laten openen zodat de gebruiker meer ruimte heeft om de tekst te bewerken. Het is mogelijk om verschillende menu balken te gebruiken bij de kleine en de grote versie.
OpenWord Hiermee is het mogelijk om rechtstreeks een Word document te importeren in de editor. Er wordt gebruikt gemaakt van een ActiveX object en hierdoor is de plugin alleen beschikbaar in Internet Explorer.
SpellWord Omdat de standaard spelling controle opties in FCKeditor op dit moment alleen beschikbaar zijn in het Engels, maakt deze plugin gebruik van de spelling controle van Word. Ook deze plugin werkt met een ActiveX besturingselement en is daardoor alleen beschikbaar in Internet Explorer.


h4. Tips

Vaak zal FCKeditor niet helemaal goede HTML terug geven. De mogelijkheden om de code op te ruimen via het programma zelf worden al steeds beter, maar via Tidy kan je de code ook opruimen. In PHP 5 zijn deze functies standaard beschikbaar.

Door je eigen bestandsbrowser te maken kan je eventuele beveiliging daarin verwerken. Wanneer je gebruik maakt van de standaard verkenners van FCKeditor geeft dat iedereen de mogelijkheid om je bestanden te bekijken.

Heb je nog steeds problemen met de editor na het lezen van dit artikel? Doneer een bedrag aan Frederico voor zijn geweldige werk en je krijgt een jaar lang gratis e-mail ondersteuning.

Bronnen

Bij het schrijven van dit artikel heb ik gebruik gemaakt van de onderstaande websites.

Ben ik handige plugins vergeten? Heb je nog een handige tip? Ben ik een belangrijke configuratie instelling over het hoofd gezien? Neem even contact op, dan zal ik kijken wat ik er aan kan doen!

Allemaal veel plezier met het gebruiken van deze geweldige editor!

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Tue, 14 Jun 2005 09:26:41 -0700 Whois script http://edwinv.nl/webdevelopment/whois-script http://edwinv.nl/webdevelopment/whois-script

De onderstaande klasse voor PHP 5 kan gebruikt worden om een whois query uit te voeren. Hiermee kan je controleren of een domeinnaam beschikbaar is. Er wordt gebruik gemaakt van de ‘whois is’ methode bij .nl domeinen, zodat het limiet van 15 aanvragen per dag omzeilt wordt.

<?php

/**
* Whois class
* Copyright by Edwin Vlieg - Flydesign.nl
*
* Example use:

$who = new whois();
$result = $who->checkDomain("flydesign", "nl");

if($result == Whois::AVAILABLE){
echo "Domain available";
} else {
echo "Domain not available";
}

*
*/

class Whois
{

const AVAILABLE = 1;
const TAKEN = 2;
const NO_EXTENSION = 3;
const NO_SERVER = 4;
const ERROR = 5;
const NO_DATA = 6;
const INVALID_NAME = 7;

private $aExtensions;
private $sExecCode;
private $iPort;
private $sResult;

/**
* @desc Create a new whois instance
*/
function __construct(){
$this->iPort = 43;

/**
* Extension array
* Insert new sExtensions in this array, to make more sExtensions available for check
*/
$this->aExtensions = array(
'nl' => array('whois.domain-registry.nl', 'is free'),
'com' => array('whois.crsnic.net', 'No match for'),
'net' => array('whois.crsnic.net', 'No match for'),
'org' => array('whois.publicinterestregistry.net', 'NOT FOUND'),
'co.uk' => array('whois.nic.uk', 'No match'),
'edu' => array('whois.internic.net', 'No match'),
'be' => array('whois.dns.be', 'No such domain'),
'cc' => array('whois.nic.cc', 'No match'),
'ac.cn' => array('whois.cnnic.net.cn', 'no matching record'),
'de' => array('whois.nic.de', 'No entries found'),
'dk' => array('whois.dk-hostmaster.dk', 'No entries found'),
'fr' => array('whois.nic.fr', 'No entries found'),
'it' => array('whois.nic.it', 'No entries found'),
'pl' => array('whois.dns.pl', 'does not exists'),
'se' => array('whois.nic-se.se', 'No data found'),
'info' => array('whois.afilias.net', 'NOT FOUND'),
'biz' => array('whois.nic.biz', 'Not found'),
'ws' => array('whois.nic.ws', 'No match for'),
'gov' => array('whois.nic.gov', 'No match for'),
'tv' => array('whois.internic.net', 'No match for'),
'name' => array('whois.nic.name', 'No match'),
'pro' => array('whois.internic.net', 'No match for'),
'ie' => array('whois.domainregistry.ie', '% There was no match in the IE Domain'),
'us' => array('whois.nic.us', 'Not found:'),
'tk' => array('whois.dot.tk', 'not known'),
'cd' => array('whois.cd', 'No match'),
'aero' => array('whois.information.aero', 'is not registered'),
'gr' => array('whois.ripe.net', 'No entries found'),
'by' => array('whois.ripe.net', 'No entries found'),
'ad' => array('whois.ripe.net', 'No entries found'),
'lv' => array('whois.ripe.net', 'No entries found'),
'eu.lv' => array('whois.biz', 'Not found'),
'bz' => array('mhpwhois1.verisign-grs.net', 'No match'),
'es' => array('whois.ripe.net', 'no entries found'),
'jp' => array('whois.nic.ad.jp', 'No match!!'),
'cl' => array('whois.nic.cl', 'no existe'),
'ag' => array('whois.nic.ag', 'NOT FOUND'),

);
}

/**
* @desc Add a new sExtension to the array (will only apply on the current object)
* @param string $sExtension Name for the sExtension
* @param string $sServer Server for whois data
* @param string $sFreeString Whois data must contain this string if the domain is free
*/
function addExtension($sExtension, $sServer, $sFreeString){
if(!empty($sExtension) AND !empty($sServer) AND

$sExtension)
foreach($this->aExtensions as $sExt => $sServer)
if(substr($sExtension, strlen($sExt)*-1) == $sExt)
$sExtension = $sExt;

if(empty($sDomain) OR empty($sExtension)){
return self::NO_DATA;
}

$sDomainName = $sDomain .".". $sExtension;

if(!preg_match("/^[w.-_]+$/i", $sDomainName)){
return self::INVALID_NAME;
}

if(!isset($this->aExtensions[$sExtension])){
return self::NO_EXTENSION;
}
$aExtensionData = $this->aExtensions[$sExtension];
$sDomainName = escapeshellcmd($sDomainName);

if($bUnix){
if($sExtension "nl"){ $this->sExecCode = "whois -h ".$aExtensionData[0]." "is ".$sDomainName."""; } else { $this->sExecCode = "whois -h ".$aExtensionData[0]." "".$sDomainName."""; } exec($this->sExecCode, $sBuffer); if(!is_array($sBuffer) OR empty($sBuffer)){ return self::ERROR; } $this->sResult = ""; foreach($sBuffer as $sRow){ $this->sResult .= $sRow."n"; } if(stristr($this->sResult, "Connection refused") OR stristr($this->sResult, "No address associated with hostname")){ return self::NO_SERVER; } } else { if($sExtension "nl"){
$this->sExecCode = "is ".$sDomainName;
} else {
$this->sExecCode = $sDomainName;
}
$rSocket = fsockopen($aExtensionData0, $this->iPort);
if(!$rSocket){
return self::NO_SERVER;
}
fputs($rSocket, $this->sExecCode);
$this->sResult = "";
while(!feof($rSocket))
$this->sResult .= fgets($rSocket, 128);
}

if($bRaw){
return $this->sResult;
}

if(stristr($this->sResult, $aExtensionData1)){
return self::AVAILABLE;
} else {
return self::TAKEN;
}

}

/**
* Returns the last server response
*/
public function getLastResponse(){
if(isset($this->sResult))
return $this->sResult;
}
}
?>

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg
Sat, 25 Sep 2004 23:00:09 -0700 Headers already sent http://edwinv.nl/webdevelopment/headers-already-sent http://edwinv.nl/webdevelopment/headers-already-sent

Dit artikel gaat over de veel voorkomende foutmelding:

Warning: Cannot add header information – headers already sent by (output started at index.php:3) in index.php on line 1

Veel mensen vragen zich af wat deze foutmelding betekent en hoe ze hem kunnen oplossen. In dit artikel zal ik de verschillende aspecten van de foutmelding behandelen en proberen een oplossing te vinden.

Wat zegt de foutmelding

De foutmelding zegt dat er output is geweest voor een bepaalde lijn. Op die lijn staat meestal een van deze functies:

Setcookie
Header
Session_start

Een voorbeeld van een fout script kan zijn:

<?php
echo "He, jij hoort hier niet, ik ga je nu redirecten!";
header("Location: redirect.html");
?>

Onduidelijker kan ook, je kunt bijvoorbeeld per ongeluk een spatie of enter voor je php code hebben staan. Dit valt nauwelijks op, maar php ziet dit wel als output.

Hier staat tekst of een spatie
<?php
session_start();
?>

In beide gevallen hebben we iets naar de browser gestuurd voordat we nog iets aan de headers willen veranderen.

Waardoor krijg ik de foutmelding?

Via een web browser werk je met het protocol HTTP. Hierin is vastgelegd hoe een pagina aanroep eruit moet zien en welke gegevens een browser terugkrijgt voor het weergeven van een bepaalde pagina. Een voorbeeld van het opvragen van een pagina kan er zo uitzien:

GET /index.php HTTP/1.1
Host: phpfreakz.nl

Als reactie op deze request krijg je een response terug, die er als volgt uit kan zien:

HTTP/1.1 200 OK
Connection close
Date: Thu, 06 Aug 1998 12:00:15 GMT
Server: Apache/1.3.0 (Unix)
Last-Modified: Mon, 22 Jun 1998
Content-Length: 6821
Content-Type: text/html

<html>
<head>
<title>Pagina</title>

...

Via de bovenstaande functies wil je gegevens aanpassen in de headers van de response. Je kunt bijvoorbeeld instellen hoe je wilt cachen of een locatie aangeven waar de pagina heen verwijst. De opbouw van HTTP vertelt ons dat na de headers een Carriage return moet komen (2x een enter) waarna de eigenlijke inhoud van de pagina komt.
Als je eerst een stukje tekst stuurt, plakt HTTP de 2 enters onder zijn headers en gaat de tekst weergeven. Als jij daarna weer headers wilt toevoegen krijg je een foutmelding, want hij heeft het gedeelte voor de headers al afgesloten en verzonden. PHP zegt heel duidelijk wat er aan de hand is, namelijk:

Warning: Cannot add header information – headers already sent by (output started at index.php:1) in index.php on line 3

Vertalen naar het Nederlands levert op:

Waarschuwing: Kan geen header informatie toevoegen – headers zijn al verzonden (output gestart op index.php:1) in index.php op regel 3

Tussen de haakjes geeft hij zelfs al aan waar je je output hebt staan, heel simpel om dat terug te vinden en op te lossen dus.

Hoe kan ik de foutmelding weg krijgen?

Er zijn 2 mogelijke oplossingen voor het probleem. De beste oplossing is ervoor zorgen dat je geen gegevens verzendt voordat je de bovenstaande functies aanroept. Bij het scripten moet je er dus rekening mee houden dat die functies altijd als eerste behandeld worden, daarna komt de rest pas. Het zijn de zaken die je als eerste moet weten, daarna komt de rest van de pagina inhoud pas. Een kleine moeite en het voorkomt een foutmelding.

Voorbeeld:

<?php
session_start();
echo "En nu pas de teksten";
?>

Mogelijkheid twee is output buffering. Via output control kan je de output naar de browser vasthouden totdat je een bepaald commando geeft. Je kunt dan je hele script door de headers aanpassen zonder foutmeldingen te krijgen. Aan het einde stuur je alle inhoud van de buffer in een keer.

Voorbeeld:

<?php
ob_start();
echo "Een stukje tekst";

setcookie("cookiename", "cookiedata");

ob_end_flush();
?>

Output buffering is eigenlijk meer het probleem omzeilen dan het eigenlijk oplossen. Het is dus zeker aan te raden om tijdens het scripten de eerste oplossing te gebruiken.

Permalink | Leave a comment  »

]]>
http://files.posterous.com/user_profile_pics/586042/9f86e6f9bff86461d58ab78f8988051d.png http://posterous.com/users/5AfGsE869oYx Edwin Vlieg winno Edwin Vlieg