table = 'field'; $this->pkey = 'id'; } public function getMatchingElements(array $settings = []): array { $query = 'SELECT * FROM #__acym_field'; $queryCount = 'SELECT COUNT(*) FROM #__acym_field'; $where = []; if (!empty($settings['types'])) { foreach ($settings['types'] as $i => $oneType) { $settings['types'][$i] = acym_escapeDB($oneType); } $where[] = ' type IN ('.implode(',', $settings['types']).')'; } if (!empty($where)) { $query .= ' WHERE '.implode(' AND ', $where); $queryCount .= ' WHERE '.implode(' AND ', $where); } $query .= ' ORDER BY `ordering` ASC'; return [ 'elements' => acym_loadObjectList($query, 'id'), 'total' => acym_loadResult($queryCount), ]; } public function getFieldsByID(array $ids): array { if (empty($ids)) { return []; } acym_arrayToInteger($ids); return acym_loadObjectList('SELECT * FROM #__acym_field WHERE `id` IN('.implode(',', $ids).') ORDER BY `ordering` ASC'); } public function getFieldsByNameKey(array $nameKeys): array { if (empty($nameKeys)) { return []; } $nameKeys = array_map('acym_escapeDB', $nameKeys); return acym_loadObjectList('SELECT * FROM #__acym_field WHERE `namekey` IN('.implode(',', $nameKeys).') ORDER BY `ordering` ASC', 'id'); } public function getFieldsByType(array $types): array { if (empty($types)) { return []; } $types = array_map('acym_escapeDB', $types); $query = 'SELECT * FROM #__acym_field WHERE `type` IN('.implode(',', $types).') ORDER BY `ordering` ASC'; return acym_loadObjectList($query); } public function getOrdering(): int { return (int)acym_loadResult('SELECT COUNT(*) FROM #__acym_field'); } public function getAllFieldsForUser(): array { return acym_loadObjectList('SELECT * FROM #__acym_field WHERE id NOT IN (1, 2) ORDER BY `ordering` ASC', 'id'); } public function getAllFieldsForModuleFront(): array { return acym_loadObjectList( 'SELECT * FROM #__acym_field WHERE id != 2 AND active = 1 ORDER BY `ordering` ASC', 'id' ); } public function getFieldsValueByUserId(int $userId): array { return acym_loadObjectList('SELECT * FROM #__acym_user_has_field WHERE user_id = '.intval($userId), 'field_id'); } public function getFieldsValueByFieldId(int $fieldId): array { return acym_loadObjectList('SELECT * FROM #__acym_user_has_field WHERE field_id = '.intval($fieldId)); } public function generateNamekey(string $name, string $namekey = ''): string { $fieldsNamekey = acym_loadResultArray('SELECT namekey FROM #__acym_field'); $columnsUser = acym_getColumns('user'); $namekeyForbidden = array_merge($fieldsNamekey, $columnsUser); $namekey = empty($namekey) ? substr(preg_replace('#[^a-z0-9_]#i', '', strtolower($name)), 0, 50) : $namekey; $baseNamekey = $namekey; $baseCount = count($namekeyForbidden); while (in_array($namekey, $namekeyForbidden)) { $namekey = $baseNamekey.'_'.$baseCount; $baseCount++; } return $namekey; } public function getValueFromDB(object $fieldDB): array { $query = 'SELECT '.acym_secureDBColumn($fieldDB->value).' AS value, '.acym_secureDBColumn($fieldDB->title).' AS title FROM `'.acym_secureDBColumn($fieldDB->database).'`.`'.acym_secureDBColumn($fieldDB->table).'`'; if (isset($fieldDB->where_value) && strlen($fieldDB->where_value) > 0) { $allowedSigns = ['=', '!=', '>', '<', '>=', '<=', 'BEGINS', 'END', 'CONTAINS', 'NOTCONTAINS', 'LIKE', 'NOT LIKE', 'REGEXP', 'NOT REGEXP', 'IS NULL', 'IS NOT NULL']; $whereSign = in_array($fieldDB->where_sign ?? '', $allowedSigns, true) ? $fieldDB->where_sign : '='; $query .= ' WHERE `'.acym_secureDBColumn($fieldDB->where).'` '.$whereSign.' '.acym_escapeDB($fieldDB->where_value); } if (!empty($fieldDB->order_by)) $query .= ' ORDER BY '.acym_secureDBColumn($fieldDB->order_by).' '.acym_secureDBColumn($fieldDB->sort_order); return acym_loadObjectList($query); } public function store(int $userID, array $fields, bool $ajax = false): void { $customField = acym_getVar('array', 'customField', [], 'FILES'); if (!empty($customField)) { $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS; $uploadPath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$userID.DS); if (!file_exists($uploadPath)) { acym_createDir($uploadPath); } $allowedExtensions = explode(',', $this->config->get('allowed_files')); foreach ($customField['tmp_name'] as $key => $value) { if (is_array($value) && isset($value[0])) $value = $value[0]; if (empty($value)) continue; // Get the uploaded file name $fileName = $customField['name'][$key]; while (is_array($fileName) && isset($fileName[0])) { $fileName = $fileName[0]; } if (!preg_match('#\.('.implode('|', $allowedExtensions).')$#Ui', $fileName)) { $ext = substr($fileName, strrpos($fileName, '.') + 1); if ($ajax) { $this->errors[] = acym_translationSprintf( 'ACYM_ACCEPTED_TYPE', esc_html($ext), implode(', ', $allowedExtensions) ); } else { acym_enqueueMessage( acym_translationSprintf( 'ACYM_ACCEPTED_TYPE', esc_html($ext), implode(', ', $allowedExtensions) ), 'error', 5000 ); } continue; } if (!acym_uploadFile($value, $uploadPath.$fileName)) { if ($ajax) { $this->errors[] = acym_translation('ACYM_ERROR_SAVING'); } else { acym_enqueueMessage(acym_translation('ACYM_ERROR_SAVING'), 'error'); } continue; } $fields[$key] = $customField['name'][$key]; } } if (empty($fields)) return; foreach ($fields as $id => $value) { $field = $this->getOneById($id); if (empty($field)) { acym_enqueueMessage(acym_translationSprintf('ACYM_WRONG_FIELD_ID', $id), 'error'); continue; } $fieldOptions = @json_decode(empty($field->option) ? '{}' : $field->option); if (is_array($value)) { if (in_array($field->type, ['multiple_dropdown', 'radio', 'phone'])) { if ($field->type === 'phone' && !empty($fieldOptions->max_characters) && !empty($value['phone'])) { $value['phone'] = substr($value['phone'], 0, $fieldOptions->max_characters); } $value = implode(',', $value); if ($value === ',') $value = ''; } elseif ($field->type == 'checkbox') { $value = implode(',', array_keys($value)); } elseif ($field->type == 'date') { $formatToDisplay = explode('%', $fieldOptions->format); unset($formatToDisplay[0]); $year = '0000'; $month = '00'; $day = '00'; $i = 0; foreach ($formatToDisplay as $one) { if ($one === 'd') { $day = $value[$i]; } if ($one === 'm') { $month = $value[$i]; } if ($one === 'y') { $year = $value[$i]; } $i++; } $value = $year.'-'.$month.'-'.$day; } else { $value = json_encode($value); } } if (in_array($field->type, ['text', 'textarea']) && !empty($fieldOptions->max_characters)) { $value = substr($value, 0, $fieldOptions->max_characters); } // If deleting a file field, also delete the physical file if ($field->type === 'file' && strlen($value) === 0) { $oldValue = acym_loadResult( 'SELECT `value` FROM #__acym_user_has_field WHERE `user_id` = '.intval($userID).' AND `field_id` = '.intval($id) ); if (!empty($oldValue)) { $fileName = @json_decode($oldValue, true); if (is_array($fileName)) $fileName = $fileName[0]; if (empty($fileName)) $fileName = $oldValue; $uploadFolder = trim(acym_cleanPath(html_entity_decode(acym_getFilesFolder(true))), DS.' ').DS; // Try new path (with user folder) first, then legacy path (without user folder) $filePath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$userID.DS.$fileName); if (!file_exists($filePath)) { $filePath = acym_cleanPath(ACYM_ROOT.$uploadFolder.'userfiles'.DS.$fileName); } acym_deleteFile($filePath); } } // The user removed a value, don't add an empty line and remove any previous value from the bd if (strlen($value) === 0) { $query = 'DELETE FROM `#__acym_user_has_field` WHERE `user_id` = '.intval($userID).' AND `field_id` = '.intval($id); } else { $query = 'INSERT INTO #__acym_user_has_field (`user_id`, `field_id`, `value`) VALUES ('.intval($userID).', '.intval($id).', '.acym_escapeDB($value).')'; $query .= ' ON DUPLICATE KEY UPDATE `value`= VALUES(`value`)'; } acym_query($query); } } public function getAllFieldsByUserIds(array $userIds): array { acym_arrayToInteger($userIds); if (empty($userIds)) return []; $query = 'SELECT user_field.user_id, user_field.value, field.name FROM #__acym_user_has_field AS user_field JOIN #__acym_field AS field ON user_field.field_id = field.id WHERE user_field.user_id IN ('.implode(',', $userIds).')'; return acym_loadObjectList($query); } public function getAllFieldsListingByUserIds(array $userIds, array $fieldIds, string $listing = ''): array { acym_arrayToInteger($userIds); if (empty($userIds)) return []; acym_arrayToInteger($fieldIds); if (empty($fieldIds)) return []; $query = 'SELECT field.type AS `type`, field.value AS `value`, field.name AS field_name, user_field.user_id AS user_id, user_field.field_id AS field_id, user_field.value AS field_value, field.active, field.option FROM #__acym_user_has_field AS user_field JOIN #__acym_field AS field ON user_field.field_id = field.id'; $conditions = []; if (!empty($listing)) { $conditions[] = $listing; } $conditions[] = 'user_field.user_id IN ('.implode(',', $userIds).')'; $conditions[] = 'user_field.field_id IN ('.implode(',', $fieldIds).')'; if (!empty($conditions)) { $query .= ' WHERE ('.implode(') AND (', $conditions).')'; } $fieldValues = []; $values = acym_loadObjectList($query); $fieldsTypeWithInField = ['radio', 'checkbox', 'single_dropdown', 'multiple_dropdown']; foreach ($values as $one) { if (intval($one->active) === 0) { continue; } $key = $one->field_id.'-'.$one->user_id; if (!in_array($one->type, $fieldsTypeWithInField)) { if ($one->type === 'phone') { if (empty($one->field_value)) { $fieldValues[$key] = ''; } else { if (substr($one->field_value, 0, 1) === ',') { $fieldValues[$key] = str_replace(',', '', $one->field_value); } else { $fieldValues[$key] = '+'.str_replace(',', ' ', $one->field_value); } } } elseif ($one->type === 'date') { if (empty($one->field_value)) { $fieldValues[$key] = ''; } else { $one->option = json_decode($one->option); $fieldValues[$key] = acym_displayDateFormat($one->option->format, '', $one->field_value, [], false); } } else { $decoded = json_decode($one->field_value); $fieldValues[$key] = is_array($decoded) ? implode(', ', $decoded) : $one->field_value; } } else { $defaultValues = json_decode($one->value, true); $defaultValues = array_filter($defaultValues, function ($fieldOption) { return !empty($fieldOption['value']) || !empty($fieldOption['title']); }); if (empty($defaultValues)) { // Options from database if (!empty($one->field_value)) { $fieldOptions = json_decode($one->option, true); if (!empty($fieldOptions['fieldDB'])) { $dbOptions = json_decode($fieldOptions['fieldDB'], true); if (!empty($dbOptions['database']) && !empty($dbOptions['table']) && !empty($dbOptions['value']) && !empty($dbOptions['title'])) { $query = 'SELECT '.acym_secureDBColumn($dbOptions['title']).' FROM '.acym_secureDBColumn($dbOptions['database']).'.'.acym_secureDBColumn($dbOptions['table']).' WHERE '.acym_secureDBColumn($dbOptions['value']).' = '.acym_escapeDB($one->field_value); $fieldValues[$key][] = acym_loadResult($query); } } } } else { // Classic options foreach ($defaultValues as $oneValue) { if (!in_array($oneValue['value'], explode(',', $one->field_value))) continue; $fieldValues[$key][] = $oneValue['title']; } } if (!empty($fieldValues[$key])) { $fieldValues[$key] = implode(', ', $fieldValues[$key]); } } } return $fieldValues; } public function getAllFieldsBackendListing(): array { $whereLanguage = '(backend_listing = 1 OR `type` = "language")'; $query = 'SELECT id, name FROM #__acym_field WHERE '.$whereLanguage.' AND active = 1 AND id NOT IN (1, 2) ORDER BY ordering'; $return = [ 'names' => [], 'ids' => [], ]; foreach (acym_loadObjectList($query) as $one) { $return['names'][] = $one->name; $return['ids'][] = $one->id; } return $return; } public function getAllFieldsFrontendListing(): array { $fields = acym_loadObjectList('SELECT id, name FROM #__acym_field WHERE frontend_listing = 1 AND active = 1 AND id NOT IN (1, 2)'); $return = [ 'names' => [], 'ids' => [], ]; foreach ($fields as $oneField) { $return['names'][] = $oneField->name; $return['ids'][] = $oneField->id; } return $return; } public function delete(array $elements): int { if (empty($elements)) return 0; acym_arrayToInteger($elements); acym_trigger('specialActionOnDelete', ['field', $elements]); acym_query('DELETE FROM #__acym_user_has_field WHERE field_id IN ('.implode(',', $elements).')'); return parent::delete($elements); } /** * @param mixed $defaultValue */ public function displayField( object $field, $defaultValue, array $valuesArray, bool $displayOutside = true, bool $displayFront = false, ?object $user = null, bool $showField = true ): void { if (intval($field->active) === 0 && intval($field->core) !== 1) { return; } $extraErrors = $this->config->get('extra_errors', '0'); $isCoreField = $field->core == 1; if (!$isCoreField && !acym_level(ACYM_ENTERPRISE)) { return; } if (!$showField) { if (!acym_isAdmin()) { return; } if (acym_isAdmin() && acym_level(ACYM_ENTERPRISE) && !$isCoreField) { return; } } $data = []; $cmsUser = false; if ($displayFront && !empty($user->id)) { $cmsUser = !empty($user->cms_id); if ($field->id == 1) { $defaultValue = $user->name; } elseif ($field->id == 2) { $defaultValue = $user->email; } else { $allValues = []; $defaultUserValue = $this->getFieldsValueByUserId($user->id); if (!empty($defaultUserValue)) { foreach ($defaultUserValue as $one) { $allValues[$one->field_id] = $one->value; } } if (isset($allValues[$field->id])) { $defaultValue = is_null(json_decode($allValues[$field->id])) ? $allValues[$field->id] : json_decode($allValues[$field->id]); } } } if (in_array($field->type, ['radio', 'checkbox'])) { $valuesArrayTmp = []; foreach ($valuesArray as $oneValue) { if (!is_object($oneValue)) { $valuesArrayTmp = $valuesArray; break; } if (!empty($oneValue->disable)) continue; $valuesArrayTmp[$oneValue->value] = $oneValue->text; } $valuesArray = $valuesArrayTmp; } // Translate text of the options if (is_array($valuesArray)) { foreach ($valuesArray as $key => $oneValue) { if (is_object($oneValue) && !empty($valuesArray[$key]->text)) { $valuesArray[$key]->text = acym_translation($valuesArray[$key]->text); } elseif (is_string($oneValue)) { $valuesArray[$key] = acym_translation($valuesArray[$key]); } } } if (acym_isMultilingual() && $displayFront && !empty($field->translation)) { $field->translation = json_decode($field->translation, true); if (!empty($field->translation[acym_getLanguageTag()]) && !empty($field->translation[acym_getLanguageTag()]['name'])) { $field->name = $field->translation[acym_getLanguageTag()]['name']; } } $field->name = acym_translation($field->name); if (!empty((array)$field->option) && isset($field->option->authorized_content)) { if (empty($field->option->error_message_invalid)) { $field->option->authorized_content->message = acym_translationSprintf('ACYM_INCORRECT_FIELD_VALUE', $field->name); } else { $field->option->authorized_content->message = $field->option->error_message_invalid; } $data['authorizedContent'] = json_encode($field->option->authorized_content); } $attributesSelectField = []; if (!empty($field->option->max_characters)) { $data['maxCharacters'] = $field->option->max_characters; } if (!empty($field->option->size)) { $attributesSelectField['style'] = 'width:'.$field->option->size.'px'; $data['style'] = 'width:'.$field->option->size.'px'; } if (!$displayOutside) { $data['placeholder'] = $field->name; } $name = 'customField['.intval($field->id).']'; if ($field->type === 'text') { $data['value'] = empty($defaultValue) ? '' : ( is_scalar($defaultValue) ? $defaultValue : json_encode($defaultValue) ); } if ( $displayOutside && ( in_array($field->id, [1, 2]) || in_array($field->type, ['text', 'textarea', 'single_dropdown', 'multiple_dropdown', 'custom_text', 'file', 'language']) ) ) { echo '