GithubHelp home page GithubHelp logo

cybercog / laravel-love Goto Github PK

View Code? Open in Web Editor NEW
1.1K 24.0 72.0 659 KB

Add Social Reactions to Laravel Eloquent Models. It lets people express how they feel about the content. Fully customizable Weighted Reaction System & Reaction Type System with Like, Dislike and any other custom emotion types. Do you react?

Home Page: https://komarev.com/sources/laravel-love

License: MIT License

PHP 99.72% Dockerfile 0.28%
laravel eloquent cog like love adore rate rating emotion favorite

laravel-love's Introduction

Laravel Love

cog-laravel-love

Discord Releases Build StyleCI Code Quality License

Introduction

Laravel Love is emotional part of the application. It let people express how they feel about the content. Make any model reactable in a minutes!

There are many implementations in modern applications:

  • GitHub Reactions
  • Facebook Reactions
  • YouTube Likes
  • Slack Reactions
  • Reddit Votes
  • Medium Claps

This package developed in mind that it should cover all the possible use cases and be viable in enterprise applications.

Official Documentation

Documentation can be found in Laravel Love Guide.

Installation

Pull in the package through Composer.

$ composer require cybercog/laravel-love

Run database migrations.

$ php artisan migrate

Upgrading

Please see UPGRADING for detailed upgrade instructions.

License

๐ŸŒŸ Stargazers over time

Stargazers over time

About CyberCog

CyberCog is a Social Unity of enthusiasts. Research the best solutions in product & software development is our passion.

CyberCog

laravel-love's People

Contributors

acidjazz avatar antonkomarev avatar chiliec avatar jfunulab avatar raniesantos avatar sburkett avatar squigg avatar ujackson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-love's Issues

Accessors with iterable type should return Collection instance

NullReactant model has these methods:

public function getReactions(): iterable
{
    return [];
}

public function getReactionCounters(): iterable
{
    return [];
}

Both of them should return new Collection() instance to have the same data type with Reactant model methods.

Same issue with NullReacter model getReactions method.

Migration Customization

There were issues with published migrations raised in #28. We need to think about the way to ignore default migrations to be executed.

1. Use global Love facade

If you are not going to use Love's default migrations, you should call the Love::ignoreMigrations method in the register method of your AppServiceProvider. You may export the default migrations using the php artisan vendor:publish --tag=love-migrations command and make changes before php artisan migrate execution.

2. Use configuration file

If you are not going to use Love's default migrations, you should export default config file using the php artisan vendor:publish --tag=love-config and change love.load_default_migrations boolean flag value to false. You may export the default migrations using the php artisan vendor:publish --tag=love-migrations command and make changes before php artisan migrate execution.

Getting error when I like a comment

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'likeable_id' cannot be null (SQL: insert into love_likes (user_id, type_id, likeable_id, likeable_type, updated_at, created_at) values (1, LIKE, , App\Comment, 2018-11-24 22:16:35, 2018-11-24 22:16:35))

Command line Recount throws error and ReactionCounter always showing 0

Hi, this is the first time I open an issue on GitHub, so forgive me if I am missing some conventions. First of all, thank you for this package.

When running "php artisan:love recount" in the command prompt, I get this error:

Symfony\Component\Debug\Exception\FatalThrowableError : Call to undefined method Cog\Laravel\Love\Reactant\ReactionTotal\Models\NullReactionTotal::update()

at /var/www/theproject/vendor/cybercog/laravel-love/src/Console/Commands/Recount.php:166
162| }
163|
164| /** @var \Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal $total */
165| $total = $reactant->getReactionTotal();
166| $total->update([
167| 'count' => $totalCount,
168| 'weight' => $totalWeight,
169| ]);
170| }

I also have an issue with reaction count in general, it seems the database tables for counters are empty, even when there are reactions.

I have some reactions as can been seen below. The reactions are added through for example $reacterFacade->reactTo($likable, $likestatus); and enter the love_reactions table as expected as seen below.

