diff --git a/src/Libs/Entity/StateEntity.php b/src/Libs/Entity/StateEntity.php index bf54f1b0..eddd7e0a 100644 --- a/src/Libs/Entity/StateEntity.php +++ b/src/Libs/Entity/StateEntity.php @@ -13,24 +13,75 @@ final class StateEntity implements iState { use LoggerAwareTrait; + /** + * @var array $data Holds the original entity data. + */ private array $data = []; + /** + * @var bool $tainted Flag indicating if the data is tainted based on its event type. + */ private bool $tainted = false; + /** + * @var string|int|null $id The corresponding database id. + */ public null|string|int $id = null; + + /** + * @var string $type What type of data this entity holds. + */ public string $type = ''; + /** + * @var int $updated When was the entity last updated. + */ public int $updated = 0; + + /** + * @var int $watched Whether the entity is watched or not. + */ public int $watched = 0; + /** + * @var string $via The backend that this entity data belongs to. + */ public string $via = ''; + + /** + * @var string $title The title of the entity usually in format of "Movie Title (Year)" if event type is movie. Or "Series Title (Year) - Season x Episode" if event type is episode. + */ public string $title = ''; + /** + * @var int|null $year The year of the entity. + */ public int|null $year = null; + /** + * @var int|null $season The season number of the episode if event type is episode. + */ public int|null $season = null; + /** + * @var int|null $episode The episode number of the episode event type is episode. + */ public int|null $episode = null; + /** + * @var array $parent The parent guids for this entity. Empty if event type is movie. + */ public array $parent = []; + + /** + * @var array $guids The guids for this entity. Empty if event type is episode. + */ public array $guids = []; + + /** + * @var array $metadata holds the metadata from various backends. + */ public array $metadata = []; + + /** + * @var array $extra holds the extra data from various backends. + */ public array $extra = []; public function __construct(array $data) @@ -455,6 +506,17 @@ final class StateEntity implements iState return $lastProgress; } + /** + * Checks if the value of a given key in the entity object is equal to the corresponding value in the current object. + * Some keys are special and require special logic to compare. For example, the updated and watched keys are special + * because they are tied together. + * + * @param string $key The key to check in the entity object. + * @param iState $entity The entity object to compare the key value with. + * + * @return bool Returns true if the value of the key in the entity object is equal to the value in the current object, + * otherwise returns false. + */ private function isEqualValue(string $key, iState $entity): bool { if (iState::COLUMN_UPDATED === $key || iState::COLUMN_WATCHED === $key) { @@ -468,6 +530,17 @@ final class StateEntity implements iState return true; } + /** + * Updates the value of a given key in the current object with the corresponding value from the remote object. + * The method follows certain logic for specific keys such as "updated" and "watched". For these keys, if the remote + * object has a greater "updated" value and a different "watched" value compared to the current object, the values in + * the current object are updated with the values from the remote object. If the key is an array column the method uses + * the recursive replacement to update the value of the key in the current object with the value from the remote + * object. Otherwise, it simply assigns the value of the key from the remote object to the current object. + * + * @param string $key The key to update in the current object. + * @param iState $remote The remote object to get the updated value from. + */ private function updateValue(string $key, iState $remote): void { if (iState::COLUMN_UPDATED === $key || iState::COLUMN_WATCHED === $key) { @@ -490,6 +563,16 @@ final class StateEntity implements iState } } + /** + * Calculates the difference between two arrays by comparing their values recursively. + * + * @param array $oldArray The original array to compare. + * @param array $newArray The new array to compare. + * + * @return array Returns an associative array that contains the differences between the two arrays. The keys are the + * differing elements from the new array, and the values are arrays that contain the old and new values + * for each differing element. + */ private function arrayDiff(array $oldArray, array $newArray): array { $difference = []; diff --git a/src/Libs/Entity/StateInterface.php b/src/Libs/Entity/StateInterface.php index 4175872f..f1412488 100644 --- a/src/Libs/Entity/StateInterface.php +++ b/src/Libs/Entity/StateInterface.php @@ -99,144 +99,148 @@ interface StateInterface extends LoggerAwareInterface /** * Make new instance. * - * @param array $data + * @param array $data Data to set. * - * @return StateInterface + * @return StateInterface Return new instance. */ public static function fromArray(array $data): self; /** - * Return An array of changed items. + * Return an array of changed items. * - * @param array $fields if omitted, will check all fields. + * @param array $fields if omitted, it will check all fields. * - * @return array + * @return array Return an array of changed items. */ public function diff(array $fields = []): array; /** - * Get All Entity keys. + * Get all entity keys. * - * @return array + * @return array Return an array of all entity keys. */ public function getAll(): array; /** * Has the entity changed? * - * @param array $fields - * @return bool + * @param array $fields if omitted, it will check all fields. + * + * @return bool Return true if the entity has changed. */ public function isChanged(array $fields = []): bool; /** * Does the entity have external ids? * - * @return bool + * @return bool Return true if the entity has external ids. */ public function hasGuids(): bool; /** * Get List of external ids. * - * @return array + * @return array Return an array of external ids. */ public function getGuids(): array; /** * Does the entity have relative external ids? * - * @return bool + * @return bool Return true if the entity has relative external ids. */ public function hasRelativeGuid(): bool; /** * Get Relative GUIDs. * - * @return array + * @return array Return an array of relative external ids. */ public function getRelativeGuids(): array; /** - * Get Relative Pointers. + * Get relative pointers. * - * @return array + * @return array Return an array of relative pointers. */ public function getRelativePointers(): array; /** - * Does the Entity have Parent external ids? + * Does the entity have parent external ids? * - * @return bool + * @return bool Return true if the entity has parent external ids. */ public function hasParentGuid(): bool; /** - * Get Parent external ids. + * Get parent external ids. * - * @return array + * @return array Return an array of parent external ids. */ public function getParentGuids(): array; /** * Is the entity of movie type? * - * @return bool + * @return bool Return true if the entity is of movie type. */ public function isMovie(): bool; /** * Is the entity of episode type? * - * @return bool + * @return bool Return true if the entity is of episode type. */ public function isEpisode(): bool; /** * Is entity marked as watched? * - * @return bool + * @return bool Return true if the entity is marked as watched. */ public function isWatched(): bool; /** - * Get constructed name. + * Get constructed name. We Return the following format depending on the type: + * * For movies : "Title (Year)" + * * For Episodes: "Title (Year) - Season(00) x Episode(000)" * * @param bool $asMovie Return episode title as movie format. * - * @return string + * @return string Return constructed name. */ public function getName(bool $asMovie = false): string; /** - * Get external ids Pointers. + * Get external ids pointers. * - * @return array + * @return array Return an array of external ids pointers. */ public function getPointers(): array; /** * Apply changes to entity. * - * @param StateInterface $entity + * @param StateInterface $entity The entity which contains the changes. * @param array $fields if omitted, it will apply all {@see StateInterface::ENTITY_KEYS} fields. * - * @return StateInterface + * @return StateInterface Return the updated entity. */ public function apply(StateInterface $entity, array $fields = []): StateInterface; /** - * Update Original data. Please do not use this unless you know what you are doing + * Update Original data. + * Please do not use this unless you know what you are doing * * @return StateInterface - * @internal + * @internal This method is used internally. */ public function updateOriginal(): StateInterface; /** * Get The Original data. * - * @return array + * @return array Return the original data. */ public function getOriginalData(): array; @@ -245,37 +249,37 @@ interface StateInterface extends LoggerAwareInterface * If the entity is not already stored in the database, then this flag is not used. * However, if the entity already exists and the flag is set to **true**, then * we will be checking **external ids** only, and if those differ {@see ENTITY_IGNORE_DIFF_CHANGES} will be updated - * as well, otherwise, nothing will be changed, This flag serve to update GUIDs via webhook unhelpful events like - * play/stop/resume. + * as well, otherwise, nothing will be changed, this flag serve to update item via webhook unhelpful events like + * play/stop/resume without alternating the play state. * * @param bool $isTainted * - * @return StateInterface + * @return StateInterface Return the updated entity. */ public function setIsTainted(bool $isTainted): StateInterface; /** - * Whether the play state is tainted. + * Is the entity data tainted? * - * @return bool + * @return bool Return true if the entity data is tainted. */ public function isTainted(): bool; /** - * Get Metadata + * Get metadata. * * @param string|null $via if via is omitted, the entire "metadata" will be returned. * - * @return array + * @return array Return an array of metadata. */ public function getMetadata(string|null $via = null): array; /** - * Set Metadata related to {$this->via} backend + * Set metadata related to {$this->via} backend. * - * @param array $metadata metadata + * @param array $metadata Metadata * - * @return StateInterface + * @return StateInterface Return the updated entity. * * @throws \RuntimeException if no via is set. */ @@ -291,11 +295,11 @@ interface StateInterface extends LoggerAwareInterface public function getExtra(string|null $via = null): array; /** - * Set Extra related to {$this->via} backend + * Set Extra related to {$this->via} backend. * * @param array $extra Extra * - * @return StateInterface + * @return StateInterface Return the updated entity. * * @throws \RuntimeException if no via is set. */ @@ -311,21 +315,21 @@ interface StateInterface extends LoggerAwareInterface * * ---------------- * - * * [1] **entity.watched** field **MUST** must be marked as unplayed. - * * [2] **db.item.watched** field **MUST** be set as played. - * * [3] **db.item.metadata** field **MUST** have pre-existing metadata from that backend. + * * [1] **entity.watched** field **MUST** must be set as **0** (unplayed). + * * [2] **db.item.watched** field **MUST** be set as **1** (played). + * * [3] **db.item.metadata** field **MUST** have pre-existing metadata from the backend that is asking to mark the item as unplayed. * * [4] **db.item.metadata.backend** JSON field **MUST** contain **watched**, **id**, **played_at** and **added_at** as keys with values. - * * [5] **db.item.metadata.backend.watched** field **MUST** be set as played. + * * [5] **db.item.metadata.backend.watched** field **MUST** be set as **1** (played). * * [6] **entity.metadata.backend.id** field **MUST** match **db.item.metadata.backend.id**. * * [7] **entity.updated** field **MUST** match **db.item.metadata.backend.added_at**. * * ---------------- * - * Ref: **.db.item.[]** refers to local db data. **entity.[]** refers to the data being received from backend. + * Ref: **db.item.[]** refers to local db data. **entity.[]** refers to the data being received from backend. * * @param StateInterface $backend Backend object. * - * @return bool + * @return bool Return true if all conditions are met. */ public function shouldMarkAsUnplayed(StateInterface $backend): bool; @@ -340,7 +344,7 @@ interface StateInterface extends LoggerAwareInterface * * @param StateInterface $backend Backend object. * - * @return StateInterface + * @return StateInterface Return the updated entity. */ public function markAsUnplayed(StateInterface $backend): StateInterface; @@ -348,14 +352,15 @@ interface StateInterface extends LoggerAwareInterface * Check item if it has play progress. * This is used to determine if we should update the progress or not. * - * @return bool + * @return bool Return true if the item has play progress. */ public function hasPlayProgress(): bool; /** * Get play progress. If the item is watched and/or has no progress, then 0 will be returned. otherwise * time in milliseconds will be returned. - * @return int + * + * @return int Return the play progress. */ public function getPlayProgress(): int; }