Passed
Push — developer ( 6b5868...bed0f9 )
by Radosław
22:42 queued 03:39
created

RecordFinder::findByEmailField()   B

Complexity

Conditions 11
Paths 27

Size

Total Lines 39
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 27
dl 0
loc 39
rs 7.3166
c 0
b 0
f 0
cc 11
nc 27
nop 3

How to fix   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
 * Mail record finder file.
4
 *
5
 * @package App
6
 *
7
 * @copyright YetiForce S.A.
8
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
9
 * @author    Mariusz Krzaczkowski <[email protected]>
10
 */
11
12
namespace App\Mail;
13
14
/**
15
 * Mail record finder class.
16
 */
17
class RecordFinder
18
{
19
	/**
20
	 * Emails cache.
21
	 *
22
	 * @var array
23
	 */
24
	private static $emailsCache = [];
25
	/**
26
	 * Domain cache.
27
	 *
28
	 * @var array
29
	 */
30
	private static $domainCache = [];
31
	/**
32
	 * Record number cache.
33
	 *
34
	 * @var array
35
	 */
36
	private static $recordNumberCache = [];
37
38
	/**
39
	 * Find email address.
40
	 *
41
	 * @param mixed $emails
42
	 * @param array $modulesFields
43
	 *
44
	 * @return array
45
	 */
46
	public static function findByEmail($emails, array $modulesFields): array
47
	{
48
		if (empty($emails)) {
49
			return [];
50
		}
51
		if (!\is_array($emails)) {
52
			$emails = explode(',', $emails);
53
		}
54
		$ids = [];
55
		foreach ($modulesFields as $module => $fieldsByType) {
56
			foreach ($fieldsByType as $uiType => $fields) {
57
				if (319 === $uiType) {
58
					$ids = array_replace_recursive($ids, static::findByDomainField($module, $fields, $emails));
59
				} else {
60
					$ids = array_replace_recursive($ids, static::findByEmailField($module, $fields, $emails));
61
				}
62
			}
63
		}
64
		return $ids;
65
	}
66
67
	/**
68
	 * Search crm ids by emails field and module name.
69
	 *
70
	 * @param string   $moduleName
71
	 * @param string[] $fields
72
	 * @param string[] $emails
73
	 *
74
	 * @return array
75
	 */
76
	public static function findByEmailField(string $moduleName, array $fields, array $emails): array
77
	{
78
		$activeFields = $conditions = $return = [];
79
		foreach ($emails as $i => $email) {
80
			if (isset(self::$emailsCache[$moduleName][$email])) {
81
				$return[$email] = self::$emailsCache[$moduleName][$email];
82
				unset($emails[$i]);
83
			}
84
		}
85
		$queryGenerator = new \App\QueryGenerator($moduleName);
86
		$queryGenerator->permissions = false;
87
		foreach ($fields as $field) {
88
			if ($fieldsModel = $queryGenerator->getModuleField($field)) {
89
				$activeFields[] = $field;
90
				$conditions[] = [$fieldsModel->getColumnName() => $emails];
91
			}
92
		}
93
		if (!$activeFields) {
94
			return [];
95
		}
96
		if ($emails) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $emails of type string[] 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...
97
			$queryGenerator->setFields(array_merge(['id'], $activeFields));
98
			$query = $queryGenerator->createQuery();
99
			$query->andWhere(array_merge(['or'], $conditions));
100
			$dataReader = $query->createCommand()->query();
101
			while ($row = $dataReader->read()) {
102
				foreach ($activeFields as $field) {
103
					$rowEmail = $row[$field];
104
					if (\in_array($rowEmail, $emails)) {
105
						self::$emailsCache[$moduleName][$rowEmail][] = $return[$rowEmail][] = $row['id'];
106
						unset($emails[array_search($rowEmail, $emails)]);
107
					}
108
				}
109
			}
110
			foreach ($emails as $i => $email) {
111
				self::$emailsCache[$moduleName][$email] = $return[$email] = [];
112
			}
113
		}
114
		return $return;
115
	}
116
117
	/**
118
	 * Search crm ids by domains field and module name.
119
	 *
120
	 * @param string   $moduleName
121
	 * @param string[] $fields
122
	 * @param string[] $emails
123
	 *
124
	 * @return array
125
	 */
126
	public static function findByDomainField(string $moduleName, array $fields, array $emails): array
127
	{
128
		$return = $activeFields = $domainsAndEmails = [];
129
		foreach ($emails as $email) {
130
			$domainsAndEmails[mb_strtolower(explode('@', $email)[1])][] = $email;
131
		}
132
		$domains = array_keys($domainsAndEmails);
133
		$queryGenerator = new \App\QueryGenerator($moduleName);
134
		$queryGenerator->permissions = false;
135
		foreach ($fields as $field) {
136
			if ($queryGenerator->getModuleField($field)) {
137
				$activeFields[] = $field;
138
				foreach ($domains as $domain) {
139
					$queryGenerator->addCondition($field, $domain, 'a', false);
140
				}
141
			}
142
		}
143
		if ($activeFields) {
144
			$queryGenerator->setFields(array_merge(['id'], $activeFields));
145
			$dataReader = $queryGenerator->createQuery()->createCommand()->query();
146
			while ($row = $dataReader->read()) {
147
				foreach ($activeFields as $field) {
148
					$rowDomains = $row[$field];
149
					$rowDomains = $rowDomains ? explode(',', trim($rowDomains, ',')) : [];
150
					if ($intersectRows = array_intersect($domains, $rowDomains)) {
151
						foreach ($intersectRows as $intersectRow) {
152
							if (isset($domainsAndEmails[$intersectRow])) {
153
								foreach ($domainsAndEmails[$intersectRow] as $email) {
154
									self::$domainCache[$moduleName][$email][] = $return[$email][] = $row['id'];
155
									unset($emails[array_search($email, $emails)]);
156
								}
157
							}
158
						}
159
					}
160
				}
161
			}
162
			foreach ($emails as $email) {
163
				self::$domainCache[$moduleName][$email] = $return[$email] = [];
164
			}
165
		}
166
		return $return;
167
	}
