Last active
April 5, 2024 16:32
-
-
Save BonBonSlick/c815b67e3a9b86281b10482ba0a22ff3 to your computer and use it in GitHub Desktop.
DateTime_$airAt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* (c) BonBonSlick - 7/27/21, 1:51 PM | |
*/ | |
// my own project snippet to create dynamic statuses based on nested content dates | |
declare(strict_types=1); | |
/* | |
* Created by BonBonSlick | |
*/ | |
namespace App\Domain\Core\Traits; | |
use App\Domain\AnimePack\Anime\Model\Anime; | |
use App\Domain\Core\DTO\DataTypes\BooleanValue; | |
use App\Domain\Core\ValueObjects\Time\AiredAt; | |
use App\Domain\EpisodePack\Episode\Model\Episode; | |
use App\Domain\StoryElement\Model\StoryElement; | |
use App\Infrastructure\Traits\Helper\TimeHelperTrait; | |
use DateTimeImmutable; | |
use DateTimeInterface; | |
/** | |
* In case AnimeComponent is being CANCELLED, element must be removed | |
* | |
* @todo - maybe in future add cancelledAt date, but do we keep cancelled anime / episodes / seasons?? | |
*/ | |
trait EntityAiredAtTrait | |
{ | |
protected AiredAt $airAt; | |
use TimeHelperTrait; | |
final public function air(DateTimeImmutable $time = null): void | |
{ | |
if (true === $this->airAt->isAnnounced()->isNegative()) { | |
$this->announce(); | |
} | |
$this->airAt = new AiredAt(airAt: $time ?? new DateTimeImmutable()); | |
} | |
/** | |
* air date is usually unknown | |
*/ | |
public function announce(DateTimeImmutable $time = null): void | |
{ | |
$now = new DateTimeImmutable(); | |
if (false === $time instanceof DateTimeInterface || $time > $now) { | |
$time = $now; | |
} | |
$this->airAt = new AiredAt(announcedAt: $time); | |
if (true === $this instanceof Episode) { | |
// this is used to prevent infinite RECURSION! | |
return; | |
} | |
$announceNestedModels = static function (StoryElement|Episode $model) use ($time): void { | |
// WARNING!! Possible infinite RECURSION!! | |
$model->announce($time); | |
}; | |
if (true === $this instanceof Anime || true === $this instanceof StoryElement) { | |
$this->storyElements()->forAll( | |
static function (StoryElement $model) use ($announceNestedModels) { | |
$announceNestedModels($model); | |
} | |
); | |
// episodes must be updated the last, because its the deepest tree root element | |
$this->episodes()->forAll( | |
static function (Episode $model) use ($announceNestedModels): void { | |
$announceNestedModels($model); | |
} | |
); | |
} | |
} | |
public function isAired(): BooleanValue | |
{ | |
if (true === $this instanceof Episode && true === $this->airAt->airAt() instanceof DateTimeInterface) { | |
return new BooleanValue( | |
$this->airAt->airAt() <= new DateTimeImmutable() | |
); | |
} | |
$returnValue = new BooleanValue(); | |
$now = new DateTimeImmutable(); | |
$isModelAired = static function (Anime|StoryElement|Episode $model) use (&$returnValue, $now): void { | |
$returnValue = new BooleanValue(true === $model->airAt->airAt() <= $now); | |
}; | |
if (true === $this instanceof Anime || true === $this instanceof StoryElement) { | |
$this->episodes()->forAll( | |
static function (Episode $model) use ($isModelAired): void { | |
$isModelAired($model); | |
} | |
); | |
$this->storyElements()->forAll( | |
static function (StoryElement $model) use ($isModelAired) { | |
$isModelAired($model); | |
} | |
); | |
} | |
return $returnValue; | |
} | |
public function isOngoing(): BooleanValue | |
{ | |
$returnValue = new BooleanValue(); | |
if (true === $this instanceof Episode) { | |
return $returnValue; | |
} | |
$self = $this; | |
$isModelToBeAired = static function (Anime|StoryElement|Episode $model) use (&$returnValue, $self): void { | |
$isExtraContentWillBeReleasedInFuture = true === $model->airAt->isAnnounced()->isPositive() || | |
true === $model->airAt->isUpcoming()->isPositive(); | |
$returnValue = new BooleanValue( | |
true === $self->airAt->isUpcoming()->isPositive() && true === $isExtraContentWillBeReleasedInFuture | |
); | |
}; | |
if (true === $this instanceof Anime || true === $this instanceof StoryElement) { | |
$this->storyElements()->forAll( | |
static function (StoryElement $model) use ($isModelToBeAired) { | |
$isModelToBeAired($model); | |
} | |
); | |
$this->episodes()->forAll( | |
static function (Episode $model) use ($isModelToBeAired): void { | |
$isModelToBeAired($model); | |
} | |
); | |
} | |
return $returnValue; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* (c) BonBonSlick | |
*/ | |
declare(strict_types=1); | |
namespace App\Domain\Core\ValueObjects\Time; | |
use App\Domain\Core\DTO\DataTypes\BooleanValue; | |
use App\Domain\Core\ValueObjects\Abstracts\AbstractVO; | |
use DateTimeImmutable; | |
use DateTimeInterface; | |
use function get_object_vars; | |
/** | |
* | |
* Anime - announced - upcoming - ongoing - released | |
* StoryElement - announced - upcoming - ongoing - released | |
* Episode - announced - upcoming - released | |
* | |
* | |
* These are dynamic statuses which we get from just using airAt and announceAt timestamps | |
* This system design is used to sync dynamic statuses automaticcally between related hierarchy of related domain models | |
* Yes, this is very bad design if you have large set of data, but in context of anime, data sets usually small | |
* the rest edge cases can be optimized using cache | |
* | |
* case UPCOMING = 'upcoming'; | |
* case ONGOING = 'ongoing'; | |
* case RELEASED = 'released'; | |
* case CANCELLED = 'cancelled'; | |
*/ | |
final class AiredAt extends AbstractVO | |
{ | |
public function __construct( | |
// - when element is going to be shown to the public, the date is known | |
protected readonly ?DateTimeImmutable $airAt = null, | |
// - the date when something was announced to be aired, the date is unknown yet | |
protected readonly ?DateTimeImmutable $announcedAt = null, | |
) { | |
} | |
public function isAnnounced(): BooleanValue | |
{ | |
return new BooleanValue(true === $this->announcedAt() instanceof DateTimeImmutable); | |
} | |
public function announcedAt(): ?DateTimeImmutable | |
{ | |
return $this->announcedAt; | |
} | |
public function isUpcoming(): BooleanValue | |
{ | |
$returnValue = new BooleanValue(); | |
if (true === $this->airAt() instanceof DateTimeInterface) { | |
$returnValue = new BooleanValue( | |
$this->airAt() > new DateTimeImmutable() | |
); | |
} | |
return $returnValue; | |
} | |
public function airAt(): ?DateTimeImmutable | |
{ | |
return $this->airAt; | |
} | |
public function value(): object | |
{ | |
return (object)get_object_vars($this); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment