Kiedy usuwam wiersz przy użyciu tej składni:
$user->delete();
Czy istnieje sposób na dołączenie jakiegoś wywołania zwrotnego, aby np. Robił to automatycznie:
$this->photo()->delete();
Najlepiej wewnątrz klasy model.
Uważam, że jest to doskonały przypadek użycia dla wydarzeń Eloquent ( http://laravel.com/docs/eloquent#model-events ). Możesz użyć zdarzenia „deleting”, aby wyczyścić:
class User extends Eloquent
{
public function photos()
{
return $this->has_many('Photo');
}
// this is a recommended way to declare event handlers
public static function boot() {
parent::boot();
static::deleting(function($user) { // before delete() method call this
$user->photos()->delete();
// do the rest of the cleanup...
});
}
}
Prawdopodobnie powinieneś również umieścić całość wewnątrz transakcji, aby zapewnić referencyjną integralność.
first()
do zapytania, aby uzyskać dostęp do zdarzenia modelu, np.User::where('id', '=', $id)->first()->delete();
Źródłoforeach($user->photos as $photo)
, a następnie$photo->delete()
upewnić się, że każde dziecko ma usunięte swoje dzieci na wszystkich poziomach, zamiast tylko jednego, jak to się dzieje z jakiegoś powodu.Photos
matags
i zrobisz to samo wPhotos
modelu (tj. Wdeleting
metodzie$photo->tags()->delete();
:), nigdy nie zostanie wyzwolony. Ale jeśli zrobięfor
pętlę i zrobię coś takiego,for($user->photos as $photo) { $photo->delete(); }
totags
również zostaną usunięte! tylko do Twojej wiadomościMożesz to ustawić w swoich migracjach:
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Źródło: http://laravel.com/docs/5.1/migrations#foreign-key-constraints
źródło
Możesz usunąć wszystkie powiązane zdjęcia przed faktycznym usunięciem użytkownika.
Mam nadzieję, że to pomoże.
źródło
$this->photos()->delete()
.photos()
Zwraca obiekt kreator zapytań.Relacja w modelu użytkownika:
Usuń rekord i powiązane:
źródło
Istnieją 3 sposoby rozwiązania tego problemu:
1. Używanie Eloquent Events On Model Boot (ref: https://laravel.com/docs/5.7/eloquent#events )
2. Korzystanie z Eloquent Event Observers (patrz: https://laravel.com/docs/5.7/eloquent#observers )
W swoim AppServiceProvider zarejestruj obserwatora w następujący sposób:
Następnie dodaj klasę Observer w następujący sposób:
3. Korzystanie z ograniczeń klucza obcego (patrz: https://laravel.com/docs/5.7/migrations#foreign-key-constraints )
źródło
Począwszy od Laravel 5.2, dokumentacja stwierdza, że tego typu programy obsługi zdarzeń powinny być zarejestrowane w AppServiceProvider:
Przypuszczam nawet, że przeniosę je do oddzielnych klas zamiast domknięć dla lepszej struktury aplikacji.
źródło
Eloquent::observe()
metoda jest również dostępna w wersji 5.2 i może być używana z AppServiceProvider.photos()
, musisz również zachować ostrożność - ten proces nie usunie wnuków, ponieważ nie ładujesz modeli. Będziesz musiał zapętlićphotos
(uwaga, niephotos()
) i uruchomićdelete()
na nich metodę jako modele, aby uruchomić zdarzenia związane z usuwaniem.Lepiej będzie, jeśli zmienisz tę
delete
metodę. W ten sposób możesz włączyć transakcje DB dodelete
samej metody. Jeśli korzystasz ze sposobu zdarzenia, będziesz musiał pokrywać wywołaniedelete
metody transakcją DB za każdym razem, gdy ją wywołasz.W Twoim
User
modelu.źródło
W moim przypadku było to całkiem proste, ponieważ moje tabele bazy danych to InnoDB z kluczami obcymi z Cascade on Delete.
Więc w tym przypadku, jeśli twoja tabela zdjęć zawiera odniesienie do klucza obcego dla użytkownika, to wszystko, co musisz zrobić, to usunąć hotel, a czyszczenie zostanie wykonane przez Bazę Danych, baza danych usunie wszystkie rekordy zdjęć z danych baza.
źródło
Iterowałbym przez kolekcję, odłączając wszystko przed usunięciem samego obiektu.
oto przykład:
Wiem, że to nie jest automatyczne, ale jest bardzo proste.
Innym prostym podejściem byłoby dostarczenie modelowi metody. Lubię to:
Następnie możesz po prostu zadzwonić tam, gdzie potrzebujesz:
źródło
Lub możesz to zrobić, jeśli chcesz, po prostu inna opcja:
Uwaga, jeśli nie używasz domyślnego połączenia laravel db, musisz wykonać następujące czynności:
źródło
Aby uszczegółowić wybraną odpowiedź, jeśli Twoje relacje mają również związki podrzędne, które należy usunąć, musisz najpierw pobrać wszystkie rekordy relacji podrzędnych, a następnie zadzwonić do
delete()
metodę, aby zdarzenia usuwania również zostały poprawnie .Możesz to łatwo zrobić z wiadomościami wyższego rzędu .
Możesz również poprawić wydajność, wysyłając zapytania tylko do kolumny ID relacji:
źródło
tak, ale jak @supersan stwierdził u góry w komentarzu, jeśli usuniesz () w QueryBuilder, zdarzenie modelu nie zostanie uruchomione, ponieważ nie ładujemy samego modelu, a następnie wywołujemy metodę delete () w tym modelu.
Zdarzenia są uruchamiane tylko wtedy, gdy używamy funkcji usuwania na wystąpieniu modelu.
Więc to powiedział:
aby usunąć tagi postów podczas usuwania użytkownika, musielibyśmy powtórzyć
$user->posts
i zadzwonić$post->delete()
foreach($user->posts as $post) { $post->delete(); }
-> to uruchomi zdarzenie usuwania w PostVS
$user->posts()->delete()
-> to nie uruchomi zdarzenia kasującego w poście, ponieważ tak naprawdę nie ładujemy Post Modelu (uruchamiamy tylko SQL typu:DELETE * from posts where user_id = $user->id
a zatem model Post nie jest nawet ładowany)źródło
Możesz użyć tej metody jako alternatywy.
To, co się stanie, to pobranie wszystkich tabel powiązanych z tabelą użytkowników i usunięcie powiązanych danych za pomocą zapętlenia
źródło