168
169
	/**
170
	 * Find email address.
171
	 *
172
	 * @param string $subject
173
	 * @param array  $modulesFields
174
	 *
175
	 * @return array
176
	 */
177
	public static function findBySubject($subject, array $modulesFields): array
178
	{
179
		$records = [];
180
		foreach ($modulesFields as $moduleName => $fields) {
181
			$numbers = self::getRecordNumberFromString($subject, $moduleName, true);
182
			if (!$numbers || !$fields) {
183
				continue;
184
			}
185
			$records = array_merge($records, \App\Utils::flatten(self::findByRecordNumber($numbers, $moduleName, \App\Utils::flatten($fields))));
186
		}
187
		return $records;
188
	}
189
190
	/**
191
	 * Gets the prefix from text.
192
	 *
193
	 * @param string $value
194
	 * @param string $moduleName
195
	 * @param bool   $multi
196
	 *
197
	 * @return bool|string|array
198
	 */
199
	public static function getRecordNumberFromString(string $value, string $moduleName, bool $multi = false)
200
	{
201
		$moduleData = \App\Fields\RecordNumber::getInstance($moduleName);
202
		$prefix = str_replace(['\{\{YYYY\}\}', '\{\{YY\}\}', '\{\{MM\}\}', '\{\{DD\}\}', '\{\{M\}\}', '\{\{D\}\}'], ['\d{4}', '\d{2}', '\d{2}', '\d{2}', '\d{1,2}', '\d{1,2}'], preg_quote($moduleData->get('prefix'), '/'));
203
		$postfix = str_replace(['\{\{YYYY\}\}', '\{\{YY\}\}', '\{\{MM\}\}', '\{\{DD\}\}', '\{\{M\}\}', '\{\{D\}\}'], ['\d{4}', '\d{2}', '\d{2}', '\d{2}', '\d{1,2}', '\d{1,2}'], preg_quote($moduleData->get('postfix'), '/'));
204
		$redex = preg_replace_callback('/\\\\{\\\\{picklist\\\\:([a-z0-9_]+)\\\\}\\\\}/i', function ($matches) {
205
			$picklistPrefix = array_column(\App\Fields\Picklist::getValues($matches[1]), 'prefix');
206
			if (!$picklistPrefix) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $picklistPrefix 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...
207
				return '';
208
			}
209
			return '((' . implode('|', $picklistPrefix) . ')*)';
210
		}, '/\[' . $prefix . '([0-9]*)' . $postfix . '\]/');
211
		if ($multi) {
212
			preg_match_all($redex, $value, $match);
213
			if (!empty($match[0])) {
214
				$return = [];
215
				foreach ($match[0] as $row) {
216
					$return[] = trim($row, '[,]');
217
				}
218
				return $return;
219
			}
220
		} else {
221
			preg_match($redex, $value, $match);
222
			if (!empty($match)) {
223
				return trim($match[0], '[,]');
224
			}
225
		}
226
		return false;
227
	}
228
229
	/**
230
	 * Find record by sequence number field.
231
	 *
232
	 * @param array  $numbers
233
	 * @param string $moduleName
234
	 * @param array  $fields
235
	 *
236
	 * @return array
237
	 */
238
	public static function findByRecordNumber(array $numbers, string $moduleName, array $fields): array
239
	{
240
		$return = [];
241
		foreach ($numbers as $i => $number) {
242
			if (isset(self::$recordNumberCache[$moduleName][$number])) {
243
				$return[$number] = self::$recordNumberCache[$moduleName][$number];
244
				unset($numbers[$i]);
245
			}
246
		}
247
		if ($numbers) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $numbers 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...
248
			$queryGenerator = new \App\QueryGenerator($moduleName);
249
			$queryGenerator->setFields(array_merge(['id'], $fields));
250
			$queryGenerator->permissions = false;
251
			foreach ($fields as $fieldName) {
252
				$queryGenerator->addCondition($fieldName, $numbers, 'e', false);
253
			}
254
			$queryGenerator->setOrder('id', 'DESC');
255
			$dataReader = $queryGenerator->createQuery()->createCommand()->query();
256
			while ($row = $dataReader->read()) {
257
				foreach ($fields as $fieldName) {
258
					$number = $row[$fieldName];
259
					self::$recordNumberCache[$moduleName][$number] = $return[$number][] = $row['id'];
260
				}
261
			}
262
		}
263
		return $return;
264
	}
265
266
	/**
267
	 * Find user email.
268
	 *
269
	 * @param array $emails
270
	 *
271
	 * @return string[]
272
	 */
273
	public static function findUserEmail(array $emails): array
274
	{
275
		foreach ($emails as $key => $email) {
276
			if (!\Users_Module_Model::checkMailExist($email)) {
277
				unset($emails[$key]);
278
			}
279
		}
280
		return $emails;
281
	}
282
}
283