여러분이 알고 있는 Laravel의 마법이 이제 조인에 적용됩니다.
조인은 여러 면에서 매우 유용합니다. 당신이 여기에 있다면 아마도 그것에 대해 알고 사용할 것입니다. Eloquent는 매우 강력하지만 조인을 사용할 때 "Laravel 방식"이 약간 부족합니다. 이 패키지는 노출할 필요가 없는 위치에서 구현 세부 정보를 숨기면서 더 적은 코드로 더 읽기 쉽게 조인을 Laravel 방식으로 만듭니다.
매우 강력한 Eloquent 기능인 조인을 사용할 때 우리가 고려하는 몇 가지 사항이 누락되었다고 생각합니다:
이 패키지가 해결하는 문제에 대한 자세한 설명은 이 블로그 게시물에서 읽을 수 있습니다.
작곡가를 통해 패키지를 설치할 수 있습니다.
composer require kirschbaum-development/eloquent-power-joins
Laravel 버전이 10 미만인 경우 3.* 버전을 사용하세요. Laravel 버전이 8 미만인 경우 2.* 버전을 사용하세요.
composer require kirschbaum-development/eloquent-power-joins:3. *
이 패키지는 몇 가지 기능을 제공합니다.
Post
모델과 hasMany
관계를 가진 User
모델이 있다고 가정해 보겠습니다. 테이블을 조인하려면 일반적으로 다음과 같이 작성합니다.
User:: select ( ' users.* ' )-> join ( ' posts ' , ' posts.user_id ' , ' = ' , ' users.id ' );
이 패키지는 완전히 동일한 작업을 수행하는 새로운 joinRelationship()
메서드를 제공합니다.
User:: joinRelationship ( ' posts ' );
두 옵션 모두 동일한 결과를 생성합니다. 코드 측면에서는 그다지 절약되지 않았지만 이제 User
와 Post
모델 간의 관계를 사용하여 테이블을 조인하고 있습니다. 이는 이제 이 관계가 배후에서 어떻게 작동하는지(구현 세부정보) 숨기고 있음을 의미합니다. 또한 관계 유형이 변경되는 경우에도 코드를 변경할 필요가 없습니다. 이제 더 읽기 쉽고 덜 부담스러운 코드를 갖게 되었습니다.
그러나 중첩된 관계에 합류 해야 할 때 더 좋습니다 . Post
와 Comment
모델 사이에 hasMany
관계가 있고 이러한 테이블을 조인해야 한다고 가정하면 다음과 같이 간단히 작성할 수 있습니다.
User:: joinRelationship ( ' posts.comments ' );
훨씬 나아졌죠? 동의하지 않나요?! 필요에 따라 관계에 left
또는 right
참여할 수도 있습니다.
User:: leftJoinRelationship ( ' posts.comments ' );
User:: rightJoinRelationship ( ' posts.comments ' );
상상해 봅시다. 다형성 관계인 Image
모델이 있습니다( Post -> morphMany -> Image
). 일반 조인 외에도 where imageable_type = Post::class
조건을 적용해야 합니다. 그렇지 않으면 지저분한 결과를 얻을 수 있습니다.
다형성 관계에 참여하면 Eloquent Power Joins가 자동으로 이 조건을 적용합니다. 동일한 메소드를 호출하기만 하면 됩니다.
Post:: joinRelationship ( ' images ' );
MorphTo 관계에 참여할 수도 있습니다.
Image:: joinRelationship ( ' imageable ' , morphable: Post::class);
참고: 관계에 대한 변형 쿼리는 한 번에 하나의 변형 가능 유형만 지원합니다.
조인에 조건 및 콜백 적용
이제 작성 중인 조인에 조건을 적용한다고 가정해 보겠습니다. 콜백을 joinRelationship
메소드의 두 번째 매개변수로 전달하기만 하면 됩니다.
User:: joinRelationship ( ' posts ' , fn ( $ join ) => $ join -> where ( ' posts.approved ' , true ))-> toSql ();
콜백에서 만들고 싶은 조인 유형을 지정할 수도 있습니다.
User:: joinRelationship ( ' posts ' , fn ( $ join ) => $ join -> left ());
중첩 호출 의 경우 관계 이름을 참조하는 배열을 전달하기만 하면 됩니다.
User:: joinRelationship ( ' posts.comments ' , [
' posts ' => fn ( $ join ) => $ join -> where ( ' posts.published ' , true ),
' comments ' => fn ( $ join ) => $ join -> where ( ' comments.approved ' , true ),
]);
여러 호출에 속 하려면 관계가 포함된 배열을 전달한 다음 테이블 이름이 포함된 배열을 전달해야 합니다.
User:: joinRelationship ( ' groups ' , [
' groups ' => [
' groups ' => function ( $ join ) {
// ...
},
// group_members is the intermediary table here
' group_members ' => fn ( $ join ) => $ join -> where ( ' group_members.active ' , true ),
]
]);
우리는 이것이 이 패키지의 가장 유용한 기능 중 하나라고 생각합니다. Post
모델에 published
범위가 있다고 가정해 보겠습니다.
public function scopePublished ( $ query )
{
$ query -> where ( ' published ' , true );
}
관계를 조인할 때 조인되는 모델에 정의된 범위를 사용할 수 있습니다. 얼마나 멋진가요?
User:: joinRelationship ( ' posts ' , function ( $ join ) {
// the $join instance here can access any of the scopes defined in Post
$ join -> published ();
});
조인 절 내에서 모델 범위를 사용하는 경우 범위의 $query
매개변수에 힌트를 입력 할 수 없습니다 . 또한 조인 내부에 있으므로 조인에서 지원하는 조건만 사용할 수 있다는 점을 기억하세요.
동일한 테이블을 두 번 이상 조인하기 때문에 조인 시 테이블 별칭을 사용해야 하는 경우도 있습니다. 이를 수행하는 한 가지 옵션은 joinRelationshipUsingAlias
메소드를 사용하는 것입니다.
Post:: joinRelationshipUsingAlias ( ' category.parent ' )-> get ();
사용할 별칭의 이름을 지정해야 하는 경우 다음 두 가지 방법으로 수행할 수 있습니다.
Post:: joinRelationshipUsingAlias ( ' category ' , ' category_alias ' )-> get ();
as
함수를 호출합니다. Post:: joinRelationship ( ' category.parent ' , [
' category ' => fn ( $ join ) => $ join -> as ( ' category_alias ' ),
' parent ' => fn ( $ join ) => $ join -> as ( ' category_parent ' ),
])-> get ()
호출을 통해 다수에 속 하거나 다수가 있는 경우 관계가 포함된 배열을 전달한 다음 테이블 이름이 포함된 배열을 전달해야 합니다.
Group:: joinRelationship ( ' posts.user ' , [
' posts ' => [
' posts ' => fn ( $ join ) => $ join -> as ( ' posts_alias ' ),
' post_groups ' => fn ( $ join ) => $ join -> as ( ' post_groups_alias ' ),
],
])-> toSql ();
조인을 할 때 select * from ...
사용하면 상위 테이블과 조인된 테이블 사이에 이름이 같은 필드가 충돌할 수 있으므로 위험할 수 있습니다. 생각해 보면, 이전에 특정 열을 선택하지 않고 joinRelationship
메소드를 호출하면 Eloquent Power Joins가 자동으로 해당 열을 포함합니다. 예를 들어, 다음 예를 살펴보십시오.
User:: joinRelationship ( ' posts ' )-> toSql ();
// select users.* from users inner join posts on posts.user_id = users.id
그리고 select 문을 지정하는 경우:
User:: select ( ' users.id ' )-> joinRelationship ( ' posts ' )-> toSql ();
// select users.id from users inner join posts on posts.user_id = users.id
SoftDeletes
특성을 사용하는 모델에 조인할 때 다음 조건도 모든 조인에 자동으로 적용됩니다.
and " users " . " deleted_at " is null
폐기된 모델을 포함하려는 경우 조인 콜백에서 ->withTrashed()
메서드를 호출할 수 있습니다.
UserProfile:: joinRelationship ( ' users ' , fn ( $ join ) => $ join -> withTrashed ());
onlyTrashed
모델을 호출할 수도 있습니다:
UserProfile:: joinRelationship ( ' users ' , ( $ join ) => $ join -> onlyTrashed ());
관계 정의에 추가 조건이 있는 경우 해당 조건이 자동으로 적용됩니다.
class User extends Model
{
public function publishedPosts ()
{
return $ this -> hasMany (Post::class)-> published ();
}
}
User::joinRelationship('publishedPosts')->get()
호출하면 조인 절에 추가 게시 범위도 적용됩니다. 대략 다음과 같은 SQL이 생성됩니다.
select users. * from users inner join posts on posts . user_id = posts . id and posts . published = 1
모델에 전역 범위가 적용된 경우 다음과 같이 조인 절에서 withGlobalScopes
메서드를 호출하여 전역 범위를 활성화할 수 있습니다.
UserProfile:: joinRelationship ( ' users ' , fn ( $ join ) => $ join -> withGlobalScopes ());
하지만 여기에 문제가 있습니다. 전역 범위는 apply
메소드의 첫 번째 매개변수에서 EloquentBuilder
클래스를 유형 힌트 할 수 없습니다 . 그렇지 않으면 오류가 발생합니다.
관계 존재를 쿼리하는 것은 Eloquent의 매우 강력하고 편리한 기능입니다. 그러나 이는 where exists
을 사용하는데, 이는 보유하고 있는 레코드 수나 테이블 구조에 따라 항상 최선은 아니며 성능이 더 좋은 선택이 아닐 수도 있습니다.
이 패키지는 동일한 기능을 구현하지만 where exists
구문을 사용하는 대신 Joins 를 사용합니다. 아래에서 이 패키지가 구현하는 메서드와 Laravel에 해당하는 메서드를 볼 수 있습니다.
방법이 유사하더라도 조인을 사용할 때 쿼리 컨텍스트에 따라 항상 동일한 결과를 얻을 수는 없다는 점에 유의하세요. where exists
와 joins
사용하여 데이터를 쿼리하는 것의 차이점을 알고 있어야 합니다.
Laravel 네이티브 메소드
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 ' );
패키지는 동일하지만 조인을 사용함
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 ' );
2개 이상의 테이블(일대다, 다대다 등)이 포함된 관계에 powerJoinWhereHas
메서드를 사용하는 경우 배열 구문을 사용하여 콜백을 전달합니다.
User:: powerJoinWhereHas ( ' commentsThroughPosts ' , [
' comments ' => fn ( $ query ) => $ query -> where ( ' body ' , ' a ' )
])-> get ());
orderByPowerJoins
메서드를 사용하여 다른 테이블의 열을 사용하여 쿼리 결과를 정렬할 수도 있습니다.
User:: orderByPowerJoins ( ' profile.city ' );
함수별 정렬을 위해 일부 원시 값을 전달해야 하는 경우 다음과 같이 할 수 있습니다.
User:: orderByPowerJoins ([ ' profile ' , DB :: raw ( ' concat(city, ", ", state) ' ]);
이 쿼리는 user_profiles
테이블의 city
열을 기준으로 결과를 정렬합니다. 집계( COUNT
, SUM
, AVG
, MIN
또는 MAX
)를 기준으로 결과를 정렬할 수도 있습니다.
예를 들어, 게시물 수가 가장 많은 사용자를 정렬하려면 다음을 수행할 수 있습니다.
$ users = User:: orderByPowerJoinsCount ( ' posts.id ' , ' desc ' )-> get ();
또는 댓글에 가장 높은 평균 득표수가 포함된 게시물 목록을 가져옵니다.
$ posts = Post:: orderByPowerJoinsAvg ( ' comments.votes ' , ' desc ' )-> get ();
SUM
, MIN
및 MAX
에 대한 메서드도 있습니다.
Post:: orderByPowerJoinsSum ( ' comments.votes ' );
Post:: orderByPowerJoinsMin ( ' comments.votes ' );
Post:: orderByPowerJoinsMax ( ' comments.votes ' );
정렬에 왼쪽 조인을 사용하려는 경우 다음을 수행할 수도 있습니다.
Post:: orderByLeftPowerJoinsCount ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsAvg ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsSum ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsMin ( ' comments.votes ' );
Post:: orderByLeftPowerJoinsMax ( ' comments.votes ' );
자세한 내용은 CONTRIBUTING을 참조하세요.
보안 관련 문제를 발견한 경우 문제 추적기를 사용하는 대신 [email protected]으로 이메일을 보내주십시오.
이 패키지의 개발은 문제 해결, 팀 구축 및 커뮤니티에 중점을 둔 개발자 중심 회사인 Kirschbaum Development Group의 후원을 받습니다. 우리에 대해 자세히 알아보거나 우리와 함께하세요!
MIT 라이센스(MIT). 자세한 내용은 라이센스 파일을 참조하십시오.