App   F
last analyzed

Complexity

Total Complexity 95

Size/Duplication

Total Lines 509
Duplicated Lines 0 %

Test Coverage

Coverage 3.24%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 191
dl 0
loc 509
ccs 6
cts 185
cp 0.0324
rs 2
c 3
b 0
f 0
wmc 95

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getMapResults() 0 4 1
A getDataMap() 0 16 5
A setMenu() 0 3 1
A getDataMapTypes() 0 5 1
A getDefaultMenu() 0 9 1
A getIPhoebeType() 0 3 1
A getName() 0 3 1
A getFormDefinition() 0 6 2
A makeMapLookupRequest() 0 2 1
A getSettings() 0 3 1
A getService() 0 6 2
B saveForm() 0 45 11
A getGridDefinition() 0 4 2
F getForm() 0 169 54
B formMergeMetaInformation() 0 24 11

How to fix   Complexity   

Complex Class

Complex classes like App often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use App, and based on these observations, apply Extract Interface, too.

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;
9
10
use neon\core\helpers\Arr;
11
use neon\core\interfaces\IDataMapProvider;
12
use neon\phoebe\services\PhoebeService;
13
use neon\phoebe\services\adapters\common\models\PhoebeClass as PhoebeClassModel;
14
use neon\phoebe\services\adapters\common\models\PhoebeObject as PhoebeObjectModel;
15
use neon\core\helpers\Html;
16
17
/**
18
 * The neon phoebe app class
19
 */
