View source
<?php
class FormBuilderLoader {
protected static $instance = NULL;
protected $formTypeInfo;
protected $paletteGroupInfo = array();
protected $elementTypeInfo = array();
protected $propertyInfo = array();
protected $formCache = array();
public static function instance() {
if (!static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
public function __construct() {
module_load_include('api.inc', 'form_builder', 'includes/form_builder');
$this
->loadFormTypeInfo();
}
protected function loadFormTypeInfo() {
$defaults = array(
'class' => 'FormBuilderFormBase',
'property class' => 'FormBuilderPropertyBase',
'element class' => 'FormBuilderElementBase',
);
$form_types = module_invoke_all('form_builder_form_types');
foreach ($form_types as $form_type => &$info) {
$info += $defaults;
}
drupal_alter('form_builder_form_types', $form_types);
$this->formTypeInfo = $form_types;
}
public function getElementTypeInfo($form_type, $form_id) {
if (!isset($this->elementTypeInfo[$form_type][$form_id])) {
$element_types = module_invoke_all('form_builder_element_types', $form_type, $form_id);
$groups = $this
->getPaletteGroupInfo($form_type, $form_id);
foreach ($element_types as $key => &$type) {
$type += array(
'class' => $this->formTypeInfo[$form_type]['element class'],
'configurable' => TRUE,
'removable' => TRUE,
'palette_group' => 'default',
'properties' => array(),
);
$type += array(
'addable' => $type['removable'] && isset($type['default']),
);
$type['unique'] = !empty($type['unique']);
$type['palette_group'] = isset($groups[$type['palette_group']]) ? $type['palette_group'] : 'default';
if (!in_array('weight', $type['properties'])) {
$type['properties'][] = 'weight';
}
$type['default'] += array(
'#form_builder' => array(),
);
if ($type['addable']) {
$type['default']['#form_builder'] += array(
'element_type' => $key,
);
if ($type['unique']) {
$type['default']['#form_builder']['element_id'] = $key;
}
}
}
uasort($element_types, '_form_builder_sort');
drupal_alter('form_builder_element_types', $element_types, $form_type, $form_id);
$this->elementTypeInfo[$form_type][$form_id] = $element_types;
}
return $this->elementTypeInfo[$form_type][$form_id];
}
public function getPaletteGroupInfo($form_type, $form_id, $reset = FALSE) {
if (!isset($this->paletteGroupInfo[$form_type]) || $reset) {
$this->paletteGroupInfo[$form_type] = module_invoke_all('form_builder_palette_groups', $form_type, $form_id);
}
return $this->paletteGroupInfo[$form_type];
}
public function getPropertyInfo($form_type, $reset = FALSE) {
if (!isset($this->propertyInfo[$form_type]) || $reset) {
$properties = array();
foreach (module_implements('form_builder_properties') as $module) {
$new_properties = module_invoke($module, 'form_builder_properties', $form_type);
$properties += $new_properties;
foreach ($new_properties as $k => $v) {
$properties[$k] = array_merge($properties[$k], $new_properties[$k]);
}
}
drupal_alter('form_builder_properties', $properties, $form_type);
$defaults['class'] = $this->formTypeInfo[$form_type]['property class'];
foreach ($properties as $property => &$params) {
$params += $defaults;
}
$this->propertyInfo[$form_type] = $properties;
}
return $this->propertyInfo[$form_type];
}
public function getForm($form_type, $form_id, $sid, $form = array()) {
if (!isset($this->formTypeInfo[$form_type])) {
return FALSE;
}
$info = $this->formTypeInfo[$form_type];
$class = $info['class'];
return new $class($form_type, $form_id, $sid, $info, $form);
}
public function fromStorage($form_type, $form_id, $sid = NULL) {
if (!isset($this->formTypeInfo[$form_type])) {
return FALSE;
}
$info = $this->formTypeInfo[$form_type];
$class = $info['class'];
return $class::loadFromStorage($form_type, $form_id, $sid, $info);
}
public function fromCache($form_type, $form_id, $sid = NULL, $reset = FALSE) {
if ($reset) {
$this->formCache = array();
}
if ($form_type && $form_id) {
if (empty($this->formCache[$form_type][$form_id])) {
$this->formCache[$form_type][$form_id] = FALSE;
if (isset($this->formTypeInfo[$form_type])) {
$info = $this->formTypeInfo[$form_type];
$class = $info['class'];
$sid = $sid ? $sid : session_id();
if ($form = $class::load($form_type, $form_id, $sid, $info)) {
$this->formCache[$form_type][$form_id] = $form;
}
}
}
return $this->formCache[$form_type][$form_id];
}
return NULL;
}
public function getElement($form_type, $form_id, $element_type, $form, &$element) {
$infos = $this
->getElementTypeInfo($form_type, $form_id);
$info = $infos[$element_type];
$class = $info['class'];
return new $class($form, $info, $element, $this);
}
}
interface FormBuilderFormInterface {
public static function loadFromStorage($form_type, $form_id, $sid, $params);
public function saveToStorage();
public static function load($form_type, $form_id, $sid, $params);
public function __construct($form_type, $params, $form);
public function save();
public function delete();
public function getElement($element_id);
public function getElementArray($element_id);
public function getElementArrays($element_ids);
public function getFormArray();
public function setElementArray($element_a, $parent_id = FORM_BUILDER_ROOT, $alter = FALSE);
public function unsetElement($element_id);
public function getElementIds();
public function getElementTypes();
}
class FormBuilderFormBase implements Serializable {
const CACHE_NAME = 'form_builder_cache';
protected $formType;
protected $params;
protected $properties;
protected $form;
protected $formId;
protected $sid;
protected $loader;
protected $elementArrays = array();
public static function fromArray($form) {
$fb = $form['#form_builder'] + array(
'sid' => NULL,
);
return FormBuilderLoader::instance()
->getForm($fb['form_type'], $fb['form_id'], $fb['sid'], $form);
}
public static function loadFromStorage($form_type, $form_id, $sid, $params) {
$form = module_invoke_all('form_builder_load', $form_type, $form_id);
drupal_alter('form_builder_load', $form, $form_type, $form_id);
return new static($form_type, $form_id, $sid, $params, $form);
}
public function saveToStorage() {
module_invoke_all('form_builder_save', $this->form, $this->formType, $this->formId);
$this
->delete();
}
public static function load($form_type, $form_id, $sid, $params) {
ctools_include('object-cache');
$obj = "{$form_type}:{$form_id}";
$form = ctools_object_cache_get($obj, self::CACHE_NAME, FALSE, $sid);
if ($form && is_array($form)) {
$form = new static($form_type, $form_id, $sid, $params, $form);
}
return $form;
}
public function __construct($form_type, $form_id, $sid, $params, $form) {
$this->formType = $form_type;
$this->formId = $form_id;
$this->sid = $sid ? $sid : session_id();
$this->params = $params;
$this->properties = NULL;
$this->form =& $form;
$this->elementArrays[FORM_BUILDER_ROOT] =& $this->form;
$this
->addDefaults($this->form);
$this
->indexElements($this->form);
}
public function serialize() {
return serialize(array(
'formType' => $this->formType,
'formId' => $this->formId,
'sid' => $this->sid,
'params' => $this->params,
'form' => $this->form,
));
}
public function unserialize($data) {
$data = unserialize($data);
$this->formType = $data['formType'];
$this->formId = $data['formId'];
$this->sid = $data['sid'];
$this->params = $data['params'];
$this->form = $data['form'];
$this->properties = array();
$this->elementArrays[FORM_BUILDER_ROOT] =& $this->form;
$this
->addDefaults($this->form);
$this
->indexElements($this->form);
}
public function save() {
ctools_include('object-cache');
$obj = "{$this->formType}:{$this->formId}";
ctools_object_cache_set($obj, self::CACHE_NAME, $this, $this->sid);
}
public function delete() {
ctools_include('object-cache');
$obj = "{$this->formType}:{$this->formId}";
ctools_object_cache_clear($obj, self::CACHE_NAME, FALSE, $this->sid);
}
public static function purge($max_age = NULL) {
$expire = isset($max_age) ? $max_age : ini_get('session.cache_expire');
return db_delete('ctools_object_cache')
->condition('name', 'form_builder_cache')
->condition('updated', REQUEST_TIME - $max_age, '<')
->execute();
drupal_static_reset('ctools_object_cache_get');
}
protected function addDefaults(&$element, $parent_id = FORM_BUILDER_ROOT, $key = NULL, &$element_info = NULL) {
if (!$element_info) {
$element_info = FormBuilderLoader::instance()
->getElementTypeInfo($this->formType, $this->formId);
}
if (isset($element['#form_builder']['element_id'])) {
$element_id = $element['#form_builder']['element_id'];
$element += array(
'#key' => $key,
);
$element['#form_builder']['form_type'] = $this->formType;
$element['#form_builder']['form_id'] = $this->formId;
$element['#form_builder']['parent_id'] = $parent_id;
$settings = array();
if (isset($element_info[$element_id]) && $element_info[$element_id]['unique']) {
$element['#form_builder']['unique'] = TRUE;
$element['#form_builder'] += array(
'element_type' => $element_id,
);
$settings = $element_info[$element_id];
}
else {
if (isset($element['#type'])) {
$element['#form_builder'] += array(
'element_type' => $element['#type'],
);
}
if (isset($element_info[$element['#form_builder']['element_type']])) {
$settings = $element_info[$element['#form_builder']['element_type']];
}
else {
unset($element['#form_builder']);
return;
}
}
$settings += array(
'configurable' => TRUE,
'removable' => TRUE,
);
$element['#form_builder'] += array(
'configurable' => $settings['configurable'],
'removable' => $settings['removable'],
);
$parent_id = $element_id;
}
foreach (element_children($element) as $key) {
$this
->addDefaults($element[$key], $parent_id, $key, $element_info);
}
}
protected function indexElements(&$element) {
if (isset($element['#form_builder']['element_id'])) {
$element_id = $element['#form_builder']['element_id'];
$this->elementArrays[$element_id] =& $element;
}
foreach (element_children($element) as $key) {
$this
->indexElements($element[$key]);
}
}
protected function unindexElements($element) {
if ($element instanceof FormBuilderElementInterface) {
unset($this->elements[$element
->getId()]);
}
foreach ($element
->getChildren() as $child) {
$this
->unindexElements($child);
}
}
public function getElement($element_id) {
if (!isset($this->elementArrays[$element_id])) {
return NULL;
}
$element =& $this->elementArrays[$element_id];
return FormBuilderLoader::instance()
->getElement($this->formType, $this->formId, $element['#form_builder']['element_type'], $this, $element);
}
public function getElementArray($element_id) {
if (isset($this->elementArrays[$element_id])) {
return $this->elementArrays[$element_id];
}
return FALSE;
}
public function getElementArrays($element_ids) {
$elements = array();
foreach ($element_ids as $element_id) {
if ($element = $this
->getElementArray($element_id)) {
$elements[$element_id] = $element;
}
}
return $elements;
}
public function getFormArray() {
return $this->form;
}
public function setElementArray($element, $parent_id = FORM_BUILDER_ROOT, $alter = FALSE) {
$return = FALSE;
$element_id = $element['#form_builder']['element_id'];
$element['#form_builder'] += array(
'parent_id' => $parent_id,
);
$parent_id = $element['#form_builder']['parent_id'];
if ($alter) {
drupal_alter('form_builder_add_element', $element, $this->formType, $this->formId);
$element_id = $element['#form_builder']['element_id'];
$parent_id = $element['#form_builder']['parent_id'];
}
$this
->addDefaults($element, $parent_id);
if (!isset($element['#form_builder'])) {
return FALSE;
}
if (isset($this->elementArrays[$parent_id])) {
$parent =& $this->elementArrays[$parent_id];
}
else {
return FALSE;
}
$old_element = FALSE;
if (isset($this->elementArrays[$element_id])) {
$old_element =& $this->elementArrays[$element_id];
if ($parent_id !== $old_element['#form_builder']['parent_id']) {
$old_parent =& $this->elementArrays[$old_element['#form_builder']['parent_id']];
unset($old_parent[$old_element['#key']]);
unset($old_element);
unset($old_parent);
$old_element = FALSE;
}
}
if ($old_element && $old_element['#key'] != $element['#key']) {
$new_parent = array();
foreach ($parent as $key => &$child) {
if ($key == $old_element['#key']) {
$new_parent[$element['#key']] =& $element;
}
else {
$new_parent[$key] =& $child;
}
}
$parent = $new_parent;
}
else {
$parent[$element['#key']] =& $element;
}
$this
->indexElements($element);
return $element_id;
}
public function unsetElement($element_id) {
$element = $this->elementArrays[$element_id];
foreach (element_children($element) as $key) {
if (!empty($element[$key]['#form_builder']['element_id'])) {
$this
->unsetElement($element[$key]['#form_builder']['element_id']);
}
}
unset($this->elementArrays[$element_id]);
$parent =& $this->elementArrays[$element['#form_builder']['parent_id']];
unset($parent[$element['#key']]);
}
public function getElementIdsInPreOrder() {
$ids = array();
$this
->_recursiveElementIds($ids, $this->form);
return $ids;
}
private function _recursiveElementIds(&$ids, $e) {
foreach (element_children($e, TRUE) as $key) {
if (isset($e[$key]['#form_builder'])) {
$ids[] = $e[$key]['#form_builder']['element_id'];
$this
->_recursiveElementIds($ids, $e[$key]);
}
}
}
public function getElementsInPreOrder() {
$elements = array();
foreach ($this
->getElementIdsInPreOrder() as $id) {
$elements[$id] = $this
->getElement($id);
}
return $elements;
}
public function getElementIds() {
$ids = array();
foreach (array_keys($this->elementArrays) as $id) {
if ($id !== FORM_BUILDER_ROOT) {
$ids[] = $id;
}
}
return $ids;
}
public function getElementTypes() {
$types = array();
foreach ($this->elementArrays as $element) {
if (isset($element['#form_builder']['element_type'])) {
$types[$element['#form_builder']['element_type']] = TRUE;
}
}
return array_keys($types);
}
public function getProperties($reset = FALSE) {
if (!$this->properties || $reset) {
$properties = FormBuilderLoader::instance()
->getPropertyInfo($this->formType, $reset);
foreach ($properties as $property => $params) {
$class = $params['class'];
$this->properties[$property] = new $class($property, $params, $this->formType);
}
}
return $this->properties;
}
public function preview() {
$form = array();
$elements = array(
FORM_BUILDER_ROOT => &$form,
);
foreach ($this
->getElementsInPreOrder() as $id => $e) {
$elements[$id] = $e
->render();
$elements[$e
->parentId()][$e
->key()] =& $elements[$id];
}
$form['#tree'] = TRUE;
$form['#form_builder'] = array(
'form_type' => $this->formType,
'form_id' => $this->formId,
'sid' => $this->sid,
);
return $form;
}
}
interface FormBuilderElementInterface {
public function __construct($form_type, $params, &$element, $loader);
public function render();
public function getProperties();
public function getSaveableProperties();
public function configurationForm($form, &$form_state);
public function configurationSubmit(&$form, &$form_state);
public function title();
}
class FormBuilderElementBase implements FormBuilderElementInterface {
protected $form;
protected $params;
protected $element;
protected $loader;
public function __construct($form, $params, &$element, $loader) {
$this->form = $form;
$this->params = $params;
$this->element =& $element;
$this->loader = $loader;
}
protected function addPreRender($element) {
if (isset($element['#type']) && (!isset($element['#pre_render']) || !in_array('form_builder_pre_render', $element['#pre_render']))) {
$element['#pre_render'] = array_merge(element_info_property($element['#type'], '#pre_render', array()), array(
'form_builder_pre_render',
));
}
return $element;
}
public function render() {
return $this
->addPreRender($this->element);
}
public function getProperties() {
$return = array();
$properties = $this->form
->getProperties();
foreach ($this->params['properties'] as $name) {
if (isset($properties[$name])) {
$return[$name] = $properties[$name];
}
}
return $return;
}
protected function setProperty($property, $value) {
if ($value === '' || is_null($value)) {
unset($this->element['#' . $property]);
}
else {
$this->element['#' . $property] = $value;
}
}
public function getSaveableProperties() {
return $this->params['properties'];
}
public function configurationForm($form, &$form_state) {
$form['#_edit_element'] = $this->element;
foreach ($this
->getProperties() as $property) {
$form = array_merge($form, $property
->form($form_state, $this));
}
return $form;
}
public function configurationSubmit(&$form, &$form_state) {
foreach ($this
->getProperties() as $property) {
$property
->submit($form, $form_state);
}
$saveable = $this
->getSaveableProperties();
foreach ($form_state['values'] as $property => $value) {
if (in_array($property, $saveable, TRUE)) {
$this
->setProperty($property, $value);
}
}
}
public function title() {
return $this->element['#title'];
}
public function parentId() {
return $this->element['#form_builder']['parent_id'];
}
public function key() {
return $this->element['#key'];
}
}
interface FormBuilderPropertyInterface {
public function __construct($property, $params, $form_type_name);
public function form(&$form_state, $element);
public function submit($form, &$form_state);
}
class FormBuilderPropertyBase implements FormBuilderPropertyInterface {
protected $property;
protected $params;
protected $formTypeName;
public function __construct($property, $params, $form_type_name) {
$this->property = $property;
$this->params = $params;
$this->formTypeName = $form_type_name;
}
public function form(&$form_state, $element) {
$e = $element
->render();
if (isset($this->params['form']) && function_exists($this->params['form'])) {
$function = $this->params['form'];
$p = $this->property;
$e['#' . $p] = isset($e['#' . $p]) ? $e['#' . $p] : NULL;
return $function($form_state, $this->formTypeName, $e, $p);
}
return array();
}
public function submit($form, &$form_state) {
if (isset($this->params['submit'])) {
foreach ($this->params['submit'] as $function) {
if (function_exists($function)) {
$function($form, $form_state);
}
}
}
}
}