misuzu/src/Profile/ProfileFields.php
flash 383e2ed0e0 Rewrote the user information class.
This one took multiple days and it pretty invasive into the core of Misuzu so issue might (will) arise, there's also some features that have gone temporarily missing in the mean time and some inefficiencies introduced that will be fixed again at a later time.
The old class isn't gone entirely because I still have to figure out what I'm gonna do about validation, but for the most part this knocks out one of the "layers of backwards compatibility", as I've been referring to it, and is moving us closer to a future where Flashii actually gets real updates.
If you run into anything that's broken and you're inhibited from reporting it through the forum, do it through chat or mail me at flashii-issues@flash.moe.
2023-08-02 22:12:47 +00:00

273 lines
10 KiB
PHP

<?php
namespace Misuzu\Profile;
use InvalidArgumentException;
use RuntimeException;
use Index\Data\DbStatementCache;
use Index\Data\DbTools;
use Index\Data\IDbConnection;
use Index\Data\IDbResult;
use Misuzu\Users\UserInfo;
class ProfileFields {
private DbStatementCache $cache;
public function __construct(IDbConnection $dbConn) {
$this->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();
}
}