#2756 Developer

Parent Category:
Documentation
Category:
DPFields
Last Updated:
Allon Moritz (laoneo), Tuesday, 01 September 2015 06:11 (Tuesday, 01 September 2015)
Created:
Monday, 17 August 2015 07:56 (Monday, 17 August 2015)
Hits:
6113

DPFields is made to be integrated into existing components and not intended to be used as a standalone product. To integrate DPFields into your existing component some requirements and small code changes are needed. They will be listed in this chapter. To illustrate the usage of DPFields, we are taking the example com_helloworld extension from the official Joomla docs tutorials. To get a running Hello World example download the archive file from the DPFields branch and install it together with DPFields on your Joomla test site.

Sidebar Integration

The entry point to DPFields is the Fields link in the sidebar. To add a menu entry just add the following code where your sidebar menu is generated. On a Joomla default component it is mostly found in the Helper class. To create a menu link a context parameter must be present which defines the context the fields should be attached to. The context parameter must have the following structure: "component.section".

if (JFolder::exists(JPATH_ADMINISTRATOR . '/components/com_dpfields'))
{
	JHtmlSidebar::addEntry(
		JText::_('COM_DPCALENDAR_SUBMENU_FIELDS'),
		'index.php?option=com_dpfields&context=com_helloworld.helloworld',
		$vName == 'fields.helloworld'
	);
}
backend sidebar integration

Convention over configuration

DPFields needs always a context to attach the fields to, similar to the extension parameter in com_categories. Every field is attached to such a context. In the hello world example the context is com_helloworld.helloworld. This context is needed when a form is prepared to edit an item (helloworld) or when an item is saved. The DPFields - System plugin hooks itself into the corresponding Joomla plugin events to do the background work for a proper fields management.

The following code contexts are important for DPFields and must be equal:

  • In the back end when the form is loaded to edit the item the onContentPrepareForm event is triggered. The form name which is loaded must be correct:
    public function getForm($data = array(), $loadData = true)
    {
    	// Get the form.
    	$form = $this->loadForm(
    		'com_helloworld.helloworld',
    		'helloworld',
    		array(
    			'control' => 'jform',
    			'load_data' => $loadData
    		)
    	);
    
    	// Do your form work
    
    	if (empty($form))
    	{
    		return false;
    	}
    
    	return $form;
    }
  • The context during the save (onContentAfterSave) and delete (onContentAfterDelete) events must be correct. Per default Joomla builds the context automatically based on the class name of the model. If they are not correct, you can set them as protected variables in your model. Put them like:
    class HelloWorldModelHelloWorld extends JModelAdmin
    {
    
    	protected $option = 'com_helloworld';
    	protected $name = 'helloworld';
    
    	// More code to handle your logic
    }
  • To attach the fields to the rendered object the onContentPrepare event is used. Normally this event is triggered in the view.html.php file on the sites component folder. On our Hello World example the code does look like:
    JEventDispatcher::getInstance()->trigger('onContentPrepare',
    	array ('com_helloworld.helloworld', &$this->item, &$params, 0));
  • To display the fields the event onContentBeforeDisplay is used. This code is mostly triggered on the site view.html.php file. The context here must be correct too. On our Hello World example the code does look like:
    $results = JEventDispatcher::getInstance()->trigger('onContentBeforeDisplay', array(
    		'com_helloworld.helloworld',
    		&$this->item,
    		&$params,
    		0
    ));
    $this->displayEvent->beforeDisplayContent = trim(implode("\n", $results));

    In the default.php file the display event variables can be printed easily like:

    <?php
    echo $this->displayEvent->beforeDisplayContent;
    echo $this->displayEvent->afterDisplayContent;
  • To show the fields when an item is edited the params fieldsets must be loaded. On our hello world example all fieldsets are loaded. In the Joomla CMS the Article Manager (com_content) loads them through a layout.

 

Load the params fieldsets

To render the custom fields inside your edit form, the params fieldsets must be loaded. In the article manager, they are loaded through a layout <?php echo JLayoutHelper::render('joomla.edit.params', $this); ?>. This is relatively new code. If you want to do it the old fashion way, the following code is needed to load the tabs in the list:

<?php
$fieldSets = $this->form->getFieldsets('params');
foreach ($fieldSets as $name => $fieldSet)
{
?>
<li>
	<a href="#params-<?php echo $name;?>" data-toggle="tab">
		<?php echo JText::_($fieldSet->label);?>
	</a>
</li>
<?php
} ?>

 To actually load the fields, the next code snippet is needed:

$fieldSets = $this->form->getFieldsets('params');
foreach ($fieldSets as $name => $fieldSet)
{ ?>
	<div class="tab-pane" id="params-<?php echo $name;?>">
		<?php foreach ($this->form->getFieldset($name) as $field)
		{
			echo $field->renderField();
		} ?>
	</div>
<?php
}
?>
 

Accessing the fields

If you fire the onContentPrepare event before the item is rendered in the view. The fields are accessible on a new parameter on the object with the name dpfields. It is an array containing the alias as keys. For example if you want to print them run the following code:

print_r($this->item->dpfields);

You can also place some mustache syntax into your items text field like described here, it will be parsed then automatically.

 

Types

