Laravel option checked

Werner S

Mitglied
Grüß euch,

wie so oft habe ich ein kleines Anfängerproblem wobei ich eure Hilfe brauche.

2 Tabellen, project und projectuser
In der Tabelle project wird das Projekt mit Titel und der UserID angelegt.
In der Tabelle projectusers werden weitere User angelegt die an dem Projekt arbeiten. "user_id" und die Project ID "project_id". Für jeden User eine eigene Spalte.

Soweit klappt dies auch.
Das Problem ist beim Editieren. Beim Editieren gibt er mir alle User aus, allerdings die die bereits am Projekt Arbeiten werden nicht mit checked "markiert"
Ich habe jetzt einige Tage etliche Lösungen versucht, komme aber zu keiner passenden Lösung.

model/Project.php
PHP:
public function user()
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

    public function projectuser()
    {
        return $this->belongsTo(Projectuser::class, 'user_id', 'id');
    }

model/Projectuser.php
PHP:
 public function user()
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

    public function project()
    {
        return $this->belongsTo(Project::class, 'user_id', 'id');
    }

Projectcontroller.php
PHP:
public function edit($id)
    {
        $projects = project::findOrFail($id);
        $users = User::all();
        $projectuser = Projectuser::all();

        return view('projects.edit', compact('projects', 'users', 'projectuser'));
    }

