Hallo allemaal,

Ik heb net een klein OOP classje gemaakt die een form op het beeld tevoorschijn geeft.

Ik ben totaal niet tevreden met het renderen van forms.
Ik heb tot nu toe 1 element gemaakt en dat is de 'text' element.

Hebben jullie wat tips om het renderen beter laten te verlopen?


<?php

class Form
{
	private $_fields = array();
	private $_attribs = array();
	
	
	//todo
	public function setAttrib($attribName, $attribValue) { $this->_attribs[$attribName] = $attribValue; }
	public function getAttrib($attribName) { return $this->_attribs[$attribName]; }
	
	public function addField($field)
	{
		$this->_fields[] = $field;
	}
	
	public function render()
	{
		$returnValue = '<form';
		
		if (isset($this->_attribs['method']))
		{
			$returnValue .= ' method="' . $this->_attribs['method'] . '"';
		}
		else
		{
			$returnValue .= ' method="post"';
		}
		
		if (isset($this->_attribs['action']))
		{
			$returnValue .= ' action="' . $this->_attribs['action'] . '"';
		}
		
		$returnValue .= '>';
		
		foreach ($this->_fields as $field)
		{
			$returnValue .= $field->render();
		}
		
		$returnValue .= '</form>';
		
		return $returnValue;
	}

}
?>


Form_Element:

<?php
class Form_Element
{
	public $_properties = array();
	public $_label = '';
	public $_name = '';
	public $_value = '';
	
	public function __construct($fieldName)
	{
		$this->_name = $fieldName;
	}
	
	public function setProperty($property, $value)
	{
		$this->_properties[$property] = $value;
	}
	
	public function setValue($value)
	{
		$this->_value = $value;
	}
	
	public function setLabel($label)
	{
		$this->_label = $label;
	}
}
?>


Form_Element_TextField:

<?php
class Form_Element_TextField extends Form_Element
{
	public function render()
	{
		$returnValue = '';
		
		if (isset($this->_label))
		{
			$returnValue .= '<label>' . $this->_label . '</label>';
		}

		$returnValue .= '<input type="text"';
		
		$returnValue .= ' name="' . $this->_name . '"';
		
		foreach ($this->_properties as $prop => $value)
		{
			$returnValue .= ' ' . $prop . '="' . $value . '"';
		}
		
		$returnValue .= ' />';

		return $returnValue;
	}
}
?>
Eerst wat tips:
- geen public properties maken, zorg dat je controle hebt over wat er in staat
- de prefix _ voor een propertienaam gebruiken sommige mensen omdat ze dan aangeven dat het niet public is. Ik zelf vind dat een beetje onzin, maar waarom gebruik je hem ook voor public properties?
- gebruik volledige namen of erkende afkortingen, dus of setAttribute of setAttr, maar ga liever geen zelf verzonnen afkortingen gebruiken.
- typ alles op dezelfde manier, dus niet zomaar 2 methods die op 1 regel staan.

Dan inhoudelijk:
- Elk Form Element moet een render method hebben, deze moet je dus verplicht stellen. Maak daarom Form_Element abstract en geef hem een abstracte render method
- Ik weet niet wat je hier fout aan vind, dit is hoe het hoort en hoe ik het ook gebruik (zie bijv. mijn OOPbuilder project waar ong. hetzelfde gebeurd).
Ik zou de render method niet in een abstracte superclass bouwen, maar verplicht stellen via een interface. Als je elk form element (of beter, elk HTML element) hetzelfde interface laat implementeren kan je elk element naar gelang je het nodig hebt invoegen.

Een eventuele abstracte superclass zou ik wel gebruiken om de standard attributen van een form element al in te bouwen. Een text, submit, checkbox, radiobutton etc zijn allemaal van het type 'input' en hebben (of kunnen) allemaal een class, id, name, value, type. Die kan je dus al in de superclass inbouwen zodat je niet voor alle elementen hetzelfde hoeft te doen.
Erwin, het lijkt me niet nodig om nog een extra interface bovenop onze momenteel al superklasse Form_Element te bouwen. Als je die nou abstract maakt met een abstracte method en elk element extend die Form_Element dan heb je volgens mij al het juiste effect?
Wouter bedankt voor je tips, deze ga ik er zeker in verwerken
Wat ik er fout aan vind is het hergebruiken van andere elementen.
Zo moet ik dan iedere keer die

foreach ($this->_properties as $prop => $value)

Doen bij ieder nieuw element, dat is toch niet mooi?
Ik zou groter denken. Een interface die je aan elke class kan geven die een html element kan bouwen, of misschien wel het hele form, of misschien wel zelfs de hele pagina. Dat maakt het extreem flexibel.

Nu houd je het op forms, maar voor tabellen en andere elementen heb je het ook nodig. Ook die moet je kunnen renderen.

Simpel addChild methode erbij en je kan op een zeer eenvoudige wijze een hele boom opbouwen die je met 1 call kan renderen.

Er is vast een pattern voor, maar ik zo 1-2-3 niet een naam ervoor vinden.

[size=xsmall]Toevoeging op 02/07/2012 15:53:26:[/size]

Als voorbeeldje, dit is de interface die ik gebruik en al mijn view classes die pagina elementen bouwen implementeren die:
<?php
interface View_Element_Interface {
public function __construct( $tag, array $attributes = array() );
public function addChild( View_Element_Interface $child );
public function __toString();
}
?>
Aan het einde heb ik dan 1 $root en die hoef ik alleen maar te echoen en de hele boom wordt opgebouwd. Inclusief forms, tabellen, scripts, head, alles.
Hmm, ja daar dacht ik ook aan toen ik op reageren drukte. Aan dat laatste (addchild) had ik nog niet gedacht, maar klinkt geweldig!
Met dat addChild en de interface, kan je zowel form als element die interface laten implementeren. Je kan dan een form bouwen door elke keer form elementen (labels, input elementen, buttons) eraan toe te voegen middels de addChild. Bij het renderen moet je ervoor zorgen dat elk element ook de render() method van zijn child-elementen op het juiste moment aanroept en het wegschrijven gaat dan feitelijk vanzelf.

Reageren