PHOCOA PHP Framework

Bindings and Binding Options

Overview

Bindings allow you to map a property of a widget to the property of another object.

So, instead of having to write code like so:

// set up form
$myTextField->setValue($myDataObject->getValue());

// put data from form back into my object
$myDataObject->setValue($myTextField->getValue());
You can simply bind the "value" property of myTextField to the "value" property of myDataObject. With PHOCOA bindings, you bind widget properties with Key-Value Coding, so you can use any legitimate keyPath on your objects. This is very convenient for large data models, where you could bind a widget value to $myBook with the keyPath "author.name".
$myTextField->bind('value', $myDataObject, 'author.name');
While you can set up bindings programmatically, you usually use the PHOCOA configuration system to set up bindings (via the .yaml file for the page):
	myTextField:
		bindings:
			value:
				instanceID: myDataObject
				controllerKey: selection
				modelKeyPath: author.name
Typically this configuration is setup in the GUI PHOCOA Builder application.

PHOCOA's bindings go beyond simply moving data around between the Model and the View. They also automatically call your data's validation and normalization function (provided by Key-Value Validation) and keep track of the errors found by KVV. More on this here.

Thus, because of the PHOCOA bindings system, most of the glue code normally written to handle moving data between the Model and the View, along with data validation and error handling is instead done simlpy by configuring the application in the PHOCOA Builder tool.

The bindings can be one-way (read-only), or two-way. One-way bindings read their value from the bound object/property and use it for the value of the widget property. Two-way bindings read their values just like one-way bindings, but also update the value of the bound object/property with the new value from the widget from the UI.

Some bindings have additional binding options that you can use to modify the values. Some of these options are specific to certain bindings. For instance, you can add an extra choice to select lists via binding options. Others are generic. The generic mechanism used to modify bindings is called a Value Transformer and can be added to any binding. Value Transformers are used to modify the value from the bound object/property without having to write additional code. Built-in value transformers are WFNegateBoolean, WFIsEmpty, WFIsNotEmpty. You can tell by their names that these can be convenient for using an existing model method with a binding that doesn't quite return exactly what you need, but with a Value Transformer, it's perfect, and you don't have to write any additional methods.

Bindings can also be mutli-value, which means that multiple sources can be combined to deliver a single value to the widget. Multi-value bindings are automatically read-only.

All of these topics are explained very well by the Cocoa documentation on bindings.

The following examples show how the various binding types work, and how to use binding options to get additional functionality out of the bindings mechanism.

Single-Value Binding

Bind a single property of a widget to single property of another object.

Example: Single-Value Binding

Output

Alan Pinstein

Template

    {WFLabel id="simpleBinding"}
    

Config

	'simpleBinding' => array(
		'bindings' => array(
			'value' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'name',
			),
		),
	),
    

Multiple Value Bindings

Multiple value bindings work just like single-value bindings, but are read-only, and have the capability of combining multiple values into a single value via various methods explained below.

Using mutliple-bindings capabilities is very convenient. If the logic behind whether a widget should be hidden is complex and depends on multiple parameters, you can use mutliple values via "hidden", "hidden2", "hiddenN" instead of having to write a special function to wrap up this logic. This is very convenient because it prevents having to write special logic code in your model or controller classes just to determine whether a widget should be hidden, for example.

Multiple Value Boolean Bindings

For multiple-boolean bindings, there are two modes. AND mode and OR mode. The mode of the binding determines how the multiple values are combined into a single value.

AND mode bindings are true IFF all bound values are TRUE, otherwise they are FALSE. An example of this is the enabled binding.

OR mode bindings are true if ANY bound value is TRUE, and are only FALSE if ALL values are false. An example of this is the hidden binding.

Example: Multiple Value Binding, but using only one value - works just like Single-Value Binding

Output

This should be visible.
(hidden WFLabel exists, but is hidden)

Template

    {WFLabel id="multOneOn"}
    {WFLabel id="multOneOff"}(hidden WFLabel exists, but is hidden)
    

Config

	'multOneOn' => array(
		'properties' => array(
			'value' => 'This should be visible.',
		),
		'bindings' => array(
			'hidden' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsFalse',
			),
		),
	),
	'multOneOff' => array(
		'properties' => array(
			'value' => 'This should be hidden.',
		),
		'bindings' => array(
			'hidden' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsTrue',
			),
		),
	),
    

