PhoebeClass::convertRenderablesToFields()   D
last analyzed

Complexity

Conditions 21
Paths 83

Size

Total Lines 53
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 42
CRAP Score 21.2902

Importance

Changes 0
Metric Value
eloc 46
dl 0
loc 53
rs 4.1666
c 0
b 0
f 0
cc 21
nc 83
nop 2
ccs 42
cts 46
cp 0.913
crap 21.2902

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @link http://www.newicon.net/neon
4
 * @copyright Copyright (c) 2018- Newicon Ltd
5
 * @license http://www.newicon.net/neon/license/
6
 */
7
8
namespace neon\phoebe\services\adapters\appforms;
9
10
use neon\phoebe\services\adapters\common\PhoebeClassBase;
11
use neon\phoebe\interfaces\forms\IPhoebeFormClass;
12
use neon\core\helpers\Hash;
13
14
15
/**
16
 * Provides a applicationForm phoebe class
17
 */
18
class PhoebeClass extends PhoebeClassBase
19
implements IPhoebeFormClass
20
{
21
	use PhoebeTrait;
22
23
	/**
24
	 * @inheritdoc
25
	 */
26 2
	public function getClassFormDefinition(array $fields=[])
27
	{
28
		// if there is no definition return an empty form
29 2
		if (empty($this->definition))
30
			return [];
31
32
		// TODO - NJ20180426 - see if we can get Phoebe to listen to $fields
33
34
		// create the form
35 2
		$definition = $this->replaceDefinitionFromDds($this->definition);
0 ignored issues
show
Bug introduced by
$this->definition of type array is incompatible with the type neon\phoebe\services\adapters\appforms\type expected by parameter $definition of neon\phoebe\services\ada...laceDefinitionFromDds(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

35
		$definition = $this->replaceDefinitionFromDds(/** @scrutinizer ignore-type */ $this->definition);
Loading history...
36 2
		$this->setMemberFieldNames($definition);
37 2
		return $this->convertToForm($definition);
38
	}
39
40
	public function getClassBuilderDefinition()
41
	{
42
		return $this->definition;
43
	}
44
45
	/**
46
	 * @inheritdoc
47
	 */
48
	public function getObjectGridDefinition($additionalColumns = [])
49
	{
50
		return parent::getObjectGridDefinition($additionalColumns);
51
	}
52
53
	/**
54
	 * @inheritdoc
55
	 */
56
	public function editClass($changes)
57
	{
58
		if (isset($changes['definition']))
59
			$changes['definition'] = $this->prepareDefinition($changes['definition']);
60
		parent::editClass($changes);
61
	}
62
63
	/**
64
	 * @inheritdoc
65
	 */
66
	public function getRequiredDataSources()
67
	{
68
		$dataSources = isset($this->definition['dataSources']) ? $this->definition['dataSources'] : [];
69
		$returnedDataSources = [];
70
		foreach ($dataSources as $dataSource) {
71
			$key = $dataSource['label'];
72
			$returnedDataSources[$key] = [
73
				'class_type'=>$dataSource['class_type'],
74
				'key'=>$key
75
			];
76
		}
77
		return $returnedDataSources;
78
	}
79
80
	/**
81
	 * @inheritdoc
82
	 */
83
	public function findPhoebeKeysForClassTypesInDefinition($ddsClassTypes)
84
	{
85
		$definition = $this->definition;
86
		$applicationDataPhoebeUuids = [];
87
		foreach ($ddsClassTypes as $ct)
88
			$applicationDataPhoebeUuids[$ct] = null;
89
		foreach ($definition['renderables'] as $k=>$r) {
90
			if ($r['type'] == 'ClassComponent' && in_array($r['class_type'], $ddsClassTypes)) {
91
				$applicationDataPhoebeUuids[$r['class_type']] = $k;
92
			}
93
		}
94
		return $applicationDataPhoebeUuids;
95
	}
96
97
	// ---------------------------------------- //
98
	// ---------- Additional Methods ---------- //
99
100
	/**
101
	 * Set the definition on the model - used when merging the stored definition
102
	 * with that from Daedalus
103
	 *
104
	 * @param array $definition
105
	 */
106 2
	public function setDefinition($definition)
107
	{
108 2
		$this->getModel()->definition = $definition;
109 2
	}
110
111
	/**
112
	 * Keep the model's definition here - overrides are applied in convertToForm
113
	 * level and not in the phoebe class definition
114
	 * @return array
115
	 */
116 2
	public function getDefinition()
117
	{
118 2
		return $this->getModel()->definition;
119
	}
120
121 2
	protected function convertToForm($definition)
122
	{
123 2
		$form = [];
124 2
		$form['name'] = $this->canonicaliseRef($definition['name']);
125 2
		$fields = $this->convertRenderablesToFields($definition['rootNode'], $definition['renderables']);
126 2
		$form['fields'] = $fields['fields'];
127
		// apply any overrides to the form
128 2
		if ($this->_overrides)
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_overrides of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
129
			$form = array_replace_recursive($form, $this->_overrides);
130 2
		return $form;
131
	}
132
133 2
	protected function convertRenderablesToFields($key, $renderables) {
134 2
		if (!isset($renderables[$key])) {
135
			dd("Key $key doesn't exist in the form definition", $renderables);
136
		throw new \RuntimeException("Key $key doesn't exist in the form definition");}
137 2
		$rend = $renderables[$key];
138 2
		$field=[];
139 2
		if (!empty($rend['type'])) {
140 2
			$field = [];
141 2
			switch($rend['type']) {
142 2
				case 'FormComponent':
143 2
					if (isset($rend['items']))
144 2
						$field['fields'] = $this->addItems($rend['items'], $renderables);
145 2
				break;
146 2
				case 'ClassComponent':
147 2
					$classDefinition = isset($rend['definition']) ? $rend['definition'] : [];
148 2
					if (count($rend['items'])>0) {
149 2
						$field['fields'] = [];
150 2
						$field['label'] = '';
151 2
						if (isset($classDefinition['showLabel']) && $classDefinition['showLabel'])
152 2
							$field['label'] = isset($classDefinition['label']) ? $classDefinition['label'] : $rend['label'];
153 2
						$field['description'] = '';
154 2
						if (isset($classDefinition['showDescription']) && $classDefinition['showDescription'])
155
							$field['description'] = isset($classDefinition['description']) ? $classDefinition['description'] : $rend['description'];
156 2
						if ($this->isRepeater($rend)) {
157 2
							$this->addRepeaterHeader($field, $rend['definition'], $key);
158 2
							if (isset($classDefinition['showLabel']) && $classDefinition['showLabel'])
159 2
								$field['template']['label'] = isset($classDefinition['label']) ? $classDefinition['label'] : $rend['label'];
160 2
							$field['template']['fields'] = $this->addItems($rend['items'], $renderables);
161 2
							$field['template']['fields'][] = $this->createHiddenField('_renderable', $key);
162 2
							$field['template']['fields'][] = $this->createHiddenField('_classType', $rend['class_type']);
163 2
							$field['template']['fields'][] = $this->createHiddenField('_uuid');
164
						} else {
165 2
							$field['class'] = '\\neon\\core\\form\\Form';
166 2
							$field['name'] = $key;
167 2
							$field['dataKey'] = $field['name'];
168 2
							$field['fields'] = $this->addItems($rend['items'], $renderables);
169 2
							$field['fields'][] = $this->createHiddenField('_renderable', $key);
170 2
							$field['fields'][] = $this->createHiddenField('_classType', $rend['class_type']);
171 2
							$field['fields'][] = $this->createHiddenField('_uuid');
172
						}
173
					}
174 2
				break;
175 2
				case 'MemberComponent':
176
				case 'ElementComponent':
177 2
					$field = $rend['definition'];
178
					// not all components have names but the form requires everything to have one
179 2
					if (empty($field['name'])) {
180 2
						$field['name'] = $this->createFieldName($field);
181
					}
182 2
				break;
183
			}
184
		}
185 2
		return $field;
186
	}
187
188 2
	protected function addItems($items, $renderables)
189
	{
190 2
		$field = [];
191 2
		$order = 1;
192 2
		foreach ($items as $rKey) {
193 2
			$subField = $this->convertRenderablesToFields($rKey, $renderables, 1);
0 ignored issues
show
Unused Code introduced by
The call to neon\phoebe\services\ada...rtRenderablesToFields() has too many arguments starting with 1. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

193
			/** @scrutinizer ignore-call */ 
194
   $subField = $this->convertRenderablesToFields($rKey, $renderables, 1);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
194 2
			if (isset($subField[$rKey]))
195 2
				$field[$rKey] = $subField[$rKey];
196
			else
197 2
				$field[$rKey] = $subField;
198 2
			$field[$rKey]['order'] = $order++;
199
		}
200 2
		return $field;
201
	}
202
203 2
	protected function isRepeater($renderable)
204
	{
205 2
		return (isset($renderable['definition']['isRepeater']) && $renderable['definition']['isRepeater'] == true);
206
	}
207
208 2
	protected function addRepeaterHeader(&$field, $repeat, $key)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

208
	protected function addRepeaterHeader(&$field, $repeat, /** @scrutinizer ignore-unused */ $key)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
209
	{
210
		// set the rpeater header part
211 2
		$field['class'] = "neon\\core\\form\\FormRepeater";
212 2
		$field['count'] = isset($repeat['defaultInstances']) ? (integer) $repeat['defaultInstances'] : 1;
213 2
		$field['countMax'] = isset($repeat['maxInstances']) ? (integer) $repeat['maxInstances'] : 0;
214 2
		$field['countMin'] = isset($repeat['minInstances']) ? (integer) $repeat['minInstances'] : 1;
215 2
		$allowChangeOfRepeats = ($field['countMin'] != $field['countMax']);
216 2
		$field['allowAdd'] = $allowChangeOfRepeats;
217 2
		$field['allowRemove'] = $allowChangeOfRepeats;
218
219
		// now set the template header part
220 2
		$field['template']['class'] =  "neon\\core\\form\\Form";
221 2
	}
222
223
	/**
224
	 * Create a hidden object id field required when sending back the data
225
	 * so we know what object it belongs to if set
226
	 * @return array
227
	 */
228 2
	protected function createHiddenField($name, $value=null)
229
	{
230
		return [
231 2
			'class' => "neon\\core\\form\\fields\\Hidden",
232 2
			'name' => $name,
233 2
			'order' => 0,
234 2
			'value' => $value
235
		];
236
	}
237
238 2
	protected function createFieldName($field)
239
	{
240 2
		$uuid = isset($field['id']) ? $field['id'] : Hash::uuid64();
241 2
		return str_replace(['-','_'],['a','Z'], $uuid);
242
	}
243
244
}