web-dev-qa-db-fra.com

Relations éloquentes - attachez (mais ne sauvegardez pas) à Has Many

J'ai mis en place les relations suivantes:

class Page {
    public function comments() {
        return $this->hasMany('Comment');
    }
}

class Comment {
    public function page() {
        return $this->belongsTo('Page');
    }
}

Assez standard de tourbière. Une page peut contenir plusieurs commentaires et un commentaire appartient à une seule page.

J'aimerais pouvoir créer une nouvelle page:

$page = new Page;

et un commentaire

$comment = new Comment;

et attachez le commentaire à la page, sans l'enregistrer

$page->comments->associate($comment);

J'ai essayé ce qui suit:

// These are for one-to-many from the MANY side (eg. $comment->page->associate...)
$page->comments->associate($comment);   // Call to undefined method Illuminate\Database\Eloquent\Collection::associate()
$page->comments()->associate($comment); // Call to undefined method Illuminate\Database\Query\Builder::associate()

// These 2 are for many-to-many relations, so don't work
$page->comments->attach($comment);      // Call to undefined method Illuminate\Database\Eloquent\Collection::attach()
$page->comments()->attach($comment);    // Call to undefined method Illuminate\Database\Query\Builder::attach()

// These 2 will (if successful) save to the DB, which I don't want
$page->comments->save($comment);        // Call to undefined method Illuminate\Database\Eloquent\Collection::save()
$page->comments()->save($comment);      // Integrity constraint violation: 1048 Column 'page_id' cannot be null

La chose vraiment étrange est que faire le contraire (attacher la page au commentaire) fonctionne correctement:

$comment->page()->associate($page);

Les documents pertinents sont ici mais ils ne font aucune mention de l'attachement à l'un côté d'un à plusieurs. Est-ce même possible? (J'ai l'impression que ça devrait être)

20
Joe

Il semble que vous souhaitiez simplement ajouter le nouvel objet de commentaire à la collection de commentaires de la page - vous pouvez le faire facilement, en utilisant la méthode d'ajout de collection de base:

$page = new Page;
$comment = new Comment;
$page->comments->add($comment);
26
Benubird

Vous ne pouvez pas le faire car il n'y a aucun identifiant à lier.

Vous devez donc d'abord enregistrer le parent ($page) puis enregistrez le modèle enfant:

// $page is existing model, $comment don't need to be
$page->comments()->save($comment); // saves the comment

ou l'inverse, cette fois sans enregistrer:

// again $page exists, $comment don't need to
$comment->page()->associate($page); // doesn't save the comment yet
$comment->save();
8
Jarek Tkaczyk

selon Benubird, je voulais juste ajouter quelque chose alors que je suis tombé dessus aujourd'hui:

Vous pouvez appeler la méthode add sur une collection comme Benubird l'a indiqué. Pour tenir compte des préoccupations d'edpaaz (requête supplémentaire déclenchée), j'ai fait ceci:

$collection = $page->comments()->getEager(); // Will return the eager collection
$collection->add($comment) // Add comment to collection

Pour autant que je puisse voir, cela empêchera la requête supplémentaire car nous utilisons uniquement l'objet relation.

Dans mon cas, l'une des entités était persistante tandis que la première (dans votre page de cas) n'était pas (et à créer). Comme je devais traiter quelques choses et que je voulais gérer cela de manière objet, je voulais ajouter un objet entité persistant à un objet non persistant. Devrait aussi fonctionner avec les deux non persistants.

Merci Benubird de m'avoir pointé dans la bonne direction. J'espère que mon ajout aide quelqu'un comme il l'a fait pour moi.

Veuillez garder à l'esprit qu'il s'agit de mon premier post stackoverflow, veuillez donc laisser vos commentaires avec un peu de préoccupation.

4
Julius Blatt