deebow's avatar

deebow started a new conversation+100 XP

5mos ago

Most of my career has been spent working with Angular. While I’ve also used Vue 2 and React in the past, Angular is where I’m most comfortable mainly because it’s opinionated, structured, and follows an MVC-style approach, so I never have to worry too much about organizing the project.

I’m starting a new project now and want to build the frontend using either Vue 3 or React. Before I dive in, I’d like to explore solid references or boilerplates that follow industry best practices for either framework.

If you have any recommendations, whether it’s a starter template, a well-structured repository, or a best-practice guide, I’d really appreciate it.

Thanks!

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

JUST HOW DUMB AM I?

Why would I even need a team_participant_round table when I already have game_participants and rounds tables. I can simply record per-round participant scoring in a game_participant_round table.

That way, I avoid creating a bulky team_participant_round table that would explode in size by a factor of (number of teams created × number of participants per team × number of rounds per game).

Thanks @martinbean for pointing what I missed out:

So you’ll need to have some sort of entity for this game or whatever, that you attach players to, and also designate what “round” the game was played.

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Hello @martinbean

First of all, apologies for not sharing the full context.

In the previous post, I ended up with a polymorphic pivot game_participants, where participants could either be athlete or club. This pivot table acts as the catalogue from which players select participants to build their team.

A Team is also composed of participants chosen from that catalogue (game_participants), so I have another pivot table: team_participants.

My challenge now is how to assign a score to each team_participant for every round. I’m considering two approaches:

  1. A dedicated pivot table, e.g. team_participant_round, referencing both team_participant and round.
    • My question: Is it acceptable or common to have a foreign key referencing the primary key of another pivot table (in this case, team_participants.id)?
  2. Use a JSON column (e.g. round_scores) within team_participants, storing key–value pairs where the key is the round ID and the value is the score.
deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Hello @glukinho , I incorrectly defined the relationship of Round. Please see updated version above.

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Scores are not entity, it's simply a score a player gets per round.

deebow's avatar

deebow started a new conversation+100 XP

5mos ago

Hello,

I have a Game, Room, Athlete, and Round entities.

Game -> Many Rooms
Room -> Many Athlete
Athlete -> Belongs to many Room

EDITED:
WRONG: (Room -> Many Rounds) 
CORRECT: Game -> Many Rounds (That means, all rooms in the game all have the same rounds)

So the tables for that would be:

games
rooms
athletes
athlete_room
rounds

now, what If athletes in the room could gain scores for each round.

so then I would have athlete_room_rounds

So let's put in some numbers and do the math, for daily metrics:

  • Average 15 games daily
  • Average 100 rooms per game
  • Average 15 athletes per room
  • Average 10 rounds per game

So that would be:

15 games x 100 rooms x 15 athletes * 10 rounds = 225,000 rows daily

My question are:

  1. Is 225k rows daily considered heavy?
  2. Should I go with athlete_room_round table? or should I simply add new round_scores json column in athlete_room?
  3. What are my other options?
deebow's avatar

deebow wrote a reply+100 XP

5mos ago

I'm really sorry, I saw your comment in my notification but it's not anywhere in the replies section of my post, tried refreshing several times. Same with Snapey's comment.

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

It's such as a relief that I am going in the right path.

Thank you!

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

"The second way seems to hide everything too much for my liking"

I guess it's true, but I think it's only partially true. For me, the #Tag[] attribute annotates it well. But again, it's a preference thing lol.

Anyway, thank you so much!

deebow's avatar

deebow started a new conversation+100 XP

5mos ago

I have an invokable action class called: AttachMembersToRoom . Now, aside from basic form request validations, I also have complex validation, like comparing values across members, identify overlapping member rooms, and more... so I decided to make each validations into custom invokable classes, like CompareMembersValues, IdentifyOverlaps , and more....

At first, I did the following to execute every validations in AttachMembersToRoom :

class AttachMembersToRoom
{
    public function __invoke(MyData $data)
    {
        foreach ($this->validators() as $validator) {
            $validator()($data);
        }

		execute main logic here...
    }

    /**
    * @return callable[]
    **/
    private function validators(): array
    {
        return [
            fn () => app(CompareMembersValues::class),
            fn () => app(IdentifyOverlaps::class),
            ...
            ...
        ];
    }
}

but looking at it, I think it's a bit excessive to use app() for every validators I have, and I'm afraid that the whole "attaching members to room" process would take up much memory than it should be.

so I decided to bind-tag it in the service container, like so:

$this->app->tag([
    CompareMembersValues::class,
    IdentifyOverlaps::class,
], 'memberValidators');

and in AttachMembersToRoom , I made the following adjustments:

