ItemManager - Field Types

Erstellt am: Monday 30 January 2017  |  Letzte Änderung am: Saturday 11 August 2018

This article describes what field types are available in ItemManager and shows a simple example of how to create your own field type. Be sure to read this article once you're comfortable with the basics: ItemManager API Reference - ItemManager class.

What are field types

In short, field types are modules designed to contain the content of items and make it available again when needed. All field types differ in how they store and/or make their content available. Field types can be assigned to a category and are then utilised by the items belonging to that category.

Available field types

Name Label
text Text field
longtext Long text field
dropdown Dropdown
checkbox Check box
editor WYSIWYG editor
hidden Hidden field
fileupload File upload field
password Password
slug Slug
chunk Chunk field
datepicker Datepicker
money Money field

An ItemManager field type consist of two parts a field and an input part. User input is validated by the input part so that the data is valid for this field type and can be saved or retrieved by the user. Note that the input fields should always be validated server-side, but can optionally be validated client-side before the content is saved.

The field part provides the view and rendering of the custom field within ItemManager's backend and is more suitable for internal use. Here is an example for the rendering of the datepicker field generated using the field part of field type:

In ItemManager based plugin IM Extra Fields I used the field part to render the ItemManager's fields within the page menu. This function is particularly interesting for displaying very complex field types such as file upload fields. In most cases, however, you will not want to render the fields, because you can create your own markup for this purpose.

What is a Chunk field and how you can use it?

According to one definition, a Chunk is a short reusable piece of code that is versatile in its use. You can use a Chunk field to save HTML/Markup and JavaScript code and to output it (non-validated) exactly like it is. See next simple example, there I define the following code as a default field value for the chunk field:

<div class="fieldarea">
    <label for="active">My Chunk Selector</label>
    <div class="field-wrapper">
        <select id="mySelect">
            <option>Select one option</option>
            <option value="one">One</option>
            <option value="two">Two</option>
            <option value="three">Three</option>
        </select>
        <br>
        <div class="options-wrapper" id="one" style="display:none;">
            <br>
            <label><input name="one" value="1" type="checkbox"> Option One</label>
        </div>
        <div class="options-wrapper" id="two" style="display:none;">
            <br>
            <label><input name="one" value="1" type="checkbox"> Option One</label>
            <label><input name="two" value="1" type="checkbox"> Option Two</label>
        </div>
       <div class="options-wrapper" id="three" style="display:none;">
           <br>
           <label><input name="one" value="1" type="checkbox"> Option One</label>
           <label><input name="two" value="1" type="checkbox"> Option Two</label>
           <label><input name="three" value="1" type="checkbox"> Option Three</label>
        </div>
    </div>
</div>
<script>
    $('#mySelect').on('change', function() {
        var active = $('#mySelect').val();
        $('.options-wrapper').hide();
        $('.options-wrapper#'+active).show();
    });
</script>

It looks like following in ItemManager's Item-Edit menu:

A custom field within a custom field is basically created here, with its own JavaScript logic. By JavaScript you could also put the selected options into a predefined hidden field value, so the value could be saved when sending the form.

Another video demonstrates how to use the chunk field to populating input fields in a form via JavaScript:

Creating your own field type

Creating your own field type is relatively simple. In the folders fields and inputs under /plugins/imanager/lib/processors/ directory you will find the already installed field and input types. You will also need to place the files of the field type you created there. As I have already mentioned, field types always consist of two parts field- and input, the associated files are stored in the corresponding folders. The file names are structured as follows:

  • Field<YourFieldName>.php - The field file
  • Input<YourFieldName>.php - The input file

Both source files must each contain a class:

  • Field<YourFieldName> - The field class
  • Input<YourFieldName> - The input class

Note also that each class must have an interface implemented:

  • FieldInterface - The field interface
  • InputInterface - The input interface

The Field class should have this structure:

class Field<YourFieldName> implements FieldInterface 
{
    public function __construct(TemplateEngine $tpl) {
        ...
    }

    public function render($sanitize = false) {
        ...
    }

    protected function sanitize($value) {
        ...
    }

    public function getConfigFieldtype() {
        ...
    }
}

The Input class should have this structure:

class Input<YourFieldName> implements InputInterface
{
    public function __construct(Field $field) {
        ...
    }

    public function prepareInput($value, $sanitize = false) {
        ...
    }

    public function prepareOutput() {
        ...
    }

    protected function sanitize($value) {
        ...
    }
}

If you want more information about the structure of the classes, see the classes FieldText and InputText - these are a good example to familiarize you with the structure of the both classes.

Now we want to create a very simple field type just to demonstrate the creation process. Our field type should be called email and is only intended for storing email addresses.

First we navigate to the /plugins/imanager/lib/processors/inputs/ directory and create a file with the name InputEmail.php. Since our email field should have similar functionalities as a normal text field, we can simply copy the complete file content of InputText.php into our file. Now we change some parts which are relevant for validating the input:

<?php

class InputEmail implements InputInterface
{
	/**
	 * @var stdClass - The vield value object
	 */
	protected $values;

	/**
	 * @var Field object
	 */
	protected $field;

	/**
	 * @var int
	 */
	protected $maxLen = 255;

	/**
	 * @var int - default value, if it wasn't defined in field settings menu
	 */
	protected $minLen = 0;

	/**
	 * @var bool - default value if it wasn't defined in field settings menu
	 */
	protected $required = false;

	/**
	 * InputEmail constructor.
	 *
	 * @param Field $field
	 */
	public function __construct(Field $field)
	{
		/**
		 * Set the field object
		 */
		$this->field = $field;

		/**
		 * Init field value and set it to null
		 */
		$this->values = new \stdClass();
		$this->values->value = null;

		/**
		 * Set local config values if these was set in the field settings (IM-Menu)
		 */
		if($this->field->required) {
			$this->required = true;
		}

		if($this->field->minimum) {
			$this->minLen = $this->field->minimum;
		}

		if($this->field->maximum) {
			$this->maxLen = $this->field->maximum;
		}
	}

	/**
	 * This method checks the field inputs and sets the field contents.
	 * If an error occurs, the method returns an error code.
	 *
	 * @param $value
	 * @param bool $sanitize
	 *
	 * @return int|stdClass
	 */
	public function prepareInput($value, $sanitize = false)
	{
		// Set empty value, the input isn't required
		if(empty($value) && !$this->required) {
			$this->values->value = '';
			return $this->values->value;
		}

		// Check input required
		if(($this->required) && empty($value)) {
			return self::ERR_REQUIRED;
		}

		// Sanitize input
		if($sanitize) {
			$this->values->value = $this->sanitize($value);
		} else {
			$this->values->value = $value;
		}

		// Sanitizer has wiped the value?
		if(!$this->values->value) { return self::ERR_FORMAT; }

		// Check min value length
		if($this->minLen > 0) {
			if(mb_strlen($this->values->value) < (int) $this->minLen) { return self::ERR_MIN_VALUE; }
		}

		// Check max value length
		if($this->maxLen > 0) {
			if(mb_strlen($this->values->value) > (int) $this->maxLen) { return self::ERR_MAX_VALUE; }
		}

		return $this->values;
	}

	/**
	 * The method that is called when initiating item content
	 * and is relevant for setting the field content.
	 * However, since we do not require any special formatting
	 * of the output, we can accept the value 1 to 1 here.
	 *
	 * @return stdClass
	 */
	public function prepareOutput() {return $this->values;}

	/**
	 * This is the method used for sanitizing.
	 * ItemManager' Sanitizer method "email" will be used for this.
	 *
	 * @param $value
	 *
	 * @return mixed
	 */
	protected function sanitize($value) {
		return imanager('sanitizer')->email($value);
	}
}

Next, create a file with the name FieldEmail.php under /plugins/imanager/lib/processors/fields/ directory. Just copy the entire contents of the FieldText.php file and paste it into the new file, but we will adjust some code parts:

<?php

class FieldEmail implements FieldInterface
{

	/**
	 * @var TemplateEngine - used for rendering input field
	 */
	protected $tpl;

	/**
	 * Field configs variable
	 *
	 * @var stdClass
	 */
	protected $configs;

	/**
	 * Set some default variables (used to assemble the field)
	 */
	public $name = null;
	public $class = null;
	public $id = null;
	public $value = null;
	public $style = null;

	/**
	 * FieldEmail constructor.
	 *
	 * @param TemplateEngine $tpl
	 */
	public function __construct(\TemplateEngine $tpl)
	{
		$this->tpl = $tpl;
		$this->configs = new \stdClass();
	}

	/**
	 * This method renders the field in the ItemManager admin area
	 *
	 * @param bool $sanitize
	 *
	 * @return bool|Template
	 */
	public function render($sanitize = false)
	{
		// Do not allow rendering of nameless fields
		if(is_null($this->name)) { return false; }
		// Create our field template
		$textfield = '<input name="[[name]]" type="email"[[class]] [[id]]value="[[value]]"[[style]]>';
		// Render template
		$output = $this->tpl->render($textfield, array(
				'name' => $this->name,
				'class' => ($this->class) ? ' class="'.$this->class.'" ' : '',
				'style' => ($this->style) ? ' style="'.$this->style.'" ' : '',
				'id' => ($this->id) ? 'id="'.$this->id.'" ' : '',
				'value' => ($sanitize) ? $this->sanitize($this->value) : $this->value
			),
			true, array()
		);
		return $output;
	}

	/**
	 * This method renders the field value when you insert it into:
	 * <input value="<value>" ...
	 *
	 * @param $value
	 *
	 * @return mixed
	 */
	protected function sanitize($value) {
		return imanager('sanitizer')->email($value);
	}

	/**
	 * If you want to make your field configurable you should
	 * use this method, an example of a configurable field
	 * can be found:
	 * /plugins/imanager/lib/processors/fields/FieldMoney.php
	 *
	 */
	public function getConfigFieldtype(){}
}

Ok, almost finished. Now we still have to adjust a backend template file /plugins/imanager/tpl/row.fields.im.tpl. Just add an additional option so that you can select your field when defining the fields for a category in IM-Fields area.:

<option value="email"[[selected-email]]>Email field</option>

At this point, your new field should be available for selection:

Autor: Bigin  |  Tags:  FrameworkPHPGetSimpleItemManager