Completed
Push — master ( d19955...af891e )
by Sam
22s
created

FieldGroup::__construct()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 17
c 1
b 0
f 0
nc 9
nop 2
dl 0
loc 29
rs 5.3846
1
<?php
2
/**
3
 * Lets you include a nested group of fields inside a template.
4
 * This control gives you more flexibility over form layout.
5
 *
6
 * Note: the child fields within a field group aren't rendered using FieldHolder().  Instead,
7
 * SmallFieldHolder() is called, which just prefixes $Field with a <label> tag, if the Title is set.
8
 *
9
 * <b>Usage</b>
10
 *
11
 * <code>
12
 * FieldGroup::create(
13
 * 	FieldGroup::create(
14
 * 		HeaderField::create('FieldGroup 1'),
15
 * 		TextField::create('Firstname')
16
 * 	),
17
 * 	FieldGroup::create(
18
 * 		HeaderField::create('FieldGroup 2'),
19
 * 		TextField::create('Surname')
20
 * 	)
21
 * )
22
 * </code>
23
 *
24
 * <b>Adding to existing FieldGroup instances</b>
25
 *
26
 * <code>
27
 * function getCMSFields() {
28
 * 	$fields = parent::getCMSFields();
29
 *
30
 * 	$fields->addFieldToTab(
31
 * 		'Root.Main',
32
 * 		FieldGroup::create(
33
 * 			TimeField::create("StartTime","What's the start time?"),
34
 * 			TimeField::create("EndTime","What's the end time?")
35
 * 		),
36
 * 		'Content'
37
 * 	);
38
 *
39
 * 	return $fields;
40
 *
41
 * }
42
 * </code>
43
 *
44
 * <b>Setting a title to a FieldGroup</b>
45
 *
46
 * <code>
47
 * $fields->addFieldToTab("Root.Main",
48
 * 		FieldGroup::create(
49
 * 			TimeField::create('StartTime','What's the start time?'),
50
 * 			TimeField::create('EndTime', 'What's the end time?')
51
 * 		)->setTitle('Time')
52
 * );
53
 * </code>
54
 *
55
 * @package forms
56
 * @subpackage fields-structural
57
 */
58
class FieldGroup extends CompositeField {
59
60
	protected $zebra;
61
62
	/**
63
	 * Create a new field group.
64
	 *
65
	 * Accepts any number of arguments.
66
	 *
67
	 * @param mixed $titleOrField Either the field title, list of fields, or first field
68
	 * @param mixed ...$otherFields Subsequent fields or field list (if passing in title to $titleOrField)
69
	 */
70
	public function __construct($titleOrField = null, $otherFields = null) {
71
		$title = null;
72
		if(is_array($titleOrField) || $titleOrField instanceof FieldList) {
73
			$fields = $titleOrField;
74
75
			// This would be discarded otherwise
76
			if($otherFields) {
77
				throw new InvalidArgumentException(
78
					'$otherFields is not accepted if passing in field list to $titleOrField'
79
				);
80
			}
81
82
		} else if(is_array($otherFields) || $otherFields instanceof FieldList) {
83
			$title = $titleOrField;
84
			$fields = $otherFields;
85
86
		} else {
87
			$fields = func_get_args();
88
			if(!is_object(reset($fields))) {
89
				$title = array_shift($fields);
90
			}
91
		}
92
93
		parent::__construct($fields);
94
95
		if($title) {
96
			$this->setTitle($title);
97
		}
98
	}
99
100
	/**
101
	 * Returns the name (ID) for the element.
102
	 * In some cases the FieldGroup doesn't have a title, but we still want
103
	 * the ID / name to be set. This code, generates the ID from the nested children
104
	 */
105
	public function getName(){
106
		if(!$this->title) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->title of type null|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
107
			$fs = $this->FieldList();
108
			$compositeTitle = '';
109
			$count = 0;
110
			foreach($fs as $subfield){
111
				/** @var FormField $subfield */
112
				$compositeTitle .= $subfield->getName();
113
				if($subfield->getName()) $count++;
114
			}
115
			/** @skipUpgrade */
116
			if($count == 1) $compositeTitle .= 'Group';
117
			return preg_replace("/[^a-zA-Z0-9]+/", "", $compositeTitle);
118
		}
119
120
		return preg_replace("/[^a-zA-Z0-9]+/", "", $this->title);
121
	}
122
123
	/**
124
	 * Set an odd/even class
125
	 *
126
	 * @param string $zebra one of odd or even.
127
	 * @return $this
128
	 */
129
	public function setZebra($zebra) {
130
		if($zebra == 'odd' || $zebra == 'even') $this->zebra = $zebra;
131
		else user_error("setZebra passed '$zebra'.  It should be passed 'odd' or 'even'", E_USER_WARNING);
132
		return $this;
133
	}
134
135
	/**
136
	 * @return string
137
	 */
138
	public function getZebra() {
139
		return $this->zebra;
140
	}
141
142
	/**
143
	 * @return string
144
	 */
145
	public function Message() {
146
		$fs = array();
147
		$this->collateDataFields($fs);
148
149
		foreach($fs as $subfield) {
150
			if($m = $subfield->Message()) $message[] = rtrim($m, ".");
0 ignored issues
show
Coding Style Comprehensibility introduced by
$message was never initialized. Although not strictly required by PHP, it is generally a good practice to add $message = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
151
		}
152
153
		return (isset($message)) ? implode(",  ", $message) . "." : "";
154
	}
155
156
	/**
157
	 * @return string
158
	 */
159
	public function MessageType() {
160
		$fs = array();
161
		$this->collateDataFields($fs);
162
163
		foreach($fs as $subfield) {
164
			if($m = $subfield->MessageType()) $MessageType[] = $m;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$MessageType was never initialized. Although not strictly required by PHP, it is generally a good practice to add $MessageType = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
165
		}
166
167
		return (isset($MessageType)) ? implode(".  ", $MessageType) : "";
168
	}
169
}
170