Project Tabelle
PHP:
Schema::create('projects', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedBigInteger('user_id')->nullable();
            $table->string('title');
            $table->timestamps();
            $table->foreign('user_id')->references('id')->on('users');

Projectuser Tabelle
PHP:
Schema::create('projectusers', function (Blueprint $table) {
            $table->increments('id');
            $table->unsignedBigInteger('user_id');
            $table->unsignedInteger('project_id');
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('project_id')->references('id')->on('projects')->onDelete('cascade');
            $table->timestamps();
        });

edit.blade.php
HTML:
<select class="select2_multiple form-control" name="userteam_id[]" multiple="multiple">
    @foreach($users as $user)
    <option value="{{ $user->id }}">{{ $user->name }}</option>
    @endforeach
</select>

In der foreach sollen sollen nun alle User ausgegeben werden, was ja bereits der Fall ist, zusätzlich aber alle user die an dem Project Arbeiten bereits markiert werden anhand der projectusers Tabelle.
 
In der Tabelle projectusers werden weitere User angelegt die an dem Projekt arbeiten. "user_id" und die Project ID "project_id". Für jeden User eine eigene Spalte.
Du meinst sicher, für jeden User eine eigene Zeile bzw. einen eigenen Eintrag/Datensatz.

Projectcontroller.php
PHP:
public function edit($id)
{
  $projects = project::findOrFail($id);
  $users = User::all();
  $projectuser = Projectuser::all();

  return view('projects.edit', compact('projects', 'users', 'projectuser'));
}
Warum nutzt du denn deine definierten Relationships gar nicht? Du benötigst ja gar nicht alle Projectuser, sondern nur die für dieses bestimmte zu bearbeitende Projekt.

Die Variable $projects würde ich übrigens zudem in $project umbenennen, da findOrFail() ja immer nur einen Eintrag zurückgeben wird.
Auch würde ich dir ggf. die Nutzung von Route Modal Binding nahelegen.

Du könntest deine Controller-Methode also z.B. wie folgt anpassen:
PHP:
public function edit(Project $project)
{
    $users = User::all();
    $projectusers = $project->projectuser;

    return view('projects.edit', compact('project', 'users', 'projectusers'));
}

Anschließend müsstest du im Template lediglich noch für jeden User prüfen, ob der User sich in der Collection mit den Projekt-Usern befindet.

Hierfür bietet sich dann aber besser die Implementation einer Methode im User-Modal an, womit du unter Angabe eines Projects prüfen kannst, ob es sich bei diesem User auch um ein Projectuser für das entsprechende Project handelt:

PHP:
public function isUserOfProject(Project $project) {
    return $this->projectuser->project->id === $project->id;
}

Voraussetzung hierfür ist natürlich, dass eine Relationship von User -> Projectuser existiert.

Anschließend kannst du die Methode wie folgt aufrufen:
HTML:
<select class="select2_multiple form-control" name="userteam_id[]" multiple="multiple">
    @foreach($users as $user)
    <option value="{{ $user->id }}" {{ $user->isUserOfProject($project) ? 'selected' : '' }}>{{ $user->name }}</option>
    @endforeach
</select>
 
Du meinst sicher, für jeden User eine eigene Zeile bzw. einen eigenen Eintrag/Datensatz.
Genau das meine ich

Warum nutzt du denn deine definierten Relationships gar nicht? Du benötigst ja gar nicht alle Projectuser, sondern nur die für dieses bestimmte zu bearbeitende Projekt.
Soweit bin ich mit Laravel noch gar nicht. Für mich ist das alles noch "Neuland", Learning by Doing, eben. Ich weiss das ich von Anfang an es direkt richtig machen soll, behalte es aber besser im Kopf wenn ich die Feinheiten zum Schluss mache.

Voraussetzung hierfür ist natürlich, dass eine Relationship von User -> Projectuser existiert.
Existiert bereits.

model/Projectuser.php
PHP:
public function user()
    {
        return $this->belongsTo(User::class, 'user_id', 'id');
    }

model/User.php
PHP:
public function project()
    {
        return $this->hasMany(Project::class, 'user_id', 'id');
    }

    public function projectusers()
    {
        return $this->hasMany(Projectuser::class, 'user_id', 'id');
    }

public function isUserOfProject(Project $project) {
        return $this->projectusers->project->id === $project->id;
    }

Ich denke das ist soweit OK.

Die edit.blade ist auch angepasst

HTML:
<select class="select2_multiple form-control" name="userteam_id[]" multiple="multiple">
    @foreach($users as $user)
    <option value="{{ $user->id }}" {{ $user->isUserOfProject($project) ? 'selected' : '' }}>{{ $user->name }}</option>
    @endforeach
</select>

Dies führt aber leider zu einem

Property [project] does not exist on this collection instance. (View: C:\MAMP\htdocs\laravel\resources\views\projects\edit.blade.php)
 
Soweit bin ich mit Laravel noch gar nicht. Für mich ist das alles noch "Neuland", Learning by Doing, eben. Ich weiss das ich von Anfang an es direkt richtig machen soll, behalte es aber besser im Kopf wenn ich die Feinheiten zum Schluss mache.
Alles klar, kein Problem.
Sich langsam an die ideale Lösung heranzuarbeiten und den Code Stück für Stück zu verbessern, ist insbesondere als Anfänger sicherlich sinnvoll.

Dies führt aber leider zu einem

Property [project] does not exist on this collection instance. (View: C:\MAMP\htdocs\laravel\resources\views\projects\edit.blade.php)
Ah, sorry. Das wird daran liegen, dass jeder User ja mehrere Projectusers hat (hasMany), demnach wird eine Collection mit Projectusern von $this->projectusers zurückgegeben.

Versuch mal das, in solchen Details bin ich auch nicht mehr so firm:
PHP:
public function isUserOfProject(Project $project) {
    return $this->projectusers()->project()->where('id', $project->id)->count() > 0; // oder where('project_id', $project->id) ?
}

Ansonsten kann man es vielleicht auch viel besser andersherum aufrollen:
PHP:
public function isUserOfProject(Project $project) {
    return $project->user->id === $this->id;
}

Du hast ja eine direkte Verknüpfung vom Projekt zum Nutzer. Dann ist Letzteres deutlich kürzer. Oh je. :D
 
Alles klar, kein Problem.
Sich langsam an die ideale Lösung heranzuarbeiten und den Code Stück für Stück zu verbessern, ist insbesondere als Anfänger sicherlich sinnvoll.
Wie das bei anderen ist, das kann ich dir nicht sagen. Bei mir ist es definitiv so. Erst mal in Laravel was halbwegs Laufbares bauen und am Ende weiter in die Materie rein zwecks Feinarbeiten. In meinem Fall ein kleines CMR für den Privaten Bereich bzw. für meine Werkstatt.
Ah, sorry. Das wird daran liegen, dass jeder User ja mehrere Projectusers hat (hasMany), demnach wird eine Collection mit Projectusern von $this->projectusers zurückgegeben.

So ist es. Jeder User kann mehrere Projekte haben (Leiter des Projects, user_id in der Projekt Tabelle) und jeder User kann an mehreren Projekten mitarbeiten bzw. zugewiesen werden (user_id und project_id in der Projectusers Tabelle).
Versuch mal das, in solchen Details bin ich auch nicht mehr so firm:

PHP:
public function isUserOfProject(Project $project) {
    return $this->projectusers()->project()->where('id', $project->id)->count() > 0; // oder where('project_id', $project->id) ?
}
Beide Varianten sagen mir
BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::project() (View: C:\MAMP\htdocs\laravel\resources\views\projects\edit.blade.php)

Ansonsten kann man es vielleicht auch viel besser andersherum aufrollen
PHP:
public function isUserOfProject(Project $project) {
    return $project->user->id === $this->id;
}
Das sieht schon besser aus, allerdings wird mir der User aus der Projects Tabelle markiert, der Leiter des Projectes und nicht die mitwirkenden aus der Projectusers Tabelle. Liegt das an diesem Teil $project->user->id? Er vergleicht ja die user_id aus der project Table mit $this->id anstatt aus der projectusers mit $this->id.

Wobei
PHP:
public function isUserOfProject(Project $project) {
        return $project->projectuser->id === $this->id;
    }
Führt auch dazu das nur der User aus der Project Tabelle markiert wird.

Ich merke schon, Laravel braucht einiges an Einarbeitung, vor allem wenn man dem Englisch nicht so mächtig ist.

Den Projektleiter markieren, weil er sich in der Project Tabelle befinden, ist im Gegensatz zu den Mitgliedern markieren ja noch einfach
PHP:
<select class="form-control" name="user_id">
                                    @foreach($users as $user)
                                    <option value="{{ $user->id }}" {{ $project->user_id == $user->id ? 'selected' : '' }}>{{ $user->name }}</option>
                                    @endforeach
                                </select>
 
Zuletzt bearbeitet:
Beide Varianten sagen mir
BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::project() (View: C:\MAMP\htdocs\laravel\resources\views\projects\edit.blade.php)
Irgendwie habe ich es schon geahnt, dass dieser Fehler dabei rauskommen wird.
Um ein einzelnes Projekt abzurufen, müssen wir natürlich aus der Liste der Projectusers-Einträge eines Users erstmal einen konkreten Projectuser heraussuchen, um dann die belongsTo-Relationship project aufrufen zu können.

Da die Projectusers-Tabelle aber bereits die Projekt-ID kennt, können wir uns diesen zusätzlichen Call sparen.

Letzter Versuch für diese Variante:
PHP:
public function isUserOfProject(Project $project) {
    return $this->projectusers()->where('project_id', $project->id)->count() > 0;
}

Ich hoffe, du kannst mir hier noch einigermaßen folgen und ich habe dich nicht total verwirrt. :D
Laravel's Relationship-System und ORM ist manchmal etwas schwer nachzuvollziehen.

Das sieht schon besser aus, allerdings wird mir der User aus der Projects Tabelle markiert, der Leiter des Projectes und nicht die mitwirkenden aus der Projectusers Tabelle. Liegt das an diesem Teil $project->user->id? Er vergleicht ja die user_id aus der project Table mit $this->id anstatt aus der projectusers mit $this->id.
Ja, stimmt. Habe kurzzeitig außer Acht gelassen, dass der User eines Projekts ja der Projektleiter ist.
Btw: Eventuell sollte man die Datenbankstruktur und Relationships nochmal überdenken, wenn das so anfällig für Verwechslungen und Missverständnisse ist. ;D

Wobei
PHP:
public function isUserOfProject(Project $project) {
return $project->projectuser->id === $this->id;
}
Führt auch dazu das nur der User aus der Project Tabelle markiert wird.
Richtig, jedes Projekt hat ja laut definierter Relationship auch nur einen User und Projectuser - und diese sind komplett identisch, da beide auf die user_id in der Projekttabelle verweisen.

Deine Relationship ist also an dieser Stelle zumindest schon mal falsch. Ein Projekt belongsToMany Projectusers.
Dann kannst du auch alle Projectuser des Projekts abrufen und prüfen, ob die User-ID in der Collection ist.

PHP:
public function isUserOfProject(Project $project) {
  return $project->projectusers()->where('user_id', $this->id)->count() > 0;
}
 
Letzter Versuch für diese Variante:
PHP:
public function isUserOfProject(Project $project) {
    return $this->projectusers()->where('project_id', $project->id)->count() > 0;
}
genau das führte zum Ergebnis. Ich dank dir!

Richtig, jedes Projekt hat ja laut definierter Relationship auch nur einen User und Projectuser - und diese sind komplett identisch, da beide auf die user_id in der Projekttabelle verweisen.

Deine Relationship ist also an dieser Stelle zumindest schon mal falsch. Ein Projekt belongsToMany Projectusers.
Dann kannst du auch alle Projectuser des Projekts abrufen und prüfen, ob die User-ID in der Collection ist.
Ich hoffe, du kannst mir hier noch einigermaßen folgen und ich habe dich nicht total verwirrt. :D
Laravel's Relationship-System und ORM ist manchmal etwas schwer nachzuvollziehen.

Noch nicht so wirklich. Ich dachte eigentlich das meine Relationship richtig sind bzw. ich das richtig Verstanden habe.
Muss wohl noch mal über hasMany, belongsTo, belongsToMany drüber schauen und mich da mal richtig einlesen.
 
Zurück
Oben Unten