| 1 |
<?php
|
| 2 |
/**
|
| 3 |
* BUGGY CONCEPT CODE!
|
| 4 |
*
|
| 5 |
* This is code for a object oriented Forms and Rendering API in Drupal 7.
|
| 6 |
*/
|
| 7 |
|
| 8 |
// The heart.
|
| 9 |
require_once drupal_get_path('module', 'fapi4') .'/classes.inc';
|
| 10 |
require_once drupal_get_path('module', 'fapi4') .'/fapi.classes.inc';
|
| 11 |
|
| 12 |
function fapi4_init() {
|
| 13 |
// This is useless here, but imagine the following line living in some other module,
|
| 14 |
// e.g. in hook_init(): This replaces hook_form_alter
|
| 15 |
connect('Fapi4TestForm', 'construct', 'fapi4_alter_the_form');
|
| 16 |
// Yet TODO: Altering all forms.
|
| 17 |
}
|
| 18 |
|
| 19 |
function fapi4_menu() {
|
| 20 |
$items['fapi4'] = array(
|
| 21 |
'title' => 'FAPI4 test page',
|
| 22 |
'description' => "foo",
|
| 23 |
'page callback' => 'fapi4_page_callback',
|
| 24 |
'access arguments' => array('access administration pages'),
|
| 25 |
);
|
| 26 |
|
| 27 |
return $items;
|
| 28 |
}
|
| 29 |
|
| 30 |
function fapi4_page_callback() {
|
| 31 |
$output = '';
|
| 32 |
|
| 33 |
// Some dynamical data, like a node or user data.
|
| 34 |
// drupal_element will pass this to the build method.
|
| 35 |
$data = array(
|
| 36 |
'value1' => 'foo',
|
| 37 |
'value2' => 'bar'
|
| 38 |
);
|
| 39 |
|
| 40 |
// Get our form. This either creates a new object or loads one from cache.
|
| 41 |
// (This is still a little buggy)
|
| 42 |
$form = Form::load('Fapi4TestForm', $data);
|
| 43 |
// This always works instead:
|
| 44 |
// $form = new Fapi4TestForm();
|
| 45 |
// $form->invoke('build', $data);
|
| 46 |
|
| 47 |
$output .= $form->render();
|
| 48 |
|
| 49 |
q($form)->descendants()->filter('#FormWidget=asdf');
|
| 50 |
|
| 51 |
// Some traversing tests.
|
| 52 |
$output .= "<pre>";
|
| 53 |
$output .= "foreach q(\$form->group1)->siblings() :\n";
|
| 54 |
foreach (q($form->group1)->siblings() as $element) {
|
| 55 |
$output .= ' '. $element->__toString() ."\n";
|
| 56 |
}
|
| 57 |
$output .= "foreach q(\$form)->group1->siblings()->children() :\n";
|
| 58 |
foreach (q($form->group1)->siblings()->children() as $element) {
|
| 59 |
$output .= ' '. $element->__toString() ."\n";
|
| 60 |
}
|
| 61 |
$output .= "foreach q(\$form)->descendants() :\n";
|
| 62 |
foreach (q($form)->descendants('#has_error=0') as $element) {
|
| 63 |
$output .= ' '. $element->__toString() ."\n";
|
| 64 |
}
|
| 65 |
$output .= "</pre>";
|
| 66 |
|
| 67 |
|
| 68 |
return $output;
|
| 69 |
}
|
| 70 |
|
| 71 |
// Our form.
|
| 72 |
class Fapi4TestForm extends DrupalForm {
|
| 73 |
|
| 74 |
// This is called only once and then cached. So only static data here.
|
| 75 |
// (think of D5 hook_menu $may_cache)
|
| 76 |
public function construct() {
|
| 77 |
$this->group1 = new Fapi4TestWidget();
|
| 78 |
$this->group1->textfield1 = new DrupalTextfield(array('title' => 'Textfield 1'));
|
| 79 |
$this->group1->addChild('textfield2', new DrupalTextfield(array('title' => 'Textfield 2')));
|
| 80 |
|
| 81 |
$this->group2 = new Fapi4TestWidget();
|
| 82 |
$this->group2->text3 = new DrupalTextfield(array('title' => 'text3'));
|
| 83 |
$this->group2->text4 = new DrupalTextfield(array('title' => 'text4'));
|
| 84 |
|
| 85 |
$this->textfieldA = new DrupalTextfield(array(
|
| 86 |
'title' => 'Yet another textfield (A)',
|
| 87 |
'description' => 'It even has a description'
|
| 88 |
));
|
| 89 |
}
|
| 90 |
|
| 91 |
// This is called no matter whether the form was cached or not.
|
| 92 |
public function build($data) {
|
| 93 |
$this->group2->text3['default_value'] = $data['value1'];
|
| 94 |
$this->group2->text4['default_value'] = $data['value2'];
|
| 95 |
parent::build();
|
| 96 |
}
|
| 97 |
|
| 98 |
public function submit() {
|
| 99 |
$debuginfo = 'submit method called. <br> STEP: '. $this['step'];
|
| 100 |
|
| 101 |
switch ($this['step']) {
|
| 102 |
case 1:
|
| 103 |
$debuginfo .= " - Add some more text fields";
|
| 104 |
$this->group2->addChild('text5', new DrupalTextfield(array(
|
| 105 |
'title' => 'text5',
|
| 106 |
'description' => 'added by submit method for step 1'
|
| 107 |
)));
|
| 108 |
$this->group2->addChild('text6', new DrupalTextfield(array(
|
| 109 |
'title' => 'text6',
|
| 110 |
'description' => 'added by submit method for step 1'
|
| 111 |
)));
|
| 112 |
$this->submit['value'] = t('On to step 2!');
|
| 113 |
break;
|
| 114 |
case 2: {
|
| 115 |
$debuginfo .= " - don't render group1 one again and alter some stuff";
|
| 116 |
// don't unset (that would also destroy values etc.)! just not render it again.
|
| 117 |
$this->group1['render'] = FALSE;
|
| 118 |
$this->submit['value'] = t('Finish!');
|
| 119 |
break;
|
| 120 |
}
|
| 121 |
case 3: {
|
| 122 |
$debuginfo .= "<br>The final step. We now do what we want to do with the form values and ";
|
| 123 |
$debuginfo .= "then call \$this->redirect(). Here, we just redirect to the empty form again.";
|
| 124 |
$debuginfo .= '<br>received form values from all steps: <br>';
|
| 125 |
foreach ($this->descendants() as $e) {
|
| 126 |
$debuginfo .= $e->__toString() . ' - <em>' . (isset($e['value']) ? $e['value'] : 'No value') . "</em><br>";
|
| 127 |
}
|
| 128 |
drupal_set_message($debuginfo);
|
| 129 |
$this->redirect();
|
| 130 |
}
|
| 131 |
}
|
| 132 |
|
| 133 |
drupal_set_message($debuginfo);
|
| 134 |
}
|
| 135 |
}
|
| 136 |
|
| 137 |
// This replaces hook_form_alter.
|
| 138 |
function fapi4_alter_the_form($form) {
|
| 139 |
// Here, you could work with all the traversing function + foreach magic (jQuery style).
|
| 140 |
// e.g. foreach ($form->['some_element']->siblings() as $element) etc.
|
| 141 |
$form->group1['description'] = ' altered by a construct callback';
|
| 142 |
}
|
| 143 |
|
| 144 |
// A non-input widget.
|
| 145 |
class Fapi4TestWidget extends DrupalWidget {
|
| 146 |
// This is the place to set default properties,
|
| 147 |
// add required children, add callbacks, etc.
|
| 148 |
// This is actually a callback for the 'init' signal, which is always registered (by DrupalWidget)
|
| 149 |
public function construct() {
|
| 150 |
$this['description'] = 'Some test widget';
|
| 151 |
}
|
| 152 |
|
| 153 |
// let's render the children as an ul list, and print the element's description and name.
|
| 154 |
protected function theme() {
|
| 155 |
$output = "<strong>{$this['name']}</strong>";
|
| 156 |
$output .= "<div class='description'>{$this['description']}</div>";
|
| 157 |
if ($this->hasChildren()) {
|
| 158 |
$output .= "<ul>";
|
| 159 |
$output .= $this->renderChildren('<li>', '</li>');
|
| 160 |
$output .= "</ul>";
|
| 161 |
}
|
| 162 |
return $output;
|
| 163 |
}
|
| 164 |
|
| 165 |
public function preRender() {
|
| 166 |
// this is invoked before the widget is rendered.
|
| 167 |
}
|
| 168 |
}
|
| 169 |
|
| 170 |
|