Tudor Ravoiu
Tudor Ravoiu

Reputation: 2150

Laravel Relationships and using the push() method

I'm trying to find a different approach on saving/updating a given model and it's relationships into database.

Basically I have a form for the "Author" page where multiple "Books" can be added. Naturally the "Author" and "Book" models have a one-to-many relationship.

According to the laravel official tutorial you have to:

  1. Add all input data to the "Author" model
  2. Create and save the "Author" model into DB
  3. For each "Book" input data
  4. Create and save each "Book" model into DB using $author->books()->save($book);

Laravel also states that "Sometimes you may wish to save not only a model, but also all of its relationships. To do so, you may use the push method: $user->push();".

But I couldn't find any tutorial on how to fill the "Author" model with "Book" relationships and in fact use the push() method

I'm searching for something like this:

$author = new Author();
$author->name = "Bill Jobs";
$author->phone = "555 - 123456";

// fill model with relations

$author->addRelation($relationsArray)

if($author->push())
{ 
   // ....
}

Also the same should work for updating an "Author": Firstly delete already stored relations, than save the new ones

Upvotes: 1

Views: 6038

Answers (3)

Waleed Mubarik
Waleed Mubarik

Reputation: 93

you can update your book and author model using push method.

$book = Book::first();
$book->author->author_name = "Mark Twin";
$book->book_name = "Life On The Mississippi";
$book->push();

here is link for details [1]: https://medium.com/@JinoAntony/10-hidden-laravel-eloquent-features-you-may-not-know-efc8ccc58d9e

Upvotes: 0

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81167

tldr; You'll find push description below, as well as difference between createMany and saveMany relation mothods

Eloqeunt doesn't handle deferred relationships (like for example Doctrine2), ie. you can't do this:

$author = new Author;
$book = new Book;
$book->author()->associate($author);
$author->push();

Because the association is done exactly, when you call associate method. And all it does is this:

$child->foreign_key = $parent->primary_key;

So in the situation above, primary_key is null, because $author has not been saved yet.


Next, while push is not said to create the associations in the docs, it may make such impression and one might be tempted to do this:

$author = Author::first(); // existing parent
$books = Book::get(); // existing children collection

$author->books = $books;
$author->push();

However, this will not work as well. First off, Eloquent doesn't let you assign relation explicitly, like above, then, even if you do it properly, still the association will not be made:

$author = Author::first();
$books = Book::get(); 

$author->setRelation('books', $books);
$author->push();

This time, the relation was assigned properly, but still the association (assigning foreign keys) was not made. So despite both author and all the books will be saved/updated, they won't be associated at all.


That being said, you eihter need to associate the models by yourself and use push OR leverage Eloquent methods (createMany / saveMany):

Start with:

$author = Author::find($someId);
// delete existing books
$author->books()->delete();

1 then manually:

// for example:
$booksInput = Input::get('books');
  // validate etc
foreach ($booksInput as $bookArray)
{
  $book = new Book;
  // assign the value from, eg.
  $book->fill($bookArray);
  $book->author()->associate($author);
  // or set FK explicitly
  $book->author_id = $author->getKey();

  // add to the author's collection
  $author->books->add($book);
}

$author->push(); // saves author and each of the books in separate queries

2 or createMany:

$booksAsArrays = Input::get('books'); // array of arrays
// validation
$author->books()->createMany($booksAsArrays); // associate and save each book

3 or saveMany:

$booksAsModels = []; // array of Book models
$booksAsArrays = Input::get('books'); // array of arrays
// validation

foreach ($booksAsArrays as $bookArray)
{
  $booksAsModels[] = new Book($bookArray);
}
$author->books()->saveMany($booksAsModels); // associate and save each book

Upvotes: 8

xAoc
xAoc

Reputation: 3588

For create many:

$author->books()->createMany($relationsArray);

Firstly delete already stored relations, than save the new ones

Then

$author->books()->delete(); // or if you are using soft delete forceDelete()
$author->books()->createMany($relationsArray);

Upvotes: 0

Related Questions