[增添]添加了datasource的setting数据库以及默认值
This commit is contained in:
351
vendor/kirschbaum-development/eloquent-power-joins/README.md
vendored
Normal file
351
vendor/kirschbaum-development/eloquent-power-joins/README.md
vendored
Normal file
@@ -0,0 +1,351 @@
|
||||

|
||||
|
||||

|
||||
[](https://github.com/kirschbaum-development/eloquent-power-joins/actions/workflows/ci.yaml)
|
||||
[](LICENSE.md)
|
||||
[](https://packagist.org/packages/kirschbaum-development/eloquent-power-joins)
|
||||
[](https://packagist.org/packages/kirschbaum-development/eloquent-power-joins)
|
||||
|
||||
The Laravel magic you know, now applied to joins.
|
||||
|
||||
Joins are very useful in a lot of ways. If you are here, you most likely know about and use them. Eloquent is very powerful, but it lacks a bit of the "Laravel way" when using joins. This package make your joins in a more Laravel way, with more readable with less code while hiding implementation details from places they don't need to be exposed.
|
||||
|
||||
A few things we consider is missing when using joins which are very powerful Eloquent features:
|
||||
|
||||
* Ability to use relationship definitions to make joins;
|
||||
* Ability to use model scopes inside different contexts;
|
||||
* Ability to query relationship existence using joins instead of where exists;
|
||||
* Ability to easily sort results based on columns or aggregations from related tables;
|
||||
|
||||
You can read a more detailed explanation on the problems this package solves on [this blog post](https://kirschbaumdevelopment.com/news-articles/adding-some-laravel-magic-to-your-eloquent-joins).
|
||||
|
||||
## Installation
|
||||
|
||||
You can install the package via composer:
|
||||
|
||||
```bash
|
||||
composer require kirschbaum-development/eloquent-power-joins
|
||||
```
|
||||
|
||||
For Laravel versions < 8, use the 2.* version:
|
||||
|
||||
```bash
|
||||
composer require kirschbaum-development/eloquent-power-joins:2.*
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
This package provides a few features.
|
||||
|
||||
### 1 - Join Relationship
|
||||
|
||||
Let's say you have a `User` model with a `hasMany` relationship to the `Post` model. If you want to join the tables, you would usually write something like:
|
||||
|
||||
```php
|
||||
User::select('users.*')->join('posts', 'posts.user_id', '=', 'users.id');
|
||||
```
|
||||
|
||||
This package provides you with a new `joinRelationship()` method, which does the exact same thing.
|
||||
|
||||
```php
|
||||
User::joinRelationship('posts');
|
||||
```
|
||||
|
||||
Both options produce the same results. In terms of code, you didn't save THAT much, but you are now using the relationship between the `User` and the `Post` models to join the tables. This means that you are now hiding how this relationship works behind the scenes (implementation details). You also don't need to change the code if the relationship type changes. You now have more readable and less overwhelming code.
|
||||
|
||||
But, **it gets better** when you need to **join nested relationships**. Let's assume you also have a `hasMany` relationship between the `Post` and `Comment` models and you need to join these tables, you can simply write:
|
||||
|
||||
```php
|
||||
User::joinRelationship('posts.comments');
|
||||
```
|
||||
|
||||
So much better, wouldn't you agree?! You can also `left` or `right` join the relationships as needed.
|
||||
|
||||
```php
|
||||
User::leftJoinRelationship('posts.comments');
|
||||
User::rightJoinRelationship('posts.comments');
|
||||
```
|
||||
|
||||
#### Joining polymorphic relationships
|
||||
|
||||
Let's imagine, you have a `Image` model that is a polymorphic relationship (`Post -> morphMany -> Image`). Besides the regular join, you would also need to apply the `where imageable_type = Post::class` condition, otherwise you could get messy results.
|
||||
|
||||
Turns out, if you join a polymorphic relationship, Eloquent Power Joins automatically applies this condition for you. You simply need to call the same method.
|
||||
|
||||
```php
|
||||
Post::joinRelationship('images');
|
||||
```
|
||||
|
||||
You can also join MorphTo relationships.
|
||||
|
||||
```php
|
||||
Image::joinRelationship('imageable', morphable: Post::class);
|
||||
```
|
||||
|
||||
Note: Querying morph to relationships only supports one morphable type at a time.
|
||||
|
||||
**Applying conditions & callbacks to the joins**
|
||||
|
||||
Now, let's say you want to apply a condition to the join you are making. You simply need to pass a callback as the second parameter to the `joinRelationship` method.
|
||||
|
||||
```php
|
||||
User::joinRelationship('posts', fn ($join) => $join->where('posts.approved', true))->toSql();
|
||||
```
|
||||
|
||||
For **nested calls**, you simply need to pass an array referencing the relationship names.
|
||||
|
||||
```php
|
||||
User::joinRelationship('posts.comments', [
|
||||
'posts' => fn ($join) => $join->where('posts.published', true),
|
||||
'comments' => fn ($join) => $join->where('comments.approved', true),
|
||||
]);
|
||||
```
|
||||
|
||||
For **belongs to many** calls, you need to pass an array with the relationship, and then an array with the table names.
|
||||
|
||||
```php
|
||||
User::joinRelationship('groups', [
|
||||
'groups' => [
|
||||
'groups' => function ($join) {
|
||||
// ...
|
||||
},
|
||||
// group_members is the intermediary table here
|
||||
'group_members' => fn ($join) => $join->where('group_members.active', true),
|
||||
]
|
||||
]);
|
||||
```
|
||||
|
||||
#### Using model scopes inside the join callbacks 🤯
|
||||
|
||||
We consider this one of the most useful features of this package. Let's say, you have a `published` scope on your `Post` model:
|
||||
|
||||
```php
|
||||
public function scopePublished($query)
|
||||
{
|
||||
$query->where('published', true);
|
||||
}
|
||||
```
|
||||
|
||||
When joining relationships, you **can** use the scopes defined in the model being joined. How cool is this?
|
||||
|
||||
```php
|
||||
User::joinRelationship('posts', function ($join) {
|
||||
// the $join instance here can access any of the scopes defined in Post 🤯
|
||||
$join->published();
|
||||
});
|
||||
```
|
||||
|
||||
When using model scopes inside a join clause, you **can't** type hint the `$query` parameter in your scope. Also, keep in mind you are inside a join, so you are limited to use only conditions supported by joins.
|
||||
|
||||
#### Using aliases
|
||||
|
||||
Sometimes, you are going to need to use table aliases on your joins because you are joining the same table more than once. One option to accomplish this is to use the `joinRelationshipUsingAlias` method.
|
||||
|
||||
```php
|
||||
Post::joinRelationshipUsingAlias('category.parent')->get();
|
||||
```
|
||||
|
||||
In case you need to specify the name of the alias which is going to be used, you can do in two different ways:
|
||||
|
||||
1. Passing a string as the second parameter (this won't work for nested joins):
|
||||
|
||||
```php
|
||||
Post::joinRelationshipUsingAlias('category', 'category_alias')->get();
|
||||
```
|
||||
|
||||
2. Calling the `as` function inside the join callback.
|
||||
|
||||
```php
|
||||
Post::joinRelationship('category.parent', [
|
||||
'category' => fn ($join) => $join->as('category_alias'),
|
||||
'parent' => fn ($join) => $join->as('category_parent'),
|
||||
])->get()
|
||||
```
|
||||
|
||||
For *belongs to many* or *has many through* calls, you need to pass an array with the relationship, and then an array with the table names.
|
||||
|
||||
```php
|
||||
Group::joinRelationship('posts.user', [
|
||||
'posts' => [
|
||||
'posts' => fn ($join) => $join->as('posts_alias'),
|
||||
'post_groups' => fn ($join) => $join->as('post_groups_alias'),
|
||||
],
|
||||
])->toSql();
|
||||
```
|
||||
|
||||
#### Select * from table
|
||||
|
||||
When making joins, using `select * from ...` can be dangerous as fields with the same name between the parent and the joined tables could conflict. Thinking on that, if you call the `joinRelationship` method without previously selecting any specific columns, Eloquent Power Joins will automatically include that for you. For instance, take a look at the following examples:
|
||||
|
||||
```php
|
||||
User::joinRelationship('posts')->toSql();
|
||||
// select users.* from users inner join posts on posts.user_id = users.id
|
||||
```
|
||||
|
||||
And, if you specify the select statement:
|
||||
|
||||
```php
|
||||
User::select('users.id')->joinRelationship('posts')->toSql();
|
||||
// select users.id from users inner join posts on posts.user_id = users.id
|
||||
```
|
||||
|
||||
#### Soft deletes
|
||||
|
||||
When joining any models which uses the `SoftDeletes` trait, the following condition will be also automatically applied to all your joins:
|
||||
|
||||
```sql
|
||||
and "users"."deleted_at" is null
|
||||
```
|
||||
|
||||
In case you want to include trashed models, you can call the `->withTrashed()` method in the join callback.
|
||||
|
||||
```php
|
||||
UserProfile::joinRelationship('users', fn ($join) => $join->withTrashed());
|
||||
```
|
||||
|
||||
You can also call the `onlyTrashed` model as well:
|
||||
|
||||
```php
|
||||
UserProfile::joinRelationship('users', ($join) => $join->onlyTrashed());
|
||||
```
|
||||
|
||||
#### Extra conditions defined in relationships
|
||||
|
||||
If you have extra conditions in your relationship definitions, they will get automatically applied for you.
|
||||
|
||||
```php
|
||||
class User extends Model
|
||||
{
|
||||
public function publishedPosts()
|
||||
{
|
||||
return $this->hasMany(Post::class)->published();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you call `User::joinRelationship('publishedPosts')->get()`, it will also apply the additional published scope to the join clause. It would produce an SQL more or less like this:
|
||||
|
||||
```sql
|
||||
select users.* from users inner join posts on posts.user_id = posts.id and posts.published = 1
|
||||
```
|
||||
|
||||
#### Global Scopes
|
||||
|
||||
If your model have global scopes applied to it, you can enable the global scopes by calling the `withGlobalScopes` method in your join clause, like this:
|
||||
|
||||
```php
|
||||
UserProfile::joinRelationship('users', fn ($join) => $join->withGlobalScopes());
|
||||
```
|
||||
|
||||
There's, though, a gotcha here. Your global scope **cannot** type-hint the `Eloquent\Builder` class in the first parameter of the `apply` method, otherwise you will get errors.
|
||||
|
||||
### 2 - Querying relationship existence (Using Joins)
|
||||
|
||||
[Querying relationship existence](https://laravel.com/docs/7.x/eloquent-relationships#querying-relationship-existence) is a very powerful and convenient feature of Eloquent. However, it uses the `where exists` syntax which is not always the best and may not be the more performant choice, depending on how many records you have or the structure of your tables.
|
||||
|
||||
This packages implements the same functionality, but instead of using the `where exists` syntax, it uses **joins**. Below, you can see the methods this package implements and also the Laravel equivalent.
|
||||
|
||||
Please note that although the methods are similar, you will not always get the same results when using joins, depending on the context of your query. You should be aware of the differences between querying the data with `where exists` vs `joins`.
|
||||
|
||||
**Laravel Native Methods**
|
||||
|
||||
``` php
|
||||
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');
|
||||
```
|
||||
|
||||
**Package equivalent, but using joins**
|
||||
|
||||
```php
|
||||
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');
|
||||
```
|
||||
|
||||
When using the `powerJoinWhereHas` method with relationships that involves more than 1 table (One to Many, Many to Many, etc.), use the array syntax to pass the callback:
|
||||
|
||||
```php
|
||||
User::powerJoinWhereHas('commentsThroughPosts', [
|
||||
'comments' => fn ($query) => $query->where('body', 'a')
|
||||
])->get());
|
||||
```
|
||||
|
||||
### 3 - Order by
|
||||
|
||||
You can also sort your query results using a column from another table using the `orderByPowerJoins` method.
|
||||
|
||||
```php
|
||||
User::orderByPowerJoins('profile.city');
|
||||
```
|
||||
|
||||
If you need to pass some raw values for the order by function, you can do like this:
|
||||
|
||||
```php
|
||||
User::orderByPowerJoins(['profile', DB::raw('concat(city, ", ", state)']);
|
||||
```
|
||||
|
||||
This query will sort the results based on the `city` column on the `user_profiles` table. You can also sort your results by aggregations (`COUNT`, `SUM`, `AVG`, `MIN` or `MAX`).
|
||||
|
||||
For instance, to sort users with the highest number of posts, you can do this:
|
||||
|
||||
```php
|
||||
$users = User::orderByPowerJoinsCount('posts.id', 'desc')->get();
|
||||
```
|
||||
|
||||
Or, to get the list of posts where the comments contain the highest average of votes.
|
||||
|
||||
```php
|
||||
$posts = Post::orderByPowerJoinsAvg('comments.votes', 'desc')->get();
|
||||
```
|
||||
|
||||
You also have methods for `SUM`, `MIN` and `MAX`:
|
||||
|
||||
```php
|
||||
Post::orderByPowerJoinsSum('comments.votes');
|
||||
Post::orderByPowerJoinsMin('comments.votes');
|
||||
Post::orderByPowerJoinsMax('comments.votes');
|
||||
```
|
||||
|
||||
In case you want to use left joins in sorting, you also can:
|
||||
|
||||
```php
|
||||
Post::orderByLeftPowerJoinsCount('comments.votes');
|
||||
Post::orderByLeftPowerJoinsAvg('comments.votes');
|
||||
Post::orderByLeftPowerJoinsSum('comments.votes');
|
||||
Post::orderByLeftPowerJoinsMin('comments.votes');
|
||||
Post::orderByLeftPowerJoinsMax('comments.votes');
|
||||
```
|
||||
|
||||
***
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
|
||||
|
||||
### Security
|
||||
|
||||
If you discover any security related issues, please email luis@kirschbaumdevelopment.com or nathan@kirschbaumdevelopment.com instead of using the issue tracker.
|
||||
|
||||
## Credits
|
||||
|
||||
- [Luis Dalmolin](https://github.com/luisdalmolin)
|
||||
|
||||
## Sponsorship
|
||||
|
||||
Development of this package is sponsored by Kirschbaum Development Group, a developer driven company focused on problem solving, team building, and community. Learn more [about us](https://kirschbaumdevelopment.com) or [join us](https://careers.kirschbaumdevelopment.com)!
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
|
||||
## Laravel Package Boilerplate
|
||||
|
||||
This package was generated using the [Laravel Package Boilerplate](https://laravelpackageboilerplate.com).
|
||||
Reference in New Issue
Block a user