In DPFields every field is bound to a type. After the field is created the type can not be changed anymore. Types are loaded from the folder administrator/components/com_dpfields/models/types. Every type must extend the DPFieldsTypeBase class and have the following name scheme: DPFieldsType{{Character}}. The character must be the same as the filename with the first letter upper case. For example the calendar type has the file location administrator/components/com_dpfields/models/types/calendar.php and does look like:

JLoader::import('components.com_dpfields.models.types.base', JPATH_ADMINISTRATOR);

class DPFieldsTypeCalendar extends DPFieldsTypeBase
{
}

If you want to add your own types put them into your component model types folder with the naming pattern described before and they will be loaded automatically.

 

Adapt to your layout

To adapt the output of the custom fields to your component you can do a layout override as described in the Joomla docs. DPFields uses the JLayout classes to render the output of the custom fields. First it tries to load the layout from your component. If that fails, then it loads the layout from dpfields itself. The code which renders the fields is stored in the file components/com_dpfields/layouts/fields/render.php. Probably you don't need to alter that file at all. The single field is rendered in the file components/com_dpfields/layouts/field/render.php and looks actually like:

 

if (! key_exists('label', $displayData) || ! key_exists('value', $displayData))
{
	return;
}

$label = $displayData['label'];
$value = $displayData['value'];
if (! $value)
{
	return;
}
?>

<dd class="dpfield-entry">
	<span class="dpfield-label"><?php echo htmlentities($label);?>: </span>
	<span class="dpfield-value"><?php echo $value;?></span>
</dd>

If you want to change the output of a single field copy the file components/com_dpfields/layouts/field/render.php to your site layout folder, on the installation it has to be on components/{{component}}/layouts/com_dpfields/field/render.php

developer layout override dpcalendar

Translation

When the fields are edited in the back end, DPFields does load the language files of the component as you are familiar with com_categories. Some of the important keys you can override are listed below.

  • COM_DPFIELDS_VIEW_FIELD_ADD_TITLE="Hello World Manager: Add New %s Field"
  • COM_DPFIELDS_VIEW_FIELD_EDIT_TITLE="Hello World Manager: Edit %s Field"
  • COM_DPFIELDS_VIEW_FIELDS_TITLE="Hello World Manager: %s Fields"
 

ACL

DPFields does fully support Joomla's ACL permission and access level feature. Every field has an Access parameter which defines who can see the field and it's value on the front. For every field the permissions can be set who can work with the field. The permissions are inherited from the component they are attached to. The asset name of the field does have the following structure component.section.field.fieldid. On our hello world example the asset names do look like com_helloworld.helloworld.field.7. But normally you don't have to care about that in your component. All is handled automatically by DPFields.

 

Database

DPFields does have a simple database structure. It contains two tables. The #__dpfields_fields table contains all the field records. The __dpfields_fields_values contains the values for every field associated with a context and an item.

 

Regular Search

To support search in your component for custom fields, there is no way to automatically do the work by DPFields. You need to directly address the values table when you create the SELECT statement. In DPCalendar we use the following code:

$search = $db->Quote('%' . $db->escape(JString::strtolower($this->getState('filter.search')), true) . '%');
$searchQuery .= ' OR LOWER(a.title) LIKE ' . $search;
$searchQuery .= ' OR LOWER(a.alias) LIKE ' . $search;
$searchQuery .= ' OR LOWER(a.description) LIKE ' . $search;
$searchQuery .= ' OR LOWER(a.metakey) LIKE ' . $search;
$searchQuery .= ' OR LOWER(a.metadesc) LIKE ' . $search;

// Search in custom fields
if (JFolder::exists(JPATH_ADMINISTRATOR . '/components/com_dpfields'))
{
	$query->join('LEFT', '#__dpfields_fields_values AS dpf ON dpf.item_id = a.id');
	$query->where('dpf.context = ' . $db->q('com_dpcalendar.event'));

	$searchQuery .= ' OR LOWER(dpf.value) LIKE ' . $search;
}
$query->where('(' . $searchQuery . ')');
 

Smart Search

If you do support Smart Search in your extension, then the only requirement is that you fire the onPrepareFinderContent event in your index function. The finder component has a handy function (FinderIndexerHelper::getContentExtras) which does the work for you:

protected function index (FinderIndexerResult $item, $format = 'html')
{
	// Add the standard fields to your item
	...

	FinderIndexerHelper::getContentExtras($item);
	$this->indexer->index($item);
}
 

Multiple Contextes

If your component does have multiple items which can support custom fields, eg. DPCalendar supports custom fields for events, locations and attendees, then you need to add an XML file in the folder administrator/components/{{your component}}/models/forms/ with the name filter_fields.xml. The content has to look like:

<?xml version="1.0" encoding="utf-8"?>
<form>
	<fields name="custom">
		<fieldset name="custom">
			<field name="section" type="section" default="com_dpcalendar.event">
				<option value="com_dpcalendar.event">COM_DPCALENDAR_FIELDS_SECTION_EVENT</option>
				<option value="com_dpcalendar.location">COM_DPCALENDAR_FIELDS_SECTION_LOCATION</option>
				<option value="com_dpcalendar.attendee">COM_DPCALENDAR_FIELDS_SECTION_ATTENDEE</option>
			</field>
		</fieldset>
	</fields>
</form>

 

backend fields list multiple sections

Comments (0)

Cookies make it easier for us to provide you with our services. With the usage of our services you permit us to use cookies.
More information Ok Decline