mysql> select * from love_reactions;
+-----+-------------+------------+------------------+---------------------+---------------------+
| id  | reactant_id | reacter_id | reaction_type_id | created_at          | updated_at          |
+-----+-------------+------------+------------------+---------------------+---------------------+
| 146 |           2 |          2 |                2 | 2019-07-16 03:24:20 | 2019-07-16 03:24:20 |
| 147 |           4 |          2 |                1 | 2019-07-16 03:24:22 | 2019-07-16 03:24:22 |
| 152 |           3 |          2 |                1 | 2019-07-16 03:25:04 | 2019-07-16 03:25:04 |
+-----+-------------+------------+------------------+---------------------+---------------------+

But the counters/totals tables are still empty.

mysql> select * from love_reactant_reaction_counters;
Empty set (0.00 sec)
mysql> select * from love_reactant_reaction_totals;
Empty set (0.00 sec)

Something like $reactantFacade->getReactionCounterOfType('Like')->getCount() also returns 0.

As far as I can tell I have set up my models as per the installation instructions and have an App\User as the Reacterable and an App\Review as Reactable.

Any advise is much appreciated.

Specific Columns in likesCounter returns null

This:
->with('likesCounter')
return
"likes_counter": {
"id": 1,
"likeable_type": "App\Company",
"likeable_id": 1,
"type_id": "LIKE",
"count": 1,
"created_at": "2018-07-07 19:28:53",
"updated_at": "2018-08-09 03:49:40"
}
And this
->with('likesCounter:count')
return
"likes_counter": null

[Question] About the use of Traits and Contracts

The README says this:

Use Cog\Contracts\Love\Liker\Models\Liker contract in model which will get likes
behavior and implement it OR just use Cog\Laravel\Love\Liker\Models\Traits\Liker trait.

(Same for Likeable.)

Emphasis on the 'OR'.

'OR' implies that this will work even if I don't use both, so I tried to use this package with traits only.

I got these errors through Tinker:

screenshot from 2018-02-17 00-26-32

If this error is intended/supposed to happen, you should change the README to say that both are needed.

Add Power to Reactions

Possible names:

  • Reaction Power
  • Reaction Rate
  • Reaction Force
  • Reaction Strength

Case 1

Allow Reacter to react to Reactant with same reaction type more than once.

Example:
In social news application user Jane can vote up article up to 5 times.

Similar to Medium's Claps:

Case 2

Reacter has some kind of authority inside of the application and his reactions should have more weight among others.

Example:
In Question & Answer application user Jane solved more than 1000 questions. Jane's reactions will have more power now.

Additionally by this way it will be easier segregate reactions from more notable application users.

[Feature Request] add configuration file and allow to specify database connection

I know I had already opened #27 about this and you mention how to workaround it by creating your own models and creating bindings

however now that you have added even more models, it seems like a very tedious solution to have to create duplicate models, extend them and then bind them in your service provider

a much more practical approach would be to allow us to publish a configuration file where we could specify the database connection for all the migrations and models. I really appreciate packages that include this allowance as I use multi-database schemes in many of my larger projects

this is a minor change that would allow full backwards compatibility including for those who don't publish the file since it would have sensible defaults

I recently created a PR for another package that added this very same thing, you can look at it here. If you want I could create a PR for your package too

laravel-notification-channels/webpush#85

Thanks for considering this!

[Proposal] extend the type of reaction.

Hi,
thanks for the great work!

Just like facebook there could be more than just 'like' or 'dislike', for example, 'sad', 'angry' or whatever you can imagine. Having this flexibility can extend the use case of this package.๐Ÿ‘๐Ÿผ

Update documentation

Hey, I followed the documentation and this is what I found
Here:

Prepare Liker Model
Use Cog\Contracts\Love\Liker\Models\Liker contract in model which will get likes behavior and implement it or just use Cog\Laravel\Love\Liker\Models\Traits\Liker trait.

use Cog\Contracts\Love\Liker\Models\Liker as LikerContract;
use Cog\Laravel\Love\Liker\Models\Traits\Liker;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements LikerContract
{
    use Liker;
}

Use Cog\Contracts\Love\Liker\Models\Liker contract in model which will get likes behavior and implement it or just use Cog\Laravel\Love\Liker\Models\Traits\Liker trait.

I tried first with the trait, gave an error, then I tried with the contract and implement it, gave an error, then I did both and it worked. The documentation said "or".
Same goes for the likeable.

Or did I do something wrong?

problem with return the number of posts likes foreach post

