[ENTITY][Actor][ActorLanguage][Language] Remove Actor::preferred_lang_id. Add ActorLanguage::order. Add Language::{short_display,long_display}. Instead of an actor having a single preffered language, the entries in ActorLanguage should be used, sorted by ActorLanguage::order

This commit is contained in:
Hugo Sales 2021-11-02 10:42:21 +00:00 committed by Diogo Peralta Cordeiro
parent 2bd05fbd47
commit 9444c34071
Signed by: diogo
GPG Key ID: 18D2D35001FBFAB0
3 changed files with 89 additions and 60 deletions

View File

@ -56,7 +56,7 @@ class Actor extends Entity
private int $id;
private string $nickname;
private ?string $fullname = null;
private int $roles = 4;
private int $roles = 4;
private ?string $homepage;
private ?string $bio;
private ?string $location;
@ -64,7 +64,6 @@ class Actor extends Entity
private ?float $lon;
private ?int $location_id;
private ?int $location_service;
private ?int $preferred_lang_id;
private DateTimeInterface $created;
private DateTimeInterface $modified;
@ -98,7 +97,7 @@ class Actor extends Entity
public function getFullname(): ?string
{
if (is_null($this->fullname)) {
if (\is_null($this->fullname)) {
return null;
}
return $this->fullname;
@ -192,17 +191,6 @@ class Actor extends Entity
return $this->location_service;
}
public function setPreferredLangId(?string $preferred_lang_id): self
{
$this->preferred_lang_id = $preferred_lang_id;
return $this;
}
public function getPreferredLangId(): ?int
{
return $this->preferred_lang_id;
}
public function setCreated(DateTimeInterface $created): self
{
$this->created = $created;
@ -324,17 +312,18 @@ class Actor extends Entity
{
// Will throw exception on invalid input.
$nickname = Nickname::normalize($nickname, check_already_used: false);
return Cache::get('relative-nickname-' . $nickname . '-' . $this->getId(),
fn () => DB::dql(<<<EOF
select a from actor a where
a.id in (select fa.followed from follow fa join actor aa with fa.followed = aa.id where fa.follower = :actor_id and aa.nickname = :nickname) or
a.id in (select fb.follower from follow fb join actor ab with fb.follower = ab.id where fb.followed = :actor_id and ab.nickname = :nickname) or
a.nickname = :nickname
EOF
,
['nickname' => $nickname, 'actor_id' => $this->getId()],
['limit' => 1]
)[0] ?? null
return Cache::get(
'relative-nickname-' . $nickname . '-' . $this->getId(),
fn () => DB::dql(
<<<'EOF'
select a from actor a where
a.id in (select fa.followed from follow fa join actor aa with fa.followed = aa.id where fa.follower = :actor_id and aa.nickname = :nickname) or
a.id in (select fb.follower from follow fb join actor ab with fb.follower = ab.id where fb.followed = :actor_id and ab.nickname = :nickname) or
a.nickname = :nickname
EOF,
['nickname' => $nickname, 'actor_id' => $this->getId()],
['limit' => 1],
)[0] ?? null,
);
}
@ -367,16 +356,18 @@ EOF
* Get the most appropraite language for $this to use when
* referring to $context (a reply or a group, for instance)
*
* @return string the Language as a string (save space in cache)
* @return string[] the Languages as string (save space in cache)
*/
public function getPreferredLanguageChoice(?self $context = null): string
public function getPreferredLanguageChoices(?self $context = null): array
{
$lang_id = $context?->getPreferredLangId() ?? $this->getPreferredLangId();
if (\is_null($lang_id)) {
return Common::config('site', 'language');
}
$key = 'actor-lang-' . $this->getId() . (!\is_null($context) ? '-' . $context->getId() : '');
return Cache::get($key, fn () => (string) DB::findOneBy('language', ['id' => $lang_id]));
$id = $context?->getId() ?? $this->getId();
return Cache::get(
'actor-' . $this->getId() . '-langs' . (!\is_null($context) ? '-' . $context->getId() : ''),
fn () => DB::dql(
'select l from actor_language al join language l with al.language_id = l.id where al.actor_id = :id order by al.order ASC',
['id' => $id],
) ?: [DB::findOneBy('language', ['locale' => Common::config('site', 'language')])],
);
}
public static function schemaDef(): array
@ -385,20 +376,19 @@ EOF
'name' => 'actor',
'description' => 'local and remote users, groups and bots are actors, for instance',
'fields' => [
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
'nickname' => ['type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username'],
'fullname' => ['type' => 'text', 'description' => 'display name'],
'roles' => ['type' => 'int', 'not null' => true, 'default' => UserRoles::USER, 'description' => 'Bitmap of permissions this actor has'],
'homepage' => ['type' => 'text', 'description' => 'identifying URL'],
'bio' => ['type' => 'text', 'description' => 'descriptive biography'],
'location' => ['type' => 'text', 'description' => 'physical location'],
'lat' => ['type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'],
'lon' => ['type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'],
'location_id' => ['type' => 'int', 'description' => 'location id if possible'],
'location_service' => ['type' => 'int', 'description' => 'service used to obtain location id'],
'preferred_lang_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Language.id', 'multiplicity' => 'one to many', 'description' => 'preferred language'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
'nickname' => ['type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'nickname or username'],
'fullname' => ['type' => 'text', 'description' => 'display name'],
'roles' => ['type' => 'int', 'not null' => true, 'default' => UserRoles::USER, 'description' => 'Bitmap of permissions this actor has'],
'homepage' => ['type' => 'text', 'description' => 'identifying URL'],
'bio' => ['type' => 'text', 'description' => 'descriptive biography'],
'location' => ['type' => 'text', 'description' => 'physical location'],
'lat' => ['type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'latitude'],
'lon' => ['type' => 'numeric', 'precision' => 10, 'scale' => 7, 'description' => 'longitude'],
'location_id' => ['type' => 'int', 'description' => 'location id if possible'],
'location_service' => ['type' => 'int', 'description' => 'service used to obtain location id'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
],
'primary key' => ['id'],
'indexes' => [

View File

@ -42,6 +42,7 @@ class ActorLanguage extends Entity
// @codeCoverageIgnoreStart
private int $actor_id;
private int $language_id;
private int $order;
public function setActorId(int $actor_id): self
{
@ -64,6 +65,17 @@ class ActorLanguage extends Entity
{
return $this->language_id;
}
public function getOrder(): int
{
return $this->order;
}
public function setOrder(int $order): self
{
$this->order = $order;
return $this;
}
// @codeCoverageIgnoreEnd
// }}} Autocode
@ -73,8 +85,9 @@ class ActorLanguage extends Entity
'name' => 'actor_language',
'description' => 'join table where one actor can have many languages',
'fields' => [
'actor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'the actor this language entry refers to'],
'language_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Language.id', 'multiplicity' => 'many to many', 'not null' => true, 'description' => 'the language this entry refers to'],
'actor_id' => ['type' => 'int', 'not null' => true, 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to many', 'not null' => true, 'description' => 'the actor this language entry refers to'],
'language_id' => ['type' => 'int', 'not null' => true, 'foreign key' => true, 'target' => 'Language.id', 'multiplicity' => 'many to many', 'not null' => true, 'description' => 'the language this entry refers to'],
'order' => ['type' => 'int', 'not null' => true, 'description' => 'the order in which a user\'s language options should be displayed'],
],
'primary key' => ['actor_id', 'language_id'],
'indexes' => [

View File

@ -41,7 +41,9 @@ class Language extends Entity
// {{{ Autocode
// @codeCoverageIgnoreStart
private int $id;
private string $language;
private string $locale;
private string $long_display;
private string $short_display;
private DateTimeInterface $created;
public function setId(int $id): self
@ -55,15 +57,37 @@ class Language extends Entity
return $this->id;
}
public function setLanguage(string $language): self
public function setLocale(string $locale): self
{
$this->language = $language;
$this->locale = $locale;
return $this;
}
public function getLanguage(): string
public function getLocale(): string
{
return $this->language;
return $this->locale;
}
public function setLongDisplay(string $long_display): self
{
$this->long_display = $long_display;
return $this;
}
public function getLongDisplay(): string
{
return $this->long_display;
}
public function setShortDisplay(string $short_display): self
{
$this->short_display = $short_display;
return $this;
}
public function getShortDisplay(): string
{
return $this->short_display;
}
public function setCreated(DateTimeInterface $created): self
@ -81,7 +105,7 @@ class Language extends Entity
public function __toString()
{
return $this->getLanguage();
return $this->getLongDisplay();
}
public static function schemaDef(): array
@ -90,16 +114,18 @@ class Language extends Entity
'name' => 'language',
'description' => 'all known languages',
'fields' => [
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
'language' => ['type' => 'char', 'length' => 64, 'description' => 'The locale identifier for the language of a note. 2-leter-iso-language-code_4-leter-script-code_2-leter-iso-country-code, but kept longer in case we get a different format'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
'locale' => ['type' => 'char', 'length' => 64, 'description' => 'The locale identifier for the language of a note. 2-leter-iso-language-code_4-leter-script-code_2-leter-iso-country-code, but kept longer in case we get a different format'],
'long_display' => ['type' => 'varchar', 'length' => 64, 'description' => 'The long display string for the language, in english (translated later)'],
'short_display' => ['type' => 'varchar', 'length' => 12, 'description' => 'The short display string for the language (used for the first option)'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
],
'primary key' => ['id'],
'unique keys' => [
'language_language_uniq' => ['language'],
'language_locale_uniq' => ['locale'],
],
'indexes' => [
'language_idx' => ['language'],
'locale_idx' => ['locale'],
],
];
}