Mutually exclusive reactions #75
Replies: 8 comments 1 reply
-
Solution №1Add boolean flag to configuration: 'is_mutually_exclusive' => true, Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
Solution №2Add special method for mutually exclusive reactions. $reacter = $user->viaLoveReacter();
$reacter->exclusiveReactTo($comment, 'Like', 2.4); Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
Solution №3Introduce special service classes which will encapsulate different reaction logic for the most common use cases out from the controllers and will throw custom exceptions for the each unexpected case. $service = new NonUnreactableReactionService();
$service->reactTo($user, $article, 'Like', $rate);
$service->unreactTo($user, $article, 'Like');
// throws `UnreactionNotAllowed` exception Mutually exclusive reactions: $service = new OverwritableReactionService();
$service->reactTo($user, $article, 'Like', $rate);
$service->reactTo($user, $article, 'Dislike', $rate);
// removes `Like` reaction and adds `Dislike` reaction Mutually exclusive reactions which will throw an exception if another one is exists: $service = new ExclusiveReactionService();
$service->reactTo($user, $article, 'Like', $rate);
$service->reactTo($user, $article, 'Dislike', $rate);
// throws `MutuallyExclusiveReactionViolation` exception Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
Solution №4Introduce special service class which will receive different reaction rules which will be executed on reaction/unreaction. $reactionRules = [
NonUnreactableReactionRule::class,
];
$service = new ReactionService($reactionRules);
$service->reactTo($user, $article, 'Like', $rate);
$service->unreactTo($user, $article, 'Like');
// throws `UnreactionNotAllowed` exception Mutually exclusive reactions: $reactionRules = [
OverwritableReactionRule::class,
];
$service = new ReactionService($reactionRules);
$service->reactTo($user, $article, 'Like', $rate);
$service->reactTo($user, $article, 'Dislike', $rate);
// removes `Like` reaction and adds `Dislike` reaction Mutually exclusive reactions which will throw an exception if another one is exists: $reactionRules = [
MutuallyExclusiveReactionRule::class,
];
$service = new ReactionService($reactionRules);
$service->reactTo($user, $article, 'Like', $rate);
$service->reactTo($user, $article, 'Dislike', $rate);
// throws `MutuallyExclusiveReactionViolation` exception This is how rule might look like: final class MutuallyExclusiveReactionRule extends AbstractReactionRule
{
public function ensureReactAllowed(
Reacterable $reacterable,
Reactable $reactable,
string $reactionTypeName,
?float $rate = null,
): void {
if ($reacterable->viaLoveReacter()->hasReactedTo($reactable)) {
throw new MutuallyExclusiveReactionViolation();
}
}
}
abstract class AbstractReactionRule
{
public function ensureReactAllowed(
Reacterable $reacterable,
Reactable $reactable,
string $reactionTypeName,
?float $rate = null,
): void {}
public function ensureUnreactAllowed(
Reacterable $reacterable,
Reactable $reactable,
string $reactionTypeName,
): void {}
} Configuration with container: $this->app->singleton(
ReactionService::class,
fn () => new ReactionService([
NonUnreactableReactionRule::class,
]),
);
$service = app(ReactionService::class);
$service->react($user, $article, 'Like', $rate);
$service->unreact($user, $article, 'Like');
// throws `UnreactionNotAllowed` exception Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
Solution №5Introduce special service class which will receive different reaction rules sets for each model type. They will be executed on reaction/unreaction depending on the provided model. $reactionRules = [
ArticleModel::class => [
NonUnreactableReactionRule::class,
],
];
$service = new ReactionService($reactionRules);
$service->reactTo($user, 'Like', $article, $rate);
$service->unreactTo($user, 'Like', $article);
// throws `UnreactionNotAllowed` exception Mutually exclusive reactions: $reactionRules = [
ArticleModel::class => [
OverwritableReactionRule::class,
],
];
$service = new ReactionService($reactionRules);
$service->reactTo($user, 'Like', $article, $rate);
$service->reactTo($user, 'Dislike', $article, $rate);
// removes `Like` reaction and adds `Dislike` reaction Mutually exclusive reactions which will throw an exception if another one is exists: $reactionRules = [
ArticleModel::class => [
MutuallyExclusiveReactionRule::class,
],
];
$service = new ReactionService($reactionRules);
$service->reactTo($user, 'Like', $article, $rate);
$service->reactTo($user, 'Dislike', $article, $rate);
// throws `MutuallyExclusiveReactionViolation` exception Configuration with container: $this->app->singleton(
ReactionService::class,
fn () => new ReactionService([
ArticleModel::class => [
NonUnreactableReactionRule::class,
],
]),
);
$service = app(ReactionService::class);
$service->react($user, 'Like', $article, $rate);
$service->unreact($user, 'Like', $article);
// throws `UnreactionNotAllowed` exception Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
Did you get anywhere on this Anton? I would be in favor of an 'exclusive-reaction' implementation on per model basis. I would also think that a model (even exclusive-reaction models) should have a max limit of reactions such as medium's claps cap. I know both systems could be implemented via the ui & controller logic but adding it to the package would be a simpler means to implement it. |
Beta Was this translation helpful? Give feedback.
-
@jayenne Not yet. I'm still on stage of researching all possible ways of implementation. As you noted - it is easy to implement in your own application, so I'm not rushing to introduce this feature. I weigh all the pros and cons and try to anticipate how this will affect further development. Thanks for mentioning max limit of reactions. That's looks like reaction rule too. |
Beta Was this translation helpful? Give feedback.
-
Solution №6Use decorator design pattern. $reacter = $user->getLoveReacter();
$reactant = $article->getLoveReactant();
$reactonType = ReactionType::fromName('Like');
$reaction = new NonUnreactableReaction(
new Reaction($reacter, $reactant, $reactionType, $rate)
);
$reaction->react();
$reaction->unreact();
// throws `UnreactionNotAllowed` exception Mutually exclusive reactions: $reacter = $user->getLoveReacter();
$reactant = $article->getLoveReactant();
$likeReactonType = ReactionType::fromName('Like');
$likeReaction = new OverwritableReaction(
new Reaction($reacter, $reactant, $reactionType, $rate)
);
$likeReaction->react();
$dislikeReactonType = ReactionType::fromName('Dislike');
$dislikeReaction = new OverwritableReaction(
new Reaction($reacter, $reactant, $reactionType, $rate)
);
$dislikeReaction->react();
// removes `Like` reaction and adds `Dislike` reaction Mutually exclusive reactions which will throw an exception if another one is exists: $reacter = $user->getLoveReacter();
$reactant = $article->getLoveReactant();
$likeReactonType = ReactionType::fromName('Like');
$likeReaction = new MutuallyExclusiveReaction(
new Reaction($reacter, $reactant, $reactionType, $rate)
);
$likeReaction->react();
$dislikeReactonType = ReactionType::fromName('Dislike');
$dislikeReaction = new MutuallyExclusiveReaction(
new Reaction($reacter, $reactant, $reactionType, $rate)
);
$dislikeReaction->react();
// throws `MutuallyExclusiveReactionViolation` exception Pros
Cons
|
Beta Was this translation helpful? Give feedback.
-
To implement functionality like Reddit Votes and YouTube Likes we need to introduce mutually exclusive reactions.
Without it Reacter could react to Reactant with
like
anddislike
simultaneously.This is non-strict requirement because same behavior could be implemented in controller on application-level.
Things to consider
In closing
If there is something I'm missing in "Things to consider" or there is other way to solve this issue? Your suggestions are welcome!
Beta Was this translation helpful? Give feedback.
All reactions