hi i am using this plugin and i made
user table - profile table and posts table
this is my code
===========================================>

 public function getfollowsposts()
    {
       $user= Auth::user();
       $a=[];
       $posts = User::find($user->id)->followings;
        foreach ($posts as $value) {
            $post =DB::table('users')
        ->where('users.id','=',$value->id)
        ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
        ->leftJoin('myprofiles', 'users.id', '=', 'myprofiles.user_id')
        ->orderBy('posts.created_at', 'desc')
        ->select('name','myprofiles.user_id','img_post','posts.created_at','posts.id','posts.title','myprofiles.avatar_pic')
        ->get();
            array_push($a,$post);
        }
        return response()->json($a,200);
    }

====================================>
how can i get the number of likes for each code coz i tryed every single way and its not working
====================>

  public function postslikesnumber(Request $request){
        $user = Auth::user();   
        $x3= posts::find($request->posts_id)->likesCount;
        return response()->json($x3, 200); 
    }

====================>>>>>>
so......
i made function that send request when the function getfollowsposts() loaded put its not good for
the server requests ....... too many requests
so any help ??? i ll be thankfull

Return value if liked or disliked (for example) is null - bug or feature?

Good evening @a-komarev

a big cnacuba for this great package, I like it ;)

I just implemented it and while I was testing it via tinker, I thought "Is this a bug or a feature?"

See examples below:

>>> $user->like($question)
=> null
>>> $user->unlike($question)
=> null
>>> $user->dislike($question)
=> null
>>> $user->like($question)
=> null
>>> $user->dislike($question)
=> null

Not sure what your view on it is, I thought that if working with the package, it would make more sense to actually return true if the action succeeded and false if it didn't, don't you think?

Thanks
Andreas

Refactor Artisan love:recount command

Use options instead of arguments as setup commands do.

Motivation

Because both arguments in current command signature are optional - they should be options instead of arguments.

Current signature is broken because we can't rebuild all counters of Like type without defining models:

$ love:recount Like

We need more obvious command:

$ love:recount --type=Like

Current Implementation

$ love:recount {reactableType?} {type?}

New Implementation

$ love:recount {--model=} {--type=}

How to highlight liked posts (by current user) within all posts

Hi, my scenario is I'm showing all the recent posts to user and I have added the heart icon on each post and when the user likes a post it's highlighted in red and if not it's just showing the border of the heart. so that the user knows a post has already been liked or no. the question is how to highlight the posts that like by the user with in all posts. That's my code:
My controller:

 $newUser = User::where('uid', '=', $user->uid)->first();

        $posts = Post::where('status', 'published')->latest()->take(75)->get();

        //Return collection of posts as resource
        return PostSource::collection($posts);

My resource:

public function toArray($request)
    {
        return [
        'id' => $this->id,
        'source_id' => SourceResource::collection($this->whenLoaded('source')),
        'source_name' => $this->source,
        'category_id' => CategoryResource::collection($this->whenLoaded('category')),
        'category_name' => $this->category,
        'fav_info' => $this->users,
        'title' => $this->title,
        'created_at' => $this->created_at,
        ];
    }

So I know there's nothing in the code above related to this library but I;m already using it to add likes and deslikes and grab the current users posts that he liked. but I can't highlight the liked posts within all the posts.
Thanks

Reacter is invalid

Hey there, just tried using your package but I can't seem to get it working.

I want to create a simple like functionality so I followed the instructions in the documentation, but it tells me the reacter is invalid.

I get this error when I try to like/dislike:
message: "Reacter not exists.", exception: "Cog\Contracts\Love\Reacter\Exceptions\ReacterInvalid",โ€ฆ} exception: "Cog\Contracts\Love\Reacter\Exceptions\ReacterInvalid" file: "D:\xampp\htdocs\readclub\vendor\cybercog\laravel-love\contracts\Reacter\Exceptions\ReacterInvalid.php" line: 24 message: "Reacter not exists."

This is my code:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Cog\Laravel\Love\ReactionType\Models\ReactionType;
use App\Prompt;
use Auth;
use Session;

