Laravel: Like/Dislike na wszystkie modele

0

Stworzyłem coś takiego. Czy ma to ręce i nogi i jest w porządku? W przyszłości chcę mieć możliwość dodania jakichś nowych reakcji, dlatego taka forma tego. No i Reagować będzie można na wiele modeli. Wcześniej w takie relacje się nie bawiłem (no, może trochu z tagami).

<?php

namespace App\Traits;

use App\Models\React;
use Illuminate\Database\Eloquent\Relations\MorphToMany;

trait ReactTrait
{
    public function reacts(): MorphToMany
    {
        return $this->morphToMany(React::class, 'reactable');
    }
}

<?php

namespace App\Contracts;

use Illuminate\Database\Eloquent\Relations\MorphToMany;

interface Reactable
{
    public function reacts(): MorphToMany;
}

<?php

namespace App\Models;

class Post extends Model implements Reactable
{
    use BroadcastsEvents, HasFactory, ReactTrait;
<?php

namespace App\Models;

class React extends Model
{
    use HasFactory;

    public function reactable()
    {
        return $this->morphTo();
    }
}

Schema::create('reacts', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });

 Schema::create('reactables', function (Blueprint $table) {
            $table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
            $table->foreignId('react_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
            $table->integer('reactable_id');
            $table->string('reactable_type');
            $table->timestamps();
        });

Jeśli coś można zrobić lepiej - poproszę rady, a jeśli to jest ok - to w jaki sposób mogę wyświetlić wszystkie lub dla konkretnego modelu reakcje danego usera?

0

Po kiego grzyba ci interfejs na modelu? Pierwszy raz widzę by ktoś to robił.

0

Haha, no w sumie to niepotrzebne i wszystko działa bez tego. Patrzyłem na różne tutoriale i tak jakoś to posklejałem. No newbie w tym temacie jestem :D

0

Będzie działac bez ale nie o to chodzi, interfejsy stosuje się w konkretnych celach i w modelu często znaleźć te zastosowania.

0

Kurcze, szczerze mówiąc to już sam nie wiem co robię. Pogubiłem się z tymi relacjami. Czyli teraz, gdy wyrzuciłem interfejs - jak do tej pory jest wszystko dobrze? Jak mogę teraz zrobić dodawanie nowej reakcji do modelu przez zalogowanego użytkownika?

0

Pomieszane to jak 150. Dependency inversion wyrzucone przez okno.

0

Rozszerz swoje pytanie o temat. co to znaczy ze chcesz like.dislike na wszystkie modele ? na model Users tez? na model Contracts tez? ludzie beda ogladac kontrakty innych i dawac liki ? o co chodzi z tym like na wszystkie modele ?

0

Z tymi modelami, chodziło mi o to, że mam np. Posty, a w nich komentarze. Są też opinie itp i chcę by można było te modele podpiąć do tych lików/reakcji. Na razie chcę mieć możliwość polubienia/nielubienia ale w przyszłości pewnie będę chciał dodać jakieś inne reakcje.

1

to musisz zrobic tak jak chciales to morp many ale w modelu zwyczajnie i niech tabela reakcje bedzie wspolna tylko dodaj tam dwa pola w jednym trzymasz model w drugim id modelu to dobrze wybrales te polimorficzne rozwiazania, ja mam tak samo z komentarzami do postow lub do wydarzenc zy do filmow, w szystko w jednym tylko w zaleznosci jaki model pyta to taki zwaraca mi komentarz

0

mozesz uzyc dodanie relacji i kasowane jej w taki prosty sposob albo update jak w normalnych relacjach

$comment = new App\Comment(['comment' =>'blabla']);
$post = App\Post::find($post->id);
$comment = $post->comments()->save($comment);
0

Moim zdaniem popełaniasz fundamentalny błąd myląc modele ORM bazodanowe z modelami biznesowymi. Łamiesz dependency inversion.

1
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class React extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name'];

    /**
     * Get all of the reviews that are assigned this react.
     */
    public function reviews()
    {
        return $this->morphedByMany(Review::class, 'reactable')->withPivot('user_id')->withTimestamps();
    }
}


Review model:

public function reacts()
    {
        return $this->morphToMany(React::class, 'reactable')->withPivot('user_id')->withTimestamps();
    }

I dodaję/aktualizuje reakcję w tej sposób:

$review->reacts()->updateOrCreate(['user_id' => 4], ['name' => 'like'], ['user_id' => 4]);

Czy teraz jest w porządku?

Bo wszystko działa, a rzeczywiście dużo czytelniejsze to wszystko jest.
Teraz nie wiem jak zdefiniować relację, tak abym mógł pobrać wszystkie reakcje, które stworzył user.

0

Albo jak mam review model i chcę dołączyć reakcje razem z userem, tak jak poniżej. To jaką relację mam stworzyć w modelu React?

public function reacts()
    {
        return $this->morphToMany(React::class, 'reactable')->with('user')->withTimestamps();
    }
0

W modelu React ja bym stworzyl zwyła relacje zwrotną w stylu

public function review()
    {
        return $this->belongsTo(Review::class);
    }
0

Ale te relacje mi się mieszają. Zmieniłem relację na taką jak mi podałeś. A do usera, który zostawił reakcję jak mogę się dostać?

Dodałem do modelu reakcji:
public function user()

    {
        return $this->belongsTo(User::class);
    }
return $review->reacts()->with('user')->get();

I otrzymuję coś takiego:

  {
    "id": 14,
    "name": "like",
    "created_at": "2021-10-07T12:19:10.000000Z",
    "updated_at": "2021-10-07T12:19:24.000000Z",
    "pivot": {
      "reactable_id": 39,
      "react_id": 14,
      "reactable_type": "App\\Models\\Review",
      "created_at": "2021-10-07T12:19:10.000000Z",
      "updated_at": "2021-10-07T12:19:10.000000Z"
    },
    "user": null
  }
]

Ten user powinien być w pivot? No i nie ładuje mi usera. Probówałem też innymi relacjami go załadować, ale bez rezultatu.

1

Wiesz co ? nie za bardzo wiem czy dobrze myślę jeśli chodzi o to co chcesz zrobić. Z tego co sobie wyobraziłem jak czytałem to wygląda to tak że:

  1. Masz na przykład model z postami na forum (przykładowo) i chcesz dodać reakcje na te wpisy (posty)
  2. Możesz dodać np wideo i pod tym wideo chcesz też mieć możliwość reakcji
  3. Dodajesz cokolwiek innego (jakiś model) i też chcesz mieć reakcje.

Zatem polimorficzna tabela powinna być ta która przechowuje reakcje, gdzie będzie w niej:
user_id - bo musimy wiedzieć kto dał reakcje
reactable_type - czyli tu będzie model z jakiego przyszeła reakcja
reactable_id - czyli id z tabeli danego modelu np wideo jakiego dotyczy, posta itd
reaction_type - czyli jaki typ reakcji, like , dislike, smile itd

Czyli w modelu reakcji

class React extends Model
{
    public function reactable()
    {
        return $this->morphTo();
    }
}

A w modelach przyszłościowych tam wideo czy post czy inne

class Post extends Model
{
    public function react()
    {
        return $this->morphMany(React::class, 'reactable');
    }
}

class Video extends Model
{
    public function react()
    {
         return $this->morphMany(React::class, 'reactable');
    }
}

I teraz napisz w czym jest problem

0

Zrobiłem tak jak napisałeś i teraz mi wyrzuca:

Column not found: 1054 Unknown column 'reacts.reactable_id'

Mam 2 tabele

Schema::create('reacts', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });
Schema::create('reactables', function (Blueprint $table) {
            $table->foreignId('user_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
            $table->foreignId('react_id')->constrained()->onUpdate('cascade')->onDelete('cascade');
            $table->integer('reactable_id');
            $table->string('reactable_type');
            $table->timestamps();
        });

Zamiast reaction_type, mam react_id. Czy ta tabela react jest potrzebna?

0

no ale sam napisales gdzies wyzej

 return $this->morphToMany(React::class

to znaczy ze masz model React czyli ta tabela reacts powinna byc ale to mozesz dowolnie zmieniac

1 użytkowników online, w tym zalogowanych: 0, gości: 1