Die Laravel-Magie, die Sie kennen, wird jetzt auf Verknüpfungen angewendet.
Verknüpfungen sind in vielerlei Hinsicht sehr nützlich. Wenn Sie hier sind, kennen Sie sie höchstwahrscheinlich und nutzen sie. Eloquent ist sehr leistungsfähig, aber bei der Verwendung von Joins mangelt es ein wenig an der „Laravel-Methode“. Dieses Paket sorgt dafür, dass Ihre Verknüpfungen eher auf Laravel-Art erfolgen, mit weniger Code besser lesbar sind und gleichzeitig Implementierungsdetails an Stellen verbergen, an denen sie nicht offengelegt werden müssen.
Einige Dinge fehlen unserer Meinung nach bei der Verwendung von Verknüpfungen, bei denen es sich um sehr leistungsstarke Eloquent-Funktionen handelt:
Eine ausführlichere Erklärung zu den Problemen, die dieses Paket löst, können Sie in diesem Blogbeitrag lesen.
Sie können das Paket über Composer installieren:
composer require kirschbaum-development/eloquent-power-joins
Für Laravel-Versionen < 10 verwenden Sie die 3.*-Version. Für Laravel-Versionen < 8 verwenden Sie die 2.*-Version:
composer require kirschbaum-development/eloquent-power-joins:3. *
Dieses Paket bietet einige Funktionen.
Nehmen wir an, Sie haben ein User
mit einer hasMany
-Beziehung zum Post
Modell. Wenn Sie die Tabellen verbinden möchten, schreiben Sie normalerweise etwas wie:
User:: select ( ' users.* ' )-> join ( ' posts ' , ' posts.user_id ' , ' = ' , ' users.id ' );
Dieses Paket stellt Ihnen eine neue Methode joinRelationship()
zur Verfügung, die genau das Gleiche tut.
User:: joinRelationship ( ' posts ' );
Beide Optionen führen zu den gleichen Ergebnissen. In Bezug auf den Code haben Sie nicht so viel gespart, aber Sie verwenden jetzt die Beziehung zwischen den User
und Post
-Modellen, um die Tabellen zu verknüpfen. Das bedeutet, dass Sie jetzt verbergen, wie diese Beziehung hinter den Kulissen funktioniert (Details zur Implementierung). Sie müssen den Code auch nicht ändern, wenn sich der Beziehungstyp ändert. Sie haben jetzt einen besser lesbaren und weniger überwältigenden Code.
Besser wird es jedoch, wenn Sie verschachtelte Beziehungen verbinden müssen. Nehmen wir an, Sie haben auch eine hasMany
-Beziehung zwischen den Post
und Comment
Modellen und müssen diese Tabellen verknüpfen. Sie können einfach schreiben:
User:: joinRelationship ( ' posts.comments ' );
So viel besser, finden Sie nicht auch?! Sie können die Beziehungen je nach Bedarf auch left
oder right
verbinden.
User:: leftJoinRelationship ( ' posts.comments ' );
User:: rightJoinRelationship ( ' posts.comments ' );
Stellen wir uns vor, Sie haben ein Image
, das eine polymorphe Beziehung darstellt ( Post -> morphMany -> Image
). Neben dem regulären Join müssten Sie auch die Bedingung where imageable_type = Post::class
anwenden, sonst könnten Sie unübersichtliche Ergebnisse erhalten.
Es stellt sich heraus, dass Eloquent Power Joins diese Bedingung automatisch für Sie anwendet, wenn Sie einer polymorphen Beziehung beitreten. Sie müssen lediglich dieselbe Methode aufrufen.
Post:: joinRelationship ( ' images ' );
Sie können auch MorphTo-Beziehungen beitreten.
Image:: joinRelationship ( ' imageable ' , morphable: Post::class);
Hinweis: Beim Abfragen von Morph-zu-Beziehungen wird jeweils nur ein morphbarer Typ unterstützt.
Anwenden von Bedingungen und Rückrufen auf die Joins
Nehmen wir nun an, Sie möchten eine Bedingung auf die Verknüpfung anwenden, die Sie durchführen. Sie müssen lediglich einen Rückruf als zweiten Parameter an die Methode joinRelationship
übergeben.
User:: joinRelationship ( ' posts ' , fn ( $ join ) => $ join -> where ( ' posts.approved ' , true ))-> toSql ();
Sie können im Rückruf auch die Art der Verknüpfung angeben, die Sie durchführen möchten:
User:: joinRelationship ( ' posts ' , fn ( $ join ) => $ join -> left ());
Bei verschachtelten Aufrufen müssen Sie lediglich ein Array übergeben, das auf die Beziehungsnamen verweist.
User:: joinRelationship ( ' posts.comments ' , [
' posts ' => fn ( $ join ) => $ join -> where ( ' posts.published ' , true ),
' comments ' => fn ( $ join ) => $ join -> where ( ' comments.approved ' , true ),
]);
Für „gehört zu vielen“ -Aufrufen müssen Sie ein Array mit der Beziehung und dann ein Array mit den Tabellennamen übergeben.
User:: joinRelationship ( ' groups ' , [
' groups ' => [
' groups ' => function ( $ join ) {
// ...
},
// group_members is the intermediary table here
' group_members ' => fn ( $ join ) => $ join -> where ( ' group_members.active ' , true ),
]
]);
Wir halten dies für eine der nützlichsten Funktionen dieses Pakets. Nehmen wir an, Sie haben einen published
Bereich in Ihrem Post
Modell:
public function scopePublished ( $ query )
{
$ query -> where ( ' published ' , true );
}
Beim Verbinden von Beziehungen können Sie die Bereiche verwenden, die im zu verbindenden Modell definiert sind. Wie cool ist das?
User:: joinRelationship ( ' posts ' , function ( $ join ) {
// the $join instance here can access any of the scopes defined in Post
$ join -> published ();
});
Wenn Sie Modellbereiche innerhalb einer Join-Klausel verwenden, können Sie in Ihrem Bereich keinen Hinweis auf den Parameter $query
eingeben. Bedenken Sie außerdem, dass Sie sich in einem Join befinden und daher nur die von Joins unterstützten Bedingungen verwenden dürfen.
Manchmal müssen Sie Tabellenaliase für Ihre Verknüpfungen verwenden, weil Sie dieselbe Tabelle mehr als einmal verknüpfen. Eine Möglichkeit, dies zu erreichen, ist die Verwendung der Methode joinRelationshipUsingAlias
“.
Post:: joinRelationshipUsingAlias ( ' category.parent ' )-> get ();
Falls Sie den Namen des zu verwendenden Alias angeben müssen, können Sie dies auf zwei verschiedene Arten tun:
Post:: joinRelationshipUsingAlias ( ' category ' , ' category_alias ' )-> get ();
as
-Funktion innerhalb des Join-Rückrufs. Post:: joinRelationship ( ' category.parent ' , [
' category ' => fn ( $ join ) => $ join -> as ( ' category_alias ' ),
' parent ' => fn ( $ join ) => $ join -> as ( ' category_parent ' ),
])-> get ()
Für „gehört zu vielen“ oder „ hat viele durch “-Aufrufe müssen Sie ein Array mit der Beziehung und dann ein Array mit den Tabellennamen übergeben.
Group:: joinRelationship ( ' posts.user ' , [
' posts ' => [
' posts ' => fn ( $ join ) => $ join -> as ( ' posts_alias ' ),
' post_groups ' => fn ( $ join ) => $ join -> as ( ' post_groups_alias ' ),
],
])-> toSql ();
Beim Erstellen von Verknüpfungen kann die Verwendung select * from ...
gefährlich sein, da es zu Konflikten zwischen Feldern mit demselben Namen zwischen der übergeordneten Tabelle und den verknüpften Tabellen kommen kann. Denken Sie darüber nach: Wenn Sie die Methode joinRelationship
aufrufen, ohne zuvor bestimmte Spalten auszuwählen, wird Eloquent Power Joins diese automatisch für Sie einschließen. Schauen Sie sich zum Beispiel die folgenden Beispiele an:
User:: joinRelationship ( ' posts ' )-> toSql ();
// select users.* from users inner join posts on posts.user_id = users.id
Und wenn Sie die SELECT-Anweisung angeben:
User:: select ( ' users.id ' )-> joinRelationship ( ' posts ' )-> toSql ();
// select users.id from users inner join posts on posts.user_id = users.id
Wenn Sie Modelle verknüpfen, die das Merkmal SoftDeletes
verwenden, wird die folgende Bedingung automatisch auf alle Ihre Verknüpfungen angewendet:
and " users " . " deleted_at " is null
Falls Sie gelöschte Modelle einbeziehen möchten, können Sie die Methode ->withTrashed()
im Join-Callback aufrufen.
UserProfile:: joinRelationship ( ' users ' , fn ( $ join ) => $ join -> withTrashed ());
Sie können auch das onlyTrashed
-Modell aufrufen:
UserProfile:: joinRelationship ( ' users ' , ( $ join ) => $ join -> onlyTrashed ());
Wenn Ihre Beziehungsdefinitionen zusätzliche Bedingungen enthalten, werden diese automatisch für Sie angewendet.
class User extends Model
{
public function publishedPosts ()
{
return $ this -> hasMany (Post::class)-> published ();
}
}
Wenn Sie User::joinRelationship('publishedPosts')->get()
aufrufen, wird auch der zusätzliche veröffentlichte Bereich auf die Join-Klausel angewendet. Es würde ein SQL in etwa wie folgt erzeugen:
select users. * from users inner join posts on posts . user_id = posts . id and posts . published = 1
Wenn auf Ihr Modell globale Bereiche angewendet werden, können Sie die globalen Bereiche aktivieren, indem Sie die Methode withGlobalScopes
in Ihrer Join-Klausel wie folgt aufrufen:
UserProfile:: joinRelationship ( ' users ' , fn ( $ join ) => $ join -> withGlobalScopes ());
Allerdings gibt es hier ein Problem. Ihr globaler Bereich kann keinen Typhinweis auf die EloquentBuilder
Klasse im ersten Parameter der apply
-Methode enthalten, andernfalls erhalten Sie Fehler.
Das Abfragen einer Beziehung ist eine sehr leistungsstarke und praktische Funktion von Eloquent. Es wird jedoch die where exists
-Syntax verwendet, die nicht immer die beste und möglicherweise nicht die leistungsfähigere Wahl ist, je nachdem, wie viele Datensätze Sie haben oder wie die Struktur Ihrer Tabellen ist.
Dieses Paket implementiert die gleiche Funktionalität, verwendet jedoch anstelle der where exists
-Syntax Joins . Unten sehen Sie die Methoden, die dieses Paket implementiert, sowie das Laravel-Äquivalent.
Bitte beachten Sie, dass die Methoden zwar ähnlich sind, Sie bei der Verwendung von Joins jedoch je nach Kontext Ihrer Abfrage nicht immer die gleichen Ergebnisse erhalten. Sie sollten sich der Unterschiede zwischen der Abfrage der Daten mit where exists
und mit joins
bewusst sein.
Native Laravel-Methoden
User:: has ( ' posts ' );
User:: has ( ' posts.comments ' );
User:: has ( ' posts ' , ' > ' , 3 );
User:: whereHas ( ' posts ' , fn ( $ query ) => $ query -> where ( ' posts.published ' , true ));
User::whereHas( ' posts.comments ' , [ ' posts ' => fn ( $ query ) => $ query -> where ( ' posts.published ' , true ));
User:: doesntHave ( ' posts ' );
Paketäquivalent, aber mit Joins
User:: powerJoinHas ( ' posts ' );
User:: powerJoinHas ( ' posts.comments ' );
User:: powerJoinHas ( ' posts.comments ' , ' > ' , 3 );
User:: powerJoinWhereHas ( ' posts ' , function ( $ join ) {
$ join -> where ( ' posts.published ' , true );
});
User:: powerJoinDoesntHave ( ' posts ' );
Wenn Sie die Methode powerJoinWhereHas
mit Beziehungen verwenden, die mehr als eine Tabelle umfassen (Eins zu Viele, Viele zu Viele usw.), verwenden Sie die Array-Syntax, um den Rückruf zu übergeben:
User:: powerJoinWhereHas ( ' commentsThroughPosts ' , [
' comments ' => fn ( $ query ) => $ query -> where ( ' body ' , ' a ' )
])-> get ());
Mit der Methode orderByPowerJoins
können Sie Ihre Abfrageergebnisse auch anhand einer Spalte aus einer anderen Tabelle sortieren.
User:: orderByPowerJoins ( ' profile.city ' );
Wenn Sie einige Rohwerte für die Funktion „Ordnung nach“ übergeben müssen, können Sie wie folgt vorgehen:
User:: orderByPowerJoins ([ ' profile ' , DB :: raw ( ' concat(city, ", ", state) ' ]);
Diese Abfrage sortiert die Ergebnisse basierend auf der city
in der Tabelle user_profiles
. Sie können Ihre Ergebnisse auch nach Aggregationen sortieren ( COUNT
, SUM
, AVG
, MIN
oder MAX
).
Um beispielsweise Benutzer mit der höchsten Anzahl an Beiträgen zu sortieren, können Sie Folgendes tun:
$ users = User:: orderByPowerJoinsCount ( ' posts.id ' , ' desc ' )-> get ();
Oder um die Liste der Beiträge zu erhalten, deren Kommentare den höchsten Stimmendurchschnitt enthalten.
$ posts = Post:: orderByPowerJoinsAvg ( ' comments.votes ' , ' desc ' )-> get ();
Sie haben auch Methoden für SUM
, MIN
und MAX
:
Post:: orderByPowerJoinsSum ( ' comments.votes ' );
Post:: orderByPowerJoinsMin ( ' comments.votes ' );
Post:: orderByPowerJoinsMax ( ' comments.votes ' );
Wenn Sie beim Sortieren Linksverknüpfungen verwenden möchten, können Sie auch Folgendes tun:
Post:: orderByLeftPowerJoinsCount ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsAvg ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsSum ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsMin ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsMax ( ' comments.votes ' );
Weitere Informationen finden Sie unter BEITRAGEN.
Wenn Sie sicherheitsrelevante Probleme entdecken, senden Sie bitte eine E-Mail an [email protected], anstatt den Issue-Tracker zu verwenden.
Die Entwicklung dieses Pakets wird von der Kirschbaum Development Group gesponsert, einem entwicklerorientierten Unternehmen, das sich auf Problemlösung, Teambildung und Community konzentriert. Erfahren Sie mehr über uns oder kommen Sie zu uns!
Die MIT-Lizenz (MIT). Weitere Informationen finden Sie in der Lizenzdatei.