class LikeController extends Controller
{
  public function likePrompt(Request $request, $slug) {
    $prompt = Prompt::where('slug', $slug)->first();
    $user = Auth::user();
    $reacter = $user->getLoveReacter();
    $reactant = $prompt->getLoveReactant();
    $likeType = ReactionType::fromName('Like');


    if (!isset($prompt) || !isset($user)) {
      return Response::json(['error' => 'Not a valid prompt or user.'], 404);
    }

    if ($reacter->isReactedTo($reactant)) {
      // Already reacted to prompt
      // Remove like from prompt
      $reacter->unreactTo($reactant, $likeType);
    } else {
      // Not reacted to prompt
      // Add like to prompt
      $reacter->reactTo($reactant, $likeType);
    }

    return Response::json(['success' => true]);

  }
}

When I debug $reacter and $reactant it tells me I have the NullReacter and NullReactent, but when I run the function $user->isRegisteredAsLoveReacter() and $prompt->isRegisteredAsLoveReactant() they both return true, so they should be registered.

Return value of LikeableService::getLikerUserId() must be of the type integer

Hi,

I am receiving following error while calling $me->toggleLike($media) . Where $me is User model and $media is Media model of MediaLibrary .

Symfony\Component\Debug\Exception\FatalThrowableError: Return value of Cog\Laravel\Love\Likeable\Services\LikeableService::getLikerUserId() must be of the type integer, object returned in file C:\Work\Website\ModelsWay.com\bin\vendor\cybercog\laravel-love\src\Likeable\Services\LikeableService.php on line 369

Please help me resolve this issue. I can paste whole stack trace if you want.

Regards,

Unable to check status of likeBy();

I am trying to check the status of likeBy() method, but can't, as it returns a void. When a user who has liked a model tries I want to return a a boolean instead of the void that is returned by the package.

I already tried to check
$like = $agent->likeBy($user->id); if($like) { dd('success') } dd('failed')
but it keeps going down to failed! Any solution for this?

[Concept] Make methods names more natural

Current Implementation

On v6 design phase I've thought that it will be better to have methods with similar signature looks same and method names should explicitly describe what will be passed in them and in what order (like in fluent form).

Method isReactedTo checks if reacter reacted to reactant with any reaction type and accepts single Reactant parameter.

$reacter->isReactedTo(Reactant);

To check if reacter reacted to reactant with concrete reaction type - there is additional method with similar signature. Because it accepts ReactionType as second parameter I've appended WithType suffix to method name.

$reacter->isReactedToWithType(Reactant, ReactionType);

If it was written in fluent form, it would look like this:

$reacter->isReactedTo(Reactant)->withType(ReactionType);

New Concept

After some time has passed I've started to think that it might be wrong decision to try to always keep parameters in the same order between logically similar methods and I should think about design of API for a next major release.

$reacter->isReactedWithTypeTo(ReactionType, Reactant);

If it was written in fluent form, it would look like this:

$reacter->isReactedWithType(ReactionType)->to(Reactant);

But at the end I stopped on this solution:

$reacter->hasReactedTo(Reactant, ?ReactionType);
$reacter->hasNotReactedTo(Reactant, ?ReactionType);

Facade for usage in templates

To simplify usage of v6 in templates we will need Facade.

Current solution

Type safe but very hard to use and read in templates.

<cog-love-reaction-component
:is-reacted="@json(auth()->check() && auth()->user()->getReacter()->isReactedToWithType($post->getReactant(), \Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('Like'))"
></cog-love-reaction-component>

Reactable methods

$post->getReactant()->isReactedByWithType($user->getReacter(), \Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('Like')): bool
$post->getReactant()->isReactedBy($user->getReacter()): bool
$post->getReactant()->getReactionCounterOfType(\Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('Like'))->getCount()
$post->getReactant()->getReactionTotal()->getCount(): int
$post->getReactant()->getReactionTotal()->getWeight(): int

Reacterable methods

$user->getReacter()->isReactedToWithType($post->getReactant(), \Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('Like')): bool
$user->getReacter()->isReactedTo($post->getReactant())

Reaction methods

$reaction->isOfType(\Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('Like')): bool
$reaction->isNotOfType(\Cog\Laravel\Love\ReactionType\Models\ReactionType::fromName('Like')): bool

Refactor API from v4 to v5

We need to revised an API methods naming and design it's extension.
A lot of methods aren't natural when you are reading them now.

Make scopes easier to use

Motivation

Since Eloquent Scopes are meant only used in user application - we will require to call getReacter() method all the time.

