Uczymy się zapisywać notatki do autorów. Kontynuacja poprzednich lekcji w poprzednim projekcie. Do dzieła.
Ok, najpierw dodajemy z użyciem metody save, jak w relacji jeden do jednego:
Artisan::command('person-add-lorem {id}', function (int $id) {
$person = Person::findOrFail($id);
$note = new Note(["title" => "Lorem", "content" => "Lorem Ipsum"]);
$person->notes()->save($note);
$this->comment("note added");
});
Dla save nie robi różnicy, czy persom ma notes jako hasOne czy tak jak tutaj hasMany. Save zapisuje jedną i koniec.
Ok, teraz od drugiej strony z associate, tak samo jak robiliśmy w relacji jeden do jednego:
Artisan::command('person-assoc-lorem {id}', function (int $id) {
$person = Person::findOrFail($id);
$note = new Note(["title" => "Lorem", "content" => "Lorem Ipsum"]);
$note->author()->associate($person)->save();
$this->comment("note added");
});
Uwaga, nie zadziała. W kodzie jest pułapka. Laravel po nazwie metody (author) wnioskuje, że szukamy author_id, a takiej kolumny nie mamy, jest person_id zgodnie z Laravelowymi konwencjami nazewniczymi.
I co wtedy? Wystarczy podać nazwę kolumny w modelu jako opcjonalny argument:
class Note extends Model
{
use HasFactory;
use SoftDeletes;
protected $fillable = ['title', 'content'];
public function author(){
return $this->belongsTo(Person::class, "person_id");
}
}
Teraz wyraźnie zaznaczyliśmy, że choć metoda nazywa się author to kolumna, w której mamy zapisane numery id autorów nazywa się person_id. Teraz associate zadziała.
Ok, ale co nowego mamy w relacjach jeden do wielu? Po pierwsze saveMany:
Artisan::command('person-save-many {id}', function (int $id) {
$person = Person::findOrFail($id);
$person->notes()->saveMany([
new Note(["title" => "Lorem", "content" => "Lorem Ipsum"]),
new Note(["title" => "Lorem2", "content" => "Lorem Ipsum 2"]),
new Note(["title" => "Lorem3", "content" => "Lorem Ipsum 3"]),
]);
$this->comment("notes added");
});
Denerwujące jest to ciągłe zapisywanie new Note, ale taka metoda istnieje, bo w realnych przypadkach często możemy dostać tablicę pełną obiektów, które trzeba zapisać.
Natomiast mamy jeszcze metodę createMany, do której przekazujemy tablicę tablic z atrybutami określonymi w fillable:
Artisan::command('person-create-many {id}', function (int $id) {
$person = Person::findOrFail($id);
$person->notes()->createMany([
["title" => "Lorem 4", "content" => "Lorem Ipsum"],
["title" => "Lorem 5", "content" => "Lorem Ipsum"]
]);
$this->comment("notes added");
});
Ok, czy mamy jeszcze coś ciekawego? Warto odwiedzić dokumentację Laravela. Po pierwsze, mamy te metody:
$user = User::find(1);
$user->posts()->createQuietly([
'title' => 'Post title.',
]);
$user->posts()->createManyQuietly([
['title' => 'First post.'],
['title' => 'Second post.'],
]);
O eventach dopiero sobie powiemy, ale tak, mamy tutaj tworzenie relacji „po cichu”, bez triggerowania eventów i observerów. Co jeszcze?
Takie coś zwane protected $touches:
class Comment extends Model
{
/**
* All of the relationships to be touched.
*
* @var array
*/
protected $touches = ['post'];
/**
* Get the post that the comment belongs to.
*/
public function post(): BelongsTo
{
return $this->belongsTo(Post::class);
}
}
Chodzi o to, aby update na modelu w relacji BelongsTo zrobił update na timestap updated_at modelu rodzica.