Het maken van een aangepast formulierveld type

From Joomla! Documentation

This page is a translated version of the page Creating a custom form field type and the translation is 100% complete.

Other languages:
English • ‎español • ‎français • ‎Nederlands
Joomla! 
3.x
serie
Copyedit.png
This Article Needs Your Help

This article is tagged because it NEEDS REVIEW. You can help the Joomla! Documentation Wiki by contributing to it.
More pages that need help similar to this one are here. NOTE-If you feel the need is satistified, please remove this notice.

JForm, een functie geïntroduceerd in Joomla! 2.5, stelt u in staat eenvoudig HTML-formulieren te maken (<form>). Formulieren gemaakt met JForm bestaan uit formuliervelden, geïmplementeerd als JFormFields. Er is een JFormField voor elk veldtype in een formulier, zoals een tekstveld en een datumveld. JForm ondersteunt een grote selectie aan standaard veldtypen. Voor een volledige lijst, zie Standaard formulierveld typen.

Joomla! 2.5 maakt het mogelijk om de standaard veldtypen uit te breiden of om uw eigen te definiëren. Bijvoorbeeld, als uw component een telefoonboek beheert, zou u een veldtype kunnen definiëren dat een lijst van steden geeft. Er zijn verschillende voordelen als u een aangepast veldtype definieert:

  • U kunt standaard veldtypen samen gebruiken met uw aangepaste veldtype in een JForm-formulier.
  • U zult uiteindelijk een herbruikbaar code pakket hebben gecreëerd dat gemakkelijk gebruikt kan worden in de rest van uw code.
  • Extensies die samenwerken met uw extensie zullen in staat zijn om formuliervelden te maken zonder zich te bemoeien met uw database tabellen en andere interne zaken.

Formulierveld type class vereisten

Een formulier veldtype is gedefinieerd in een class die een (niet noodzakelijkerwijs directe) subclass van JFormField moet zijn. Om correct te werken, moet de class tenminste drie methoden definiëren:

  • public function getLabel()
    Deze functie wordt aangeroepen voor het maken van het label dat bij uw veld hoort en moet een HTML-tekenreeks teruggeven die het veld bevat. Omdat JFormField een klaar-om-te-gebruiken getLabel() implementatie definieert, definieren de aangepaste veldtypes meestal niet hun eigen getLabel(). Als je het leeg laat, zal de overgeërfde methode van het maken van labels worden gebruikt. Het wordt aanbevolen om de getLabel() methode voor consistentie en snelheid weg te laten, tenzij u echt de HTML-code van het label wilt wijzigen.
  • public function getInput()
    Deze functie wordt aangeroepen om het veld zelf te maken en moet een HTML-tekenreeks teruggeven. Dit is ook waar de meeste verwerking plaatsvindt. In ons telefoonboek voorbeeld (veld stad), zal deze functie een lijst met beschikbare steden moeten opzoeken en de HTML <select> teruggeven met de steden ingevoegd als <option>.
  • public function getValue()
    Deze functie zal gebruikt worden om de veldwaarde aan te roepen. De waarde wordt verkregen vanuit de functie LoadFormData in het model.

Binnen uw code, moet u de attributen verwerken van de door de gebruikers van de velden in het XML formulier ingestelde definitie. Sommige van deze attributen zijn toegankelijk via protected member variabelen van JFormField. Het name attribuut is bijvoorbeeld in uw code beschikbaar als $this->name. Net zo zijn label, description, default, multiple en class beschikbaar als eigenschappen van $this. Andere parameters die u heeft gedefinieerd kunnen benaderd worden via de $this->element array: het attribuut size zal zitten in $this->element['size'].

Welke class wordt een subclass?

Om een formulier veldtype bruikbaar te laten zijn in JForm, moet het een subclass van JFormField zijn. Het hoeft echter geen direct kind van die class te zijn: u kunt ook een subclass maken van een bestaand (standaard of eigen) formulier veldtype en daardoor handige code overerven.

Als uw formulier veldtype ongeveer gelijk is aan een bestaand type, zou u een subclass van dat type moeten maken. Maak, vooral als uw formulier veldtype een list is, dan een subclass JFormFieldList. U hoeft alleen een override te maken van de getOptions() method om de opties te laten zien; de getInput() method converteert deze opties naar HTML.

