mirror of
https://github.com/standardebooks/web.git
synced 2025-07-05 14:20:29 -04:00
258 lines
6.3 KiB
PHP
258 lines
6.3 KiB
PHP
<?
|
|
use function Safe\preg_match;
|
|
use Safe\DateTimeImmutable;
|
|
|
|
/**
|
|
* @property Ebook $Ebook
|
|
* @property User $ManagerUser
|
|
* @property User $ReviewerUser
|
|
* @property string $Url
|
|
*/
|
|
class Project{
|
|
use Traits\Accessor;
|
|
use Traits\PropertyFromHttp;
|
|
|
|
public int $ProjectId;
|
|
public int $EbookId;
|
|
public Enums\ProjectStatusType $Status = Enums\ProjectStatusType::InProgress;
|
|
public string $ProducerName;
|
|
public ?string $ProducerEmail = null;
|
|
public ?string $DiscussionUrl = null;
|
|
public string $VcsUrl;
|
|
public DateTimeImmutable $Created;
|
|
public DateTimeImmutable $Updated;
|
|
public DateTimeImmutable $Started;
|
|
public ?DateTimeImmutable $Ended = null;
|
|
public int $ManagerUserId;
|
|
public int $ReviewerUserId;
|
|
public ?DateTimeImmutable $LastCommitTimestamp = null;
|
|
|
|
protected Ebook $_Ebook;
|
|
protected User $_ManagerUser;
|
|
protected User $_ReviewerUser;
|
|
protected string $_Url;
|
|
|
|
|
|
// *******
|
|
// GETTERS
|
|
// *******
|
|
|
|
protected function GetUrl(): string{
|
|
if(!isset($this->_Url)){
|
|
$this->_Url = '/projects/' . $this->ProjectId;
|
|
}
|
|
|
|
return $this->_Url;
|
|
}
|
|
|
|
|
|
// *******
|
|
// METHODS
|
|
// *******
|
|
|
|
/**
|
|
* @throws Exceptions\InvalidProjectException If the `Project` is invalid.
|
|
*/
|
|
public function Validate(): void{
|
|
$error = new Exceptions\InvalidProjectException();
|
|
|
|
if(!isset($this->EbookId)){
|
|
$error->Add(new Exceptions\EbookRequiredException());
|
|
}
|
|
|
|
$this->ProducerEmail = trim($this->ProducerEmail ?? '');
|
|
if($this->ProducerEmail == ''){
|
|
$this->ProducerEmail = null;
|
|
}
|
|
|
|
// If we have an email address, try to see if we have a matching `User` in the database that we can pull the name from.
|
|
if($this->ProducerEmail !== null){
|
|
try{
|
|
$user = User::GetByEmail($this->ProducerEmail);
|
|
if($user->Name !== null){
|
|
$this->ProducerName = $user->Name;
|
|
}
|
|
}
|
|
catch(Exceptions\UserNotFoundException){
|
|
// Pass.
|
|
}
|
|
}
|
|
|
|
$this->ProducerName = trim($this->ProducerName ?? '');
|
|
if($this->ProducerName == ''){
|
|
$error->Add(new Exceptions\ProducerNameRequiredException());
|
|
}
|
|
|
|
$this->DiscussionUrl = trim($this->DiscussionUrl ?? '');
|
|
if($this->DiscussionUrl == ''){
|
|
$this->DiscussionUrl = null;
|
|
}
|
|
|
|
$this->VcsUrl = rtrim(trim($this->VcsUrl ?? ''), '/');
|
|
if($this->VcsUrl == ''){
|
|
$error->Add(new Exceptions\VcsUrlRequiredException());
|
|
}
|
|
elseif(!preg_match('|^https://github.com/[^/]+/[^/]+|ius', $this->VcsUrl)){
|
|
$error->Add(new Exceptions\InvalidVcsUrlException());
|
|
}
|
|
|
|
if(!isset($this->ManagerUserId)){
|
|
$error->Add(new Exceptions\ManagerRequiredException());
|
|
}
|
|
else{
|
|
try{
|
|
$this->_ManagerUser = User::Get($this->ManagerUserId);
|
|
}
|
|
catch(Exceptions\UserNotFoundException){
|
|
$error->Add(new Exceptions\UserNotFoundException('Manager user not found.'));
|
|
}
|
|
}
|
|
|
|
if(!isset($this->ReviewerUserId)){
|
|
$error->Add(new Exceptions\ManagerRequiredException());
|
|
}
|
|
else{
|
|
try{
|
|
$this->_ReviewerUser = User::Get($this->ReviewerUserId);
|
|
}
|
|
catch(Exceptions\UserNotFoundException){
|
|
$error->Add(new Exceptions\UserNotFoundException('Reviewer user not found.'));
|
|
}
|
|
}
|
|
|
|
if(!isset($this->Started)){
|
|
$error->Add(new Exceptions\StartedTimestampRequiredException());
|
|
}
|
|
|
|
if($error->HasExceptions){
|
|
throw $error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @throws Exceptions\InvalidProjectException If the `Project` is invalid.
|
|
* @throws Exceptions\EbookIsNotAPlaceholderException If the `Project`'s `Ebook` is not a placeholder.
|
|
* @throws Exceptions\ProjectExistsException If the `Project`'s `Ebook` already has an active `Project`.
|
|
*/
|
|
public function Create(): void{
|
|
$this->Validate();
|
|
|
|
// Is this ebook already released?
|
|
if(!$this->Ebook->IsPlaceholder()){
|
|
throw new Exceptions\EbookIsNotAPlaceholderException();
|
|
}
|
|
|
|
// Does this `Ebook` already has an active `Project`?
|
|
if($this->Ebook->ProjectInProgress !== null){
|
|
throw new Exceptions\ProjectExistsException();
|
|
}
|
|
|
|
Db::Query('
|
|
INSERT into Projects
|
|
(
|
|
EbookId,
|
|
Status,
|
|
ProducerName,
|
|
ProducerEmail,
|
|
DiscussionUrl,
|
|
VcsUrl,
|
|
Created,
|
|
Updated,
|
|
Started,
|
|
Ended,
|
|
ManagerUserId,
|
|
ReviewerUserId,
|
|
LastCommitTimestamp
|
|
)
|
|
values
|
|
(
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?,
|
|
?
|
|
)
|
|
', [$this->EbookId, $this->Status, $this->ProducerName, $this->ProducerEmail, $this->DiscussionUrl, $this->VcsUrl, NOW, NOW, $this->Started, $this->Ended, $this->ManagerUserId, $this->ReviewerUserId, $this->LastCommitTimestamp]);
|
|
|
|
$this->ProjectId = Db::GetLastInsertedId();
|
|
}
|
|
|
|
/**
|
|
* @throws Exceptions\InvalidProjectException If the `Project` is invalid.
|
|
*/
|
|
public function Save(): void{
|
|
$this->Validate();
|
|
|
|
Db::Query('
|
|
UPDATE
|
|
Projects
|
|
set
|
|
Status = ?,
|
|
ProducerName = ?,
|
|
ProducerEmail = ?,
|
|
DiscussionUrl = ?,
|
|
VcsUrl = ?,
|
|
Started = ?,
|
|
Ended = ?,
|
|
ManagerUserId = ?,
|
|
ReviewerUserId = ?,
|
|
LastCommitTimestamp = ?
|
|
where
|
|
ProjectId = ?
|
|
', [$this->Status, $this->ProducerName, $this->ProducerEmail, $this->DiscussionUrl, $this->VcsUrl, $this->Started, $this->Ended, $this->ManagerUserId, $this->ReviewerUserId, $this->LastCommitTimestamp, $this->ProjectId]);
|
|
|
|
if($this->Status == Enums\ProjectStatusType::Abandoned){
|
|
Db::Query('
|
|
UPDATE
|
|
EbookPlaceholders
|
|
set
|
|
IsInProgress = false
|
|
where
|
|
EbookId = ?
|
|
', [$this->EbookId]);
|
|
}
|
|
}
|
|
|
|
public function FillFromHttpPost(): void{
|
|
$this->PropertyFromHttp('ProducerName');
|
|
$this->PropertyFromHttp('ProducerEmail');
|
|
$this->PropertyFromHttp('DiscussionUrl');
|
|
$this->PropertyFromHttp('Status');
|
|
$this->PropertyFromHttp('VcsUrl');
|
|
$this->PropertyFromHttp('Started');
|
|
$this->PropertyFromHttp('Ended');
|
|
$this->PropertyFromHttp('ManagerUserId');
|
|
$this->PropertyFromHttp('ReviewerUserId');
|
|
}
|
|
|
|
|
|
// ***********
|
|
// ORM METHODS
|
|
// ***********
|
|
|
|
/**
|
|
* @throws Exceptions\ProjectNotFoundException If the `Project` can't be found.
|
|
*/
|
|
public static function Get(?int $projectId): Project{
|
|
if($projectId === null){
|
|
throw new Exceptions\ProjectNotFoundException();
|
|
}
|
|
|
|
return Db::Query('SELECT * from Projects where ProjectId = ?', [$projectId], Project::class)[0] ?? throw new Exceptions\ProjectNotFoundException();
|
|
}
|
|
|
|
/**
|
|
* @return array<Project>
|
|
*/
|
|
public static function GetAllByStatus(Enums\ProjectStatusType $status): array{
|
|
return Db::Query('SELECT * from Projects where Status = ? order by Started desc', [$status], Project::class);
|
|
}
|
|
}
|