Comment::whereReactedBy(auth()->user()->getReacter())->get();

For developers it will be easier to write:

Comment::whereReactedBy(auth()->user())->get();

Current Implementation

Comment::whereReactedBy(
  Reacter $reacter,
  ?ReactionType $reactionType = null
);

Comment::joinReactionCounterOfType(
  ReactionType $reactionType
);

Comment::joinReactionTotal();

New Implementation

Comment::whereReactedBy(
  Reacterable $reacterable,
  ?string $reactionTypeName = null
);

Comment::joinReactionCounterOfType(
  string $reactionTypeName,
  ?string $alias = null
);

Comment::joinReactionTotal(
  ?string $alias = null
);

We can add one more scope method with inverse filtering:

Comment::whereNotReactedBy(
  Reacterable $reacterable,
  ?string $reactionTypeName = null
);

It will be useful when you want to promote some new content to user, but don't want to show items which are already reacted by user.

Join Scopes Aliases

Each join scope method should accept nullable $alias as last parameter. If it's empty - then default virtual column name will be generated, otherwise user defined alias will be used.

Join Reaction Counter

Default counters alias: 'reaction_' . Str::snake($reactionType->getName())

WithComment::joinReactionCounterOfType('DoubleLike') call you will have 2 virtual columns:

  • reaction_double_like_count
  • reaction_double_like_weight

WithComment::joinReactionCounterOfType('DoubleLike', 'custom_name') call you will have 2 virtual columns:

  • custom_name_count
  • custom_name_weight

Join Reaction Total

Default totals alias: reaction_total.

WithComment::joinReactionTotal() call you will have 2 virtual columns:

  • reaction_total_count
  • reaction_total_weight

WithComment::joinReactionTotal('custom_name') call you will have 2 virtual columns:

  • custom_name_count
  • custom_name_weight

in a nutshell what are the reasons for the huge changes between v5 and v6?

Just wondering because I'm now using V5 and it's working perfectly fine for me. Is V6 more versatile somehow? Does it allow for more stats? More flexibility? Or is it just a cleaner refactoring that doesn't really add benefits to the end-user?

In my application I only have users "liking" other users.. as simple a use-case as possible I imagine. I like to stay up to date with packages but I'd like to know what I'll gain if anything from doing this upgrade.

Many thanks!

Change table name?

Is it possible to change the name of the table through the configuration?

Egear loader on like and dislike count

Hello,

Can we eager load on the like and dislike count?
I display these two count on each comment. So for 50 comments it makes 100 queries of this type:
image

Any way to reduce the queries number of theses counts using eager loader or another trick?

Regards

cannot use custom migrations even after publishing them

It seems that as a result of the PR here #11

Even if you publish the migrations, the changes are ignored and instead the package's migrations are used.

On a side note, I personally feel that it was ok how you were doing it before, that in order to use the package the user is required to publish the migrations first.. this is how 90% of packages that depend on migrations are doing it.. and it leaves more flexibility

So I would just revert that PR and include publishing the migrations in the docs, which you already do.

Implement Reacter & Reactant Facades

Since package API is strict typed its might be harder to use and couple your application with the package subsystems. Developers will pass to the reactTo method reactable instance and string value of reaction type name: ->reactTo($comment, 'Like')

Facade design pattern to the rescue. Not the same as Laravel Facades (which act as "static proxies").

These facades will replace experimental global Cog\Laravel\Love\Facades\Love facade.

Facade concept

Facade shields developers from the complex details of the system and provides them with a simplified view of it which is easy to use. It also decouples the code that uses the system from the details of the subsystems, making it easier to modify the system later. It decreases maintenance cost, but adds additional layer of code & decreases runtime performance.

Reacter Facade

User via Reacterable trait will have additional method which will provide simpler access to Reacter model methods. This method returns Facades\Reacter class which hide internal complexity behind a single interface that appears simple from the outside. Method will have via (by way of) prefix.

trait Reacterable
{
    public function viaLoveReacter(): ReacterFacade
    {
        return new ReacterFacade($this->getLoveReacter());
    }
}

Usage

Instead default strict typed Reacter model calls:

$reactant = $comment->getLoveReactant();
$reactionType = ReactionType::fromName('Like');

$user->getLoveReacter()->reactTo($reactant, $reactionType);

