1 <?php
2 3 4 5 6 7 8
9 class CompositeField extends FormField {
10
11 12 13
14 protected $children;
15
16 17 18
19 protected $readonly;
20
21 22 23 24 25 26 27 28
29 protected $columnCount = null;
30
31 public function __construct($children = null) {
32 if($children instanceof FieldSet) {
33 $this->children = $children;
34 } elseif(is_array($children)) {
35 $this->children = new FieldSet($children);
36 } else {
37 $children = is_array(func_get_args()) ? func_get_args() : array();
38 $this->children = new FieldSet($children);
39 }
40 $this->children->setContainerField($this);
41
42
43
44 $this->brokenOnConstruct = false;
45 Object::__construct();
46 }
47
48 49 50
51 public function FieldSet() {
52 return $this->children;
53 }
54
55 public function setID($id) {
56 $this->id = $id;
57 }
58
59 public function Field() {
60 return $this->FieldHolder();
61 }
62
63 64 65 66
67 public function getChildren() {
68 return $this->children;
69 }
70
71 72 73
74 public function setChildren($children) {
75 $this->children = $children;
76 }
77
78 79 80
81 function FieldHolder() {
82 $fs = $this->FieldSet();
83 $idAtt = isset($this->id) ? " id=\"{$this->id}\"" : '';
84 $className = ($this->columnCount) ? "field {$this->class} {$this->extraClass()} multicolumn" : "field {$this->class} {$this->extraClass()}";
85 $content = "<div class=\"$className\"$idAtt>\n";
86
87 foreach($fs as $subfield) {
88 if($this->columnCount) {
89 $className = "column{$this->columnCount}";
90 if(!next($fs)) $className .= " lastcolumn";
91 $content .= "\n<div class=\"{$className}\">\n" . $subfield->FieldHolder() . "\n</div>\n";
92 } else if($subfield){
93 $content .= "\n" . $subfield->FieldHolder() . "\n";
94 }
95 }
96 $content .= "</div>\n";
97
98 return $content;
99 }
100
101 102 103
104 function SmallFieldHolder() {
105 $fs = $this->FieldSet();
106 $idAtt = isset($this->id) ? " id=\"{$this->id}\"" : '';
107 $className = ($this->columnCount) ? "field CompositeField {$this->extraClass()} multicolumn" : "field CompositeField {$this->extraClass()}";
108 $content = "<div class=\"$className\"$idAtt>";
109
110 foreach($fs as $subfield) {
111 if($this->columnCount) {
112 $className = "column{$this->columnCount}";
113 if(!next($fs)) $className .= " lastcolumn";
114 $content .= "<div class=\"{$className}\">" . $subfield->FieldHolder() . "</div>";
115 } else if($subfield){
116 $content .= $subfield->SmallFieldHolder() . " ";
117 }
118 }
119 $content .= "</div>";
120
121 return $content;
122 }
123 124 125 126
127 public function collateDataFields(&$list, $saveableOnly = false) {
128 foreach($this->children as $field) {
129 if(is_object($field)) {
130 if($field->isComposite()) $field->collateDataFields($list, $saveableOnly);
131 if($saveableOnly) {
132 $isIncluded = ($field->hasData() && !$field->isReadonly() && !$field->isDisabled());
133 } else {
134 $isIncluded = ($field->hasData());
135 }
136 if($isIncluded) {
137 $name = $field->Name();
138 if($name) {
139 $formName = (isset($this->form)) ? $this->form->FormName() : '(unknown form)';
140 if(isset($list[$name])) user_error("collateDataFields() I noticed that a field called '$name' appears twice in your form: '{$formName}'. One is a '{$field->class}' and the other is a '{$list[$name]->class}'", E_USER_ERROR);
141 $list[$name] = $field;
142 }
143 }
144 }
145 }
146 }
147
148 function setForm($form) {
149 foreach($this->children as $f) if(is_object($f)) $f->setForm($form);
150 parent::setForm($form);
151 }
152
153 function setColumnCount($columnCount) {
154 $this->columnCount = $columnCount;
155 }
156
157 function isComposite() { return true; }
158 function hasData() { return false; }
159
160 public function fieldByName($name) {
161 return $this->children->fieldByName($name);
162 }
163 164 165
166 public function push(FormField $field) {
167 $this->children->push($field);
168 }
169
170 171 172
173 public function insertBefore($field, $insertBefore) {
174 $ret = $this->children->insertBefore($field, $insertBefore);
175 $this->sequentialSet = null;
176 return $ret;
177 }
178
179 public function insertAfter($field, $insertAfter) {
180 $ret = $this->children->insertAfter($field, $insertAfter);
181 $this->sequentialSet = null;
182 return $ret;
183 }
184
185 186 187 188 189 190 191 192 193
194 public function removeByName($fieldName, $dataFieldOnly = false) {
195 $this->children->removeByName($fieldName, $dataFieldOnly);
196 }
197
198 public function replaceField($fieldName, $newField) {
199 return $this->children->replaceField($fieldName, $newField);
200 }
201
202 function rootFieldSet() {
203 if(is_object($this->containerFieldSet)) return $this->containerFieldSet->rootFieldSet();
204 else return $this->children;
205 }
206
207 208 209 210
211 public function performReadonlyTransformation() {
212 $newChildren = new FieldSet();
213 $clone = clone $this;
214 foreach($clone->getChildren() as $idx => $child) {
215 if(is_object($child)) $child = $child->transform(new ReadonlyTransformation());
216 $newChildren->push($child, $idx);
217 }
218
219 $clone->children = $newChildren;
220 $clone->readonly = true;
221 return $clone;
222 }
223
224 225 226 227
228 public function performDisabledTransformation($trans) {
229 $newChildren = new FieldSet();
230 $clone = clone $this;
231 if($clone->getChildren()) foreach($clone->getChildren() as $idx => $child) {
232 if(is_object($child)) {
233 $child = $child->transform($trans);
234 }
235 $newChildren->push($child, $idx);
236 }
237
238 $clone->children = $newChildren;
239 $clone->readonly = true;
240
241 return $clone;
242 }
243
244 function IsReadonly() {
245 return $this->readonly;
246 }
247
248 249 250 251 252 253 254
255 function fieldPosition($field) {
256 if(is_string($field)) $field = $this->fieldByName($field);
257 if(!$field) return false;
258
259 $i = 0;
260 foreach($this->children as $child) {
261 if($child->Name() == $field->Name()) return $i;
262 $i++;
263 }
264
265 return false;
266 }
267
268 269 270 271 272
273 function makeFieldReadonly($field) {
274 $fieldName = ($field instanceof FormField) ? $field->Name() : $field;
275
276
277 foreach($this->children as $i => $item) {
278 if($item->isComposite()) {
279 $item->makeFieldReadonly($fieldName);
280 } else {
281
282 if($item->Name() == $fieldName) {
283 $this->children->replaceField($fieldName, $item->transform(new ReadonlyTransformation()));
284
285
286 $this->sequentialSet = null;
287
288
289 return true;
290 }
291 }
292 }
293 return false;
294 }
295
296 function debug() {
297 $result = "$this->class ($this->name) <ul>";
298 foreach($this->children as $child) {
299 $result .= "<li>" . Debug::text($child) . " </li>";
300 }
301 $result .= "</ul>";
302 return $result;
303 }
304
305 function validate($validator){
306
307 $valid = true;
308 foreach($this->children as $idx => $child){
309 $valid = ($child && $child->validate($validator) && $valid);
310 }
311
312 return $valid;
313 }
314 }
315
316 ?>
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the
Silverstripe Forums to ask development related questions.
-