cache = new DbStatementCache($dbConn); } public function getFields(?array $fieldValueInfos = null): array { $hasFieldValueInfos = $fieldValueInfos !== null; if($hasFieldValueInfos && empty($fieldValueInfos)) return []; $query = 'SELECT field_id, field_order, field_key, field_title, field_regex FROM msz_profile_fields'; if($hasFieldValueInfos) $query .= sprintf(' WHERE field_id IN (%s)', DbTools::prepareListString($fieldValueInfos)); $query .= ' ORDER BY field_order ASC'; $stmt = $this->cache->get($query); $args = 0; if($hasFieldValueInfos) foreach($fieldValueInfos as $fieldValueInfo) { if(!($fieldValueInfo instanceof ProfileFieldValueInfo)) throw new InvalidArgumentException('All values in $fieldValueInfos must be of ProfileFieldValueInfo type.'); $stmt->addParameter(++$args, $fieldValueInfo->getFieldId()); } $stmt->execute(); $result = $stmt->getResult(); $fields = []; while($result->next()) $fields[] = new ProfileFieldInfo($result); return $fields; } public function getField(string $fieldId): ProfileFieldInfo { $stmt = $this->cache->get('SELECT field_id, field_order, field_key, field_title, field_regex FROM msz_profile_fields WHERE field_id = ?'); $stmt->addParameter(1, $fieldId); $stmt->execute(); $result = $stmt->getResult(); if(!$result->next()) throw new RuntimeException('No field found with the provided field id.'); return new ProfileFieldInfo($result); } public function getFieldFormats( ?array $fieldInfos = null, ?array $fieldValueInfos = null ): array { $hasFieldInfos = $fieldInfos !== null; $hasFieldValueInfos = $fieldValueInfos !== null; if($hasFieldInfos && empty($fieldInfos)) return []; if($hasFieldValueInfos && empty($fieldValueInfos)) return []; $args = 0; $query = 'SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats'; if($hasFieldInfos) { ++$args; $query .= sprintf(' WHERE field_id IN (%s)', DbTools::prepareListString($fieldInfos)); } if($hasFieldValueInfos) $query .= sprintf(' %s format_id IN (%s)', (++$args > 1 ? 'AND' : 'WHERE'), DbTools::prepareListString($fieldValueInfos) ); $stmt = $this->cache->get($query); $args = 0; if($hasFieldInfos) foreach($fieldInfos as $fieldInfo) { if(!($fieldInfo instanceof ProfileFieldInfo)) throw new InvalidArgumentException('All values in $fieldInfos must be of ProfileFieldInfo type.'); $stmt->addParameter(++$args, $fieldInfo->getId()); } if($hasFieldValueInfos) foreach($fieldValueInfos as $fieldValueInfo) { if(!($fieldValueInfo instanceof ProfileFieldValueInfo)) throw new InvalidArgumentException('All values in $fieldValueInfos must be of ProfileFieldValueInfo type.'); $stmt->addParameter(++$args, $fieldValueInfo->getFormatId()); } $stmt->execute(); $result = $stmt->getResult(); $formats = []; while($result->next()) $formats[] = new ProfileFieldFormatInfo($result); return $formats; } public function getFieldFormat(string $formatId): ProfileFieldFormatInfo { $stmt = $this->cache->get('SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats WHERE format_id = ?'); $stmt->addParameter(1, $formatId); $stmt->execute(); $result = $stmt->getResult(); if(!$result->next()) throw new RuntimeException('No format found with the provided format id.'); return new ProfileFieldFormatInfo($result); } public function selectFieldFormat( ProfileFieldInfo|string $fieldInfo, string $value ): ProfileFieldFormatInfo { if($fieldInfo instanceof ProfileFieldInfo) $fieldInfo = $fieldInfo->getId(); $stmt = $this->cache->get('SELECT format_id, field_id, format_regex, format_link, format_display FROM msz_profile_fields_formats WHERE field_id = ? AND (format_regex IS NULL OR ? REGEXP format_regex) ORDER BY format_regex IS NULL ASC'); $stmt->addParameter(1, $fieldInfo); $stmt->addParameter(2, $value); $stmt->execute(); $result = $stmt->getResult(); if(!$result->next()) throw new RuntimeException('Could not determine an appropriate format for this field (missing default formatting)'); return new ProfileFieldFormatInfo($result); } public function getFieldValues(UserInfo|string $userInfo): array { if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); // i don't really want to bother with the join for the ordering so i'll just do that somewhere in PHP for now // will probably add the ability for people to order them in whatever way they want, as well as visibility controls $stmt = $this->cache->get('SELECT field_id, user_id, format_id, field_value FROM msz_profile_fields_values WHERE user_id = ?'); $stmt->addParameter(1, $userInfo); $stmt->execute(); $result = $stmt->getResult(); $values = []; while($result->next()) $values[] = new ProfileFieldValueInfo($result); return $values; } public function getFieldValue( ProfileFieldInfo|string $fieldInfo, UserInfo|string $userInfo ): ProfileFieldValueInfo { if($fieldInfo instanceof ProfileFieldInfo) $fieldInfo = $fieldInfo->getId(); if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); $stmt = $this->cache->get('SELECT field_id, user_id, format_id, field_value FROM msz_profile_fields_values WHERE field_id = ? AND user_id = ?'); $stmt->addParameter(1, $fieldInfo); $stmt->addParameter(2, $userInfo); $stmt->execute(); $result = $stmt->getResult(); if(!$result->next()) throw new RuntimeException('No value for this field and user combination found.'); return new ProfileFieldValueInfo($result); } public function setFieldValues( UserInfo|string $userInfo, ProfileFieldInfo|string|array $fieldInfos, string|array $values ): void { if(empty($fieldInfos)) return; if(!is_array($fieldInfos)) { if(is_array($values)) throw new InvalidArgumentException('If $fieldInfos is not an array, $values may not be either'); $fieldInfos = [$fieldInfos]; $values = [$values]; } elseif(!is_array($values)) throw new InvalidArgumentException('If $fieldInfos is an array, $values must be as well.'); $fieldsCount = count($fieldInfos); if($fieldsCount !== count($values)) throw new InvalidArgumentException('$fieldsInfos and $values have the same amount of values and be in the same order.'); if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); $rows = []; foreach($fieldInfos as $key => $fieldInfo) { if(is_string($fieldInfo)) $fieldInfo = $this->getField($fieldInfo); elseif(!($fieldInfo instanceof ProfileFieldInfo)) throw new InvalidArgumentException('Entries of $fieldInfos must either be field IDs or instances of ProfileFieldInfo.'); $value = $fieldInfo->matchValue($values[$key]); if($value === false) throw new InvalidArgumentException('One of the values in $values is not correct formatted.'); $rows[] = [ $fieldInfo->getId(), $this->selectFieldFormat($fieldInfo, $value)->getId(), $value, ]; } $args = 0; $stmt = $this->cache->get( 'REPLACE INTO msz_profile_fields_values (field_id, user_id, format_id, field_value) VALUES ' . DbTools::prepareListString($rows, '(?, ?, ?, ?)') ); foreach($rows as $row) { $stmt->addParameter(++$args, $row[0]); $stmt->addParameter(++$args, $userInfo); $stmt->addParameter(++$args, $row[1]); $stmt->addParameter(++$args, $row[2]); } $stmt->execute(); } public function removeFieldValues( UserInfo|string $userInfo, ProfileFieldInfo|string|array $fieldInfos ): void { if(empty($fieldInfos)) return; if($userInfo instanceof UserInfo) $userInfo = $userInfo->getId(); if(!is_array($fieldInfos)) $fieldInfos = [$fieldInfos]; foreach($fieldInfos as $key => $value) { if($value instanceof ProfileFieldInfo) $fieldInfos[$key] = $value->getId(); elseif(is_string($value)) throw new InvalidArgumentException('$fieldInfos array may only contain string IDs or instances of ProfileFieldInfo'); } $args = 0; $stmt = $this->cache->get(sprintf( 'DELETE FROM msz_profile_fields_values WHERE user_id = ? AND field_id IN (%s)', DbTools::prepareListString($fieldInfos) )); $stmt->addParameter(++$args, $userInfo); foreach($fieldInfos as $value) $stmt->addParameter(++$args, $value); $stmt->execute(); } }