Facades\Reacter class has simpler interface:

$user->viaLoveReacter()->reactTo($comment, 'Like');

Under the hood it will resolve Reactant model from $comment & ReactionType from the string name and call strict typed method.

Reactant Facade

Comment via Reactable trait will have additional method which will provide simpler access to Reactant model methods. This method returns Facades\Reactant class which hide internal complexity behind a single interface that appears simple from the outside. Method will have via (by way of) prefix.

trait Reactable
{
    public function viaLoveReactant(): ReactantFacade
    {
        return new ReactantFacade($this->getLoveReactant());
    }
}

Usage

Instead default strict typed Reactant model calls:

$reacter = $user->getLoveReacter();
$reactionType = ReactionType::fromName('Like');

$comment->getLoveReactant()->isReactedByWithType($reacter, $reactionType);

Facades\Reactant class has simpler interface:

$comment->viaLoveReactant()->isReactedBy($user, 'Like');

Under the hood it will resolve Reacter model from $user & ReactionType from the string name and call strict typed method.

Naming

Facades\Reacter & Facades\Reactant instantiation methods name candidate variants described in comments below.

Weighted Reaction System v2

Resolves #26 #73

Motivation

We need to allow people to react to the reactants with more pressure or multiple times with one type.

It was designed as #26 Reaction Power initially, but I decided to reserve word power for Reacter's authority.

Use cases

  • React multiple times on the same post with Claps on Medium.com
  • Have more influence on the vote weight with Authority on Dirty.ru
  • US Electoral System, when voting power depends on where you live in

Current Implementation

Each type of reaction has weight which proxies to reactions, then sums up and gives total reaction weight affecting on the reactant.

Reaction.weight = ReactionType.weight

New Implementation

Each type of reaction has mass which proxies to reactions, then sums up and gives total reaction mass affecting on the reactant.

Reaction will have new rate attribute which will increase influence of the reacter on the reactant. Weight in new system is equal to the mass of the reaction type multiplied by the reaction rate.

Reaction.weight = ReactionType.mass * Reaction.rate

Wondering why just not add rate attribute without renaming reaction type weight attribute? Read design process section below for the detailed explanation and difference between weight and mass.

Following changes are required:

  • ReactionType attribute weight will be renamed to mass
  • ReactionType method getWeight() will be renamed to getMass()
  • Reaction will have additional attribute rate

These changes are not mandatory but will increase statistics possibilities:

  • Reaction will have additional method getRate()
  • Reaction will have additional method getMass()
  • ReactionCounter will receive additional attributes mass & rate
  • ReactionCounter will receive additional methods getMass() & getRate()
  • ReactionTotal will have additional attributes mass & rate
  • ReactionTotal will have additional methods getMass() & getRate()

Update console command:

  • php artisan love:reaction-type-add --mass="-1"

Design Process

I was inspired by physics and chemistry while designed new system.

In physics, Reaction Force formula:

force = mass * acceleration

Acceleration is the rate of change of velocity of an object with respect to time.

Let's replace acceleration in this formula with rate:

force = mass * rate

Rate is the velocity of an reactant becoming popular.

Weight is the force caused by gravity:

weight = force * gravity

That means reaction could have different weight depends of reactant location.

Example:
Reaction to the post in closed group can weight more than in public group.

Because we don't need gravity operand in weighting formula yet we could define it's default value as 1 so it wouldn't affect on any applications which don't need this feature.

weight = mass * rate * 1

Or even simpler for now:

weight = mass * rate