class AttachMembersToRoom
{
    public function __construct(#[Tag('memberValidators')] protected iterable $memberValidators) {}

    public function __invoke(MyData $data)
    {
        foreach ($this->memberValidators as $validator) {
            $validator($data);
        }

		execute main logic here...
    }
}

At this point, I'm not even sure if I'm doing the right thing, or am I even overcomplicating things?

But my goal for all of this is the testability.. at some point, I want to mock each of these validators, and bypass some of these validators during testing.

deebow's avatar

deebow started a new conversation+100 XP

5mos ago

First of all, I'm a Laravel newbie, and feel free to roast what I did :D

Before getting to my main question, here’s the context: the app uses a lot of invokable action classes, and they’re executed like this: app(SomeActionClass::class)($data)

So here are my questions:

  1. If these invokable classes don’t have any dependencies, why call them using app() instead of the classic (new SomeActionClass)($data)?

  2. Regarding the code below, did I even do the right thing just to run a series of invokable validator classes?

private function validators(): array
{
	return [
		fn () => app(ValidatorOne::class),
  		fn () => app(ValidatorTwo::class),
		...
		...
	];
}

// and called this way
$data = new MyData(...);

foreach ($this->validators() as $validator) {
	$validator()($data);
}

So the follow-up questions for #2 are:

  1. Is this even a good way to execute each validators, or am I just overcomplicating it?
  2. Is calling app() for every invokable class excessive?
  3. What would you personally recommend as the best approach?

Edit: It seems that my post lack context, but one of my goal really is to establish testability, so I can easily mock each of these validations. But if someone could suggest a better approach to this, then it would be greatly appreciated :)

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

I know it's too late, but for someone who's dealing with the same case:

I guess you could do:

Teach::with('account')
    ->orderBy(Account::select('surname')->whereColumn('accounts.id', 'teachers.account_id'))
	->paginate() // or get()

or even a query builder, much faster.

Reference: https://laraveldaily.com/post/order-by-belongsto-relationship-column-eloquent-vs-query-builder

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Downside is, when you need to paginate the data. The sorting would only apply per page, you'd then get incorrect result.

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Ahh, silly... I could specify the table name in the model protected $table = 'game_participants' for example... then the ide-helper will then recognize it.

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Although I'm having problems with making barryvdh/laravel-ide-helper work with this.

The problem is, I decided to make these pivot into a model extending Illuminate\Database\Eloquent\Relations\MorphPivot, since there are additional columns to each pivot, and it's much easier to manipulate it this way:

game_participants
	- game_id
	- participantable
	- more columns...

tournament_participants
	- tournament_id
	- participantable
	- more columns...

Now, since ide-helper expects the MorphPivot model to have a singular database migration, like game_participant and tournament_participant... it can't be analyzed, so it's not generating the necessary docblocks.

deebow's avatar

deebow liked a comment+100 XP

5mos ago

@deebow Would a tournament not be made up of multiple games? Personally, I’d have a Game model, that then has many “participants”, which would be your polymorphic relation (a “participant” would either be a club or individual player).

For tournaments, I’d just have a has-many relation to games. Again, you could add a has-many polymorphic relation to participants if you wanted to show what clubs/players were playing in a tournament, but players in the constituent games had not been decided yet (e.g. matches still needed to drawn).

So you’d have the following tables:

  • clubs
  • players
  • games
  • tournaments
  • game_participants
  • tournament_participants

You could try and be “clever” and create some sort of “participants” table with two polymorphic relations linking a club/player to a game/tournament, but for the sake of clarity I’d just have a table each for games and tournaments, otherwise your queries and model relations may get a bit gnarly.

deebow's avatar

deebow liked a comment+100 XP

5mos ago

Can a club/player really participate in a tournament? Or in fact they can participate in a game which is a part of a tournament?

Can a player participate in a game/tournament by himself, without a club?

Maybe your real relations are:

Player -> belongsTo -> Club  
Club   -> hasMany   -> Player

Club -> belongsToMany -> Game  
Game -> belongsToMany -> Club

Game       -> belongsTo -> Tournament  
Tournament -> hasMany   -> Game

And Player is related to a Tournament/Game not directly but through several other relations.

deebow's avatar

deebow wrote a reply+100 XP

5mos ago

Thanks everyone for your input :)

Since I have the following relationships:

Athlete -> BelongsTo -> Club
Club -> HasMany -> Athlete

Game -> BelongsTo -> Tournament
Tournament -> HasMany -> Game

I could go with contenderables, having 2 polymorphic columns for game/tournament and athelte/club, but it seems very complex, and I just want to simplify things, so I ended up with the following:

game_participants
tournament_participants
deebow's avatar

deebow liked a comment+100 XP

5mos ago

Keep it simple...

deebow's avatar

deebow started a new conversation+100 XP

5mos ago

Hi guys, I need your suggestion or insights.

I have the following entities.

  • Game
  • Tournament
  • Club
  • Player

Clubs and Players may participate in many Games and Tournaments.

My two options:

  1. Two-way Polymorphic Many-to-Many:
    • eventables where both columns are polymorphic:
      • eventable: game, tournament
      • contenderable: club, player
  2. Separate pivot for each:
    • game_club, game_athlete, tournament_club, tournament_athlete

But at this point, I'm not really sure which is the best. I want to go with Option 1 but I don't see much discussions that relates to it.

Please let me know what's your take.

Thank you!