[增添]添加了datasource的setting数据库以及默认值
This commit is contained in:
78
vendor/kirschbaum-development/eloquent-power-joins/.github/workflows/ci.yaml
vendored
Normal file
78
vendor/kirschbaum-development/eloquent-power-joins/.github/workflows/ci.yaml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
name: run-tests
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
php: [8.0, 8.1, 8.2, 8.3]
|
||||
laravel: [8.*, 9.*, 10.*, 11.*]
|
||||
include:
|
||||
- laravel: 11.*
|
||||
testbench: 9.*-dev
|
||||
- laravel: 10.*
|
||||
testbench: 8.*
|
||||
- laravel: 9.*
|
||||
testbench: 7.*
|
||||
- laravel: 8.*
|
||||
testbench: 6.*
|
||||
exclude:
|
||||
- laravel: 11.*
|
||||
php: 8.0
|
||||
- laravel: 11.*
|
||||
php: 8.1
|
||||
- laravel: 10.*
|
||||
php: 8.0
|
||||
- laravel: 8.*
|
||||
php: 8.1
|
||||
- laravel: 8.*
|
||||
php: 8.2
|
||||
- laravel: 9.*
|
||||
php: 8.2
|
||||
- laravel: 8.*
|
||||
php: 8.3
|
||||
- laravel: 9.*
|
||||
php: 8.3
|
||||
|
||||
|
||||
name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install SQLite 3
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install sqlite3
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.composer/cache/files
|
||||
key: dependencies-pw-v2-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: curl, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, iconv
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
composer --version
|
||||
composer require "laravel/framework:${{ matrix.laravel }}" --no-interaction --no-update
|
||||
composer require "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update --dev
|
||||
composer update --prefer-dist --no-interaction --no-suggest --dev
|
||||
composer dump
|
||||
|
||||
- name: Execute tests
|
||||
run: vendor/bin/phpunit
|
||||
100
vendor/kirschbaum-development/eloquent-power-joins/.php_cs
vendored
Normal file
100
vendor/kirschbaum-development/eloquent-power-joins/.php_cs
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->in(__DIR__ . '/src')
|
||||
->name('*.php')
|
||||
->ignoreDotFiles(true)
|
||||
->ignoreVCS(true);
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setFinder($finder)
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'phpdoc_no_empty_return' => false,
|
||||
'phpdoc_var_annotation_correct_order' => true,
|
||||
'array_syntax' => [
|
||||
'syntax' => 'short',
|
||||
],
|
||||
'no_singleline_whitespace_before_semicolons' => true,
|
||||
'no_extra_blank_lines' => [
|
||||
'break', 'case', 'continue', 'curly_brace_block', 'default',
|
||||
'extra', 'parenthesis_brace_block', 'return',
|
||||
'square_brace_block', 'switch', 'throw', 'use', 'useTrait', 'use_trait',
|
||||
],
|
||||
'cast_spaces' => [
|
||||
'space' => 'single',
|
||||
],
|
||||
'single_quote' => true,
|
||||
'lowercase_cast' => true,
|
||||
'lowercase_static_reference' => true,
|
||||
'no_empty_phpdoc' => true,
|
||||
'no_empty_comment' => true,
|
||||
'array_indentation' => true,
|
||||
'short_scalar_cast' => true,
|
||||
'no_mixed_echo_print' => [
|
||||
'use' => 'echo',
|
||||
],
|
||||
'ordered_imports' => [
|
||||
'sort_algorithm' => 'alpha',
|
||||
],
|
||||
'no_unused_imports' => true,
|
||||
'binary_operator_spaces' => [
|
||||
'default' => 'single_space',
|
||||
],
|
||||
'no_empty_statement' => true,
|
||||
'unary_operator_spaces' => true, // $number ++ becomes $number++
|
||||
'hash_to_slash_comment' => true, // # becomes //
|
||||
'standardize_not_equals' => true, // <> becomes !=
|
||||
'native_function_casing' => true,
|
||||
'ternary_operator_spaces' => true,
|
||||
'ternary_to_null_coalescing' => true,
|
||||
'declare_equal_normalize' => [
|
||||
'space' => 'single',
|
||||
],
|
||||
'function_typehint_space' => true,
|
||||
'no_leading_import_slash' => true,
|
||||
'blank_line_before_statement' => [
|
||||
'statements' => [
|
||||
'break', 'case', 'continue',
|
||||
'declare', 'default', 'die',
|
||||
'do', 'exit', 'for', 'foreach',
|
||||
'goto', 'if', 'include',
|
||||
'include_once', 'require', 'require_once',
|
||||
'return', 'switch', 'throw', 'try', 'while', 'yield',
|
||||
],
|
||||
],
|
||||
'combine_consecutive_unsets' => true,
|
||||
'method_chaining_indentation' => true,
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
'blank_line_after_opening_tag' => true,
|
||||
'no_trailing_comma_in_list_call' => true,
|
||||
'list_syntax' => ['syntax' => 'short'],
|
||||
// public function getTimezoneAttribute( ? Banana $value) becomes public function getTimezoneAttribute(?Banana $value)
|
||||
'compact_nullable_typehint' => true,
|
||||
'explicit_string_variable' => true,
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
'trailing_comma_in_multiline_array' => true,
|
||||
'not_operator_with_successor_space' => true,
|
||||
'object_operator_without_whitespace' => true,
|
||||
'single_blank_line_before_namespace' => true,
|
||||
'no_blank_lines_after_class_opening' => true,
|
||||
'no_blank_lines_after_phpdoc' => true,
|
||||
'no_whitespace_before_comma_in_array' => true,
|
||||
'no_trailing_comma_in_singleline_array' => true,
|
||||
'multiline_whitespace_before_semicolons' => [
|
||||
'strategy' => 'no_multi_line',
|
||||
],
|
||||
'no_multiline_whitespace_around_double_arrow' => true,
|
||||
'no_useless_return' => true,
|
||||
'phpdoc_add_missing_param_annotation' => false,
|
||||
'phpdoc_order' => true,
|
||||
'phpdoc_scalar' => false,
|
||||
'phpdoc_separation' => false,
|
||||
'phpdoc_single_line_var_spacing' => false,
|
||||
'single_trait_insert_per_statement' => true,
|
||||
'return_type_declaration' => [
|
||||
'space_before' => 'none',
|
||||
],
|
||||
])
|
||||
->setLineEnding("\n");
|
||||
27
vendor/kirschbaum-development/eloquent-power-joins/CHANGELOG.md
vendored
Normal file
27
vendor/kirschbaum-development/eloquent-power-joins/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to `eloquent-power-joins` will be documented in this file.
|
||||
|
||||
## 2.2.2 - 2020-10
|
||||
- Fixed the ability to pass nested closures in join callbacks when using aliases;
|
||||
|
||||
## 2.2.1 - 2020-10
|
||||
- Fixed nested conditions in relationship definitions;
|
||||
|
||||
## 2.1.0 - 2020-09
|
||||
- Added the ability to include trashed models in join clauses;
|
||||
|
||||
## 2.0.0 - 2020-09
|
||||
- Introduced trait that has to be used by models;
|
||||
- Automatically applying extra relationship conditions;
|
||||
- Ability to order by using left joins;
|
||||
- Laravel 8 support;
|
||||
_ Lots of bugfixes;
|
||||
- Changed the method signature for sorting;
|
||||
- Changed the method signature for querying relationship existence;
|
||||
|
||||
## 1.1.0
|
||||
- Added the ability to use table aliases;
|
||||
|
||||
## 1.0.0
|
||||
- Initial release;
|
||||
55
vendor/kirschbaum-development/eloquent-power-joins/CONTRIBUTING.md
vendored
Normal file
55
vendor/kirschbaum-development/eloquent-power-joins/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Contributing
|
||||
|
||||
Contributions are **welcome** and will be fully **credited**.
|
||||
|
||||
Please read and understand the contribution guide before creating an issue or pull request.
|
||||
|
||||
## Etiquette
|
||||
|
||||
This project is open source, and as such, the maintainers give their free time to build and maintain the source code
|
||||
held within. They make the code freely available in the hope that it will be of use to other developers. It would be
|
||||
extremely unfair for them to suffer abuse or anger for their hard work.
|
||||
|
||||
Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the
|
||||
world that developers are civilized and selfless people.
|
||||
|
||||
It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
|
||||
quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.
|
||||
|
||||
## Viability
|
||||
|
||||
When requesting or submitting new features, first consider whether it might be useful to others. Open
|
||||
source projects are used by many developers, who may have entirely different needs to your own. Think about
|
||||
whether or not your feature is likely to be used by other users of the project.
|
||||
|
||||
## Procedure
|
||||
|
||||
Before filing an issue:
|
||||
|
||||
- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
|
||||
- Check to make sure your feature suggestion isn't already present within the project.
|
||||
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
|
||||
- Check the pull requests tab to ensure that the feature isn't already in progress.
|
||||
|
||||
Before submitting a pull request:
|
||||
|
||||
- Check the codebase to ensure that your feature doesn't already exist.
|
||||
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
|
||||
|
||||
## Requirements
|
||||
|
||||
If the project maintainer has any additional requirements, you will find them listed here.
|
||||
|
||||
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer).
|
||||
|
||||
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
|
||||
|
||||
- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
|
||||
|
||||
- **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option.
|
||||
|
||||
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
|
||||
|
||||
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting.
|
||||
|
||||
**Happy coding**!
|
||||
21
vendor/kirschbaum-development/eloquent-power-joins/LICENSE.md
vendored
Normal file
21
vendor/kirschbaum-development/eloquent-power-joins/LICENSE.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Luis Dalmolin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
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).
|
||||
55
vendor/kirschbaum-development/eloquent-power-joins/composer.json
vendored
Normal file
55
vendor/kirschbaum-development/eloquent-power-joins/composer.json
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "kirschbaum-development/eloquent-power-joins",
|
||||
"description": "The Laravel magic applied to joins.",
|
||||
"keywords": [
|
||||
"laravel",
|
||||
"eloquent",
|
||||
"mysql",
|
||||
"join"
|
||||
],
|
||||
"homepage": "https://github.com/kirschbaum-development/eloquent-power-joins",
|
||||
"license": "MIT",
|
||||
"type": "library",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Luis Dalmolin",
|
||||
"email": "luis.nh@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"illuminate/support": "^8.0|^9.0|^10.0|^11.0",
|
||||
"illuminate/database": "^8.0|^9.0|^10.0|^11.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/legacy-factories": "^1.0@dev",
|
||||
"orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0",
|
||||
"phpunit/phpunit": "^8.0|^9.0|^10.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Kirschbaum\\PowerJoins\\": "src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Kirschbaum\\PowerJoins\\Tests\\": "tests"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit",
|
||||
"test-coverage": "vendor/bin/phpunit --coverage-html coverage"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Kirschbaum\\PowerJoins\\PowerJoinsServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
8
vendor/kirschbaum-development/eloquent-power-joins/config/config.php
vendored
Normal file
8
vendor/kirschbaum-development/eloquent-power-joins/config/config.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* You can place your custom package configuration in here.
|
||||
*/
|
||||
return [
|
||||
//
|
||||
];
|
||||
BIN
vendor/kirschbaum-development/eloquent-power-joins/screenshots/eloquent-power-joins.jpg
vendored
Normal file
BIN
vendor/kirschbaum-development/eloquent-power-joins/screenshots/eloquent-power-joins.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
BIN
vendor/kirschbaum-development/eloquent-power-joins/screenshots/mysql-cpu-graph.png
vendored
Normal file
BIN
vendor/kirschbaum-development/eloquent-power-joins/screenshots/mysql-cpu-graph.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
26
vendor/kirschbaum-development/eloquent-power-joins/src/EloquentJoins.php
vendored
Normal file
26
vendor/kirschbaum-development/eloquent-power-joins/src/EloquentJoins.php
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentQueryBuilder;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Kirschbaum\PowerJoins\Mixins\JoinRelationship;
|
||||
use Kirschbaum\PowerJoins\Mixins\QueryBuilderExtraMethods;
|
||||
use Kirschbaum\PowerJoins\Mixins\QueryRelationshipExistence;
|
||||
use Kirschbaum\PowerJoins\Mixins\RelationshipsExtraMethods;
|
||||
|
||||
class EloquentJoins
|
||||
{
|
||||
/**
|
||||
* Register macros with Eloquent.
|
||||
*/
|
||||
public static function registerEloquentMacros()
|
||||
{
|
||||
EloquentQueryBuilder::mixin(new JoinRelationship);
|
||||
EloquentQueryBuilder::mixin(new QueryRelationshipExistence);
|
||||
QueryBuilder::mixin(new QueryBuilderExtraMethods);
|
||||
|
||||
Relation::mixin(new RelationshipsExtraMethods);
|
||||
}
|
||||
}
|
||||
23
vendor/kirschbaum-development/eloquent-power-joins/src/FakeJoinCallback.php
vendored
Normal file
23
vendor/kirschbaum-development/eloquent-power-joins/src/FakeJoinCallback.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
/**
|
||||
* @method static as(string $alias)
|
||||
*/
|
||||
class FakeJoinCallback extends PowerJoinClause
|
||||
{
|
||||
public function getAlias(): ?string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
if ($name === 'as') {
|
||||
$this->alias = $arguments[0];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
122
vendor/kirschbaum-development/eloquent-power-joins/src/JoinsHelper.php
vendored
Normal file
122
vendor/kirschbaum-development/eloquent-power-joins/src/JoinsHelper.php
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
class JoinsHelper
|
||||
{
|
||||
static array $instances = [];
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static function make(): static
|
||||
{
|
||||
$objects = array_map(fn ($object) => spl_object_id($object), func_get_args());
|
||||
|
||||
return static::$instances[implode('-', $objects)] ??= new self();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache to not join the same relationship twice.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $joinRelationshipCache = [];
|
||||
|
||||
/**
|
||||
* Join method map.
|
||||
*/
|
||||
public static $joinMethodsMap = [
|
||||
'join' => 'powerJoin',
|
||||
'leftJoin' => 'leftPowerJoin',
|
||||
'rightJoin' => 'rightPowerJoin',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Format the join callback.
|
||||
*
|
||||
* @param mixed $callback
|
||||
* @return mixed
|
||||
*/
|
||||
public function formatJoinCallback($callback)
|
||||
{
|
||||
if (is_string($callback)) {
|
||||
return function ($join) use ($callback) {
|
||||
$join->as($callback);
|
||||
};
|
||||
}
|
||||
|
||||
return $callback;
|
||||
}
|
||||
|
||||
public function generateAliasForRelationship(Relation $relation, string $relationName): array|string
|
||||
{
|
||||
if ($relation instanceof BelongsToMany || $relation instanceof HasManyThrough) {
|
||||
return [
|
||||
md5($relationName.'table1'.time()),
|
||||
md5($relationName.'table2'.time()),
|
||||
];
|
||||
}
|
||||
|
||||
return md5($relationName.time());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the join alias name from all the different options.
|
||||
*/
|
||||
public function getAliasName(bool $useAlias, Relation $relation, string $relationName, string $tableName, $callback): null|string|array
|
||||
{
|
||||
if ($callback) {
|
||||
if (is_callable($callback)) {
|
||||
$fakeJoinCallback = new FakeJoinCallback($relation->getBaseQuery(), 'inner', $tableName);
|
||||
$callback($fakeJoinCallback);
|
||||
|
||||
if ($fakeJoinCallback->getAlias()) {
|
||||
return $fakeJoinCallback->getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($callback) && isset($callback[$tableName])) {
|
||||
$fakeJoinCallback = new FakeJoinCallback($relation->getBaseQuery(), 'inner', $tableName);
|
||||
$callback[$tableName]($fakeJoinCallback);
|
||||
|
||||
if ($fakeJoinCallback->getAlias()) {
|
||||
return $fakeJoinCallback->getAlias();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $useAlias
|
||||
? $this->generateAliasForRelationship($relation, $relationName)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the relationship was already joined.
|
||||
*/
|
||||
public function relationshipAlreadyJoined($model, string $relation): bool
|
||||
{
|
||||
return isset($this->joinRelationshipCache[spl_object_id($model)][$relation]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the relationship as already joined.
|
||||
*/
|
||||
public function markRelationshipAsAlreadyJoined($model, string $relation): void
|
||||
{
|
||||
$this->joinRelationshipCache[spl_object_id($model)][$relation] = true;
|
||||
}
|
||||
|
||||
public function clear(): void
|
||||
{
|
||||
$this->joinRelationshipCache = [];
|
||||
}
|
||||
}
|
||||
560
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/JoinRelationship.php
vendored
Normal file
560
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/JoinRelationship.php
vendored
Normal file
@@ -0,0 +1,560 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins\Mixins;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
use Illuminate\Database\Query\Expression;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Kirschbaum\PowerJoins\JoinsHelper;
|
||||
use Kirschbaum\PowerJoins\PowerJoinClause;
|
||||
use Kirschbaum\PowerJoins\StaticCache;
|
||||
|
||||
/**
|
||||
* @mixin Builder
|
||||
* @method \Illuminate\Database\Eloquent\Model getModel()
|
||||
* @property \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
class JoinRelationship
|
||||
{
|
||||
/**
|
||||
* New clause for making joins, where we pass the model to the joiner class.
|
||||
*/
|
||||
public function powerJoin(): Closure
|
||||
{
|
||||
return function ($table, $first, $operator = null, $second = null, $type = 'inner', $where = false): static {
|
||||
$model = $operator instanceof Model ? $operator : null;
|
||||
$join = $this->newPowerJoinClause($this->query, $type, $table, $model);
|
||||
|
||||
// If the first "column" of the join is really a Closure instance the developer
|
||||
// is trying to build a join with a complex "on" clause containing more than
|
||||
// one condition, so we'll add the join and call a Closure with the query.
|
||||
if ($first instanceof Closure) {
|
||||
$first($join);
|
||||
|
||||
$this->query->joins[] = $join;
|
||||
|
||||
$this->query->addBinding($join->getBindings(), 'join');
|
||||
}
|
||||
|
||||
// If the column is simply a string, we can assume the join simply has a basic
|
||||
// "on" clause with a single condition. So we will just build the join with
|
||||
// this simple join clauses attached to it. There is not a join callback.
|
||||
else {
|
||||
$method = $where ? 'where' : 'on';
|
||||
|
||||
$this->query->joins[] = $join->$method($first, $operator, $second);
|
||||
|
||||
$this->query->addBinding($join->getBindings(), 'join');
|
||||
}
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* New clause for making joins, where we pass the model to the joiner class.
|
||||
*/
|
||||
public function leftPowerJoin(): Closure
|
||||
{
|
||||
return function ($table, $first, $operator = null, $second = null) {
|
||||
return $this->powerJoin($table, $first, $operator, $second, 'left');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* New clause for making joins, where we pass the model to the joiner class.
|
||||
*/
|
||||
public function rightPowerJoin(): Closure
|
||||
{
|
||||
return function ($table, $first, $operator = null, $second = null) {
|
||||
return $this->powerJoin($table, $first, $operator, $second, 'right');
|
||||
};
|
||||
}
|
||||
|
||||
public function newPowerJoinClause(): Closure
|
||||
{
|
||||
return function (QueryBuilder $parentQuery, $type, $table, Model $model = null) {
|
||||
return new PowerJoinClause($parentQuery, $type, $table, $model);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the relationship(s).
|
||||
*/
|
||||
public function joinRelationship(): Closure
|
||||
{
|
||||
return function (
|
||||
$relationName,
|
||||
$callback = null,
|
||||
$joinType = 'join',
|
||||
$useAlias = false,
|
||||
bool $disableExtraConditions = false,
|
||||
string $morphable = null
|
||||
) {
|
||||
$joinType = JoinsHelper::$joinMethodsMap[$joinType] ?? $joinType;
|
||||
$useAlias = is_string($callback) ? false : $useAlias;
|
||||
$joinHelper = JoinsHelper::make($this->getModel());
|
||||
$callback = $joinHelper->formatJoinCallback($callback);
|
||||
|
||||
$this->getQuery()->beforeQuery(function () use ($joinHelper) {
|
||||
$joinHelper->clear();
|
||||
});
|
||||
|
||||
if (is_null($this->getSelect())) {
|
||||
$this->select(sprintf('%s.*', $this->getModel()->getTable()));
|
||||
}
|
||||
|
||||
if (Str::contains($relationName, '.')) {
|
||||
$this->joinNestedRelationship($relationName, $callback, $joinType, $useAlias, $disableExtraConditions);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$relationCallback = $callback;
|
||||
if ($callback && is_array($callback) && isset($callback[$relationName]) && is_array($callback[$relationName])) {
|
||||
$relationCallback = $callback[$relationName];
|
||||
}
|
||||
|
||||
$relation = $this->getModel()->{$relationName}();
|
||||
$relationQuery = $relation->getQuery();
|
||||
$alias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relationQuery->getModel()->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
|
||||
if ($relation instanceof BelongsToMany && !is_array($alias)) {
|
||||
$extraAlias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relation->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
$alias = [$extraAlias, $alias];
|
||||
}
|
||||
|
||||
$aliasString = is_array($alias) ? implode('.', $alias) : $alias;
|
||||
$useAlias = $alias ? true : $useAlias;
|
||||
|
||||
$relationJoinCache = $alias
|
||||
? "{$aliasString}.{$relationQuery->getModel()->getTable()}.{$relationName}"
|
||||
: "{$relationQuery->getModel()->getTable()}.{$relationName}";
|
||||
|
||||
if ($joinHelper->relationshipAlreadyJoined($this->getModel(), $relationJoinCache)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($useAlias) {
|
||||
StaticCache::setTableAliasForModel($relation->getModel(), $alias);
|
||||
}
|
||||
|
||||
$joinHelper->markRelationshipAsAlreadyJoined($this->getModel(), $relationJoinCache);
|
||||
StaticCache::clear();
|
||||
|
||||
$relation->performJoinForEloquentPowerJoins(
|
||||
builder: $this,
|
||||
joinType: $joinType,
|
||||
callback: $relationCallback,
|
||||
alias: $alias,
|
||||
disableExtraConditions: $disableExtraConditions,
|
||||
morphable: $morphable,
|
||||
);
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Join the relationship(s) using table aliases.
|
||||
*/
|
||||
public function joinRelationshipUsingAlias(): Closure
|
||||
{
|
||||
return function ($relationName, $callback = null, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relationName, $callback, 'join', true, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Left join the relationship(s) using table aliases.
|
||||
*/
|
||||
public function leftJoinRelationshipUsingAlias(): Closure
|
||||
{
|
||||
return function ($relationName, $callback = null, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relationName, $callback, 'leftJoin', true, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Right join the relationship(s) using table aliases.
|
||||
*/
|
||||
public function rightJoinRelationshipUsingAlias(): Closure
|
||||
{
|
||||
return function ($relationName, $callback = null, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relationName, $callback, 'rightJoin', true, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function joinRelation(): Closure
|
||||
{
|
||||
return function (
|
||||
$relationName,
|
||||
$callback = null,
|
||||
$joinType = 'join',
|
||||
$useAlias = false,
|
||||
bool $disableExtraConditions = false
|
||||
) {
|
||||
return $this->joinRelationship($relationName, $callback, $joinType, $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function leftJoinRelationship(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'leftJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function leftJoinRelation(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'leftJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function rightJoinRelationship(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'rightJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
public function rightJoinRelation(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $useAlias = false, bool $disableExtraConditions = false) {
|
||||
return $this->joinRelationship($relation, $callback, 'rightJoin', $useAlias, $disableExtraConditions);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Join nested relationships.
|
||||
*/
|
||||
public function joinNestedRelationship(): Closure
|
||||
{
|
||||
return function (
|
||||
string $relationships,
|
||||
$callback = null,
|
||||
$joinType = 'join',
|
||||
$useAlias = false,
|
||||
bool $disableExtraConditions = false
|
||||
) {
|
||||
$relations = explode('.', $relationships);
|
||||
$joinHelper = JoinsHelper::make($this->getModel());
|
||||
/** @var Relation */
|
||||
$latestRelation = null;
|
||||
|
||||
$part = [];
|
||||
foreach ($relations as $relationName) {
|
||||
$part[] = $relationName;
|
||||
$fullRelationName = join(".", $part);
|
||||
|
||||
$currentModel = $latestRelation ? $latestRelation->getModel() : $this->getModel();
|
||||
$relation = $currentModel->{$relationName}();
|
||||
$relationCallback = null;
|
||||
|
||||
if ($callback && is_array($callback) && isset($callback[$relationName])) {
|
||||
$relationCallback = $callback[$relationName];
|
||||
}
|
||||
|
||||
if ($callback && is_array($callback) && isset($callback[$fullRelationName])) {
|
||||
$relationCallback = $callback[$fullRelationName];
|
||||
}
|
||||
|
||||
$alias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relation->getQuery()->getModel()->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
|
||||
if ($alias && $relation instanceof BelongsToMany && !is_array($alias)) {
|
||||
$extraAlias = $joinHelper->getAliasName(
|
||||
$useAlias,
|
||||
$relation,
|
||||
$relationName,
|
||||
$relation->getTable(),
|
||||
$relationCallback
|
||||
);
|
||||
|
||||
$alias = [$extraAlias, $alias];
|
||||
}
|
||||
|
||||
$aliasString = is_array($alias) ? implode('.', $alias) : $alias;
|
||||
$useAlias = $alias ? true : $useAlias;
|
||||
|
||||
if ($alias) {
|
||||
$relationJoinCache = $latestRelation
|
||||
? "{$aliasString}.{$relation->getQuery()->getModel()->getTable()}.{$latestRelation->getModel()->getTable()}.{$relationName}"
|
||||
: "{$aliasString}.{$relation->getQuery()->getModel()->getTable()}.{$relationName}";
|
||||
} else {
|
||||
$relationJoinCache = $latestRelation
|
||||
? "{$relation->getQuery()->getModel()->getTable()}.{$latestRelation->getModel()->getTable()}.{$relationName}"
|
||||
: "{$relation->getQuery()->getModel()->getTable()}.{$relationName}";
|
||||
}
|
||||
|
||||
if ($useAlias) {
|
||||
StaticCache::setTableAliasForModel($relation->getModel(), $alias);
|
||||
}
|
||||
|
||||
|
||||
if ($joinHelper->relationshipAlreadyJoined($this->getModel(), $relationJoinCache)) {
|
||||
$latestRelation = $relation;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$relation->performJoinForEloquentPowerJoins(
|
||||
$this,
|
||||
$joinType,
|
||||
$relationCallback,
|
||||
$alias,
|
||||
$disableExtraConditions
|
||||
);
|
||||
|
||||
$latestRelation = $relation;
|
||||
$joinHelper->markRelationshipAsAlreadyJoined($this->getModel(), $relationJoinCache);
|
||||
}
|
||||
|
||||
StaticCache::clear();
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by a field in the defined relationship.
|
||||
*/
|
||||
public function orderByPowerJoins(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc', $aggregation = null, $joinType = 'join') {
|
||||
if (is_array($sort)) {
|
||||
$relationships = explode('.', $sort[0]);
|
||||
$column = $sort[1];
|
||||
$latestRelationshipName = $relationships[count($relationships) - 1];
|
||||
} else {
|
||||
$relationships = explode('.', $sort);
|
||||
$column = array_pop($relationships);
|
||||
$latestRelationshipName = $relationships[count($relationships) - 1];
|
||||
}
|
||||
|
||||
$this->joinRelationship(implode('.', $relationships), null, $joinType);
|
||||
|
||||
$latestRelationshipModel = array_reduce($relationships, function ($model, $relationshipName) {
|
||||
return $model->$relationshipName()->getModel();
|
||||
}, $this->getModel());
|
||||
|
||||
if ($aggregation) {
|
||||
$aliasName = sprintf(
|
||||
'%s_%s_%s',
|
||||
$latestRelationshipModel->getTable(),
|
||||
$column,
|
||||
$aggregation
|
||||
);
|
||||
|
||||
$this->selectRaw(
|
||||
sprintf(
|
||||
'%s(%s.%s) as %s',
|
||||
$aggregation,
|
||||
$latestRelationshipModel->getTable(),
|
||||
$column,
|
||||
$aliasName
|
||||
)
|
||||
)
|
||||
->groupBy(sprintf('%s.%s', $this->getModel()->getTable(), $this->getModel()->getKeyName()))
|
||||
->orderBy(DB::raw(sprintf('%s', $aliasName)), $direction);
|
||||
} else {
|
||||
if ($column instanceof Expression) {
|
||||
$this->orderBy($column, $direction);
|
||||
} else {
|
||||
$this->orderBy(
|
||||
sprintf('%s.%s', $latestRelationshipModel->getTable(), $column),
|
||||
$direction
|
||||
);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoins(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, null, 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the COUNT aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsCount(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'COUNT');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsCount(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'COUNT', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the SUM aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsSum(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'SUM');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsSum(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'SUM', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the AVG aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsAvg(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'AVG');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsAvg(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'AVG', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the MIN aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsMin(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MIN');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsMin(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MIN', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by the MAX aggregation using joins.
|
||||
*/
|
||||
public function orderByPowerJoinsMax(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MAX');
|
||||
};
|
||||
}
|
||||
|
||||
public function orderByLeftPowerJoinsMax(): Closure
|
||||
{
|
||||
return function ($sort, $direction = 'asc') {
|
||||
return $this->orderByPowerJoins($sort, $direction, 'MAX', 'leftJoin');
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as Laravel 'has`, but using joins instead of where exists.
|
||||
*/
|
||||
public function powerJoinHas(): Closure
|
||||
{
|
||||
return function ($relation, $operator = '>=', $count = 1, $boolean = 'and', Closure|array $callback = null, string $morphable = null): static {
|
||||
if (is_null($this->getSelect())) {
|
||||
$this->select(sprintf('%s.*', $this->getModel()->getTable()));
|
||||
}
|
||||
|
||||
if (is_null($this->getGroupBy())) {
|
||||
$this->groupBy($this->getModel()->getQualifiedKeyName());
|
||||
}
|
||||
|
||||
if (is_string($relation)) {
|
||||
if (Str::contains($relation, '.')) {
|
||||
$this->hasNestedUsingJoins($relation, $operator, $count, 'and', $callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$relation = $this->getRelationWithoutConstraintsProxy($relation);
|
||||
}
|
||||
$relation->performJoinForEloquentPowerJoins($this, 'leftPowerJoin', $callback, morphable: $morphable);
|
||||
$relation->performHavingForEloquentPowerJoins($this, $operator, $count, morphable: $morphable);
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
public function hasNestedUsingJoins(): Closure
|
||||
{
|
||||
return function ($relations, $operator = '>=', $count = 1, $boolean = 'and', Closure|array $callback = null): static {
|
||||
$relations = explode('.', $relations);
|
||||
|
||||
/** @var Relation */
|
||||
$latestRelation = null;
|
||||
|
||||
foreach ($relations as $index => $relation) {
|
||||
$relationName = $relation;
|
||||
|
||||
if (!$latestRelation) {
|
||||
$relation = $this->getRelationWithoutConstraintsProxy($relation);
|
||||
} else {
|
||||
$relation = $latestRelation->getModel()->query()->getRelationWithoutConstraintsProxy($relation);
|
||||
}
|
||||
|
||||
$relation->performJoinForEloquentPowerJoins($this, 'leftPowerJoin', is_callable($callback) ? $callback : $callback[$relationName] ?? null);
|
||||
|
||||
if (count($relations) === ($index + 1)) {
|
||||
$relation->performHavingForEloquentPowerJoins($this, $operator, $count);
|
||||
}
|
||||
|
||||
$latestRelation = $relation;
|
||||
}
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
public function powerJoinDoesntHave(): Closure
|
||||
{
|
||||
return function ($relation, $boolean = 'and', Closure $callback = null) {
|
||||
return $this->powerJoinHas($relation, '<', 1, $boolean, $callback);
|
||||
};
|
||||
}
|
||||
|
||||
public function powerJoinWhereHas(): Closure
|
||||
{
|
||||
return function ($relation, $callback = null, $operator = '>=', $count = 1) {
|
||||
return $this->powerJoinHas($relation, $operator, $count, 'and', $callback);
|
||||
};
|
||||
}
|
||||
}
|
||||
20
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/QueryBuilderExtraMethods.php
vendored
Normal file
20
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/QueryBuilderExtraMethods.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins\Mixins;
|
||||
|
||||
class QueryBuilderExtraMethods
|
||||
{
|
||||
public function getGroupBy()
|
||||
{
|
||||
return function () {
|
||||
return $this->groups;
|
||||
};
|
||||
}
|
||||
|
||||
public function getSelect()
|
||||
{
|
||||
return function () {
|
||||
return $this->columns;
|
||||
};
|
||||
}
|
||||
}
|
||||
31
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/QueryRelationshipExistence.php
vendored
Normal file
31
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/QueryRelationshipExistence.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins\Mixins;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
class QueryRelationshipExistence
|
||||
{
|
||||
public function getGroupBy()
|
||||
{
|
||||
return function () {
|
||||
return $this->getQuery()->getGroupBy();
|
||||
};
|
||||
}
|
||||
|
||||
public function getSelect()
|
||||
{
|
||||
return function () {
|
||||
return $this->getQuery()->getSelect();
|
||||
};
|
||||
}
|
||||
|
||||
protected function getRelationWithoutConstraintsProxy()
|
||||
{
|
||||
return function ($relation) {
|
||||
return Relation::noConstraints(function () use ($relation) {
|
||||
return $this->getModel()->{$relation}();
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
538
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/RelationshipsExtraMethods.php
vendored
Normal file
538
vendor/kirschbaum-development/eloquent-power-joins/src/Mixins/RelationshipsExtraMethods.php
vendored
Normal file
@@ -0,0 +1,538 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins\Mixins;
|
||||
|
||||
use Stringable;
|
||||
use Illuminate\Support\Str;
|
||||
use Kirschbaum\PowerJoins\StaticCache;
|
||||
use Kirschbaum\PowerJoins\PowerJoinClause;
|
||||
use Kirschbaum\PowerJoins\Tests\Models\Post;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphOneOrMany;
|
||||
|
||||
/**
|
||||
* @method \Illuminate\Database\Eloquent\Model getModel()
|
||||
* @method string getTable()
|
||||
* @method string getForeignPivotKeyName()
|
||||
* @method string getRelatedPivotKeyName()
|
||||
* @method bool isOneOfMany()
|
||||
* @method \Illuminate\Database\Eloquent\Builder|void getOneOfManySubQuery()
|
||||
* @method \Illuminate\Database\Eloquent\Builder getQuery()
|
||||
* @method \Illuminate\Database\Eloquent\Model getThroughParent()
|
||||
* @method string getForeignKeyName()
|
||||
* @method string getMorphType()
|
||||
* @method string getMorphClass()
|
||||
* @method string getFirstKeyName()
|
||||
* @method string getQualifiedLocalKeyName()
|
||||
* @method string getExistenceCompareKey()
|
||||
* @mixin \Illuminate\Database\Eloquent\Relations\Relation
|
||||
* @mixin \Illuminate\Database\Eloquent\Relations\HasOneOrMany
|
||||
* @mixin \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
* @property \Illuminate\Database\Eloquent\Builder $query
|
||||
* @property \Illuminate\Database\Eloquent\Model $parent
|
||||
* @property \Illuminate\Database\Eloquent\Model $throughParent
|
||||
* @property string $foreignKey
|
||||
* @property string $parentKey
|
||||
* @property string $ownerKey
|
||||
* @property string $localKey
|
||||
* @property string $secondKey
|
||||
* @property string $secondLocalKey
|
||||
* @property \Illuminate\Database\Eloquent\Model $farParent
|
||||
*/
|
||||
class RelationshipsExtraMethods
|
||||
{
|
||||
/**
|
||||
* Perform the JOIN clause for eloquent power joins.
|
||||
*/
|
||||
public function performJoinForEloquentPowerJoins()
|
||||
{
|
||||
return function ($builder, $joinType = 'leftJoin', $callback = null, $alias = null, bool $disableExtraConditions = false, string $morphable = null) {
|
||||
return match (true) {
|
||||
$this instanceof MorphToMany => $this->performJoinForEloquentPowerJoinsForMorphToMany($builder, $joinType, $callback, $alias, $disableExtraConditions),
|
||||
$this instanceof BelongsToMany => $this->performJoinForEloquentPowerJoinsForBelongsToMany($builder, $joinType, $callback, $alias, $disableExtraConditions),
|
||||
$this instanceof MorphOneOrMany => $this->performJoinForEloquentPowerJoinsForMorph($builder, $joinType, $callback, $alias, $disableExtraConditions),
|
||||
$this instanceof HasMany || $this instanceof HasOne => $this->performJoinForEloquentPowerJoinsForHasMany($builder, $joinType, $callback, $alias, $disableExtraConditions),
|
||||
$this instanceof HasManyThrough => $this->performJoinForEloquentPowerJoinsForHasManyThrough($builder, $joinType, $callback, $alias, $disableExtraConditions),
|
||||
$this instanceof MorphTo => $this->performJoinForEloquentPowerJoinsForMorphTo($builder, $joinType, $callback, $alias, $disableExtraConditions, $morphable),
|
||||
default => $this->performJoinForEloquentPowerJoinsForBelongsTo($builder, $joinType, $callback, $alias, $disableExtraConditions),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for the BelongsTo (or similar) relationships.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForBelongsTo()
|
||||
{
|
||||
return function ($query, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false) {
|
||||
$joinedTable = $this->query->getModel()->getTable();
|
||||
$parentTable = StaticCache::getTableOrAliasForModel($this->parent);
|
||||
|
||||
$query->{$joinType}($joinedTable, function ($join) use ($callback, $joinedTable, $parentTable, $alias, $disableExtraConditions) {
|
||||
if ($alias) {
|
||||
$join->as($alias);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$parentTable}.{$this->foreignKey}",
|
||||
'=',
|
||||
"{$joinedTable}.{$this->ownerKey}"
|
||||
);
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($this->query->getModel())) {
|
||||
$join->whereNull("{$joinedTable}.{$this->query->getModel()->getDeletedAtColumn()}");
|
||||
}
|
||||
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
$callback($join);
|
||||
}
|
||||
}, $this->query->getModel());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for the BelongsToMany (or similar) relationships.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForBelongsToMany()
|
||||
{
|
||||
return function ($builder, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false) {
|
||||
[$alias1, $alias2] = $alias;
|
||||
|
||||
$joinedTable = $alias1 ?: $this->getTable();
|
||||
$parentTable = StaticCache::getTableOrAliasForModel($this->parent);
|
||||
|
||||
$builder->{$joinType}($this->getTable(), function ($join) use ($callback, $joinedTable, $parentTable, $alias1) {
|
||||
if ($alias1) {
|
||||
$join->as($alias1);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$joinedTable}.{$this->getForeignPivotKeyName()}",
|
||||
'=',
|
||||
"{$parentTable}.{$this->parentKey}"
|
||||
);
|
||||
|
||||
if (is_array($callback) && isset($callback[$this->getTable()])) {
|
||||
$callback[$this->getTable()]($join);
|
||||
}
|
||||
});
|
||||
|
||||
$builder->{$joinType}($this->getModel()->getTable(), function ($join) use ($callback, $joinedTable, $alias2, $disableExtraConditions) {
|
||||
if ($alias2) {
|
||||
$join->as($alias2);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$this->getModel()->getTable()}.{$this->getModel()->getKeyName()}",
|
||||
'=',
|
||||
"{$joinedTable}.{$this->getRelatedPivotKeyName()}"
|
||||
);
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($this->query->getModel())) {
|
||||
$join->whereNull($this->query->getModel()->getQualifiedDeletedAtColumn());
|
||||
}
|
||||
|
||||
// applying any extra conditions to the belongs to many relationship
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if (is_array($callback) && isset($callback[$this->getModel()->getTable()])) {
|
||||
$callback[$this->getModel()->getTable()]($join);
|
||||
}
|
||||
}, $this->getModel());
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for the MorphToMany (or similar) relationships.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForMorphToMany()
|
||||
{
|
||||
return function ($builder, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false) {
|
||||
[$alias1, $alias2] = $alias;
|
||||
|
||||
$joinedTable = $alias1 ?: $this->getTable();
|
||||
$parentTable = StaticCache::getTableOrAliasForModel($this->parent);
|
||||
|
||||
$builder->{$joinType}($this->getTable(), function ($join) use ($callback, $joinedTable, $parentTable, $alias1, $disableExtraConditions) {
|
||||
if ($alias1) {
|
||||
$join->as($alias1);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$joinedTable}.{$this->getForeignPivotKeyName()}",
|
||||
'=',
|
||||
"{$parentTable}.{$this->parentKey}"
|
||||
);
|
||||
|
||||
// applying any extra conditions to the belongs to many relationship
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if (is_array($callback) && isset($callback[$this->getTable()])) {
|
||||
$callback[$this->getTable()]($join);
|
||||
}
|
||||
});
|
||||
|
||||
$builder->{$joinType}($this->getModel()->getTable(), function ($join) use ($callback, $joinedTable, $alias2, $disableExtraConditions) {
|
||||
if ($alias2) {
|
||||
$join->as($alias2);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$this->getModel()->getTable()}.{$this->getModel()->getKeyName()}",
|
||||
'=',
|
||||
"{$joinedTable}.{$this->getRelatedPivotKeyName()}"
|
||||
);
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($this->query->getModel())) {
|
||||
$join->whereNull($this->query->getModel()->getQualifiedDeletedAtColumn());
|
||||
}
|
||||
|
||||
if (is_array($callback) && isset($callback[$this->getModel()->getTable()])) {
|
||||
$callback[$this->getModel()->getTable()]($join);
|
||||
}
|
||||
}, $this->getModel());
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for the Morph (or similar) relationships.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForMorph()
|
||||
{
|
||||
return function ($builder, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false) {
|
||||
$builder->{$joinType}($this->getModel()->getTable(), function ($join) use ($callback, $disableExtraConditions) {
|
||||
$join->on(
|
||||
"{$this->getModel()->getTable()}.{$this->getForeignKeyName()}",
|
||||
'=',
|
||||
"{$this->parent->getTable()}.{$this->localKey}"
|
||||
)->where("{$this->getModel()->getTable()}.{$this->getMorphType()}", '=', $this->getMorphClass());
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($this->query->getModel())) {
|
||||
$join->whereNull($this->query->getModel()->getQualifiedDeletedAtColumn());
|
||||
}
|
||||
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
$callback($join);
|
||||
}
|
||||
}, $this->getModel());
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for when calling the morphTo method from the morphable class.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForMorphTo()
|
||||
{
|
||||
return function ($builder, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false, string $morphable = null) {
|
||||
$modelInstance = new $morphable;
|
||||
|
||||
$builder->{$joinType}($modelInstance->getTable(), function ($join) use ($modelInstance, $callback, $disableExtraConditions) {
|
||||
$join->on(
|
||||
"{$this->getModel()->getTable()}.{$this->getForeignKeyName()}",
|
||||
'=',
|
||||
"{$modelInstance->getTable()}.{$modelInstance->getKeyName()}"
|
||||
)->where("{$this->getModel()->getTable()}.{$this->getMorphType()}", '=', $modelInstance->getMorphClass());
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($modelInstance)) {
|
||||
$join->whereNull($modelInstance->getQualifiedDeletedAtColumn());
|
||||
}
|
||||
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
$callback($join);
|
||||
}
|
||||
}, $modelInstance);
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for the HasMany (or similar) relationships.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForHasMany()
|
||||
{
|
||||
return function ($builder, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false) {
|
||||
$joinedTable = $alias ?: $this->query->getModel()->getTable();
|
||||
$parentTable = StaticCache::getTableOrAliasForModel($this->parent);
|
||||
$isOneOfMany = method_exists($this, 'isOneOfMany') ? $this->isOneOfMany() : false;
|
||||
|
||||
if ($isOneOfMany) {
|
||||
foreach ($this->getOneOfManySubQuery()->getQuery()->columns as $column) {
|
||||
$builder->addSelect($column);
|
||||
}
|
||||
|
||||
$builder->take(1);
|
||||
}
|
||||
|
||||
$builder->{$joinType}($this->query->getModel()->getTable(), function ($join) use ($callback, $joinedTable, $parentTable, $alias, $disableExtraConditions) {
|
||||
if ($alias) {
|
||||
$join->as($alias);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
$this->foreignKey,
|
||||
'=',
|
||||
"{$parentTable}.{$this->localKey}"
|
||||
);
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($this->query->getModel())) {
|
||||
$join->whereNull(
|
||||
"{$joinedTable}.{$this->query->getModel()->getDeletedAtColumn()}"
|
||||
);
|
||||
}
|
||||
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
$callback($join);
|
||||
}
|
||||
}, $this->query->getModel());
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the JOIN clause for the HasManyThrough relationships.
|
||||
*/
|
||||
protected function performJoinForEloquentPowerJoinsForHasManyThrough()
|
||||
{
|
||||
return function ($builder, $joinType, $callback = null, $alias = null, bool $disableExtraConditions = false) {
|
||||
[$alias1, $alias2] = $alias;
|
||||
$throughTable = $alias1 ?: $this->getThroughParent()->getTable();
|
||||
$farTable = $alias2 ?: $this->getModel()->getTable();
|
||||
|
||||
$builder->{$joinType}($this->getThroughParent()->getTable(), function (PowerJoinClause $join) use ($callback, $throughTable, $alias1, $disableExtraConditions) {
|
||||
if ($alias1) {
|
||||
$join->as($alias1);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$throughTable}.{$this->getFirstKeyName()}",
|
||||
'=',
|
||||
$this->getQualifiedLocalKeyName()
|
||||
);
|
||||
|
||||
if ($disableExtraConditions === false && $this->usesSoftDeletes($this->getThroughParent())) {
|
||||
$join->whereNull($this->getThroughParent()->getQualifiedDeletedAtColumn());
|
||||
}
|
||||
|
||||
if ($disableExtraConditions === false) {
|
||||
$this->applyExtraConditions($join);
|
||||
}
|
||||
|
||||
if (is_array($callback) && isset($callback[$this->getThroughParent()->getTable()])) {
|
||||
$callback[$this->getThroughParent()->getTable()]($join);
|
||||
}
|
||||
|
||||
if ($callback && is_callable($callback)) {
|
||||
$callback($join);
|
||||
}
|
||||
}, $this->getThroughParent());
|
||||
|
||||
$builder->{$joinType}($this->getModel()->getTable(), function (PowerJoinClause $join) use ($callback, $throughTable, $farTable, $alias1, $alias2) {
|
||||
if ($alias2) {
|
||||
$join->as($alias2);
|
||||
}
|
||||
|
||||
$join->on(
|
||||
"{$farTable}.{$this->secondKey}",
|
||||
'=',
|
||||
"{$throughTable}.{$this->secondLocalKey}"
|
||||
);
|
||||
|
||||
if ($this->usesSoftDeletes($this->getModel())) {
|
||||
$join->whereNull("{$farTable}.{$this->getModel()->getDeletedAtColumn()}");
|
||||
}
|
||||
|
||||
if (is_array($callback) && isset($callback[$this->getModel()->getTable()])) {
|
||||
$callback[$this->getModel()->getTable()]($join);
|
||||
}
|
||||
}, $this->getModel());
|
||||
|
||||
return $this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the "HAVING" clause for eloquent power joins.
|
||||
*/
|
||||
public function performHavingForEloquentPowerJoins()
|
||||
{
|
||||
return function ($builder, $operator, $count, string $morphable = null) {
|
||||
if ($morphable) {
|
||||
$modelInstance = new $morphable;
|
||||
|
||||
$builder
|
||||
->selectRaw(sprintf('count(%s) as %s_count', $modelInstance->getQualifiedKeyName(), Str::replace('.', '_', $modelInstance->getTable())))
|
||||
->havingRaw(sprintf('count(%s) %s %d', $modelInstance->getQualifiedKeyName(), $operator, $count));
|
||||
} else {
|
||||
$builder
|
||||
->selectRaw(sprintf('count(%s) as %s_count', $this->query->getModel()->getQualifiedKeyName(), Str::replace('.', '_', $this->query->getModel()->getTable())))
|
||||
->havingRaw(sprintf('count(%s) %s %d', $this->query->getModel()->getQualifiedKeyName(), $operator, $count));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the relationship model uses soft deletes.
|
||||
*/
|
||||
public function usesSoftDeletes()
|
||||
{
|
||||
return function ($model) {
|
||||
return in_array(SoftDeletes::class, class_uses_recursive($model));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the throughParent for the HasManyThrough relationship.
|
||||
*/
|
||||
public function getThroughParent()
|
||||
{
|
||||
return function () {
|
||||
return $this->throughParent;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the farParent for the HasManyThrough relationship.
|
||||
*/
|
||||
public function getFarParent()
|
||||
{
|
||||
return function () {
|
||||
return $this->farParent;
|
||||
};
|
||||
}
|
||||
|
||||
public function applyExtraConditions()
|
||||
{
|
||||
return function (PowerJoinClause $join) {
|
||||
foreach ($this->getQuery()->getQuery()->wheres as $condition) {
|
||||
if ($this->shouldNotApplyExtraCondition($condition)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($condition['type'], ['Basic', 'Null', 'NotNull', 'Nested'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$method = "apply{$condition['type']}Condition";
|
||||
$this->$method($join, $condition);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public function applyBasicCondition()
|
||||
{
|
||||
return function ($join, $condition) {
|
||||
$join->where($condition['column'], $condition['operator'], $condition['value'], $condition['boolean']);
|
||||
};
|
||||
}
|
||||
|
||||
public function applyNullCondition()
|
||||
{
|
||||
return function ($join, $condition) {
|
||||
$join->whereNull($condition['column'], $condition['boolean']);
|
||||
};
|
||||
}
|
||||
|
||||
public function applyNotNullCondition()
|
||||
{
|
||||
return function ($join, $condition) {
|
||||
$join->whereNotNull($condition['column'], $condition['boolean']);
|
||||
};
|
||||
}
|
||||
|
||||
public function applyNestedCondition()
|
||||
{
|
||||
return function ($join, $condition) {
|
||||
$join->where(function ($q) use ($condition) {
|
||||
foreach ($condition['query']->wheres as $condition) {
|
||||
$method = "apply{$condition['type']}Condition";
|
||||
$this->$method($q, $condition);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
public function shouldNotApplyExtraCondition()
|
||||
{
|
||||
return function ($condition) {
|
||||
if (isset($condition['column']) && Str::endsWith($condition['column'], '.')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! $key = $this->getPowerJoinExistenceCompareKey()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isset($condition['query'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($key)) {
|
||||
return in_array($condition['column'], $key);
|
||||
}
|
||||
|
||||
return $condition['column'] === $key;
|
||||
};
|
||||
}
|
||||
|
||||
public function getPowerJoinExistenceCompareKey()
|
||||
{
|
||||
return function () {
|
||||
if ($this instanceof MorphTo) {
|
||||
return [$this->getMorphType(), $this->getForeignKeyName()];
|
||||
}
|
||||
|
||||
if ($this instanceof BelongsTo) {
|
||||
return $this->getQualifiedOwnerKeyName();
|
||||
}
|
||||
|
||||
if ($this instanceof HasMany || $this instanceof HasOne) {
|
||||
return $this->getExistenceCompareKey();
|
||||
}
|
||||
|
||||
if ($this instanceof HasManyThrough) {
|
||||
return $this->getQualifiedFirstKeyName();
|
||||
}
|
||||
|
||||
if ($this instanceof BelongsToMany) {
|
||||
return $this->getExistenceCompareKey();
|
||||
}
|
||||
|
||||
if ($this instanceof MorphOneOrMany) {
|
||||
return [$this->getQualifiedMorphType(), $this->getExistenceCompareKey()];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
260
vendor/kirschbaum-development/eloquent-power-joins/src/PowerJoinClause.php
vendored
Normal file
260
vendor/kirschbaum-development/eloquent-power-joins/src/PowerJoinClause.php
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Str;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\SoftDeletingScope;
|
||||
|
||||
class PowerJoinClause extends JoinClause
|
||||
{
|
||||
/**
|
||||
* @var \Illuminate\Database\Eloquent\Model
|
||||
*/
|
||||
public $model;
|
||||
|
||||
/**
|
||||
* Table name backup in case an alias is being used.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $tableName;
|
||||
|
||||
/**
|
||||
* Alias name.
|
||||
*/
|
||||
public ?string $alias = null;
|
||||
|
||||
/**
|
||||
* Joined table alias name (mostly for belongs to many aliases).
|
||||
*/
|
||||
public ?string $joinedTableAlias = null;
|
||||
|
||||
/**
|
||||
* Create a new join clause instance.
|
||||
*/
|
||||
public function __construct(Builder $parentQuery, $type, string $table, Model $model = null)
|
||||
{
|
||||
parent::__construct($parentQuery, $type, $table);
|
||||
|
||||
$this->model = $model;
|
||||
$this->tableName = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alias to the table being joined.
|
||||
*/
|
||||
public function as(string $alias, ?string $joinedTableAlias = null): self
|
||||
{
|
||||
$this->alias = $alias;
|
||||
$this->joinedTableAlias = $joinedTableAlias;
|
||||
$this->table = sprintf('%s as %s', $this->table, $alias);
|
||||
$this->useTableAliasInConditions();
|
||||
|
||||
if ($this->model) {
|
||||
StaticCache::setTableAliasForModel($this->model, $alias);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function on($first, $operator = null, $second = null, $boolean = 'and'): self
|
||||
{
|
||||
parent::on($first, $operator, $second, $boolean);
|
||||
$this->useTableAliasInConditions();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getModel()
|
||||
{
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the global scopes to the joined query.
|
||||
*/
|
||||
public function withGlobalScopes(): self
|
||||
{
|
||||
if (! $this->model) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
foreach ($this->model->getGlobalScopes() as $scope) {
|
||||
if ($scope instanceof Closure) {
|
||||
$scope->call($this, $this);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($scope instanceof SoftDeletingScope) {
|
||||
continue;
|
||||
}
|
||||
|
||||
(new $scope())->apply($this, $this->model);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the table alias in the existing join conditions.
|
||||
*/
|
||||
protected function useTableAliasInConditions(): self
|
||||
{
|
||||
if (! $this->alias || ! $this->model) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->wheres = collect($this->wheres)->filter(function ($where) {
|
||||
return in_array($where['type'] ?? '', ['Column', 'Basic']);
|
||||
})->map(function ($where) {
|
||||
$key = $this->model->getKeyName();
|
||||
$table = $this->tableName;
|
||||
$replaceMethod = sprintf('useAliasInWhere%sType', ucfirst($where['type']));
|
||||
|
||||
return $this->{$replaceMethod}($where);
|
||||
})->toArray();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function useAliasInWhereColumnType(array $where): array
|
||||
{
|
||||
$key = $this->model->getKeyName();
|
||||
$table = $this->tableName;
|
||||
|
||||
// if it was already replaced, skip
|
||||
if (Str::startsWith($where['first'] . '.', $this->alias . '.') || Str::startsWith($where['second'] . '.', $this->alias . '.')) {
|
||||
return $where;
|
||||
}
|
||||
|
||||
if (Str::contains($where['first'], $table) && Str::contains($where['second'], $table)) {
|
||||
// if joining the same table, only replace the correct table.key pair
|
||||
$where['first'] = str_replace($table . '.' . $key, $this->alias . '.' . $key, $where['first']);
|
||||
$where['second'] = str_replace($table . '.' . $key, $this->alias . '.' . $key, $where['second']);
|
||||
} else {
|
||||
$where['first'] = str_replace($table . '.', $this->alias . '.', $where['first']);
|
||||
$where['second'] = str_replace($table . '.', $this->alias . '.', $where['second']);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
protected function useAliasInWhereBasicType(array $where): array
|
||||
{
|
||||
$table = $this->tableName;
|
||||
|
||||
if (Str::startsWith($where['column'] . '.', $this->alias . '.')) {
|
||||
return $where;
|
||||
}
|
||||
|
||||
if (Str::contains($where['column'], $table)) {
|
||||
// if joining the same table, only replace the correct table.key pair
|
||||
$where['column'] = str_replace($table . '.', $this->alias . '.', $where['column']);
|
||||
} else {
|
||||
$where['column'] = str_replace($table . '.', $this->alias . '.', $where['column']);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
public function whereNull($columns, $boolean = 'and', $not = false)
|
||||
{
|
||||
if ($this->alias && Str::contains($columns, $this->tableName)) {
|
||||
$columns = str_replace("{$this->tableName}.", "{$this->alias}.", $columns);
|
||||
}
|
||||
|
||||
return parent::whereNull($columns, $boolean, $not);
|
||||
}
|
||||
|
||||
public function newQuery(): self
|
||||
{
|
||||
return new static($this->newParentQuery(), $this->type, $this->table, $this->model); // <-- The model param is needed
|
||||
}
|
||||
|
||||
public function where($column, $operator = null, $value = null, $boolean = 'and'): self
|
||||
{
|
||||
if ($this->alias && is_string($column) && Str::contains($column, $this->tableName)) {
|
||||
$column = str_replace("{$this->tableName}.", "{$this->alias}.", $column);
|
||||
} elseif ($this->alias && ! is_callable($column)) {
|
||||
$column = $this->alias . '.' . $column;
|
||||
}
|
||||
|
||||
if (is_callable($column)) {
|
||||
$query = new self($this, $this->type, $this->table, $this->model);
|
||||
$column($query);
|
||||
return $this->addNestedWhereQuery($query);
|
||||
} else {
|
||||
return parent::where($column, $operator, $value, $boolean);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the soft delete condition in case the model implements soft deletes.
|
||||
*/
|
||||
public function withTrashed(): self
|
||||
{
|
||||
if (! $this->getModel() || ! in_array(SoftDeletes::class, class_uses_recursive($this->getModel()))) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->wheres = array_filter($this->wheres, function ($where) {
|
||||
if ($where['type'] === 'Null' && Str::contains($where['column'], $this->getModel()->getDeletedAtColumn())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the soft delete condition in case the model implements soft deletes.
|
||||
*/
|
||||
public function onlyTrashed(): self
|
||||
{
|
||||
if (! $this->getModel() || ! in_array(SoftDeletes::class, class_uses_recursive($this->getModel()))) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->wheres = array_map(function ($where) {
|
||||
if ($where['type'] === 'Null' && Str::contains($where['column'], $this->getModel()->getDeletedAtColumn())) {
|
||||
$where['type'] = 'NotNull';
|
||||
}
|
||||
|
||||
return $where;
|
||||
}, $this->wheres);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __call($name, $arguments)
|
||||
{
|
||||
$scope = 'scope' . ucfirst($name);
|
||||
|
||||
if (! $this->getModel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (method_exists($this->getModel(), $scope)) {
|
||||
return $this->getModel()->{$scope}($this, ...$arguments);
|
||||
} else {
|
||||
if (static::hasMacro($name)) {
|
||||
return $this->macroCall($name, $arguments);
|
||||
}
|
||||
|
||||
$eloquentBuilder = $this->getModel()->newEloquentBuilder($this);
|
||||
if (method_exists($eloquentBuilder, $name)) {
|
||||
return $eloquentBuilder->{$name}(...$arguments);
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Method %s does not exist in PowerJoinClause class', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
9
vendor/kirschbaum-development/eloquent-power-joins/src/PowerJoins.php
vendored
Normal file
9
vendor/kirschbaum-development/eloquent-power-joins/src/PowerJoins.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
|
||||
trait PowerJoins
|
||||
{
|
||||
//
|
||||
}
|
||||
23
vendor/kirschbaum-development/eloquent-power-joins/src/PowerJoinsServiceProvider.php
vendored
Normal file
23
vendor/kirschbaum-development/eloquent-power-joins/src/PowerJoinsServiceProvider.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class PowerJoinsServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap the application services.
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the application services.
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
EloquentJoins::registerEloquentMacros();
|
||||
}
|
||||
}
|
||||
29
vendor/kirschbaum-development/eloquent-power-joins/src/StaticCache.php
vendored
Normal file
29
vendor/kirschbaum-development/eloquent-power-joins/src/StaticCache.php
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Kirschbaum\PowerJoins;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class StaticCache
|
||||
{
|
||||
/**
|
||||
* Cache to not join the same relationship twice.
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public static array $powerJoinAliasesCache = [];
|
||||
|
||||
public static function getTableOrAliasForModel(Model $model): string
|
||||
{
|
||||
return static::$powerJoinAliasesCache[spl_object_id($model)] ?? $model->getTable();
|
||||
}
|
||||
|
||||
public static function setTableAliasForModel(Model $model, $alias): void
|
||||
{
|
||||
static::$powerJoinAliasesCache[spl_object_id($model)] = $alias;
|
||||
}
|
||||
|
||||
public static function clear(): void
|
||||
{
|
||||
static::$powerJoinAliasesCache = [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user