Draft Features for v3 (#153)

Reaction Gravity

Reaction Gravity represents environment around the reactant and will affect on the reaction weight, but it wouldn't affect on net Reaction Force.

weight = mass * rate * gravity

Default value: 1.0.

Reaction Force

Reaction Force might be useful for sorting statistical data ignoring the gravity. In current version it's equal to Reaction Weight because we don't have gravity yet.

force = mass * rate

Reacter Power

Reacter Power represents reserve of strength which could be used to increase rate of the reactions.

Power reserve logic depends on the business requirements, it could be:

  • infinite
  • finite
  • finite but refillable
  • ...

Add console command to add columns to application tables

Reacterable

Command:

$ php artisan love:setup-reacterable --model=App\User

Should create database migration file:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddLoveReacterIdToUsersTable extends Migration
{
    public function up(): void
    {
         Schema::table('users', function (Blueprint $table) {
             $table->unsignedBigInteger('love_reacter_id');
         });

        $table
            ->foreign('love_reacter_id')
            ->references('id')
            ->on('love_reacters');
    }
}

Reactant

Command:

$ php artisan love:setup-reactable --model=App\Comment

Should create database migration file:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddLoveReactantIdToCommentsTable extends Migration
{
    public function up(): void
    {
         Schema::table('comments', function (Blueprint $table) {
             $table->unsignedBigInteger('love_reactant_id');
         });

        $table
            ->foreign('love_reactant_id')
            ->references('id')
            ->on('love_reactants');
    }
}

upgrade guide from cybercog/laravel-likeable ?

I've been using cybercog/laravel-likeable for what seems like a solid year.. in a production environment too

Now I see you're putting out this new and improved version of it.. but I am wondering if the upgrade is super straightforward or not? I obviously don't want to lose any of the existing data

any chance you could post a step-by-step upgrade guide since you know best what's changed and what backwards compatibility might be affected?

Also, I had asked you long ago about the possibility of using cybercog/laravel-likeable to use dynamic states

for example.. by default this package provides the ability for a model to like/dislike another model

I want that, and I am using that. But I also need to allow models to do things like "block/unblock" models and "hide/unhide" models

It would be great if I could do all of these things with this package alone.. does your new version attempt to cover this use case by any chance?

many thanks!

Change Artisan reaction-type-add command signature

In continue of #81 to follow same convention with other commands we should change:

php artisan love:reaction-type-add Favorite 1

To more expressive signature:

php artisan love:reaction-type-add --name=Favorite --weight=1

Motivation

The main benefit from it that we will be able to reorder options:

php artisan love:reaction-type-add --weight=1 --name=Favorite

Or even pass only weight and ask for missing options interactively.

php artisan love:reaction-type-add --weight=1

Refactor API from v5 to v6

The main goal of this refactoring is start to use strict types where it is possible and refactor relationships.

Right now API v5 has issue with methods naming because Likeable model cannot act as Liker model in the same time. This could be useful when User can like User.

Library Architecture in v6

This is simplified UML diagram enlighten how this package will look like in v6.

190102-cog-laravel-love-uml

  • Reacter โ€” one who reacts.
  • Reacterable โ€” polymorphic connection with Reacter (User, Person, Organization, etc).
  • Reactant โ€” subject which could receive Reactions.
  • Reactable โ€” polymorphic connection with Reactant (Article, Comment, etc).
  • Reaction โ€” the response that reveals Reacter's feelings or attitude.
  • ReactionType โ€” type of the emotional response (Like, Dislike, Love, Hate, etc).
  • ReactionCounter โ€” computed statistical values of ReactionTypes related to Reactable entities.
  • ReactionTotal โ€” computed statistical values of total Reactions count & their weight related to Reactable entities.

Sorting by likes should sort by the different between likes and dislikes

Original issue from @sroy:

There is no way to sort by ( likes - dislikes ) that I can find currently, only by total amount of likes and total amount of dislikes. Something to sort by likesDiffDislikesCount() would be really nice :) I'm not experienced enough send a PR.

To implement this feature we will require to introduce additional table or add extra rows in like_counter table with additional enum type related to likes_diff_dislikes. Otherwise queries and sorting in runtime will be significantly slow on big databases.

Create reactions counters on the fly

Initially we've created counters for each type of reaction on reactant create. This was designed this way to exclude checks if counter exists on each addReaction operation. This is very important and helps to keep our code cleaner and simpler and minimize client waiting time, but has undesirable side effects.

It's pretty common for services to have a lot of types of reactions. Slack & Mattermost are great examples when you can mark post with any emoji you want. In this case our current solution is overkill because we will require to create counter for all the emojis which are exists (around 3k in Unicode Standard at this moment). For only 1000 messages we'll have ~3 millions of counters and this will be very harmful for application performance.

As a solution we could check if counter exists on addReaction operation and create them on the fly if there is need. To avoid client freeze we can make it as background job.

To follow the same logic we could completely exclude necessity of summary statistics on reactant creation by removing ReactionTotal from Reactant observer created event.

