Passed
Push — master ( f5da16...2e3bf1 )
by Jean-Christophe
12:28
created

CRUDHelper::search()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 22
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 3.0015

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 18
c 1
b 0
f 0
dl 0
loc 22
ccs 17
cts 18
cp 0.9444
rs 9.6666
cc 3
nc 2
nop 4
crap 3.0015
1
<?php
2
3
namespace Ubiquity\controllers\crud;
4
5
use Ubiquity\orm\OrmUtils;
6
use Ubiquity\utils\http\URequest;
7
use Ubiquity\orm\DAO;
8
use Ubiquity\orm\parser\Reflexion;
9
use Ubiquity\cache\database\DbCache;
10
use Ubiquity\db\SqlUtils;
11
use Ubiquity\db\utils\DbTypes;
12
13
/**
14
 * Ubiquity\controllers\crud$CRUDHelper
15
 * This class is part of Ubiquity
16
 *
17
 * @author jc
18
 * @version 1.0.4
19
 *
20
 */
21
class CRUDHelper {
22
23 7
	public static function getIdentifierFunction($model) {
24 7
		$pks = OrmUtils::getKeyMembers ( $model );
25
		return function ($index, $instance) use ($pks) {
26 7
			$values = [ ];
27 7
			foreach ( $pks as $pk ) {
28 7
				$getter = 'get' . \ucfirst ( $pk );
29 7
				if (\method_exists ( $instance, $getter )) {
30 7
					$values [] = $instance->{$getter} ();
31
				}
32
			}
33 7
			return \implode ( '_', $values );
34 7
		};
35
	}
36
37 1
	public static function search($model, $search, $fields, $initialCondition = '1=1') {
38 1
		$words = preg_split ( "@(\s*?(\(|\)|\|\||\&\&)\s*?)@", $search );
39 1
		$params = [ ];
40 1
		$count = \count ( $fields );
41 1
		$db = DAO::getDb ( $model );
42 1
		$like = $db->getSpecificSQL ( 'tostring' ) . ' LIKE ';
43 1
		SqlUtils::$quote = $db->quote;
44 1
		if ($words !== false) {
45 1
			$words = array_filter ( $words, 'strlen' );
46 1
			$condition = "(" . SqlUtils::getSearchWhere ( $like, $fields, '?', '', '' ) . ")";
47 1
			foreach ( $words as $word ) {
48 1
				$word = \trim ( $word );
49 1
				$params = [ ...$params,...(\array_fill ( 0, $count, "%{$word}%" )) ];
50
			}
51
52 1
			$condition = \str_replace ( '||', ' OR ', $condition );
53 1
			$condition = \str_replace ( '&&', ' AND ', $condition );
54 1
			$condition = '(' . $condition . ') AND ' . $initialCondition . '';
55
		} else {
56
			$condition = $initialCondition;
57
		}
58 1
		return DAO::getAll ( $model, $condition, false, $params );
59
	}
60
61 3
	public static function update($instance, $values, $setValues = true, $updateMany = true, $eventCallback = null) {
62 3
		$className = \get_class ( $instance );
63 3
		$fieldsInRelationForUpdate = OrmUtils::getFieldsInRelationsForUpdate_ ( $className );
64 3
		$manyToOneRelations = $fieldsInRelationForUpdate ['manyToOne'];
65 3
		$manyToManyRelations = $fieldsInRelationForUpdate ['manyToMany'];
66 3
		$oneToManyRelations = $fieldsInRelationForUpdate ['oneToMany'];
67
68 3
		$members = \array_keys ( $values );
69 3
		OrmUtils::setFieldToMemberNames ( $members, $fieldsInRelationForUpdate ['relations'] );
70 3
		$update = false;
71
72 3
		$fieldTypes = OrmUtils::getFieldTypes ( $className );
73 3
		foreach ( $fieldTypes as $property => $type ) {
74 3
			if (DbTypes::isBoolean($type)) {
75
				if (isset ( $values [$property] )) {
76
					$values [$property] = 1;
77
				} else {
78
					$values [$property] = 0;
79
				}
80
			}
81
		}
82 3
		if ($setValues) {
83 3
			URequest::setValuesToObject ( $instance, $values );
84
		}
85 3
		if ($manyToOneRelations) {
86
			self::updateManyToOne ( $manyToOneRelations, $members, $className, $instance, $values );
87
		}
88 3
		if (isset ( $instance )) {
89 3
			if (isset ( $eventCallback )) {
90 3
				$eventCallback ( $instance, $instance->_new );
91
			}
92 3
			if ($instance->_new) {
93 1
				$update = DAO::insert ( $instance );
94
			} else {
95 2
				$update = DAO::update ( $instance );
96 2
				if (DbCache::$active) {
97
					// TODO update dbCache
98
				}
99
			}
100 3
			if ($updateMany && $update && $manyToManyRelations) {
101
				self::updateManyToMany ( $manyToManyRelations, $members, $className, $instance, $values );
102
			}
103 3
			if ($updateMany && $update && $oneToManyRelations) {
104 3
				self::updateOneToMany ( $oneToManyRelations, $members, $className, $instance, $values );
105
			}
106
		}
107 3
		return $update;
108
	}
109
110
	private static function getInputValues($values,$index){
111
		$r=[];
112
		foreach ($values as $k=>$oValues){
113
			if($k!=='_status') {
114
				$r[$k] = $oValues[$index];
115
			}
116
		}
117
		return $r;
118
	}
119
120
	private static function getOneToManyKeys($keys,$values,$index,$defaultId){
121
		foreach ( $keys as $k){
122
			$nk=$values[$k][$index]??$defaultId;
123
			$r[$k]=$nk;
124
			if($nk==''){
125
				return false;
126
			}
127
		}
128
		return $r;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $r seems to be defined by a foreach iteration on line 121. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
129
	}
130
131 3
	protected static function updateOneToMany($oneToManyRelations,$members,$className,$instance,$values){
132 3
		$id=OrmUtils::getFirstKeyValue($instance);
133 3
		foreach ($oneToManyRelations as $name){
134 3
			$member=$name.'Ids';
135 3
			$len=\strlen($member);
136 3
			if(($values[$member]??'')==='updated'){
137
				foreach ($values as $k=>$v){
138
					if(\substr($k, 0, $len) === $member){
139
						$newK=\substr($k,$len+1);
140
						if($newK!=null) {
141
							$newValues[$newK] = $v;
142
						}
143
					}
144
				}
145
				$r=OrmUtils::getAnnotationInfoMember($className,'#oneToMany',$name);
146
				$fkClass=$r['className'];
147
				$keys=\array_keys(OrmUtils::getKeyFields($fkClass));
1 ignored issue
show
Bug introduced by
It seems like Ubiquity\orm\OrmUtils::getKeyFields($fkClass) can also be of type boolean; however, parameter $array of array_keys() does only seem to accept array, 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

147
				$keys=\array_keys(/** @scrutinizer ignore-type */ OrmUtils::getKeyFields($fkClass));
Loading history...
148
				foreach ($newValues['_status'] as $index=>$status){
149
					$kv=self::getOneToManyKeys($keys,$newValues,$index,$id);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $newValues does not seem to be defined for all execution paths leading up to this point.
Loading history...
150
					if($kv!==false) {
151
						switch ($status) {
152
							case 'deleted':
153
								DAO::deleteById($fkClass,$kv);
154
								break;
155
							case 'updated':
156
								$o = DAO::getById($fkClass, $kv);
157
								if ($o) {
158
									$oValues = self::getInputValues($newValues, $index);
159
									URequest::setValuesToObject($o, $oValues);
160
									DAO::update($o);
161
								}
162
								break;
163
							case 'added':
164
								$o=new $fkClass();
165
								$oValues = \array_merge($kv,self::getInputValues($newValues, $index));
166
								URequest::setValuesToObject($o, $oValues);
167
								DAO::insert($o);
168
								break;
169
						}
170
					}
171
				}
172
			}
173
		}
174 3
	}
175
176
	protected static function updateManyToOne($manyToOneRelations, $members, $className, $instance, $values) {
177
		foreach ( $manyToOneRelations as $member ) {
178
			if (\array_search ( $member, $members ) !== false) {
179
				$joinColumn = OrmUtils::getAnnotationInfoMember ( $className, '#joinColumn', $member );
180
				if ($joinColumn) {
181
					$fkClass = $joinColumn ['className'];
182
					$fkField = $joinColumn ['name'];
183
					if (isset ( $values [$fkField] )) {
184
						if ($values [$fkField] != null) {
185
							$fkObject = DAO::getById ( $fkClass, $values ["$fkField"] );
186
							Reflexion::setMemberValue ( $instance, $member, $fkObject );
187
						} elseif ($joinColumn ['nullable'] ?? false) {
188
							Reflexion::setMemberValue ( $instance, $member, null );
189
						}
190
					}
191
				}
192
			}
193
		}
194
	}
195
196
	protected static function updateManyToMany($manyToManyRelations, $members, $className, $instance, $values) {
197
		foreach ( $manyToManyRelations as $member ) {
198
			if (\array_search ( $member, $members ) !== false) {
199
				if (($annot = OrmUtils::getAnnotationInfoMember ( $className, '#manyToMany', $member )) !== false) {
200
					$newField = $member . 'Ids';
201
					$fkClass = $annot ['targetEntity'];
202
					$fkObjects = DAO::getAll ( $fkClass, self::getMultiWhere ( $values [$newField], $fkClass ) );
203
					if (Reflexion::setMemberValue ( $instance, $member, $fkObjects )) {
204
						DAO::insertOrUpdateManyToMany ( $instance, $member );
205
					}
206
				}
207
			}
208
		}
209
	}
210
211
	private static function getMultiWhere($ids, $class) {
212
		$pk = OrmUtils::getFirstKey ( $class );
213
		$ids = explode ( ',', $ids );
214
		$idCount = \count ( $ids );
215
		if ($idCount < 1)
216
			return '';
217
		$strs = [ ];
218
		for($i = 0; $i < $idCount; $i ++) {
219
			$strs [] = $pk . "='" . $ids [$i] . "'";
220
		}
221
		return \implode ( " OR ", $strs );
222
	}
223
224 3
	public static function getFkIntance($instance, $model, $member, $included = false) {
225 3
		$result = [ ];
226 3
		if (($annot = OrmUtils::getAnnotationInfoMember ( $model, '#oneToMany', $member )) !== false) {
227 3
			$objectFK = DAO::getOneToMany ( $instance, $member, $included );
228 3
			$fkClass = $annot ['className'];
229
		} elseif (($annot = OrmUtils::getAnnotationInfoMember ( $model, '#manyToMany', $member )) !== false) {
230
			$objectFK = DAO::getManyToMany ( $instance, $member );
231
			$fkClass = $annot ['targetEntity'];
232
		} else {
233
			$objectFK = Reflexion::getMemberValue ( $instance, $member );
234
			if ($objectFK!=null && ! is_object ( $objectFK )) {
235
				$objectFK = DAO::getManyToOne ( $instance, $member, $included );
236
			}
237
			if (isset ( $objectFK ))
238
				$fkClass = \get_class ( $objectFK );
239
		}
240 3
		if (isset ( $fkClass )) {
241 3
			$fkTable = OrmUtils::getTableName ( $fkClass );
242 3
			$result [$member] = compact ( 'objectFK', 'fkClass', 'fkTable' );
243
		}
244 3
		return $result;
245
	}
246
247 3
	public static function getFKIntances($instance, $model, $included = false) {
248 3
		$result = [ ];
249 3
		$relations = OrmUtils::getFieldsInRelations ( $model );
250 3
		foreach ( $relations as $member ) {
251 3
			$fkInstance = self::getFkIntance ( $instance, $model, $member, $included );
252 3
			if (\count ( $fkInstance ) > 0) {
253 3
				$result = \array_merge ( $result, $fkInstance );
254
			}
255
		}
256 3
		return $result;
257
	}
258
}
259
260