Laad, om een subclass te maken van een bestaand type, bijvoorbeeld JFormFieldList, het dor het volgende toe te voegen na jimport('joomla.form.formfield');:

jimport('joomla.form.helper');
JFormHelper::loadFieldClass('list');

Als uw formulier veldtype ongelijk elk ander bestaand type is, maak dan een subclass direct van JFormField aan.

Locatie van bestanden

  • De standaard formulier veldtypes stan in libraries/joomla/form/fields/. U moet hier geen eigen velden opslaan. U hoeft dit pad ook niet in uw code te gebruiken, maar de standaard types zijn in het algemeen goed voorbeelden.
  • De eigen veldtypes die bij uw component horen staan meestal in administrator/components/<naam van uw component>/models/fields. U kunt dit of een ander pad in uw code opnemen:
JForm::addFieldPath(JPATH_COMPONENT . '/models/fields');
  • De XML bestanden die formulieren definiëren staan meestal in administrator/components/<naam van uw component>/models/forms. Gebruik iets als het volgende fragment om een pad naar uw formulieren te definiëren:
JForm::addFormPath(JPATH_COMPONENT . '/models/forms');

Naam-afspraken en skelet

In deze sectie, vertegenwoordigt <ComponentName> de met hoofdletters geschreven naam van uw component en <FieldName> vertegenwoordigt de met hoofdletters geschreven naam van uw formulier veldtype. De class van het veld class moet staan in administrator/components/<NaamVanUwComponent>/models/fields/<naam van uw veld>.php en ziet er zo uit:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

jimport('joomla.form.formfield');

// The class name must always be the same as the filename (in camel case)
class JFormField<FieldName> extends JFormField {

	//The field class must know its own type through the variable $type.
	protected $type = '<FieldName>';

	public function getLabel() {
		// code that returns HTML that will be shown as the label
	}

	public function getInput() {
		// code that returns HTML that will be shown as the form field
	}
}

Het groeperen van eigen veldtypes

Waarschuwing: deze informatie is gedeeltelijk onjuist en moet verbeterd worden.

Eigen veldtypes kunnen gegroepeerd worden door een underscore in de veldnaam te gebruiken. Een veld class met bijvoorbeeld als naam "JFormFieldMy_randomField" moet opgeslagen worden in administrator/components/<naam van uw component>/models/fields/my/randomField.php. We kunnen onze formulier veldnamen laten voorafgaan van een groepsnaam, daarna een underscore en daarna de naam van het veld.

Een voorbeeld van een eigen veldtype

Stel dat u werkt aan uw component genaamd com_phonebook en u wilt een veld definiëren dat steden bevat. Maak het bestand administrator/components/com_phonebook/models/fields/city.php en schrijf iets als het volgende:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

jimport('joomla.form.formfield');

class JFormFieldCity extends JFormField {
	
	protected $type = 'City';

	// getLabel() left out

	public function getInput() {
		return '<select id="'.$this->id.'" name="'.$this->name.'">'.
		       '<option value="1" >New York</option>'.
		       '<option value="2" >Chicago</option>'.
		       '<option value="3" >San Francisco</option>'.
		       '</select>';
	}
}

Een meer geavanceerde aanpak is de JFormFieldList class uitbreiden. Stel u wilt een drop-down lijst maken met steden uit de database gebaseerd op dynamische condities, dan kan dat op de volgende manier:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

JFormHelper::loadFieldClass('list');

class JFormFieldCity extends JFormFieldList {

	protected $type = 'City';

	public function getOptions() {
                $app = JFactory::getApplication();
                $country = $app->input->get('country'); //country is the dynamic value which is being used in the view
                $db = JFactory::getDbo();
                $query = $db->getQuery(true);
                $query->select('a.cityname')->from('`#__tablename` AS a')->where('a.country = "'.$country.'" ');
		$rows = $db->setQuery($query)->loadObjectlist();
                foreach($rows as $row){
                    $cities[] = $row->cityname;
                }
                // Merge any additional options in the XML definition.
		$options = array_merge(parent::getOptions(), $cities);
                return $options;
	}
}

