<?php
namespace Cms\CoreBundle\Entity\OneRoster;
use Cms\CoreBundle\Entity\AbstractOneRosterEntity;
use Doctrine\ORM\Mapping as ORM;
use Reinder83\BinaryFlags\Bits;
/**
* @see https://www.imsglobal.org/oneroster-v11-final-specification#_Toc480452019
*
* Class OneRosterUser
* @package Cms\CoreBundle\Entity\OneRoster
*
* @ORM\Entity(
* repositoryClass = "Cms\CoreBundle\Doctrine\OneRoster\OneRosterUserRepository"
* )
*/
class OneRosterUser extends AbstractOneRosterEntity
{
const ONEROSTER_TYPE = 'user';
const DISCR = 'User';
const ROLES_MAPPING = [
// staff
self::ENUMS__ROLE_TYPE__ADMINISTRATOR => self::TYPES__STAFF,
self::ENUMS__ROLE_TYPE__AIDE => self::TYPES__STAFF,
self::ENUMS__ROLE_TYPE__PROCTOR => self::TYPES__STAFF,
self::ENUMS__ROLE_TYPE__TEACHER => self::TYPES__STAFF,
// custom
self::ENUMS__ROLE_TYPE__STAFF => self::TYPES__STAFF,
self::ENUMS__ROLE_TYPE__COMMUNITY => self::TYPES__COMMUNITY,
// family
self::ENUMS__ROLE_TYPE__GUARDIAN => self::TYPES__FAMILY,
self::ENUMS__ROLE_TYPE__PARENT => self::TYPES__FAMILY,
self::ENUMS__ROLE_TYPE__RELATIVE => self::TYPES__FAMILY,
// student
self::ENUMS__ROLE_TYPE__STUDENT => self::TYPES__STUDENT,
];
const TYPES_MAPPING = [
self::TYPES__STAFF => [
self::ENUMS__ROLE_TYPE__ADMINISTRATOR,
self::ENUMS__ROLE_TYPE__AIDE,
self::ENUMS__ROLE_TYPE__PROCTOR,
self::ENUMS__ROLE_TYPE__TEACHER,
// custom
self::ENUMS__ROLE_TYPE__STAFF,
],
self::TYPES__FAMILY => [
self::ENUMS__ROLE_TYPE__GUARDIAN,
self::ENUMS__ROLE_TYPE__PARENT,
self::ENUMS__ROLE_TYPE__RELATIVE,
],
self::TYPES__STUDENT => [
self::ENUMS__ROLE_TYPE__STUDENT,
],
self::TYPES__COMMUNITY => [
self::ENUMS__ROLE_TYPE__COMMUNITY,
],
];
const TYPES = [
'staff' => self::TYPES__STAFF,
'family' => self::TYPES__FAMILY,
'student' => self::TYPES__STUDENT,
'community' => self::TYPES__COMMUNITY,
];
const TYPES_LOOKUP = [
self::TYPES__STAFF => 'staff',
self::TYPES__FAMILY => 'family',
self::TYPES__STUDENT => 'student',
self::TYPES__COMMUNITY => 'community',
];
const TYPES__STAFF = Bits::BIT_1;
const TYPES__FAMILY = Bits::BIT_2;
const TYPES__STUDENT = Bits::BIT_3;
const TYPES__COMMUNITY = Bits::BIT_4;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = false,
* )
*/
protected ?string $username = null;
/**
* @var array|array[]
*
* @ORM\Column(
* type = "json",
* nullable = false,
* )
*/
protected array $userIds = [];
/**
* @var bool
*
* @ORM\Column(
* type = "boolean",
* nullable = false,
* options = {
* "default" = false,
* },
* )
*/
protected bool $enabledUser = false;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = false,
* )
*/
protected ?string $givenName = null;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = false,
* )
*/
protected ?string $familyName = null;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = true,
* )
*/
protected ?string $middleName = null;
/**
* @see https://www.imsglobal.org/oneroster-v11-final-specification#_Toc480452025
*
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = false,
* )
*/
protected ?string $role = null;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = true,
* )
*/
protected ?string $identifier = null;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = true,
* )
*/
protected ?string $email = null;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = true,
* )
*/
protected ?string $sms = null;
/**
* @var string|null
*
* @ORM\Column(
* type = "string",
* nullable = true,
* )
*/
protected ?string $phone = null;
/**
* @var array|array[]
*
* @ORM\Column(
* type = "json",
* nullable = false,
* )
*/
protected array $agents = [];
/**
* @var array|array[]
*
* @ORM\Column(
* type = "json",
* nullable = false,
* )
*/
protected array $orgs = [];
/**
* TODO: should this be nullable?
*
* @see https://ceds.ed.gov/CEDSElementDetails.aspx?TermId=7100
*
* @var array|string[]
*
* @ORM\Column(
* type = "json",
* nullable = false,
* )
*/
protected array $grades = [];
/**
* @return string|null
*/
public function getUsername(): ?string
{
return $this->username;
}
/**
* @param string $value
* @return $this
*/
public function setUsername(string $value): self
{
$this->username = $value;
return $this;
}
/**
* @return array|array[]
*/
public function getUserIds(): array
{
return $this->userIds;
}
/**
* @param array|array[] $value
* @return $this
*/
public function setUserIds(array $value): self
{
$this->userIds = $this->parseArray(
$value,
function (array $a, array $b) {
$result = strcmp($a['type'], $b['type']);
if ($result === 0) {
$result = strcmp($a['identifier'], $b['identifier']);
}
return $result;
}
);
return $this;
}
/**
* @return bool
*/
public function isEnabledUser(): bool
{
return $this->enabledUser;
}
/**
* @param bool $value
* @return $this
*/
public function setEnabledUser(bool $value): self
{
$this->enabledUser = $value;
return $this;
}
/**
* NOTE: this is NOT a OneRoster data point
* This is an internal helper method to easier determine if the record should be usable in the system or not.
* Usable records are both "active" (base OneRoster status) and set as and "enabled user".
*
* @return bool
*/
public function isUsable(): bool
{
return ($this->isStatusActive() && $this->isEnabledUser());
}
/**
* TODO: hijacked this to allow nulls, by one roster rules this is not allowed, but gg4l data seems to allow it...
*
* @return string|null
*/
public function getGivenName(): ?string
{
return $this->givenName;
}
/**
* TODO: hijacked this to allow nulls, by one roster rules this is not allowed, but gg4l data seems to allow it...
*
* @param string|null $value
* @return $this
*/
public function setGivenName(?string $value): self
{
$this->givenName = trim($value) ?: null;
return $this;
}
/**
* TODO: hijacked this to allow nulls, by one roster rules this is not allowed, but gg4l data seems to allow it...
*
* @return string|null
*/
public function getFamilyName(): ?string
{
return $this->familyName;
}
/**
* TODO: hijacked this to allow nulls, by one roster rules this is not allowed, but gg4l data seems to allow it...
*
* @param string|null $value
* @return $this
*/
public function setFamilyName(?string $value): self
{
$this->familyName = trim($value) ?: null;
return $this;
}
/**
* @return string|null
*/
public function getMiddleName(): ?string
{
return $this->middleName;
}
/**
* @param string|null $value
* @return $this
*/
public function setMiddleName(?string $value): self
{
$this->middleName = trim($value) ?: null;
return $this;
}
/**
* @return string|null
*/
public function getRole(): ?string
{
return $this->role;
}
/**
* @param string $value
* @return $this
*/
public function setRole(string $value): self
{
$this->role = $value;
return $this;
}
/**
* @return int|null
*/
public function getRoleType(): ?int
{
return ($this->getRole()) ? self::ROLES_MAPPING[$this->getRole()] : null;
}
/**
* @return string|null
*/
public function getRoleTypeName(): ?string
{
return ($this->getRoleType()) ? self::TYPES_LOOKUP[$this->getRoleType()] : null;
}
/**
* @param int $type
* @return bool
*/
public function isRoleType(int $type): bool
{
return ($this->getRoleType() === $type);
}
/**
* TODO: rename and fix code...
*
* @return bool
*/
public function isRoleStaff(): bool
{
return $this->isRoleType(self::TYPES__STAFF);
}
/**
* TODO: rename and fix code...
*
* @return bool
*/
public function isRoleStudent(): bool
{
return $this->isRoleType(self::TYPES__STUDENT);
}
/**
* TODO: rename and fix code...
*
* @return bool
*/
public function isRoleCommunity(): bool
{
return $this->isRoleType(self::TYPES__COMMUNITY);
}
/**
* TODO: rename and fix code...
*
* @return bool
*/
public function isRoleFamily(): bool
{
return $this->isRoleType(self::TYPES__FAMILY);
}
/**
* @return string|null
*/
public function getIdentifier(): ?string
{
return $this->identifier;
}
/**
* @param string|null $value
* @return $this
*/
public function setIdentifier(?string $value): self
{
$this->identifier = trim($value) ?: null;
return $this;
}
/**
* @param string $type
* @return array|string[]
*/
public function getContacts(string $type): array
{
$func = sprintf(
'get%sContacts',
ucfirst($type)
);
if ( ! method_exists($this, $func)) {
throw new \Exception();
}
return call_user_func([$this, $func]);
}
/**
* @return string|null
*/
public function getEmail(): ?string
{
return strtolower(trim($this->email)) ?: null;
}
/**
* @param string|null $value
* @return $this
*/
public function setEmail(?string $value): self
{
$this->email = strtolower(trim($value)) ?: null;
return $this;
}
/**
* @return array|string[]
*/
public function getEmailContacts(): array
{
$values = array_values(array_filter([
$this->getEmail(),
]));
sort($values);
return $values;
}
/**
* @return string|null
*/
public function getSms(): ?string
{
return trim($this->sms) ?: null;
}
/**
* @param string|null $value
* @return $this
*/
public function setSms(?string $value): self
{
$this->sms = trim($value) ?: null;
return $this;
}
/**
* @return array|string[]
*/
public function getSmsContacts(): array
{
$values = array_values(array_filter([
$this->getSms(),
]));
sort($values);
return $values;
}
/**
* @return string|null
*/
public function getPhone(): ?string
{
return trim($this->phone) ?: null;
}
/**
* @param string|null $value
* @return $this
*/
public function setPhone(?string $value): self
{
$this->phone = trim($value) ?: null;
return $this;
}
/**
* @return array|string[]
*/
public function getVoiceContacts(): array
{
$values = array_values(array_filter([
$this->getPhone(),
]));
sort($values);
return $values;
}
/**
* @return array|array[]
*/
public function getAgents(): array
{
return $this->agents;
}
/**
* @param array|array[] $value
* @return $this
*/
public function setAgents(array $value): self
{
$this->agents = $this->parseGuidRefs($value);
return $this;
}
/**
* @return array<string>
*/
public function getAgentsSourcedIds(): array
{
return array_values(array_filter(array_unique(array_map(
static function (array $agent) {
return $agent['sourcedId'];
},
$this->getAgents(),
))));
}
/**
* @return array|array[]
*/
public function getOrgs(): array
{
// TODO: is this hack needed?
if ($this->orgs && is_string($this->orgs[0])) {
return array_map(
static function (string $sourcedId) {
return [
'type' => 'org',
'sourcedId' => $sourcedId,
];
},
$this->orgs
);
}
return $this->orgs;
}
/**
* @return array<string>
*/
public function getOrgsSourcedIds(): array
{
return array_values(array_filter(array_unique(array_map(
static function (array $org) {
return $org['sourcedId'];
},
$this->getOrgs(),
))));
}
/**
* @param array|array[] $value
* @return $this
*/
public function setOrgs(array $value): self
{
$this->orgs = $this->parseGuidRefs($value);
return $this;
}
/**
* @return array|string[]
*/
public function getGrades(): array
{
return $this->grades;
}
/**
* @param array|string[] $value
* @return $this
*/
public function setGrades(array $value): OneRosterUser
{
$this->grades = $this->parseArray($value);
return $this;
}
}