misuzu/src/Profile/ProfileFields.php

272 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(?iterable $fieldValueInfos = null): iterable {
$hasFieldValueInfos = $fieldValueInfos !== null;
if($hasFieldValueInfos) {
if(!is_array($fieldValueInfos))
$fieldValueInfos = iterator_to_array($fieldValueInfos);
if(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();
return $stmt->getResult()->getIterator(ProfileFieldInfo::fromResult(...));
}
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 ProfileFieldInfo::fromResult($result);
}
public function getFieldFormats(
?iterable $fieldInfos = null,
?iterable $fieldValueInfos = null
): iterable {
$hasFieldInfos = $fieldInfos !== null;
$hasFieldValueInfos = $fieldValueInfos !== null;
if($hasFieldInfos) {
if(!is_array($fieldInfos))
$fieldInfos = iterator_to_array($fieldInfos);
if(empty($fieldInfos))
return [];
}
if($hasFieldValueInfos) {
if(!is_array($fieldValueInfos))
$fieldValueInfos = iterator_to_array($fieldValueInfos);
if(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();
return $stmt->getResult()->getIterator(ProfileFieldFormatInfo::fromResult(...));
}
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 ProfileFieldFormatInfo::fromResult($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 ProfileFieldFormatInfo::fromResult($result);
}
public function getFieldValues(UserInfo|string $userInfo): iterable {
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();
return $stmt->getResult()->getIterator(ProfileFieldValueInfo::fromResult(...));
}
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 ProfileFieldValueInfo::fromResult($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();
}
}