20
class App extends \neon\core\BaseApp
21
implements IDataMapProvider
22
{
23
	public $requires = 'dds';
24
25
	/**
26
	 * The phoebe service reference. One per app creation.
27
	 * @var neon\phoebe\services\PhoebeService
0 ignored issues
show
Bug introduced by
The type neon\phoebe\neon\phoebe\services\PhoebeService was not found. Did you mean neon\phoebe\services\PhoebeService? If so, make sure to prefix the type with \.
Loading history...
28
	 */
29
	public $phoebeService = null;
30
31
	/**
32
	 * @inheritdoc
33
	 */
34
	public function getName()
35
	{
36
		return 'Phoebe';
37
	}
38
39
	/**
40
	 * Override in config with an array to change menu options
41
	 * for e.g:
42
	 * ```php
43
	 * 'menu' => [
44
	 *     [
45
	 *         'label' => 'App Forms',
46
	 *         'order' => 1020,
47
	 *         'url' => ['/phoebe/appforms/index/index'],
48
	 *         'visible' => function() { // rules },
49
	 *     ],
50
	 * ]
51
	 * ```
52
	 * @see getMenu
53
	 * @see setMenu
54
	 * @var null
55
	 */
56
	protected $_menu = null;
57
58
	/**
59
	 * Enable default phoebe menu to be overridden
60
	 * @param $menu
61
	 */
62
	public function setMenu($menu)
63
	{
64
		$this->_menu = $menu;
65
	}
66
67
	/**
68
	 * @inheritdoc
69
	 */
70
	public function getDefaultMenu()
71
	{
72
		return [
73
			[
74
				'label' => 'Forms',
75
				'order' => 1400,
76
				'url' => ['/phoebe/appforms/index/index'],
77
				'visible' => neon()->user->hasRole('neon-administrator'),
78
				'active' => is_route('/phoebe/appforms/*'),
79
			]
80
		];
81
	}
82
83
	/**
84
	 * @inheritdoc
85
	 */
86
	public function getSettings()
87
	{
88
		return [];
89
	}
90
91
	/**
92
	 * @inheritdoc
93
	 */
94
	public function getDataMap($key, $query='', $filters=[], $fields=[], $start=0, $length=100)
95
	{
96
		// convert generic form builder filters to phoebe class ones
97
		$filters = Arr::replaceKeys($filters, ['uuid'=> 'class_type']);
98
		switch ($key) {
99
			// changed from Class to phoebe_class but need both for backwards compatibility
100
			case 'Class': case 'phoebe_class':
101
				return PhoebeClassModel::listClassTypes($query, $filters);
102
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
103
			// changed from Object to phoebe_object but need both for backwards compatibility
104
			case 'Object': case 'phoebe_object':
105
				return PhoebeObjectModel::listObjects($query, $filters);
106
			break;
107
			default:
108
				return [];
109
			break;
110
		}
111
	}
112
113
	/**
114
	 * @inheritdoc
115
	 */
116
	public function getDataMapTypes()
117
	{
118
		return [
119
			'phoebe_class' => 'Phoebe Class',
120
			'phoebe_object' => 'Phoebe Object'
121
		];
122
	}
123
124
	/**
125
	 * @inheritdoc
126
	 */
127
	public function getMapResults($requestKey)
128
	{
129
		// TODO: Implement getMapResults() method.
130
		return [];
131
	}
132
133
	/**
134
	 * @inheritdoc
135
	 */
136
	public function makeMapLookupRequest($key, $ids, $fields = [])
137
	{
138
		// TODO: Implement makeMapLookupRequest() method.
139
	}
140
141
	/**
142
	 * Get the phoebe service
143
	 * @return \neon\phoebe\interfaces\IPhoebeService
144
	 */
145 8
	public function getService()
146
	{
147 8
		if (!$this->phoebeService) {
148 2
			$this->phoebeService = new PhoebeService();
0 ignored issues
show
Documentation Bug introduced by
It seems like new neon\phoebe\services\PhoebeService() of type neon\phoebe\services\PhoebeService is incompatible with the declared type neon\phoebe\neon\phoebe\services\PhoebeService of property $phoebeService.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
149
		}
150 8
		return $this->phoebeService;
151
	}
152
153
	/**
154
	 * return neon\phoebe\interfaces\IPhoebeType
155
	 */
156 2
	public function getIPhoebeType($phoebeType)
157
	{
158 2
		return $this->getService()->getPhoebeType($phoebeType);
159
	}
160
161
	/**
162
	 * TODO - 20180507 - Tidy some of the form functions away into
163
	 * somewhere else - e.g. the PhoebeObject/Class/Type. That way you can make the
164
	 * methods specific to the type of form that is created
165
	 */
166
167
	/**
168
	 * Get hold of a form definition given the phoebe and class type
169
	 * Applies a cache per php request (cacheArray - a php in memory component)
170
	 * @param string $phoebeType  e.g. 'daedalus'
171
	 * @param string $classType  e.g. 'mytable'
172
	 * @param array $fields  if available for the phoebeType, the set of fields
173
	 *   that you want to display and in what order
174
	 * @return array
175
	 */
176
	public function getFormDefinition($phoebeType, $classType, array $fields=[])
177
	{
178
		$cacheKey = md5(serialize(func_get_args()));
179
		return neon()->cacheArray->getOrSet($cacheKey, function() use ($classType, $phoebeType, $fields) {
180
			$class = $this->getService()->getPhoebeType($phoebeType)->getClass($classType);
181
			return $class ? $class->getClassFormDefinition($fields) : [];
182
		});
183
	}
184
185
	/**
186
	 * Strings used for setting form meta data
187
	 * @var string
188
	 */
189
	private $formMetaPrefix = '_mt';
190
	private $formMetaDataSourceString = 'ds_';
191
	private $formMetaReturnUrlString = 'ru_';
192
	private $formMetaUuidString = 'ud_';
193
194
	/**
195
	 * Get a Phoebe form
196
	 *
197
	 * TODO - 13/07/2018 NJ - Move these into a more appropriate place
198
	 *
199
	 * Depending on settings, this can return an empty form or, so long as this
200
	 * is not a posted request, a form filled with the object from the database
201
	 * Note: if you are using a different name for the form, you must pass this
202
	 * in in the options
203
	 *
204
	 * @param string $phoebeType  the phoebe type required for e.g. 'daedalus'
205
	 * @param string $classType the phoebe class type
206
	 * @param array $options  a set of options to set on the form
207
	 *   'cssClass' => string - set additional css classes for the form
208
	 *   'id' => string - an id for the form
209
	 *   'label' => the form label. Omit for the default, or set to '' to remove,
210
	 *     or to the new label string.
211
	 *   'fields' => if available for the phoebe type, the set of fields that you want to
212
	 *     display and in what order as ['field1',...]
213
	 *   'fieldDefaults' => any defaults for the form as ['field'=>default]
214
	 *   'mapFilters' => if available for the phoebe type, filters for any fields that get
215
	 *     their data through a dataMapProvider. These should be as
216
	 *     ['formField1'=>['tableField1'=>'value1', ...], 'formField2'=>...]
217
	 *   'fieldProperties' => if available for the phoebe type, set provided properties for
218
	 *     the form fields as ['field'=>['property'=>'value']]
219
	 *   'save' => ['label' - the default submit button label]
220
	 *   'buttons' => an array of buttons as [['name', 'label', 'class'],...]
221
	 *     These will override the default submit button.
222
	 *   'enableAjaxValidation' => boolean  whether or not to use AJAX validation
223
	 *   'enableAjaxSubmission' => boolean  whether or not to use AJAX submission
224
	 *   'ajaxValidationUrl' => the URL to use for AJAX validation
225
	 *   'readOnly' => [true|false]  if set and true the form is read only
226
	 *   'printOnly' => [true|false]  if set and true the form is printable
227
	 *
228
	 * Additional meta information options can be passed.
229
	 *   'name' => pass in the form name if not defined by the classType
230
	 *   'action' => where the form should go to for processing
231
	 *   'uuid' => if the instance object already exists, set the UUID here. If this isn't
232
	 *      a posted form, the form will be loaded from the database
233
	 *   'dataSources' => if required, a set of data sources that the object needs
234
	 *      for saving itself. These are [key=>value] pairs
235
	 *   'returnUrl' => the return URL after processing the form
236
	 * @param array $action  if set then set this action on the form
237
	 * @return \neon\core\form\Form
238
	 * @throws
239
	 */
240
	public function getForm($phoebeType, $classType, $options)
241
	{
242
		$form = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $form is dead and can be removed.
Loading history...
243
		$fieldCount = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $fieldCount is dead and can be removed.
Loading history...
244
		$readOnly = empty($options['readOnly']) ? false : $options['readOnly'];
245
		$printOnly = empty($options['printOnly']) ? false : $options['printOnly'];
246
		$fields = empty($options['fields']) ? [] : $options['fields'];
247
248
		// see if we this is for an existing object and if so determine if it
249
		// had any overrides we need to take care of
250
		$phoebe = $this->getIPhoebeType($phoebeType);
251
		$object = null;
252
		$formDefinition = [];
253
		if (!empty($options['uuid'])) {
254
			$object = $phoebe->getObject($options['uuid']);
255
			if (!$object)
256
				throw new \RuntimeException('The requested form object was not found. Uuid='.$options['uuid']);
257
			$class = $object->getIPhoebeClass();
258
			$formDefinition = $class->getClassFormDefinition($fields);
259
		} else {
260
			// otherwise get a clean class
261
			if ($classType) {
262
				$formDefinition = $this->getFormDefinition($phoebeType, $classType, $fields);
263
				if (!count($formDefinition))
264
					throw new \RuntimeException('The requested form type was not found. Type='.$classType);
265
			}
266
		}
267
		$fieldCount = count($formDefinition['fields']);
268
		$form = new \neon\core\form\Form($formDefinition);
269
270
271
		// temporary code to cover problems with differences between appForms and ddsForms
272
		if ($phoebeType !== 'applicationForm' && !empty($options['initialiseFromDds']))
273
			throw new \RuntimeException('Only applicationForms work with initialiseFromDds');
274
275
		// set the form class
276
		if (!empty($options['cssClass']))
277
			$form->setAttributes(['class'=>$options['cssClass']]);
278
279
		// set the form id
280
		if (!empty($options['id']))
281
			$form->setId($options['id']);
282
		$formId = $form->getId();
283
		if ($printOnly) {
284
			$form->printOnly = true;
285
			$form->setId('PrintOnly'.$formId);
286
		} else if ($readOnly) {
287
			$form->readOnly = true;
288
			$form->setId('ReadOnly'.$formId);
289
		}
290
291
		// set the forms label - allow clearing of it via empty string
292
		if (isset($options['label']))
293
			$form->setLabel($options['label']);
294
295
296
		// check to see if we are not posting from the client, populate it from the database
297
		// !set the form name before checking data set!
298
		if (!empty($options['name']))
299
			$form->setName($options['name']);
300
		if (!empty($options['initialiseFromDds']) && (!$object || !$object->data)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $object->data 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...
301
			if (!$object)
302
				$object = $phoebe->createStubObject($classType);
0 ignored issues
show
Bug introduced by
The method createStubObject() does not exist on neon\phoebe\interfaces\IPhoebeType. It seems like you code against a sub-type of said class. However, the method does not exist in neon\phoebe\interfaces\d...lus\IPhoebeDaedalusType. Are you sure you never get one of those? ( Ignorable by Annotation )

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

302
				/** @scrutinizer ignore-call */ 
303
    $object = $phoebe->createStubObject($classType);
Loading history...
303
			$object->initialiseFromDds($options['initialiseFromDds']);
304
		}
305
		if ($object && !$form->hasRequestData()) {
306
			$form->loadFromDb($object->data);
307
		}
308
309
		if (!($printOnly || $readOnly)) {
310
			if (!empty($options['uuid']))
311
				$form->addFieldHidden("{$this->formMetaPrefix}{$this->formMetaUuidString}", ['value'=>$options['uuid']]);
312
313
			// set any additional data sources
314
			if (!empty($options['dataSources'])) {
315
				foreach ($options['dataSources'] as $key=>$value) {
316
					$form->addFieldHidden("{$this->formMetaPrefix}{$this->formMetaDataSourceString}$key", ['value'=>$value]);
317
					// for dds forms, set the values on the form too for initial display
318
					if ($phoebeType == 'daedalus') {
319
						if ($form->hasField($key))
320
							$form->getField($key)->setValue($value);
321
					}
322
				}
323
			}
324
325
			// set any map filters
326
			// NJ 20180617 - I think this should change the definition above and not be here
327
			// so that way it can work on appForms as well as ddsForms
328
			if (!empty($options['mapFilters'])) {
329
				foreach ($options['mapFilters'] as $key=>$filters) {
330
					$f = $form->getField($key);
331
					if ($f && isset($f->dataMapFilters))
0 ignored issues
show
Bug Best Practice introduced by
The property dataMapFilters does not exist on neon\core\form\fields\Field. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property dataMapFilters does not exist on neon\core\form\Form. Since you implemented __get, consider adding a @property annotation.
Loading history...
332
						$f->dataMapFilters = $filters;
0 ignored issues
show
Bug Best Practice introduced by
The property dataMapFilters does not exist on neon\core\form\Form. Since you implemented __set, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property dataMapFilters does not exist on neon\core\form\fields\Field. Since you implemented __set, consider adding a @property annotation.
Loading history...
333
				}
334
			}
335
336
			// set any map fields
337
			// NJ 20180617 - I think this should change the definition above and not be here
338
			// so that way it can work on appForms as well as ddsForms
339
			if (!empty($options['mapFields'])) {
340
				foreach ($options['mapFields'] as $key=>$mapFields) {
341
					$f = $form->getField($key);
342
					if ($f && isset($f->dataMapFields))
0 ignored issues
show
Bug Best Practice introduced by
The property dataMapFields does not exist on neon\core\form\Form. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property dataMapFields does not exist on neon\core\form\fields\Field. Since you implemented __get, consider adding a @property annotation.
Loading history...
343
						$f->dataMapFields = $mapFields;
0 ignored issues
show
Bug Best Practice introduced by
The property dataMapFields does not exist on neon\core\form\fields\Field. Since you implemented __set, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property dataMapFields does not exist on neon\core\form\Form. Since you implemented __set, consider adding a @property annotation.
Loading history...
344
				}
345
			}
346
347
			if (!empty($options['fieldDefaults'])) {
348
				foreach ($options['fieldDefaults'] as $field=>$default) {
349
					$f = $form->getField($field);
350
					if ($f) {
351
						$f->value = $default;
0 ignored issues
show
Bug Best Practice introduced by
The property value does not exist on neon\core\form\Form. Since you implemented __set, consider adding a @property annotation.
Loading history...
352
					}
353
				}
354
			}
355
356
			if (!empty($options['fieldProperties'])) {
357
				foreach ($options['fieldProperties'] as $field=>$properties) {
358
					$f = $form->getField($field);
359
					if ($f) {
360
						foreach ($properties as $property => $value) {
361
							$f->$property = $value;
362
						}
363
					}
364
				}
365
			}
366
367
			// set the forms action
368
			if (!empty($options['action']))
369
				$form->setAction($options['action']);
370
371
			// set whether or not ajax validation is required
372
			if (isset($options['enableAjaxValidation']))
373
				$form->enableAjaxValidation = (boolean) $options['enableAjaxValidation'];
374
375
			// set whether or not ajax submission is required
376
			if (isset($options['enableAjaxSubmission']))
377
				$form->enableAjaxSubmission = (boolean) $options['enableAjaxSubmission'];
378
379
			// set where the form will check itself via ajaxValidation
380
			if (!empty($options['ajaxValidationUrl']))
381
				$form->validationUrl = $options['ajaxValidationUrl'];
382
383
			// set where the browser will go to after completion of the form
384
			if (!empty($options['returnUrl'])) {
385
				$form->addFieldHidden("{$this->formMetaPrefix}{$this->formMetaReturnUrlString}", ['value'=>$options['returnUrl']]);
386
			}
387
388
			if (!empty($options['buttons'])) {
389
				foreach ($options['buttons'] as $button) {
390
					$btnOptions = [
391
						'order' => $fieldCount++,
392
						'label' => !empty($button['label']) ? $button['label'] : 'Label Required',
393
						'attributes' => [
394
							'class' => !empty($button['class']) ? $button['class'] : null
395
						]
396
					];
397
					$form->addFieldSubmit($button['name'], $btnOptions);
398
				}
399
			} else {
400
				// sort out the default submit button
401
				$submitOptions = [
402
					'order' => $fieldCount++,
403
					'label' => !empty($options['save']['label']) ? $options['save']['label'] : _t('Submit Form')
404
				];
405
				$form->addFieldSubmit('Save', $submitOptions);
406
			}
407
		}
408
		return $form;
409
	}
410
411
	/**
412
	 * Save a phoebe form. This saves generically to daedalus and applicationForm forms.
413
	 *
414
	 * TODO - 13/07/2018 NJ - Move these into a more appropriate place
415
	 *
416
	 * @param string $phoebeType - the phoebe type of the form e.g. daedalus
417
	 * @param string $classType - the name of the form class type e.g. myTable
418
	 * @param object $form - the form if already created or null if it will be here
419
	 * @param string $formName - the form name if not the same as the class type
420
	 * @param string $metaInfo - any additional information that should be used in
421
	 *   the saving. The values would have been saved on the form during creation
422
	 *   if passed in then (@see getForm) and the fields were rendered.
423
	 *   These values if provided override and are any of [
424
	 *     'uuid' => the object uuid if editing
425
	 *     'dataSources' => any data sources that should be set on the saved object
426
	 *     'returnUrl' => where the form should go to after saving
427
	 *   ].
428
	 * @param string &$uuid - the saved object uuid either passed in or set on return
429
	 * @param array &$changeLogUuids - the object change log uuids that occured during the
430
	 *   saving. This will be 'edit' and possibly 'add' if the object was new
431
	 * @return bool - returns true if saved correctly or the set of errors if the
432
	 *   form couldn't validate
433
	 */
434
	public function saveForm($phoebeType, $classType, $form=null, $formName=null, $metaInfo=null, &$uuid=null, &$changeLogUuids=[])
435
	{
436
		$changeLogUuids = [];
437
		if (!$form) {
438
			$definition = $this->getFormDefinition($phoebeType, $classType);
439
			$form = new \neon\core\form\Form($definition);
440
		}
441
		if (!empty($formName))
442
			$form->setName($formName);
443
		if ($form->processRequest()) {
444
			$data = $form->getData();
445
			// prevent multiple renders resulting in multiple saves of the form
446
			static $alreadySubmitted = [];
447
			// allow odd case of submissions of different types of form within one post
448
			// from a controller using this directly. Don't include the data in the key as
449
			// this can change between submission and rerenders of the template.
450
			$submittedCheck = md5($phoebeType.$classType);
451
			if (!array_key_exists($submittedCheck, $alreadySubmitted)) {
452
				$meta = $this->formMergeMetaInformation($form, $metaInfo);
453
				$phoebe = $this->getIPhoebeType($phoebeType);
454
				$object = null;
455
				if (!empty($meta['uuid'])) {
456
					$object = $phoebe->getObject($meta['uuid']);
457
				} else if ($phoebeType == 'daedalus' && $form->hasField('_uuid')) {
458
					$object = $phoebe->getObject($form->getField('_uuid')->getValue());
0 ignored issues
show
Bug introduced by
It seems like $form->getField('_uuid')->getValue() can also be of type array and array; however, parameter $objectId of neon\phoebe\interfaces\IPhoebeType::getObject() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

458
					$object = $phoebe->getObject(/** @scrutinizer ignore-type */ $form->getField('_uuid')->getValue());
Loading history...
459
				} else {
460
					$object = $phoebe->addObject($classType);
461
					$changeLogUuids['add'] = $object->getChangeLogUuid();
462
				}
463
				$uuid = $object->uuid;
464
				if (!empty($meta['dataSources']))
465
					$object->setDataSources($meta['dataSources']);
0 ignored issues
show
Bug introduced by
The method setDataSources() does not exist on neon\phoebe\interfaces\IPhoebeObject. Since it exists in all sub-types, consider adding an abstract or default implementation to neon\phoebe\interfaces\IPhoebeObject. ( Ignorable by Annotation )

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

465
					$object->/** @scrutinizer ignore-call */ 
466
              setDataSources($meta['dataSources']);
Loading history...
466
				if ($object->editObject($data) === true) {
467
					$alreadySubmitted[$submittedCheck] = $uuid;
468
					$changeLogUuids['edit'] = $object->getChangeLogUuid();
469
					if (!empty($meta['returnUrl']))
470
						neon()->response->redirect(html_entity_decode($meta['returnUrl']));
471
					return true;
472
				}
473
			} else {
474
				$uuid = $alreadySubmitted[$submittedCheck];
475
				return true;
476
			}
477
		}
478
		return $form->getErrors();
479
	}
480
481
	/**
482
	 * Get hold of an object grid definition given the phoebe and class type
483
	 * @param string $phoebeType  e.g. 'daedalus'
484
	 * @param string $classType  e.g. 'mytable'
485
	 * @param boolean $includeData  set to true to include the data field (can be big)
486
	 * @param boolean $includeDeleted  set to true to include the deleted column
487
	 * @return array
488
	 */
489
	public function getGridDefinition($phoebeType, $classType, $additionalColumns = [])
490
	{
491
		$class = $this->getService()->getPhoebeType($phoebeType)->getClass($classType);
492
		return $class ? $class->getObjectGridDefinition($additionalColumns) : [];
493
	}
494
495
496
	/**
497
	 * Extract out any form meta information added. Any non empty meta information
498
	 * passed in via the method takes precedence over anything returned from the form.
499
	 * This is to allow for extra security in the cases where the data can be derived
500
	 * on the server too.
501
	 * @param Form $form
502
	 * @param array $metaInfo - an array of any of 'uuid', 'returnUrl', 'dataSources'
503
	 * @return array
504
	 */
505
	protected function formMergeMetaInformation($form, $meta)
506
	{
507
		$data = $form->getData();
508
		foreach ($data as $k=>$v) {
509
			if (strpos($k, $this->formMetaPrefix) === 0) {
510
				$key = substr($k, strlen($this->formMetaPrefix));
511
				if ($key == $this->formMetaUuidString && empty($meta['uuid'])) {
512
					$meta['uuid'] = $v;
513
				} else if (strpos($key, $this->formMetaDataSourceString) === 0) {
514
					$itemKey = substr($key, strlen($this->formMetaDataSourceString));
515
					if (empty($meta['dataSources'][$itemKey]))
516
						$meta['dataSources'][$itemKey] = $v;
517
				} else if ($key==$this->formMetaReturnUrlString && empty($meta['returnUrl'])) {
518
					$meta['returnUrl'] = $v;
519
				}
520
			}
521
		}
522
		// capture the case where the form posted a uuid but the server didn't know
523
		// to create the uuid field as it didn't know the uuid at that point
524
		if (empty($meta['uuid'])) {
525
			$postedUuid = $form->getRawRequestData($this->formMetaPrefix.$this->formMetaUuidString);
526
			$meta['uuid'] = $postedUuid ? Html::sanitise($postedUuid) : null;
527
		}
528
		return $meta;
529
	}
530
531
}
532