Example: Hidden (OR mode) via Multiple Value Boolean Binding

In this example, two values are bound to the "hidden" property. You can see from this example that if either value is TRUE, the item will be hidden.

Output

This should be visible.
(hidden WFLabel exists, but is hidden)

Template

    {WFLabel id="multMultHiddenOn"}
    {WFLabel id="multMultHiddenOff"}(hidden WFLabel exists, but is hidden)
    

Config

	'multMultHiddenOn' => array(
		'properties' => array(
			'value' => 'This should be visible.',
		),
		'bindings' => array(
			'hidden' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsFalse',
			),
			'hidden2' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'alsoReturnsFalse',
			),
		),
	),
	'multMultHiddenOff' => array(
		'properties' => array(
			'value' => 'This should be hidden.',
		),
		'bindings' => array(
			'hidden' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsFalse',
			),
			'hidden2' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsTrue',
			),
		),
	),
    

Example: Enabled (AND mode) via Multiple Value Boolean Binding

In this example, two values are bound to the "enabled" property. You can see from this example that both values must be TRUE for the item to be enabled.

Output



Template

    {WFTextField id="multMultEnabledOn"}
    {WFTextField id="multMultEnabledOff"}
    

Config

	'multMultEnabledOn' => array(
		'bindings' => array(
			'value' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'name',
			),
			'enabled' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsTrue',
			),
			'enabled2' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'alsoReturnsTrue',
			),
		),
	),
	'multMultEnabledOff' => array(
		'bindings' => array(
			'value' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'name',
			),
			'enabled' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsTrue',
			),
			'enabled2' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsFalse',
			),
		),
	),
    

Example: Multiple Value Pattern Binding

Pattern bindings allow you to create strings from multiple data sources. This is convenient for strings like "<name> has <count> favorite colors."

To enable mutliple-value pattern binding, simply set the binding option ValuePattern for the value binding to the desired format string. For each variable you want replaced, enter "%N%" where N goes from 1 to N. The "value" binding will be used for "%1%", the "value2" for "%2%", and on through N.

You will notice another great PHOCOA Key-Value Coding feature here. Notice the "@count" in the keyPath for "value2". There are a number of "array" operators in Key-Value coding that perform calculations on arrays. These are well explained in the Cocoa docs, and PHOCOA supports all of them.

Output

Alan Pinstein has 2 favorite colors.

Template

    {WFLabel id="valuePattern"}
    

Config

	'valuePattern' => array(
		'bindings' => array(
			'value' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'name',
				'options' => array(
					'ValuePattern' => '%1% has %2% favorite colors.',
				),
			),
			'value2' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'favoriteColors.@count',
			),
		),
	),
    

Value Transformers

Value Transformers are simple ways to munge data received from a binding before using the value. These are very useful in that they allow you to use existing model functions to help drive the UI without having to write any additional code.

Example: Value Transformer

Output

'You have already set your favorite colors.'
'You have no favorite colors on file with us.'

Template

    {WFLabel id="hideIfEmpty"}
    {WFLabel id="hideIfNotEmpty"}
    

Config

	'hideIfEmpty' => array(
		'properties' => array(
			'value' => 'You have already set your favorite colors.',
		),
		'bindings' => array(
			'hidden' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'favoriteColors',
				'options' => array(
					'valueTransformer' => 'WFIsEmpty',
				),
			),
		),
	),
	'hideIfNotEmpty' => array(
		'properties' => array(
			'value' => 'You have no favorite colors on file with us.',
		),
		'bindings' => array(
			'hidden' => array(
				'instanceID' => 'person',
				'controllerKey' => 'selection',
				'modelKeyPath' => 'returnsEmptyArray',
				'options' => array(
					'valueTransformer' => 'WFIsNotEmpty',
				),
			),
		),
	),
    

Examples

Cookbook
  Widgets
  Bindings
  Pagination
  Formatters

Basic Examples
  Email
  Skin Browser
  Forms
  Regex Tester

AJAX Examples
  Infrastructure

  (YUI Examples)
  AutoComplete
  ColorPicker
  Menu
  Tree View
  Tab View
  Container

Appcelerator Integration
  Demo
Copyright (c) 2014 Alan Pinstein. All Rights Reserved.