Passed
Push — develop ( 5f0710...340c0b )
by Neill
12:23 queued 14s
created

DdsDataDefinitionManager::addDataType()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3.0146

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 21
rs 9.7333
c 0
b 0
f 0
cc 3
nc 3
nop 5
ccs 15
cts 17
cp 0.8824
crap 3.0146
1
<?php
2
/**
3
 * @link http://www.newicon.net/neon
4
 * @copyright Copyright (c) 2016 Newicon Ltd
5
 * @license http://www.newicon.net/neon/license/
6
 */
7
8
namespace neon\daedalus\services\ddsManager;
9
10
use neon\daedalus\interfaces\IDdsDataTypeManagement;
11
use neon\daedalus\interfaces\IDdsClassManagement;
12
use neon\daedalus\services\ddsManager\DdsCore;
13
use neon\daedalus\services\ddsManager\models\DdsClass;
14
use neon\daedalus\services\ddsManager\models\DdsDataType;
15
use neon\daedalus\services\ddsManager\models\DdsMember;
16
17
class DdsDataDefinitionManager extends DdsCore
18
implements IDdsDataTypeManagement, IDdsClassManagement
19
{
20
21
	/** --------------------------------------------------- **/
22
	/** ---------- interface IDdsClassManagement ---------- **/
23
	/** --------------------------------------------------- **/
24
25
	/** ---------- Utility Methods ---------- **/
26
27
	/**
28
	 * @inheritdoc
29
	 */
30 6
	public function isClassTypeUnique($candidate)
31
	{
32 6
		$ct = $this->canonicaliseRef($candidate);
33 6
		$class = DdsClass::find()->where(['class_type'=>$ct])->one();
34 6
		return ($class == null);
35
	}
36
37
	/**
38
	 * @inheritdoc
39
	 */
40 4
	public function isMemberRefUnique($classType, $candidate)
41
	{
42 4
		if ($this->isClassTypeUnique($classType))
43 2
			throw new \InvalidArgumentException("Class type ".$this->canonicaliseRef($classType)." unknown");
44 2
		$mr = $this->canonicaliseRef($candidate);
45 2
		$member = DdsMember::find()->where(['class_type'=>$classType, 'member_ref'=>$mr])->one();
46 2
		return ($member == null);
47
	}
48
49
	/** ---------- Class Manipulations ---------- **/
50
51
	/**
52
	 * @param null $module
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $module is correct as it would always require null to be passed?
Loading history...
53
	 * @param bool $includeDeleted
54
	 * @return \yii\db\ActiveQuery
55
	 */
56
	public function countClasses($module=null, $includeDeleted=false)
57
	{
58
		$query = $this->_getClassesQuery($module, $includeDeleted);
59
		return $query->count();
60
	}
61
62
	/**
63
	 * @inheritdoc
64
	 */
65 6
	public function listClasses($module, &$total, $includeDeleted=false, $start=0, $length=100, $orderBy='label')
66
	{
67 6
		$query = $this->_getClassesQuery($module, $includeDeleted);
68 6
		if ($start == 0)
69 6
			$total = (int) $query->count();
70 6
		$results = $query->asArray()
71 6
			->offset($start)
72 6
			->limit($length)
73 6
			->orderBy($orderBy)
74 6
			->all();
75 6
		foreach ($results as &$r)
76 4
			$r['count_current'] = $r['count_total'] - $r['count_deleted'];
77 6
		return $results;
78
	}
79
80
	/**
81
	 * @inheritdoc
82
	 */
83 2
	public function getMappableClasses()
84
	{
85 2
		$ddsMemberTbl = DdsMember::tableName();
86 2
		$ddsClassTbl = DdsClass::tableName();
87 2
		$mappable = DdsClass::find()
88 2
			->innerJoin($ddsMemberTbl, "$ddsClassTbl.class_type = $ddsMemberTbl.class_type")
89 2
			->select("$ddsClassTbl.class_type, $ddsClassTbl.label")
90 2
			->where([
91 2
				"$ddsMemberTbl.map_field" => 1,
92 2
				"$ddsClassTbl.deleted" => 0,
93 2
				"$ddsMemberTbl.deleted" => 0
94
			])
95 2
			->asArray()
96 2
			->all();
97 2
		$map = [];
98 2
		foreach ($mappable as $m)
99 2
			$map[$m['class_type']] = $m['label'];
100 2
		return $map;
101
	}
102
103
	/**
104
	 * Get the map field for a class
105
	 * @param string $class
106
	 */
107 2
	public function getClassMapField($class)
108
	{
109 2
		$member = $this->getMapMemberForClass($class);
110 2
		return $member ? $member['member_ref'] : null;
111
	}
112
113
	/**
114
	 * @inheritdoc
115
	 */
116 84
	public function addClass(&$classType, $module)
117
	{
118 84
		$classType = $this->canonicaliseRef($classType);
119 84
		if (DdsClass::findOne(['class_type'=>$classType]) !== null)
120
			throw new \InvalidArgumentException("The class $classType already exists");
121 84
		$c = new DdsClass();
122 84
		$c->class_type = $classType;
123 84
		$c->module = (empty($module) ? null : $module);
124 84
		if (!$c->save())
125
			throw new \RuntimeException("Couldn't save the class: ".print_r($c->errors,true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($c->errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

125
			throw new \RuntimeException("Couldn't save the class: "./** @scrutinizer ignore-type */ print_r($c->errors,true));
Loading history...
126 84
		$upSql = $this->getClassTypeMigrationSql($classType);
127 84
		$downSql = "DELETE FROM `dds_class` WHERE `class_type`='$classType';";
128 84
		$this->storeMigration($upSql, $downSql);
129 84
		$this->createClassTable($classType);
0 ignored issues
show
Bug introduced by
$classType of type string is incompatible with the type neon\daedalus\services\ddsManager\type expected by parameter $classType of neon\daedalus\services\d...ore::createClassTable(). ( Ignorable by Annotation )

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

129
		$this->createClassTable(/** @scrutinizer ignore-type */ $classType);
Loading history...
130 84
		return $c->class_type;
131
	}
132
133
	/**
134
	 * @inheritdoc
135
	 */
136 12
	public function getClass($classType, $includeMembers=false)
137
	{
138 12
		if ($this->findClass($classType, $class)) {
139 12
			$data = $class->toArray();
140 12
			if ($includeMembers)
141
				$data['members'] = $this->listMembers($class['class_type']);
142 12
			return $data;
143
		}
144
		return null;
145
	}
146
147
	/**
148
	 * @inheritdoc
149
	 */
150 30
	public function editClass($classType, $changes)
151
	{
152 30
		$allowed = array_intersect_key($changes, array_flip(['label', 'description', 'module', 'change_log']));
153 30
		if (count($allowed)==0)
154
			return;
155 30
		$this->clearClassCache($classType);
156 30
		$downSql = $this->getClassTypeMigrationSql($classType);
157 30
		if ($this->findClass($classType, $class)) {
158
			// find the minimum set of actual changes and only update if there are any
159 30
			$updates = array_diff_assoc($allowed, $class->attributes);
160 30
			if (count($updates)) {
161 30
				$class->attributes = $updates;
162 30
				if (!$class->save())
163
					throw new \RuntimeException("Dds: Couldn't update the class '$classType': ".print_r($class->errors));
0 ignored issues
show
Bug introduced by
Are you sure print_r($class->errors) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

163
					throw new \RuntimeException("Dds: Couldn't update the class '$classType': "./** @scrutinizer ignore-type */ print_r($class->errors));
Loading history...
164 30
				$upSql = $this->getClassTypeMigrationSql($classType);
165 30
				$this->storeMigration($upSql, $downSql);
166
			}
167
		}
168 30
	}
169
170
	/**
171
	 * @inheritdoc
172
	 */
173 24
	public function deleteClass($classType)
174
	{
175
		// delete a class if it hasn't already been deleted
176 24
		if ($this->findClass($classType, $class) && $class->deleted == 0) {
177 24
			$upSql = "UPDATE `dds_class` SET `deleted`=1 WHERE `class_type`='{$class->class_type}';";
178 24
			neon()->db->createCommand($upSql)->execute();
179 24
			$downSql = "UPDATE `dds_class` SET `deleted`=0 WHERE `class_type`='{$class->class_type}';";
180 24
			$this->storeMigration($upSql, $downSql);
181 24
			$this->clearClassCache($classType);
182
		}
183 24
	}
184
185
	/**
186
	 * @inheritdoc
187
	 */
188 4
	public function undeleteClass($classType)
189
	{
190
		// undelete a class if it is already deleted
191 4
		if ($this->findClass($classType, $class) && $class->deleted == 1) {
192 4
			$upSql = "UPDATE `dds_class` SET `deleted`=0 WHERE `class_type`='{$class->class_type}';";
193 4
			neon()->db->createCommand($upSql)->execute();
194 4
			$downSql = "UPDATE `dds_class` SET `deleted`=1 WHERE `class_type`='{$class->class_type}';";
195 4
			$this->storeMigration($upSql, $downSql);
196 4
			$this->clearClassCache($classType);
197
		}
198 4
	}
199
200
	/**
201
	 * @inheritdoc
202
	 */
203 28
	public function destroyClass($classType)
204
	{
205 28
		if ($this->findClass($classType, $class)) {
206 28
			if ($this->hasObjects($classType))
207
				throw new \RunTimeException("You need to delete all objects before you can destroy a class");
208
209
			// now delete the rows
210 28
			$members = DdsMember::find()->where(['class_type'=>$class->class_type])->asArray()->all();
211 28
			$errors = [];
212 28
			foreach ($members as $member) {
213
				try {
214 22
					$this->destroyMember($member['class_type'], $member['member_ref']);
215
				} catch (\Exception $e) {
216
					$errors[] = $e->getMessage();
217
				}
218
			}
219 28
			if (count($errors))
220
				throw new \RuntimeException("Couldn't destroy all of the members: ".print_r($errors, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

220
				throw new \RuntimeException("Couldn't destroy all of the members: "./** @scrutinizer ignore-type */ print_r($errors, true));
Loading history...
221
			// now delete the class
222
			// can also return 0 - which is valid - false means there has been an error
223 28
			if ($class->delete() === false)
224
				throw new \RuntimeException("Couldn't destroy the class: ".print_r($class->errors, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($class->errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

224
				throw new \RuntimeException("Couldn't destroy the class: "./** @scrutinizer ignore-type */ print_r($class->errors, true));
Loading history...
225
			// and clear away the table
226 28
			$this->dropClassTable($class->class_type);
227 28
			$this->clearClassCache($classType);
228
		}
229 28
	}
230
231
232
	/** ---------- Member Manipulations(!!) ---------- **/
233
234
	/**
235
	 * @inheritdoc
236
	 */
237 8
	public function listMembers($classType, $includeDeleted=false, $keyBy='member_ref')
238
	{
239 8
		return $this->listMembersForClass($classType, $includeDeleted, $keyBy);
240
	}
241
242
	/**
243
	 * @inheritdoc
244
	 */
245 82
	public function addMember($classType, &$memberRef, $dataTypeRef, $label, $description, $additional=null)
246
	{
247 82
		$classType = $this->canonicaliseRef($classType);
248 82
		$memberRef = $this->canonicaliseRef($memberRef);
249 82
		$class = null;
250 82
		if ($this->findClass($classType, $class)) {
251
			// extract out any additional information
252 82
			$choices = ((!empty($additional['choices']) && is_array($additional['choices'])) ? $additional['choices'] : []);
253 82
			$linkClass = (!empty($additional['link_class']) ? $additional['link_class'] : null);
254 82
			if (DdsMember::findOne(['class_type' => $classType, 'member_ref' => $memberRef])!==null)
255
				throw new \InvalidArgumentException("The member $memberRef already exists");
256 82
			if (in_array($dataTypeRef, ['link_uni', 'link_multi']) && !$linkClass) {
257
				throw new \InvalidArgumentException("Link_uni, link_multi data types require a link_class to be passed for member '$classType::$memberRef'. You passed in ".print_r($additional, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($additional, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

257
				throw new \InvalidArgumentException("Link_uni, link_multi data types require a link_class to be passed for member '$classType::$memberRef'. You passed in "./** @scrutinizer ignore-type */ print_r($additional, true));
Loading history...
258
			}
259 82
			$member = new DdsMember();
260 82
			$member->class_type = $classType;
261 82
			$member->member_ref = $memberRef;
262 82
			$member->data_type_ref = $dataTypeRef;
263 82
			$member->label = $label;
264 82
			$member->description = $description;
265 82
			$member->choices = ($this->memberAllowedChoices($dataTypeRef) ? $choices : null);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->memberAllowedChoi...eRef) ? $choices : null can also be of type array. However, the property $choices is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
266 82
			$member->link_class = ($this->memberAllowedLinks($dataTypeRef) ? $linkClass : null);
267 82
			$member->created = $this->now();
0 ignored issues
show
Bug Best Practice introduced by
The property created does not exist on neon\daedalus\services\ddsManager\models\DdsMember. Since you implemented __set, consider adding a @property annotation.
Loading history...
268 82
			if (!$member->save())
269
				throw new \RuntimeException("Couldn't save the member: ".print_r($member->errors, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($member->errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

269
				throw new \RuntimeException("Couldn't save the member: "./** @scrutinizer ignore-type */ print_r($member->errors, true));
Loading history...
270
271
			// create the migrations
272 82
			$savedMember = $this->getMember($classType, $memberRef);
273 82
			$upMember = $this->getTableRowReplaceSql('dds_member', $savedMember);
0 ignored issues
show
Bug introduced by
$savedMember of type array is incompatible with the type string expected by parameter $row of neon\daedalus\services\d...getTableRowReplaceSql(). ( Ignorable by Annotation )

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

273
			$upMember = $this->getTableRowReplaceSql('dds_member', /** @scrutinizer ignore-type */ $savedMember);
Loading history...
274 82
			$downMember = "DELETE FROM `dds_member` WHERE `class_type`='$classType' AND `member_ref`='$memberRef';";
275 82
			$mId = $this->storeMigration($upMember, $downMember);
276
277
			// and create the member column
278 82
			if (($error=$this->addClassMemberColumn($classType, $member->member_ref)) !== true) {
279
				$member->delete();
280
				$this->removeMigration($mId);
281
				throw new \RuntimeException("Couldn't create the member column. Error=".$error);
282
			}
283 82
			$this->clearClassMemberCache($classType);
284 82
			return $member->member_ref;
285
		}
286
	}
287
288
	/**
289
	 * @inheritdoc
290
	 */
291 82
	public function getMember($classType, $memberRef, $fields=[])
292
	{
293
		// !! keep member as an object so it runs all conversion code
294 82
		$query = DdsMember::find();
295 82
		if (count($fields)) {
296 2
			$selection = array_intersect($fields, [
297 2
				'class_type', 'member_ref', 'data_type_ref', 'label', 'description', 'definition', 'choices', 'link_class', 'deleted'
298
			]);
299
			// ensure only allowed fields are passed through
300 2
			$query = $query->select($selection);
301
		}
302 82
		$member = $query->where(['member_ref' => $memberRef, 'class_type' => $classType])->one();
303 82
		return $member->toArray();
304
	}
305
306
	/**
307
	 * @inheritdoc
308
	 */
309 6
	public function editMember($classType, $memberRef, $changes)
310
	{
311
		// check that only allowed updates are made
312 6
		$allowed = array_intersect_key($changes, array_flip(['label', 'description', 'definition', 'choices', 'link_class']));
313 6
		if (count($allowed)==0)
314
			return;
315
316
		// find the member and remove any illegitamate updates
317 6
		if (!$this->findMember($classType, $memberRef, $member))
318
			throw new \InvalidArgumentException("No member found");
319 6
		if (isset($allowed['choices'])) {
320 2
			$allowed['choices'] = empty($allowed['choices']) ? [] : $allowed['choices'];
321 2
			if (!(is_array($allowed['choices']) && $this->memberAllowedChoices($member->data_type_ref))) {
322
				unset($allowed['choices']);
323
			}
324
		}
325
326 6
		if (isset($allowed['link_class']) && !$this->memberAllowedLinks($member->data_type_ref))
327
			unset($allowed['link_class']);
328
329
		// finally check to see if there are any actual updates and if so save the provided updates
330 6
		$updates = $this->getMemberUpdateDifferences($allowed, $member->attributes);
331 6
		if (count($updates)) {
332 6
			$downSql = $this->getTableRowReplaceSql('dds_member', $member);
333 6
			$member->attributes = $updates;
334 6
			if (!$member->save())
335
				throw new \RuntimeException("Couldn't update the member: ".print_r ($member->errors, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($member->errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

335
				throw new \RuntimeException("Couldn't update the member: "./** @scrutinizer ignore-type */ print_r ($member->errors, true));
Loading history...
336 6
			$upSql = $this->getTableRowReplaceSql('dds_member', $member);
337 6
			$this->storeMigration($upSql, $downSql);
338 6
			$this->clearClassMemberCache($classType);
339
		}
340 6
	}
341
342
	/**
343
	 * @inheritdoc
344
	 */
345 26
	public function setMemberAsMapField($classType, $memberRef)
346
	{
347 26
		if (!$this->findMember($classType, $memberRef, $member))
348
			throw new \InvalidArgumentException("No member found");
349
350
		// find out which member had the map field set for migrations
351 26
		$oldMember = DdsMember::findOne(['class_type'=>$classType, 'map_field'=>1]);
352 26
		if ($oldMember && $oldMember->member_ref == $memberRef)
353
			return;
354 26
		$upSql = "UPDATE `dds_member` SET `map_field`=(IF (`member_ref`='$memberRef', 1, 0)) WHERE `class_type`='$classType';";
355 26
		$downSql = ($oldMember ? "UPDATE `dds_member` SET `map_field`=(IF (`member_ref`='{$oldMember->member_ref}', 1, 0)) WHERE `class_type`='$classType';" : null);
0 ignored issues
show
introduced by
$oldMember is of type yii\db\ActiveRecord, thus it always evaluated to true.
Loading history...
356 26
		neon()->db->createCommand($upSql)->execute();
357 26
		$this->storeMigration($upSql, $downSql);
358 26
		$this->clearClassMemberCache($classType);
359 26
	}
360
361
362
	/**
363
	 * @inheritdoc
364
	 */
365 2
	public function deleteMember($classType, $memberRef)
366
	{
367
		// delete a member if it isn't already deleted
368 2
		if ($this->findMember($classType, $memberRef, $member) && $member->deleted==0) {
369 2
			$upSql = "UPDATE `dds_member` SET `deleted`=1 WHERE `class_type`='$classType' AND `member_ref`='$memberRef';";
370 2
			$downSql = "UPDATE `dds_member` SET `deleted`=0 WHERE `class_type`='$classType' AND `member_ref`='$memberRef';";
371 2
			neon()->db->createCommand($upSql)->execute();
372 2
			$this->storeMigration($upSql, $downSql);
373 2
			$this->clearClassMemberCache($classType);
374
		}
375 2
	}
376
377
	/**
378
	 * @inheritdoc
379
	 */
380 2
	public function undeleteMember($classType, $memberRef)
381
	{
382
		// undelete a member if it is already deleted
383 2
		if ($this->findMember($classType, $memberRef, $member) && $member->deleted==1) {
384
			// create migrations
385 2
			$upSql = "UPDATE `dds_member` SET `deleted`=0 WHERE `class_type`='$classType' AND `member_ref`='$memberRef';";
386 2
			$downSql = "UPDATE `dds_member` SET `deleted`=1 WHERE `class_type`='$classType' AND `member_ref`='$memberRef';";
387 2
			neon()->db->createCommand($upSql)->execute();
388 2
			$this->storeMigration($upSql, $downSql);
389 2
			$this->clearClassMemberCache($classType);
390
		}
391 2
	}
392
393
	/**
394
	 * @inheritdoc
395
	 */
396 26
	public function destroyMember($classType, $memberRef)
397
	{
398 26
		if ($this->findMember($classType, $memberRef, $member)) {
399
			// try and drop the column first and then the member definition
400 26
			$this->dropClassMemberColumn($classType, $memberRef);
401 26
			$upSql = "DELETE FROM `dds_member` WHERE `class_type`='$classType' AND `member_ref`='$memberRef';";
402 26
			$downSql = $this->getTableRowReplaceSql('dds_member', $member);
403 26
			neon()->db->createCommand($upSql)->execute();
404 26
			$this->storeMigration($upSql, $downSql);
405 26
			$this->clearClassMemberCache($classType);
406
		}
407 26
	}
408
409
	/** ------------------------------------------------------ **/
410
	/** ---------- interface IDdsDataTypeManagement ---------- **/
411
	/** ------------------------------------------------------ **/
412
413
	/** ---------- Utility Methods ---------- **/
414
415
	/**
416
	 * @inheritdoc
417
	 */
418 2
	public function isDataTypeUnique($candidate)
419
	{
420 2
		$dt = $this->canonicaliseRef($candidate);
421 2
		$dataType = DdsDataType::find()->where(['data_type_ref'=>$dt])->one();
422 2
		return ($dataType == null);
423
	}
424
425
	/** ---------- Data Type Methods ---------- **/
426
427
	/**
428
	 * @inheritdoc
429
	 */
430 2
	public function listDataTypes($includeDeleted=false)
431
	{
432 2
		$query = DdsDataType::find();
433 2
		$select = ['data_type_ref', 'label', 'description', 'definition', 'storage_ref'];
434 2
		if ($includeDeleted) {
435 2
			$select[] = 'deleted';
436
		} else {
437 2
			$query->where(['deleted'=>0]);
438
		}
439 2
		return $query->select($select)->asArray()->all();
440
	}
441
442
	/**
443
	 * @inheritdoc
444
	 */
445 84
	public function addDataType(&$dataTypeRef, $label, $description, $definition, $storageRef)
446
	{
447 84
		$dataTypeRef = $this->canonicaliseRef($dataTypeRef);
448 84
		if ($this->findDataType($dataTypeRef))
449
			throw new \InvalidArgumentException("The dataType $dataTypeRef already exists");
450 84
		$dt = new DdsDataType();
451 84
		$dt->data_type_ref = $dataTypeRef;
452 84
		$dt->label = $label;
453 84
		$dt->description = $description;
454 84
		$dt->definition = $definition;
455 84
		$dt->storage_ref = $storageRef;
456 84
		if (!$dt->save())
457
			throw new \RuntimeException("Couldn't create the datatype $dataTypeRef: ".print_r($dt->errors, true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($dt->errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

457
			throw new \RuntimeException("Couldn't create the datatype $dataTypeRef: "./** @scrutinizer ignore-type */ print_r($dt->errors, true));
Loading history...
458
459
		// store the migration
460 84
		$this->findDataType($dataTypeRef, $dt);
461 84
		$upSql = $this->getTableRowReplaceSql('dds_data_type', $dt);
462 84
		$downSql = "DELETE FROM `dds_data_type` WHERE `data_type_ref`='$dataTypeRef';";
463 84
		$this->storeMigration($upSql, $downSql);
464
465 84
		return $dt->data_type_ref;
466
	}
467
468
	/**
469
	 * @inheritdoc
470
	 */
471 6
	public function getDataType($dataTypeRef)
472
	{
473 6
		return DdsDataType::find()->where(['data_type_ref'=>$dataTypeRef])->asArray()->one();
474
	}
475
476
	/**
477
	 * @inheritdoc
478
	 */
479 2
	public function editDataType($dataTypeRef, $changes)
480
	{
481 2
		$allowed = array_intersect_key($changes, array_flip(['label', 'description', 'definition']));
482 2
		if (count($allowed) == 0)
483
			return;
484 2
		if ($this->findDataType($dataTypeRef, $dataType)) {
485
			// make the updates if there is anything to change
486 2
			$updates = array_diff($allowed, $dataType->attributes);
487 2
			if (count($updates)) {
488 2
				$downSql = $this->getTableRowReplaceSql('dds_data_type', $dataType);
489 2
				$dataType->attributes = $updates;
490 2
				if (!$dataType->save())
491
					throw new \RuntimeException("Couldn't save the datatype: ".print_r($dataType->errors(),true));
0 ignored issues
show
Bug introduced by
Are you sure print_r($dataType->errors(), true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

491
					throw new \RuntimeException("Couldn't save the datatype: "./** @scrutinizer ignore-type */ print_r($dataType->errors(),true));
Loading history...
492 2
				$upSql = $this->getTableRowReplaceSql('dds_data_type', $dataType);
493 2
				$this->storeMigration($upSql, $downSql);
494
			}
495
		}
496 2
	}
497
498
	/**
499
	 * @inheritdoc
500
	 */
501 2
	public function deleteDataType($dataTypeRef)
502
	{
503
		// delete the datatype if not already deleted
504 2
		if ($this->findDataType($dataTypeRef, $dataType) && $dataType->deleted == 0) {
505 2
			$upSql = "UPDATE `dds_data_type` SET `deleted`=1 WHERE `data_type_ref`='$dataTypeRef';";
506 2
			$downSql = "UPDATE `dds_data_type` SET `deleted`=0 WHERE `data_type_ref`='$dataTypeRef';";
507 2
			neon()->db->createCommand($upSql)->execute();
508 2
			$this->storeMigration($upSql, $downSql);
509
		}
510 2
	}
511
512
	/**
513
	 * @inheritdoc
514
	 */
515 2
	public function undeleteDataType($dataTypeRef)
516
	{
517
		// undelete the datatype if not already undeleleted
518 2
		if ($this->findDataType($dataTypeRef, $dataType) && $dataType->deleted = 1) {
519 2
			$upSql = "UPDATE `dds_data_type` SET `deleted`=0 WHERE `data_type_ref`='$dataTypeRef';";
520 2
			$downSql = "UPDATE `dds_data_type` SET `deleted`=1 WHERE `data_type_ref`='$dataTypeRef';";
521 2
			neon()->db->createCommand($upSql)->execute();
522 2
			$this->storeMigration($upSql, $downSql);
523
		}
524 2
	}
525
526
	/**
527
	 * @inheritdoc
528
	 */
529 2
	public function destroyDataType($dataTypeRef)
530
	{
531
		// destroy the datatype if it exists
532 2
		if ($this->findDataType($dataTypeRef, $dataType)) {
533 2
			$upSql = "DELETE FROM `dds_data_type` WHERE `data_type_ref`='$dataTypeRef';";
534 2
			$downSql = $this->getTableRowReplaceSql('dds_data_type', $dataType);
535 2
			neon()->db->createCommand($upSql)->execute();
536 2
			$this->storeMigration($upSql, $downSql);
537
		}
538 2
	}
539
540
541
542
	/** ------------------------------------ **/
543
	/** ---------- Private Methods --------- **/
544
	/** ------------------------------------ **/
545
546
547
	/**
548
	 * Convert a dds_class entry into an insert statement for migrations
549
	 * @param string $classType
550
	 * @return null|string
551
	 */
552 84
	private function getClassTypeMigrationSql($classType)
553
	{
554 84
		$ddsClass = DdsClass::findOne(['class_type'=>$classType]);
555 84
		if ($ddsClass == null)
556
			return null;
557 84
		return $this->getTableRowReplaceSql('dds_class', $ddsClass);
0 ignored issues
show
Bug introduced by
$ddsClass of type yii\db\ActiveRecord is incompatible with the type string expected by parameter $row of neon\daedalus\services\d...getTableRowReplaceSql(). ( Ignorable by Annotation )

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

557
		return $this->getTableRowReplaceSql('dds_class', /** @scrutinizer ignore-type */ $ddsClass);
Loading history...
558
	}
559
560
	/**
561
	 * Check if a particular member type is allowed to store choices.
562
	 *
563
	 * @param string $dataTypeRef
564
	 * @return bool
565
	 */
566 82
	private function memberAllowedChoices($dataTypeRef)
567
	{
568
		// if additional datatypes are allowed then update appropriately
569 82
		$allowedDataTypes = ['choice', 'choice_multiple'];
570 82
		return in_array($dataTypeRef, $allowedDataTypes);
571
	}
572
573
	/**
574
	 * Check if a particular member type is allowed to store links in the links table
575
	 *
576
	 * @param string $dataTypeRef
577
	 * @return bool
578
	 */
579 82
	private function memberAllowedLinks($dataTypeRef)
580
	{
581
		// if additional datatypes can be links then update appropriately
582
		$allowedDataTypes = [
583 82
			'link_multi',
584
			'link_uni',
585
			'file_ref_multi'
586
		];
587 82
		return in_array($dataTypeRef, $allowedDataTypes);
588
	}
589
590
	/**
591
	 * Get the difference between a set of changes and the member fields
592
	 *
593
	 * @param array $changes  set of requested changes
594
	 * @param array $member  current member values
595
	 */
596 6
	protected function getMemberUpdateDifferences($changes, $member)
597
	{
598 6
		$a = $changes;
599 6
		$b = $member;
600 6
		$diffs = [];
601 6
		foreach ($a as $k=>$v) {
602 6
			if (array_key_exists($k, $b)) {
603 6
				if (is_array($v)) {
604 2
					$diff = $this->getMemberUpdateDifferences($v, $b[$k]);
605
					// we want all of the array if there were any differences
606 2
					if (count($diff))
607 2
						$diffs[$k] = $v;
608
				} else {
609 6
					if ((string)$v !== (string)$b[$k])
610 6
						$diffs[$k] = $v;
611
				}
612
			} else {
613 2
				$diffs[$k] = $v;
614
			}
615
		}
616 6
		return $diffs;
617
	}
618
619
620
	/**
621
	 * static cache array of class data to reduce database calls
622
	 * @var array
623
	 */
624
	private static $_classCache = [];
0 ignored issues
show
introduced by
The private property $_classCache is not used, and could be removed.
Loading history...
625
626 6
	private function _getClassesQuery($module=null, $includeDeleted=false)
627
	{
628 6
		$query = DdsClass::find();
629 6
		$select = ['class_type', 'label', 'description', 'module', 'count_total', 'count_deleted', 'change_log'];
630 6
		if ($includeDeleted) {
631 4
			$select[] = 'deleted';
632
		} else {
633 4
			$query->andWhere(['deleted' => 0]);
634
		}
635 6
		$query->select($select);
636 6
		if ($module != null)
637 6
			$query->andWhere(['or', ['module' => $module], ['module' => NULL]]);
638 6
		return $query;
639
	}
640
641
}
642