Bovenstaande voorbeeld toont een eenvoudige query die een lijst van steden uit een tabel toont waarbij de naam van de stad behoort tot het respectievelijk land. U kunt een drop-down maken op basis van meer complexe query's.

Valkuilen

Het laden van een extra veld kan resulteren in een Fatal Error, als er een core veld bestaat met dezelfde bestandsnaam en het extra veld het core veld 'uitbreid'.

Beschouw een bestand testfields/radio.php dat bevat

<?php

class TestFormFieldRadio extends JFormFieldRadio {}

Het aanroepen van JFormHelper::loadFieldClass('radio') zal resulteren in een Fatal error: Class 'JFormFieldRadio' not found.

Er kunnen hier twee redenen voor zijn.

  1. JLoader kan JFormFieldRadio niet automatisch laden, want de class naam (JFormField*) komt niet overeen de padnaam (joomla/form/fields/* - let op het meervoud van fields).
  2. JFormHelper kan JFormFieldRadio niet laden, want custom paden worden eer gescanned en het gevraagde veldtype ('radio') wordt gevonden voor de core classes worden bereikt.

Oplossing

Gebruik het core-veld bestand direct:

<?php
require_once JPATH_LIBRARIES . '/joomla/form/fields/radio.php';

class TestFormFieldRadio extends JFormFieldRadio {}

en gebruik JFormHelper::loadFieldClass naar behoren met 'test.radio' in plaats van 'radio'.

Met behulp van het aangepaste veldtype

Gelinkt aan een formulier

Om het veldtype te gebruiken, moeten we het XML bestand bijwerken dat het formulierveld bevat. Open uw XML bestand in administrator/components/com_phonebook/models/forms en voeg het veld op de gebruikelijke manier toe:

<field name="title" type="City" label="JGLOBAL_TITLE"
	description="JFIELD_TITLE_DESC"
	required="true" />

De attribuutnaam is HoOfDlEtTeRgEvOeLiG.

Bovendien moet u misschien het veld-pad naar de bovenliggende <fieldset> toevoegen:

<fieldset addfieldpath="/administrator/components/<component name>/models/fields">

Niet aan een formulier gelinkt

Als u bijvoorbeeld het veld nodig heeft als drop-down in een component als admin/site filter.

//Get custom field
JFormHelper::addFieldPath(JPATH_COMPONENT . '/models/fields');
$cities = JFormHelper::loadFieldType('City', false);
$cityOptions=$cities->getOptions(); // works only if you set your field getOptions on public!!

Overschrijven (overriden) getLabel()

Zoals genoemd in de sectie Formulierveld type class eisen, definiëren eigen formulier veldtypes in het algemeen hun eigen getLabel(). Als u een eigen label wilt aanmaken, kunt u toch gebruik maken van de getLabel() dat ieder veldtype class overerft van JFormField, door het bijvoorbeeld als volgt te definiëren:

public function getLabel() {
     return '<span style="text-decoration: underline;">' . parent::getLabel() . '</span>';
}

Deze code zal uw formulierlabels onderstrepen. (Let op: Als uw doel is om formulierlabels te onderstrepen is het gebruik van CSS de aanbevolen manier.)

Als u iets compleet anders wilt doen, kunt u het ook volledig overriden:

public function getLabel() {
	// Initialize variables.
	$label = '';
	$replace = '';

	// Get the label text from the XML element, defaulting to the element name.
	$text = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];

	// Build the class for the label.
	$class = !empty($this->description) ? 'hasTip' : '';
	$class = $this->required == true ? $class.' required' : $class;
		
	// Add replace checkbox
	$replace = '<input type="checkbox" name="update['.$this->name.']" value="1" />';
		
	// Add the opening label tag and main attributes attributes.
	$label .= '<label id="'.$this->id.'-lbl" for="'.$this->id.'" class="'.$class.'"';

	// If a description is specified, use it to build a tooltip.
	if (!empty($this->description)) {
		$label .= ' title="'.htmlspecialchars(trim(JText::_($text), ':').'::' .
				JText::_($this->description), ENT_COMPAT, 'UTF-8').'"';
	}

	// Add the label text and closing tag.
	$label .= '>'.$replace.JText::_($text).'</label>';
	
	return $label; 
}

Dit voorbeeld zal een keuzevakje in het label toevoegen.