Refactor package relations

I decided to revise and extend relationships in v6. Initially was planned to do it in v5 but it will require database changes and Laravel 5.6 morphTo implementation.

There is a need to fetch:

  1. Likeables of the Liker.
  2. Likers of the Likeable.
  3. (?) Likes which were added to Likeables.
  4. (?) Likes which were added by Liker.

I'm not 100% sure about points 3 & 4. Do we really need to get those likes? Need to write use cases for them.

Old implementation

Only 3rd point is implemented right now.

// Likes and dislikes related to Likeable
$likesAndDislikes = $article->likesAndDislikes();

// Likes related to Likeable
$likes = $article->likes();

// Dislikes related to Likeable
$dislikes = $article->dislikes();

reactTo Method

Is it the reactTo() included in the following trait?
use Cog\Laravel\Love\Reactable\Models\Traits\Reactable;

My model Post which is using the Reactable trait cannot find the reactTo method...I am getting the following error: "Call to undefined method App\Post::reactTo()"

How can I fix it?

Laravel 5.7 support

Trying to update from 5.6 to 5.7 i get this message:

Problem 1
    - Conclusion: don't install cybercog/laravel-love 5.1.1
    - Conclusion: don't install laravel/framework v5.7.2
    - Installation request for cybercog/laravel-love ^5.1 -> satisfiable by cybercog/laravel-love[5.1.0, 5.1.1].
    - Conclusion: don't install laravel/framework v5.7.1
    - cybercog/laravel-love 5.1.0 requires illuminate/database ~5.5.0|~5.6.0 -> satisfiable by illuminate/database[v5.5.0, v5.5.16, v5.5.17, v5.5.2, v5.5.28, v5.5.33, v5.5.34, v5.5.35, v5.5.36, v5.5.37, v5.5.39, v5.5.40, v5.5.41, v5.5.43, v5.6.0, v5.6.1, v5.6.10, v5.6.11, v5.6.12, v5.6.13, v5.6.14, v5.6.15, v5.6.16, v5.6.17, v5.6.19, v5.6.2, v5.6.20, v5.6.21, v5.6.22, v5.6.23, v5.6.24, v5.6.25, v5.6.26, v5.6.27, v5.6.28, v5.6.29, v5.6.3, v5.6.30, v5.6.31, v5.6.32, v5.6.33, v5.6.34, v5.6.35, v5.6.36, v5.6.37, v5.6.38, v5.6.4, v5.6.5, v5.6.6, v5.6.7, v5.6.8, v5.6.9].

and so on

Syntax for adding reaction types not matching documentation

Hi,

According to the documentation, this is how you should add a reaction type on the command line:

Pass name & weight arguments in command line to skip interaction.

$ php artisan love:reaction-type-add name=Hate weight=-4

I would just like to point out, that it seems that is not how it is working at the moment
(see example below).

user@server:/var/www/theproject$ php artisan love:reaction-type-add name=Favorite weight=1
Reaction type with name `Name=Favorite` is invalid.

user@server:/var/www/vlogtrends$ php artisan love:reaction-type-add name="Favorite" weight=1
Reaction type with name `Name=Favorite` is invalid.

user@server:/var/www/theproject$ php artisan love:reaction-type-add Favorite weight=1
Reaction type with name `Favorite` and weight `0` was added.

If this is how it is intended to work, then perhaps the docs need updating?

Get likes and relation of user

Hello,
I want to get the places that have like, I do this:
$users = $place->likes()->paginate();

How do I get the user's relationship to get the name for example?
dd($users[0]->user->name);

Is the relationship missing?

Thanks!

how to specify database connection when using multiple databases

I'm using two databases, and currently it is defaulting to the wrong database, ie not the one that contains the laravel-love tables

usually I get around this by simply specifying the connection inside the model. But since there is no configuration file where you can specify which model to use, I can create a model of my own and then extend your model

so is there another way of specifying which connection the two models (love_likes and love_likes_counters) are using?

$user->getReacter() or $user->getLoveReacter() ?

In README it's $user->getReacter()
but I think you mean $user->getLoveReacter() is that right?

#### Get reacter model

Only `Reacter` model can react to content. Get `Reacter` model from your `Reacterable` model. 

```php
$reacter = $user->getReacter();

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.