Repository: fico7489/laravel-eloquent-join
Branch: master
Commit: 847096fac908
Files: 60
Total size: 90.0 KB
Directory structure:
gitextract_4l8jykqq/
├── .github/
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .php_cs
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml
├── src/
│ ├── EloquentJoinBuilder.php
│ ├── Exceptions/
│ │ ├── InvalidAggregateMethod.php
│ │ ├── InvalidDirection.php
│ │ ├── InvalidRelation.php
│ │ ├── InvalidRelationClause.php
│ │ ├── InvalidRelationGlobalScope.php
│ │ └── InvalidRelationWhere.php
│ ├── Relations/
│ │ ├── BelongsToJoin.php
│ │ ├── HasManyJoin.php
│ │ └── HasOneJoin.php
│ └── Traits/
│ ├── EloquentJoin.php
│ ├── ExtendRelationsTrait.php
│ └── JoinRelationTrait.php
└── tests/
├── Models/
│ ├── BaseModel.php
│ ├── City.php
│ ├── Integration.php
│ ├── Key/
│ │ ├── Location.php
│ │ ├── Order.php
│ │ └── Seller.php
│ ├── Location.php
│ ├── LocationAddress.php
│ ├── LocationWithGlobalScope.php
│ ├── Order.php
│ ├── OrderItem.php
│ ├── Seller.php
│ ├── State.php
│ ├── User.php
│ └── ZipCode.php
├── Scope/
│ └── TestExceptionScope.php
├── ServiceProvider.php
├── TestCase.php
├── Tests/
│ ├── AggregateJoinTest.php
│ ├── AppendRelationsCountTest.php
│ ├── Clauses/
│ │ ├── JoinRelationsTest.php
│ │ ├── OrWhereInTest.php
│ │ ├── OrWhereNotInTest.php
│ │ ├── OrWhereTest.php
│ │ ├── OrderByTest.php
│ │ ├── WhereInTest.php
│ │ ├── WhereNotInTest.php
│ │ └── WhereTest.php
│ ├── ClosureOnRelationTest.php
│ ├── ClosureTest.php
│ ├── ExceptionTest.php
│ ├── JoinTypeTest.php
│ ├── KeysOwnerTest.php
│ ├── KeysTest.php
│ ├── OptionsTest.php
│ ├── Relations/
│ │ ├── BelongsToTest.php
│ │ ├── HasManyTest.php
│ │ └── HasOneTest.php
│ └── SoftDeleteTest.php
└── database/
└── migrations/
└── 2017_11_04_163552_create_database.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
pull_request:
push:
branches:
- master
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
php_version: [7.4, 8.2]
laravel_version: [8.*, 10.*, 11.*]
steps:
- name: Checkout commit
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php_version }}
- name: Validate composer.json
run: composer validate
- name: Run composer install
run: composer install --no-interaction --no-suggest
- name: Run find-and-replace to replace * with 0
uses: mad9000/actions-find-and-replace-string@1
id: laravel_version_cleaned
with:
source: ${{ matrix.laravel_version }}
find: '*'
replace: '0'
- name: Install Laravel
run: composer update --no-interaction illuminate/database:^${{ steps.laravel_version_cleaned.outputs.value }}
- name: Run PHPUnit
run: ./vendor/bin/phpunit
================================================
FILE: .gitignore
================================================
/vendor
/.idea
composer.lock
.php_cs.cache
.phpunit.result.cache
================================================
FILE: .php_cs
================================================
<?php
use PhpCsFixer\Config;
use PhpCsFixer\Finder;
/*
* Define folders to fix
*/
$finder = Finder::create()
->in([
__DIR__ .'/src',
__DIR__ .'/tests',
]);
;
/*
* Do the magic
*/
return Config::create()
->setUsingCache(false)
->setRules([
'@PSR2' => true,
'@Symfony' => true,
])
->setFinder($finder)
;
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Filip Horvat
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.
================================================
FILE: README.md
================================================

# Laravel Eloquent Join
This package introduces the join magic for eloquent models and relations.
## Introduction
Eloquent is a powerful ORM but its join capabilities are very poor.
#### First Eloquent Problem (sorting)
With laravel you can't perform sorting of the relationship fields without manually joining related table which is very awkward. Let me give you a few reasons why. If you have a table with **posts** and related **categories** your code might look like this:
```
$posts = Post::select('posts.*')
->join('categories', 'categories.id', '=', 'posts.category_id')
->groupBy('posts.id')
->where('categories.deleted_at', '=', null)
->orderBy('categories.name');
if(request()->get('date')){
$posts->where('posts.date', $date)
}
$posts = $posts->get();
```
1.The first problem is that you need to worry about select.
```
->select('posts.*')
```
Reason : without **select** id from the category can be selected and hydrated into the Post model.
2.The second problem is that you need to worry about **groupBy**.
->groupBy('posts.id');
Reason : if the relation is HasOne and there are more than one categories for the post, the query will return more rows for categories.
3.The third problem is that you need to change all other where clauses from :
```
->where('date', $date)
```
to
```
->where('posts.date', $date)
```
Reason : a **post** and **category** can have "date" attribute and in that case without selecting an attribute with table "ambiguous column" error will be thrown.
4.The fourth problem is that you are using table names(not models) and this is also bad and awkward.
```
->where('posts.date', $date)
```
5.The fifth problem is that you need to worry about soft deletes for joined tables. If the **category** is using SoftDeletes trait you must add :
```
->where('categories.deleted_at', '=', null)
```
This package will take care of all above problems for you.
Unlike **sorting**, you can perform **filtering** on the relationship fields without joining related tables, but this package will give you the ability to do this easier.
#### Second Eloquent Problem (subqueries)
With laravel you can perform where on the relationship attribute but laravel will generate subqueries which are more slower than joins.
With this package you will be available to perform where on the relationship with joins in an elegant way.
## Requirements
| Laravel Version | Package Tag | Supported | Development Branch
|-----------------|-------------|-----------| -----------|
| >= 5.5.0 | 4.* | yes | master
| < 5.5.0 | - | no | -
Package is also tested for SQLite, MySql and PostgreSql
## Installation & setup
1.Install package with composer
```
composer require fico7489/laravel-eloquent-join
```
With this statement, a composer will install highest available package version for your current laravel version.
2.Use Fico7489\Laravel\EloquentJoin\Traits\EloquentJoinTrait trait in your base model or only in particular models.
```
...
use Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin;
use Illuminate\Database\Eloquent\Model;
abstract class BaseModel extends Model
{
use EloquentJoin;
...
```
3.IMPORTANT
For **MySql** make sure that **strict** configuration is set to **false**
config/database.php
```
'mysql' => [
...
'strict' => false,
...
```
and that's it, you are ready to go.
## Options
Options can be set in the model :
```
class Seller extends BaseModel
{
protected $useTableAlias = false;
protected $appendRelationsCount = false;
protected $leftJoin = false;
protected $aggregateMethod = 'MAX';
```
or on query :
```
Order::setUseTableAlias(true)->get();
Order::setAppendRelationsCount(true)->get();
Order::setLeftJoin(true)->get();
Order::setAggregateMethod(true)->get();
```
#### **useTableAlias**
Should we use an alias for joined tables (default = false)
With **true** query will look like this :
```
select "sellers".* from "sellers"
left join "locations" as "5b5c093d2e00f"
...
```
With **false** query will look like this :
```
select "sellers".*
from "sellers"
left join "locations"
...
```
Alias is a randomly generated string.
#### **appendRelationsCount**
Should we automatically append relation count field to results (default = false)
With **true** query will look like this :
```
select "sellers".*, count(locations.id) AS locations_count
from "sellers"
left join "locations" as "5b5c093d2e00f"
...
```
Each **relation** is glued with an underscore and at the end **_count** prefix is added. For example for
->joinRelations('seller.locations')
field would be __seller_locations_count__
#### **leftJoin**
Should we use **inner join** or **left join** (default = true)
```
select "sellers".*
from "sellers"
inner join "locations"
...
```
vs
```
select "sellers".*
from "sellers"
left join "locations"
...
```
#### **aggregateMethod**
Which aggregate method to use for ordering (default = 'MAX').
When join is performed on the joined table we must apply aggregate functions on the sorted field so we could perform group by clause and prevent duplication of results.
```
select "sellers".*, MAX("locations" ."number") AS sort
from "sellers"
left join "locations"
group by "locations" ."id"
order by sort
...
```
Options are : **SUM**, **AVG**, **MAX**, **MIN**, **COUNT**
## Usage
### Currently available relations for join queries
* **BelongsTo**
* **HasOne**
* **HasMany**
### New clauses for eloquent builder on BelongsTo and HasOne relations :
**joinRelations($relations, $leftJoin = null)**
* ***$relations*** which relations to join
* ***$leftJoin*** use **left join** or **inner join**, default **left join**
**orderByJoin($column, $direction = 'asc', $aggregateMethod = null)**
* ***$column*** and ***$direction*** arguments are the same as in default eloquent **orderBy()**
* ***$aggregateMethod*** argument defines which aggregate method to use ( **SUM**, **AVG**, **MAX**, **MIN**, **COUNT**), default **MAX**
**whereJoin($column, $operator, $value, $boolean = 'and')**
* arguments are the same as in default eloquent **where()**
**orWhereJoin($column, $operator, $value)**
* arguments are the same as in default eloquent **orWhere()**
**whereInJoin($column, $values, $boolean = 'and', $not = false)**
* arguments are the same as in default eloquent **whereIn()**
**whereNotInJoin($column, $values, $boolean = 'and')**
* arguments are the same as in default eloquent **whereNotIn()**
**orWhereInJoin($column, $values)**
* arguments are the same as in default eloquent **orWhereIn()**
**orWhereNotInJoin($column, $values)**
* arguments are the same as in default eloquent **orWhereNotIn()**
### Allowed clauses on BelongsTo, HasOne and HasMany relations on which you can use join clauses on the query
* Relations that you want to use for join queries can only have these clauses : **where**, **orWhere**, **withTrashed**, **onlyTrashed**, **withoutTrashed**.
* Clauses **where** and **orWhere** can only have these variations
** **->where($column, $operator, $value)**
** **->where([$column => $value])**
* Closures are not allowed.
* Other clauses like **whereHas**, **orderBy** etc. are not allowed.
* You can add not allowed clauses on relations and use them in the normal eloquent way, but in these cases, you can't use those relations for join queries.
Allowed relation:
```
public function locationPrimary()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 1)
->orWhere('is_primary', '=', 1)
->withTrashed();
}
```
Not allowed relation:
```
public function locationPrimary()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 1)
->orWhere('is_primary', '=', 1)
->withTrashed()
->whereHas('state', function($query){return $query;}
->orderBy('name')
->where(function($query){
return $query->where('is_primary', '=', 1);
});
}
```
The reason why the second relation is not allowed is that this package should apply all those clauses on the join clause, eloquent use all those clauses isolated with subqueries NOT on join clause and that is more simpler to do.
You might get a picture that there are too many rules and restriction, but it is really not like that.
Don't worry, if you do create the query that is not allowed appropriate exception will be thrown and you will know what happened.
### Other
* If the model uses the SoftDelete trait, where deleted_at != null will be automatically applied
* You can combine new clauses unlimited times
* If you combine clauses more times on same relation package will join related table only once
```
Seller::whereJoin('city.title', '=', 'test')
->orWhereJoin('city.title', '=', 'test2');
```
* You can call new clauses inside closures
```
Seller::where(function ($query) {
$query
->whereJoin('city.title', '=', 'test')
->orWhereJoin('city.title', '=', 'test2');
});
```
* You can combine join clauses e.g. whereJoin() with eloquent clauses e.g. orderBy()
```
Seller::whereJoin('title', '=', 'test')
->whereJoin('city.title', '=', 'test')
->orderByJoin('city.title')
->get();
```
## See action on real example
Database schema :

Models :
```
class Seller extends BaseModel
{
public function locations()
{
return $this->hasMany(Location::class);
}
public function locationPrimary()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 1);
}
public function city()
{
return $this->belongsTo(City::class);
}
```
```
class Location extends BaseModel
{
public function locationAddressPrimary()
{
return $this->hasOne(LocationAddress::class)
->where('is_primary', '=', 1);
}
```
```
class City extends BaseModel
{
public function state()
{
return $this->belongsTo(State::class);
}
}
```
### Join
##### Join BelongsTo
```Seller::joinRelations('city')```
##### Join HasOne
```Seller::joinRelations('locationPrimary')```
##### Join HasMany
```Seller::joinRelations('locations')```
##### Join Mixed
```Seller::joinRelations('city.state')```
### Join (mix left join)
```Seller::joinRelations('city', true)->joinRelations('city.state', false)```
### Join (multiple relationships)
```Seller::join(['city.state', 'locations'])```
### Ordering
##### Order BelongsTo
```Seller::orderByJoin('city.title')```
##### Order HasOne
```Seller::orderByJoin('locationPrimary.address')```
##### Order HasMany
```Seller::orderByJoin('locations.title')```
##### Order Mixed
```Seller::orderByJoin('city.state.title')```
### Ordering (special cases with aggregate functions)
##### Order by relation count
```Seller::orderByJoin('locations.id', 'asc', 'COUNT')```
##### Order by relation field SUM
```Seller::orderByJoin('locations.is_primary', 'asc', 'SUM')```
##### Order by relation field AVG
```Seller::orderByJoin('locations.is_primary', 'asc', 'AVG')```
##### Order by relation field MAX
```Seller::orderByJoin('locations.is_primary', 'asc', 'MAX')```
##### Order by relation field MIN
```Seller::orderByJoin('locations.is_primary', 'asc', 'MIN')```
### Filtering (where or orWhere)
##### Filter BelongsTo
```Seller::whereJoin('city.title', '=', 'test')```
##### Filter HasOne
```Seller::whereJoin('locationPrimary.address', '=', 'test')```
##### Filter HasMany
```Seller::whereJoin('locations.title', '=', 'test')```
##### Filter Mixed
```Seller::whereJoin('city.state.title', '=', 'test')```
### Relation count
```
$sellers = Seller::setAppendRelationsCount(true)->join('locations', '=', 'test')
->get();
foreach ($sellers as $seller){
echo 'Number of location = ' . $seller->locations_count;
}
```
### Filter (mix left join)
```
Seller::joinRelations('city', true)
->joinRelations('city.state', false)
->whereJoin('city.id', '=', 1)
->orWhereJoin('city.state.id', '=', 1)
```
## Generated queries
Query :
```
Order::whereJoin('seller.id', '=', 1)->get();
```
Sql :
```
select "orders".*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "sellers"."id" = ?
and "orders"."deleted_at" is null
group by "orders"."id"
```
Query :
```
Order::orderByJoin('seller.id', '=', 1)->get();
```
Sql :
```
select "orders".*, MAX(sellers.id) as sort
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "orders"."deleted_at" is null
group by "orders"."id"
order by sort asc
```
## Elegance of package
Lets look how first example from documentation now looks like. This code :
```
$posts = Post::select('posts.*')
->join('categories', 'categories.id', '=', 'posts.category_id')
->groupBy('posts.id')
->where('categories.deleted_at', '=', null)
->orderBy('categories.name');
if(request()->get('date')){
$posts->where('date', $date)
}
$posts = $posts->get();
```
is now :
```
$posts = Post::orderByJoin('category.name');
if(request()->get('date')){
$posts->where('posts.date', $date)
}
$posts = $posts->get();
```
Both snippets do the same thing.
## Tests
This package is well covered with tests. If you want run tests just run **composer update** and then run tests with **"vendor/bin/phpunit"**
## Contribution
Feel free to create new issue for :
* bug
* notice
* request new feature
* question
* clarification
* etc...
License
----
MIT
**Free Software, Hell Yeah!**
================================================
FILE: composer.json
================================================
{
"name": "fico7489/laravel-eloquent-join",
"description": "This package introduces the join magic for eloquent models and relations.",
"keywords": [
"laravel join",
"laravel eloquent join",
"laravel sort join",
"laravel where join",
"laravel join relation"
],
"homepage": "https://github.com/fico7489/laravel-eloquent-join",
"support": {
"issues": "https://github.com/fico7489/laravel-eloquent-join/issues",
"source": "https://github.com/fico7489/laravel-eloquent-join"
},
"license": "MIT",
"authors": [
{
"name": "Filip Horvat",
"email": "filip.horvat@am2studio.hr",
"homepage": "http://am2studio.hr",
"role": "Developer"
}
],
"require": {
"illuminate/database": "^8.0|^9.0|^10.0|^11.0|^12.0"
},
"require-dev": {
"orchestra/testbench": "*",
"friendsofphp/php-cs-fixer" : "*",
"phpunit/phpunit": "*"
},
"autoload": {
"psr-4": {
"Fico7489\\Laravel\\EloquentJoin\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Fico7489\\Laravel\\EloquentJoin\\Tests\\": "tests/"
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
================================================
FILE: phpunit.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/5.7/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="vendor/autoload.php"
>
<php>
<ini name="error_reporting" value="-1"/>
</php>
<testsuites>
<testsuite name="Remember Upload Service Testsuit">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./src</directory>
<exclude>
<directory>./tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
================================================
FILE: src/EloquentJoinBuilder.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidAggregateMethod;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidDirection;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelation;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationClause;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationGlobalScope;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationWhere;
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToJoin;
use Fico7489\Laravel\EloquentJoin\Relations\HasManyJoin;
use Fico7489\Laravel\EloquentJoin\Relations\HasOneJoin;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Database\Query\JoinClause;
class EloquentJoinBuilder extends Builder
{
//constants
const AGGREGATE_SUM = 'SUM';
const AGGREGATE_AVG = 'AVG';
const AGGREGATE_MAX = 'MAX';
const AGGREGATE_MIN = 'MIN';
const AGGREGATE_COUNT = 'COUNT';
//use table alias for join (real table name or random sha1)
protected $useTableAlias = false;
//appendRelationsCount
protected $appendRelationsCount = false;
//leftJoin
protected $leftJoin = true;
//aggregate method
protected $aggregateMethod = self::AGGREGATE_MAX;
//base builder
protected $baseBuilder;
//store if ->select(...) is already called on builder (we want only one groupBy())
protected $selected = false;
//store joined tables, we want join table only once (e.g. when you call orderByJoin more time)
protected $joinedTables = [];
//store clauses on relation for join
public $relationClauses = [];
//query methods
public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column instanceof \Closure) {
$query = $this->model->newModelQuery();
$baseBuilderCurrent = $this->baseBuilder ? $this->baseBuilder : $this;
$query->baseBuilder = $baseBuilderCurrent;
$column($query);
$this->query->addNestedWhereQuery($query->getQuery(), $boolean);
} else {
$this->query->where(...func_get_args());
}
return $this;
}
public function whereJoin($column, $operator, $value, $boolean = 'and')
{
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
return $this->where($column, $operator, $value, $boolean);
}
public function orWhereJoin($column, $operator, $value)
{
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
return $this->orWhere($column, $operator, $value);
}
public function whereInJoin($column, $values, $boolean = 'and', $not = false)
{
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
return $this->whereIn($column, $values, $boolean, $not);
}
public function whereNotInJoin($column, $values, $boolean = 'and')
{
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
return $this->whereNotIn($column, $values, $boolean);
}
public function orWhereInJoin($column, $values)
{
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
return $this->orWhereIn($column, $values);
}
public function orWhereNotInJoin($column, $values)
{
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
return $this->orWhereNotIn($column, $values);
}
public function orderByJoin($column, $direction = 'asc', $aggregateMethod = null)
{
$direction = strtolower($direction);
$this->checkDirection($direction);
$dotPos = strrpos($column, '.');
$query = $this->baseBuilder ? $this->baseBuilder : $this;
$column = $query->performJoin($column);
if (false !== $dotPos) {
//order by related table field
$aggregateMethod = $aggregateMethod ? $aggregateMethod : $this->aggregateMethod;
$this->checkAggregateMethod($aggregateMethod);
$sortsCount = count($this->query->orders ?? []);
$sortAlias = 'sort'.(0 == $sortsCount ? '' : ($sortsCount + 1));
$grammar = \DB::query()->getGrammar();
$query->selectRaw($aggregateMethod.'('.$grammar->wrap($column).') as '.$sortAlias);
return $this->orderByRaw($sortAlias.' '.$direction);
}
//order by base table field
return $this->orderBy($column, $direction);
}
/**
* Joining relations.
*
* @param string|array $relations
* @param bool|null $leftJoin
*
* @return $this
*
* @throws InvalidRelation
*/
public function joinRelations($relations, $leftJoin = null)
{
$leftJoin = null !== $leftJoin ? $leftJoin : $this->leftJoin;
$query = $this->baseBuilder ? $this->baseBuilder : $this;
if (is_array($relations)) {
foreach ($relations as $relation) {
$query->joinRelations($relation, $leftJoin);
}
} else {
$query->performJoin($relations.'.FAKE_FIELD', $leftJoin);
}
return $this;
}
//helpers methods
protected function performJoin($relations, $leftJoin = null)
{
//detect join method
$leftJoin = null !== $leftJoin ? $leftJoin : $this->leftJoin;
$joinMethod = $leftJoin ? 'leftJoin' : 'join';
//detect current model data
$relations = explode('.', $relations);
$column = end($relations);
$baseModel = $this->getModel();
$baseTable = $baseModel->getTable();
$basePrimaryKey = $baseModel->getKeyName();
$currentModel = $baseModel;
$currentTableAlias = $baseTable;
$relationsAccumulated = [];
foreach ($relations as $relation) {
if ($relation == $column) {
//last item in $relations argument is sort|where column
break;
}
/** @var Relation $relatedRelation */
$relatedRelation = $currentModel->$relation();
$relatedModel = $relatedRelation->getRelated();
$relatedPrimaryKey = $relatedModel->getKeyName();
$relatedTable = $relatedModel->getTable();
$relatedTableAlias = $this->useTableAlias ? sha1($relatedTable.rand()) : $relatedTable;
$relationsAccumulated[] = $relatedTableAlias;
$relationAccumulatedString = implode('_', $relationsAccumulated);
//relations count
if ($this->appendRelationsCount) {
$this->selectRaw('COUNT('.$relatedTableAlias.'.'.$relatedPrimaryKey.') as '.$relationAccumulatedString.'_count');
}
if (!in_array($relationAccumulatedString, $this->joinedTables)) {
$joinQuery = $relatedTable.($this->useTableAlias ? ' as '.$relatedTableAlias : '');
if ($relatedRelation instanceof BelongsToJoin) {
$relatedKey = is_callable([$relatedRelation, 'getQualifiedForeignKeyName']) ? $relatedRelation->getQualifiedForeignKeyName() : $relatedRelation->getQualifiedForeignKey();
$relatedKey = last(explode('.', $relatedKey));
$ownerKey = is_callable([$relatedRelation, 'getOwnerKeyName']) ? $relatedRelation->getOwnerKeyName() : $relatedRelation->getOwnerKey();
$this->$joinMethod($joinQuery, function ($join) use ($relatedRelation, $relatedTableAlias, $relatedKey, $currentTableAlias, $ownerKey) {
$join->on($relatedTableAlias.'.'.$ownerKey, '=', $currentTableAlias.'.'.$relatedKey);
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
});
} elseif ($relatedRelation instanceof HasOneJoin || $relatedRelation instanceof HasManyJoin) {
$relatedKey = $relatedRelation->getQualifiedForeignKeyName();
$relatedKey = last(explode('.', $relatedKey));
$localKey = $relatedRelation->getQualifiedParentKeyName();
$localKey = last(explode('.', $localKey));
$this->$joinMethod($joinQuery, function ($join) use ($relatedRelation, $relatedTableAlias, $relatedKey, $currentTableAlias, $localKey) {
$join->on($relatedTableAlias.'.'.$relatedKey, '=', $currentTableAlias.'.'.$localKey);
$this->joinQuery($join, $relatedRelation, $relatedTableAlias);
});
} else {
throw new InvalidRelation();
}
}
$currentModel = $relatedModel;
$currentTableAlias = $relatedTableAlias;
$this->joinedTables[] = implode('_', $relationsAccumulated);
}
if (!$this->selected && count($relations) > 1) {
$this->selected = true;
$this->selectRaw($baseTable.'.*');
$this->groupBy($baseTable.'.'.$basePrimaryKey);
}
return $currentTableAlias.'.'.$column;
}
protected function joinQuery($join, $relation, $relatedTableAlias)
{
/** @var Builder $relationQuery */
$relationBuilder = $relation->getQuery();
//apply clauses on relation
if (isset($relationBuilder->relationClauses)) {
foreach ($relationBuilder->relationClauses as $clause) {
foreach ($clause as $method => $params) {
$this->applyClauseOnRelation($join, $method, $params, $relatedTableAlias);
}
}
}
//apply global SoftDeletingScope
foreach ($relationBuilder->scopes as $scope) {
if ($scope instanceof SoftDeletingScope) {
$this->applyClauseOnRelation($join, 'withoutTrashed', [], $relatedTableAlias);
} else {
throw new InvalidRelationGlobalScope();
}
}
}
private function applyClauseOnRelation(JoinClause $join, string $method, array $params, string $relatedTableAlias)
{
if (in_array($method, ['where', 'orWhere'])) {
try {
if (is_array($params[0])) {
foreach ($params[0] as $k => $param) {
$params[0][$relatedTableAlias.'.'.$k] = $param;
unset($params[0][$k]);
}
} elseif (is_callable($params[0])) {
throw new InvalidRelationWhere();
} else {
$params[0] = $relatedTableAlias.'.'.$params[0];
}
call_user_func_array([$join, $method], $params);
} catch (\Exception $e) {
throw new InvalidRelationWhere();
}
} elseif (in_array($method, ['withoutTrashed', 'onlyTrashed', 'withTrashed'])) {
if ('withTrashed' == $method) {
//do nothing
} elseif ('withoutTrashed' == $method) {
call_user_func_array([$join, 'where'], [$relatedTableAlias.'.deleted_at', '=', null]);
} elseif ('onlyTrashed' == $method) {
call_user_func_array([$join, 'where'], [$relatedTableAlias.'.deleted_at', '<>', null]);
}
} else {
throw new InvalidRelationClause();
}
}
private function checkAggregateMethod($aggregateMethod)
{
if (!in_array($aggregateMethod, [
self::AGGREGATE_SUM,
self::AGGREGATE_AVG,
self::AGGREGATE_MAX,
self::AGGREGATE_MIN,
self::AGGREGATE_COUNT,
])) {
throw new InvalidAggregateMethod();
}
}
private function checkDirection($direction)
{
if (!in_array($direction, ['asc', 'desc'], true)) {
throw new InvalidDirection();
}
}
//getters and setters
public function isUseTableAlias(): bool
{
return $this->useTableAlias;
}
public function setUseTableAlias(bool $useTableAlias)
{
$this->useTableAlias = $useTableAlias;
return $this;
}
public function isLeftJoin(): bool
{
return $this->leftJoin;
}
public function setLeftJoin(bool $leftJoin)
{
$this->leftJoin = $leftJoin;
return $this;
}
public function isAppendRelationsCount(): bool
{
return $this->appendRelationsCount;
}
public function setAppendRelationsCount(bool $appendRelationsCount)
{
$this->appendRelationsCount = $appendRelationsCount;
return $this;
}
public function getAggregateMethod(): string
{
return $this->aggregateMethod;
}
public function setAggregateMethod(string $aggregateMethod)
{
$this->checkAggregateMethod($aggregateMethod);
$this->aggregateMethod = $aggregateMethod;
return $this;
}
}
================================================
FILE: src/Exceptions/InvalidAggregateMethod.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Exceptions;
class InvalidAggregateMethod extends \Exception
{
public $message = 'Invalid aggregate method';
}
================================================
FILE: src/Exceptions/InvalidDirection.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Exceptions;
class InvalidDirection extends \Exception
{
public $message = 'Invalid direction. Order direction must be either \'asc\' or \'desc\'';
}
================================================
FILE: src/Exceptions/InvalidRelation.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Exceptions;
class InvalidRelation extends \Exception
{
public $message = 'Package allows only following relations : BelongsTo, HasOne and HasMany.';
}
================================================
FILE: src/Exceptions/InvalidRelationClause.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Exceptions;
class InvalidRelationClause extends \Exception
{
public $message = 'Package allows only following clauses on relation : where, orWhere, withTrashed, onlyTrashed and withoutTrashed.';
}
================================================
FILE: src/Exceptions/InvalidRelationGlobalScope.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Exceptions;
class InvalidRelationGlobalScope extends \Exception
{
public $message = 'Package allows only SoftDeletingScope global scope.';
}
================================================
FILE: src/Exceptions/InvalidRelationWhere.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Exceptions;
class InvalidRelationWhere extends \Exception
{
public $message = 'Package allows only following where(orWhere) clauses type on relation : ->where($column, $operator, $value) and ->where([$column => $value]).';
}
================================================
FILE: src/Relations/BelongsToJoin.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Relations;
use Fico7489\Laravel\EloquentJoin\Traits\JoinRelationTrait;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BelongsToJoin extends BelongsTo
{
use JoinRelationTrait;
}
================================================
FILE: src/Relations/HasManyJoin.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Relations;
use Fico7489\Laravel\EloquentJoin\Traits\JoinRelationTrait;
use Illuminate\Database\Eloquent\Relations\HasMany;
class HasManyJoin extends HasMany
{
use JoinRelationTrait;
}
================================================
FILE: src/Relations/HasOneJoin.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Relations;
use Fico7489\Laravel\EloquentJoin\Traits\JoinRelationTrait;
use Illuminate\Database\Eloquent\Relations\HasOne;
class HasOneJoin extends HasOne
{
use JoinRelationTrait;
}
================================================
FILE: src/Traits/EloquentJoin.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Traits;
use Fico7489\Laravel\EloquentJoin\EloquentJoinBuilder;
/**
* Trait EloquentJoin.
*
* @method static EloquentJoinBuilder joinRelations($relations, $leftJoin = null)
* @method static EloquentJoinBuilder whereJoin($column, $operator, $value, $boolean = 'and')
* @method static EloquentJoinBuilder orWhereJoin($column, $operator, $value)
* @method static EloquentJoinBuilder whereInJoin($column, $values, $boolean = 'and', $not = false)
* @method static EloquentJoinBuilder whereNotInJoin($column, $values, $boolean = 'and')
* @method static EloquentJoinBuilder orWhereInJoin($column, $values)
* @method static EloquentJoinBuilder orWhereNotInJoin($column, $values)
* @method static EloquentJoinBuilder orderByJoin($column, $direction = 'asc', $aggregateMethod = null)
*/
trait EloquentJoin
{
use ExtendRelationsTrait;
/**
* @param $query
*
* @return EloquentJoinBuilder
*/
public function newEloquentBuilder($query)
{
$newEloquentBuilder = new EloquentJoinBuilder($query);
if (isset($this->useTableAlias)) {
$newEloquentBuilder->setUseTableAlias($this->useTableAlias);
}
if (isset($this->appendRelationsCount)) {
$newEloquentBuilder->setAppendRelationsCount($this->appendRelationsCount);
}
if (isset($this->leftJoin)) {
$newEloquentBuilder->setLeftJoin($this->leftJoin);
}
if (isset($this->aggregateMethod)) {
$newEloquentBuilder->setAggregateMethod($this->aggregateMethod);
}
return $newEloquentBuilder;
}
}
================================================
FILE: src/Traits/ExtendRelationsTrait.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Traits;
use Fico7489\Laravel\EloquentJoin\Relations\BelongsToJoin;
use Fico7489\Laravel\EloquentJoin\Relations\HasManyJoin;
use Fico7489\Laravel\EloquentJoin\Relations\HasOneJoin;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
trait ExtendRelationsTrait
{
protected function newBelongsTo(Builder $query, Model $child, $foreignKey, $ownerKey, $relation)
{
return new BelongsToJoin($query, $child, $foreignKey, $ownerKey, $relation);
}
protected function newHasOne(Builder $query, Model $parent, $foreignKey, $localKey)
{
return new HasOneJoin($query, $parent, $foreignKey, $localKey);
}
protected function newHasMany(Builder $query, Model $parent, $foreignKey, $localKey)
{
return new HasManyJoin($query, $parent, $foreignKey, $localKey);
}
}
================================================
FILE: src/Traits/JoinRelationTrait.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Traits;
use Fico7489\Laravel\EloquentJoin\EloquentJoinBuilder;
trait JoinRelationTrait
{
/**
* Handle dynamic method calls to the relationship.
*
* @param string $method
* @param array $parameters
*
* @return mixed
*/
public function __call($method, $parameters)
{
if ($this->getQuery() instanceof EloquentJoinBuilder) {
$this->getQuery()->relationClauses[] = [$method => $parameters];
}
return parent::__call($method, $parameters);
}
}
================================================
FILE: tests/Models/BaseModel.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Fico7489\Laravel\EloquentJoin\Traits\EloquentJoin;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model
{
use EloquentJoin;
}
================================================
FILE: tests/Models/City.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class City extends BaseModel
{
use SoftDeletes;
protected $table = 'cities';
protected $fillable = ['name'];
public function state()
{
return $this->belongsTo(State::class);
}
public function zipCodePrimary()
{
return $this->hasOne(ZipCode::class)
->where('is_primary', '=', 1);
}
public function sellers()
{
return $this->belongsToMany(Seller::class, 'locations', 'seller_id', 'city_id');
}
public function zipCodes()
{
return $this->hasMany(ZipCode::class);
}
}
================================================
FILE: tests/Models/Integration.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class Integration extends BaseModel
{
use SoftDeletes;
protected $table = 'integrations';
protected $fillable = ['name'];
}
================================================
FILE: tests/Models/Key/Location.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models\Key;
use Fico7489\Laravel\EloquentJoin\Tests\Models\BaseModel;
class Location extends BaseModel
{
protected $primaryKey = 'id_location_primary';
protected $table = 'key_locations';
protected $fillable = ['address', 'id_seller_foreign'];
}
================================================
FILE: tests/Models/Key/Order.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models\Key;
use Fico7489\Laravel\EloquentJoin\Tests\Models\BaseModel;
class Order extends BaseModel
{
protected $primaryKey = 'id_order_primary';
protected $table = 'key_orders';
protected $fillable = ['number', 'id_seller_foreign'];
public function seller()
{
return $this->belongsTo(Seller::class, 'id_seller_foreign', 'id_seller_primary');
}
public function sellerOwner()
{
return $this->belongsTo(Seller::class, 'id_seller_foreign', 'id_seller_owner');
}
}
================================================
FILE: tests/Models/Key/Seller.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models\Key;
use Fico7489\Laravel\EloquentJoin\Tests\Models\BaseModel;
class Seller extends BaseModel
{
protected $primaryKey = 'id_seller_primary';
protected $table = 'key_sellers';
protected $fillable = ['title'];
public function location()
{
return $this->hasOne(Location::class, 'id_seller_foreign', 'id_seller_primary');
}
public function locations()
{
return $this->hasMany(Location::class, 'id_seller_foreign', 'id_seller_primary');
}
public function locationOwner()
{
return $this->hasOne(Location::class, 'id_seller_foreign', 'id_seller_owner');
}
public function locationsOwner()
{
return $this->hasMany(Location::class, 'id_seller_foreign', 'id_seller_owner');
}
}
================================================
FILE: tests/Models/Location.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class Location extends BaseModel
{
use SoftDeletes;
protected $table = 'locations';
protected $fillable = ['address', 'seller_id', 'is_primary', 'is_secondary', 'city_id'];
public function seller()
{
return $this->belongsTo(Seller::class);
}
public function city()
{
return $this->belongsTo(City::class);
}
public function locationAddressPrimary()
{
return $this->hasOne(LocationAddress::class)
->where('is_primary', '=', 1);
}
public function integrations()
{
return $this->hasMany(Integration::class);
}
}
================================================
FILE: tests/Models/LocationAddress.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class LocationAddress extends BaseModel
{
use SoftDeletes;
protected $table = 'location_addresses';
protected $fillable = ['address', 'is_primary'];
public function users()
{
return $this->hasMany(User::class);
}
}
================================================
FILE: tests/Models/LocationWithGlobalScope.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Fico7489\Laravel\EloquentJoin\Tests\Scope\TestExceptionScope;
use Illuminate\Database\Eloquent\SoftDeletes;
class LocationWithGlobalScope extends BaseModel
{
use SoftDeletes;
protected $table = 'locations';
protected static function boot()
{
parent::boot();
static::addGlobalScope(new TestExceptionScope());
}
}
================================================
FILE: tests/Models/Order.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends BaseModel
{
use SoftDeletes;
protected $table = 'orders';
protected $fillable = ['number', 'seller_id'];
public function seller()
{
return $this->belongsTo(Seller::class);
}
}
================================================
FILE: tests/Models/OrderItem.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class OrderItem extends BaseModel
{
use SoftDeletes;
protected $table = 'order_items';
protected $fillable = ['name', 'order_id'];
public function order()
{
return $this->belongsTo(Order::class);
}
public function orderWithTrashed()
{
return $this->belongsTo(Order::class, 'order_id')
->withTrashed();
}
public function orderOnlyTrashed()
{
return $this->belongsTo(Order::class, 'order_id')
->onlyTrashed();
}
}
================================================
FILE: tests/Models/Seller.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
class Seller extends BaseModel
{
protected $table = 'sellers';
protected $fillable = ['title', 'deleted_at'];
public function location()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 0)
->where('is_secondary', '=', 0);
}
public function locations()
{
return $this->hasMany(Location::class);
}
public function locationPrimary()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 1);
}
public function locationPrimaryInvalid()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 1)
->orderBy('is_primary');
}
public function locationPrimaryInvalid2()
{
return $this->hasOne(Location::class)
->where(function ($query) {
return $query->where(['id' => 1]);
});
}
public function locationPrimaryInvalid3()
{
return $this->hasOne(LocationWithGlobalScope::class);
}
public function locationSecondary()
{
return $this->hasOne(Location::class)
->where('is_secondary', '=', 1);
}
public function locationPrimaryOrSecondary()
{
return $this->hasOne(Location::class)
->where('is_primary', '=', 1)
->orWhere('is_secondary', '=', 1);
}
public function city()
{
return $this->belongsTo(City::class);
}
}
================================================
FILE: tests/Models/State.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class State extends BaseModel
{
use SoftDeletes;
protected $table = 'states';
protected $fillable = ['name'];
public function cities()
{
return $this->hasMany(City::class);
}
}
================================================
FILE: tests/Models/User.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends BaseModel
{
use SoftDeletes;
protected $table = 'users';
protected $fillable = ['name'];
}
================================================
FILE: tests/Models/ZipCode.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class ZipCode extends BaseModel
{
use SoftDeletes;
protected $table = 'zip_codes';
protected $fillable = ['name', 'is_primary'];
}
================================================
FILE: tests/Scope/TestExceptionScope.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class TestExceptionScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('test', '=', 'test');
}
}
================================================
FILE: tests/ServiceProvider.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests;
class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
public function register()
{
//register
}
public function boot()
{
$this->loadMigrationsFrom(__DIR__.'/database/migrations/');
}
protected function loadMigrationsFrom($path)
{
$_ENV['type'] = 'sqlite'; //sqlite, mysql, pgsql
\Artisan::call('migrate', ['--database' => $_ENV['type']]);
$migrator = $this->app->make('migrator');
$migrator->run($path);
}
}
================================================
FILE: tests/TestCase.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Location;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\Models\OrderItem;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
abstract class TestCase extends \Orchestra\Testbench\TestCase
{
public function setUp(): void
{
parent::setUp();
$seller = Seller::create(['title' => 1]);
$seller2 = Seller::create(['title' => 2]);
$seller3 = Seller::create(['title' => 3]);
$seller4 = Seller::create(['title' => 4]);
Location::create(['address' => 1, 'seller_id' => $seller->id]);
Location::create(['address' => 2, 'seller_id' => $seller2->id]);
Location::create(['address' => 3, 'seller_id' => $seller3->id]);
Location::create(['address' => 3, 'seller_id' => $seller3->id]);
Location::create(['address' => 4, 'seller_id' => $seller3->id, 'is_primary' => 1]);
Location::create(['address' => 5, 'seller_id' => $seller3->id, 'is_secondary' => 1]);
$order = Order::create(['number' => '1', 'seller_id' => $seller->id]);
$order2 = Order::create(['number' => '2', 'seller_id' => $seller2->id]);
$order3 = Order::create(['number' => '3', 'seller_id' => $seller3->id]);
OrderItem::create(['name' => '1', 'order_id' => $order->id]);
OrderItem::create(['name' => '2', 'order_id' => $order2->id]);
OrderItem::create(['name' => '3', 'order_id' => $order3->id]);
$this->startListening();
}
protected function startListening()
{
\DB::enableQueryLog();
}
protected function fetchLastLog()
{
$log = \DB::getQueryLog();
return end($log);
}
protected function fetchQuery()
{
$query = $this->fetchLastLog()['query'];
$bindings = $this->fetchLastLog()['bindings'];
foreach ($bindings as $binding) {
$binding = is_string($binding) ? ('"'.$binding.'"') : $binding;
$query = preg_replace('/\?/', $binding, $query, 1);
}
return $query;
}
protected function fetchBindings()
{
return $this->fetchLastLog()['bindings'];
}
protected function getEnvironmentSetUp($app)
{
// Setup default database to use sqlite :memory:
$app['config']->set('database.connections.sqlite', [
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
]);
$app['config']->set('database.connections.mysql', [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'join',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'strict' => true,
]);
$app['config']->set('database.connections.pgsql', [
'driver' => 'pgsql',
'host' => 'localhost',
'database' => 'join',
'username' => 'postgres',
'password' => 'root',
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
'sslmode' => 'prefer',
]);
$app['config']->set('database.default', env('type', 'sqlite'));
}
protected function getPackageProviders($app)
{
return [ServiceProvider::class];
}
protected function assertQueryMatches($expected, $actual)
{
$actual = preg_replace('/\s\s+/', ' ', $actual);
$actual = str_replace(['\n', '\r'], '', $actual);
$expected = preg_replace('/\s\s+/', ' ', $expected);
$expected = str_replace(['\n', '\r'], '', $expected);
$expected = '/'.$expected.'/';
$expected = preg_quote($expected);
if ('mysql' == $_ENV['type']) {
$expected = str_replace(['"'], '`', $expected);
}
$this->assertMatchesRegularExpression($expected, $actual);
}
}
================================================
FILE: tests/Tests/AggregateJoinTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\EloquentJoinBuilder;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class AggregateJoinTest extends TestCase
{
private $queryTest = 'select orders.*, SUM("sellers"."id") as sort
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "orders"."deleted_at" is null
group by "orders"."id"
order by sort asc';
public function testAvg()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc', EloquentJoinBuilder::AGGREGATE_SUM)
->get();
$queryTest = str_replace(EloquentJoinBuilder::AGGREGATE_SUM, EloquentJoinBuilder::AGGREGATE_SUM, $this->queryTest);
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testSum()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc', EloquentJoinBuilder::AGGREGATE_AVG)
->get();
$queryTest = str_replace(EloquentJoinBuilder::AGGREGATE_SUM, EloquentJoinBuilder::AGGREGATE_AVG, $this->queryTest);
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testMax()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc', EloquentJoinBuilder::AGGREGATE_MAX)
->get();
$queryTest = str_replace(EloquentJoinBuilder::AGGREGATE_SUM, EloquentJoinBuilder::AGGREGATE_MAX, $this->queryTest);
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testMin()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc', EloquentJoinBuilder::AGGREGATE_MIN)
->get();
$queryTest = str_replace(EloquentJoinBuilder::AGGREGATE_SUM, EloquentJoinBuilder::AGGREGATE_MIN, $this->queryTest);
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testCount()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc', EloquentJoinBuilder::AGGREGATE_COUNT)
->get();
$queryTest = str_replace(EloquentJoinBuilder::AGGREGATE_SUM, EloquentJoinBuilder::AGGREGATE_COUNT, $this->queryTest);
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/AppendRelationsCountTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class AppendRelationsCountTest extends TestCase
{
public function testWhere()
{
Order::setAppendRelationsCount(true)->joinRelations('seller.locationPrimary.locationAddressPrimary')->get();
$queryTest = 'select COUNT(sellers.id) as sellers_count, COUNT(locations.id) as sellers_locations_count, COUNT(location_addresses.id) as sellers_locations_location_addresses_count, orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1
and "locations"."deleted_at" is null
left join "location_addresses" on "location_addresses"."location_id" = "locations"."id"
and "location_addresses"."is_primary" = 1
and "location_addresses"."deleted_at" is null
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/JoinRelationsTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class JoinRelationsTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/OrWhereInTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class OrWhereInTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->whereInJoin('seller.id', [1, 2])
->orWhereInJoin('seller.id', [3, 4])
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where ("sellers"."id" in (1, 2)
or
"sellers"."id" in (3, 4))
and "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/OrWhereNotInTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class OrWhereNotInTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->whereInJoin('seller.id', [1, 2])
->orWhereNotInJoin('seller.id', [3, 4])
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where ("sellers"."id" in (1, 2)
or
"sellers"."id" not in (3, 4))
and "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/OrWhereTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class OrWhereTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->whereJoin('seller.id', '=', 1)
->orWhereJoin('seller.id', '=', 2)
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where ("sellers"."id" = 1 or "sellers"."id" = 2)
and "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/OrderByTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class OrderByTest extends TestCase
{
public function testOrderBy()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc')
->get();
$queryTest = 'select orders.*, MAX("sellers"."id") as sort
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "orders"."deleted_at" is null
group by "orders"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testOrderByMultiple()
{
Order::joinRelations('seller')
->orderByJoin('seller.id', 'asc')
->orderByJoin('seller.title', 'desc')
->get();
$queryTest = 'select orders.*, MAX("sellers"."id") as sort, MAX("sellers"."title") as sort2
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "orders"."deleted_at" is null
group by "orders"."id"
order by sort asc, sort2 desc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/WhereInTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class WhereInTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->whereInJoin('seller.id', [1, 2])
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "sellers"."id" in (1, 2)
and "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/WhereNotInTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class WhereNotInTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->whereNotInJoin('seller.id', [1, 2])
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "sellers"."id" not in (1, 2)
and "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Clauses/WhereTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Clauses;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class WhereTest extends TestCase
{
public function testWhere()
{
Order::joinRelations('seller')
->whereJoin('seller.id', '=', 1)
->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "sellers"."id" = 1
and "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/ClosureOnRelationTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class ClosureOnRelationTest extends TestCase
{
public function testWhereOnRelationWithOrderByJoin()
{
//location have two where ['is_primary => 0', 'is_secondary' => 0]
$items = Seller::orderByJoin('location.id', 'desc')->get();
$queryTest = 'select sellers.*, MAX("locations"."id") as sort from "sellers"
left join "locations"
on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 0
and "locations"."is_secondary" = 0
and "locations"."deleted_at" is null
group by "sellers"."id"
order by sort desc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
//locationPrimary have one where ['is_primary => 1']
$items = Seller::orderByJoin('locationPrimary.id', 'desc')->get();
$queryTest = 'select sellers.*, MAX("locations"."id") as sort from "sellers"
left join "locations"
on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1
and "locations"."deleted_at" is null
group by "sellers"."id"
order by sort desc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
//locationPrimary have one where ['is_secondary => 1']
$items = Seller::orderByJoin('locationSecondary.id', 'desc')->get();
$queryTest = 'select sellers.*, MAX("locations"."id") as sort from "sellers"
left join "locations"
on "locations"."seller_id" = "sellers"."id"
and "locations"."is_secondary" = 1
and "locations"."deleted_at" is null
group by "sellers"."id"
order by sort desc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
//locationPrimary have one where ['is_primary => 1'] and one orWhere ['is_secondary => 1']
$items = Seller::orderByJoin('locationPrimaryOrSecondary.id', 'desc')->get();
$queryTest = 'select sellers.*, MAX("locations"."id") as sort from "sellers"
left join "locations"
on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1
or "locations"."is_secondary" = 1
and "locations"."deleted_at" is null
group by "sellers"."id"
order by sort desc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testWhereOnRelationWithoutOrderByJoin()
{
$seller = Seller::find(1);
$seller->locationPrimary;
$queryTest = 'select * from "locations"
where "locations"."seller_id" = 1
and "locations"."seller_id" is not null
and "is_primary" = 1
and "locations"."deleted_at" is null
limit 1';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
$seller->locationPrimary()->where(['is_secondary' => 1])->get();
$queryTest = 'select * from "locations"
where "locations"."seller_id" = 1
and "locations"."seller_id" is not null
and "is_primary" = 1
and ("is_secondary" = 1)
and "locations"."deleted_at" is null';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/ClosureTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\OrderItem;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class ClosureTest extends TestCase
{
public function testNestOne()
{
OrderItem::where(function ($query) {
$query
->orWhereJoin('order.id', '=', 1)
->orWhereJoin('order.id', '=', 2);
})->get();
$queryTest = 'select order_items.*
from "order_items"
left join "orders" on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is null
where ("orders"."id" = 1 or "orders"."id" = 2)
and "order_items"."deleted_at" is null';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testNestTwo()
{
OrderItem::where(function ($query) {
$query
->orWhereJoin('order.id', '=', 1)
->orWhereJoin('order.id', '=', 2)
->where(function ($query) {
$query->orWhereJoin('order.seller.locationPrimary.id', '=', 3);
});
})->get();
$queryTest = 'select order_items.*
from "order_items"
left join "orders" on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is null
left join "sellers" on "sellers"."id" = "orders"."seller_id"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1
and "locations"."deleted_at" is null
where ("orders"."id" = 1 or "orders"."id" = 2
and ("locations"."id" = 3))
and "order_items"."deleted_at" is null';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/ExceptionTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidAggregateMethod;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidDirection;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelation;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationClause;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationGlobalScope;
use Fico7489\Laravel\EloquentJoin\Exceptions\InvalidRelationWhere;
use Fico7489\Laravel\EloquentJoin\Tests\Models\City;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class ExceptionTest extends TestCase
{
public function testInvalidRelation()
{
try {
City::whereJoin('sellers.id', '=', 'test')->get();
} catch (InvalidRelation $e) {
$this->assertEquals((new InvalidRelation())->message, $e->getMessage());
return;
}
$this->assertTrue(false);
}
public function testInvalidRelationWhere()
{
try {
Seller::whereJoin('locationPrimaryInvalid2.name', '=', 'test')->get();
} catch (InvalidRelationWhere $e) {
$this->assertEquals((new InvalidRelationWhere())->message, $e->getMessage());
return;
}
$this->assertTrue(false);
}
public function testInvalidRelationClause()
{
try {
Seller::whereJoin('locationPrimaryInvalid.name', '=', 'test')->get();
} catch (InvalidRelationClause $e) {
$this->assertEquals((new InvalidRelationClause())->message, $e->getMessage());
return;
}
$this->assertTrue(false);
}
public function testInvalidRelationGlobalScope()
{
try {
Seller::whereJoin('locationPrimaryInvalid3.id', '=', 'test')->get();
} catch (InvalidRelationGlobalScope $e) {
$this->assertEquals((new InvalidRelationGlobalScope())->message, $e->getMessage());
return;
}
$this->assertTrue(false);
}
public function testInvalidAggregateMethod()
{
try {
Seller::orderByJoin('locationPrimary.id', 'asc', 'wrong')->get();
} catch (InvalidAggregateMethod $e) {
$this->assertEquals((new InvalidAggregateMethod())->message, $e->getMessage());
return;
}
$this->assertTrue(false);
}
public function testOrderByInvalidDirection()
{
$this->expectException(InvalidDirection::class);
Seller::orderByJoin('locationPrimary.id', ';DROP TABLE orders;--', 'test')->get();
}
}
================================================
FILE: tests/Tests/JoinTypeTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class JoinTypeTest extends TestCase
{
public function testLeftJoin()
{
Seller::setLeftJoin(true)->whereJoin('city.name', '=', 'test')->get();
$queryTest = 'select sellers.*
from "sellers"
left join "cities"
on "cities"."id" = "sellers"."city_id"
and "cities"."deleted_at" is null
where "cities"."name" = "test"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testInnerJoin()
{
Seller::setLeftJoin(false)->whereJoin('city.name', '=', 'test')->get();
$queryTest = 'select sellers.*
from "sellers"
inner join "cities"
on "cities"."id" = "sellers"."city_id"
and "cities"."deleted_at" is null
where "cities"."name" = "test"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testMixedJoin()
{
Order::joinRelations('seller', true)->joinRelations('seller.city', false)->joinRelations('seller.city.state', true)->get();
$queryTest = 'select orders.*
from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
inner join "cities" on "cities"."id" = "sellers"."city_id"
and "cities"."deleted_at" is null
left join "states" on "states"."id" = "cities"."state_id"
and "states"."deleted_at" is null
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/KeysOwnerTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Key\Order;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Key\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class KeysOwnerTest extends TestCase
{
public function testBelogsTo()
{
Order::joinRelations('sellerOwner')
->get();
$queryTest = 'select key_orders.*
from "key_orders"
left join "key_sellers" on "key_sellers"."id_seller_owner" = "key_orders"."id_seller_foreign"
group by "key_orders"."id_order_primary"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasOne()
{
Seller::joinRelations('locationOwner')
->get();
$queryTest = 'select key_sellers.*
from "key_sellers"
left join "key_locations" on "key_locations"."id_seller_foreign" = "key_sellers"."id_seller_owner"
group by "key_sellers"."id_seller_primary"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasMany()
{
Seller::joinRelations('locationsOwner')
->get();
$queryTest = 'select key_sellers.*
from "key_sellers"
left join "key_locations" on "key_locations"."id_seller_foreign" = "key_sellers"."id_seller_owner"
group by "key_sellers"."id_seller_primary"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/KeysTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Key\Order;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Key\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class KeysTest extends TestCase
{
public function testBelongsTo()
{
Order::joinRelations('seller')
->get();
$queryTest = 'select key_orders.*
from "key_orders"
left join "key_sellers" on "key_sellers"."id_seller_primary" = "key_orders"."id_seller_foreign"
group by "key_orders"."id_order_primary"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasOne()
{
Seller::joinRelations('location')
->get();
$queryTest = 'select key_sellers.*
from "key_sellers"
left join "key_locations" on "key_locations"."id_seller_foreign" = "key_sellers"."id_seller_primary"
group by "key_sellers"."id_seller_primary"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasMany()
{
Seller::joinRelations('locations')
->get();
$queryTest = 'select key_sellers.*
from "key_sellers"
left join "key_locations" on "key_locations"."id_seller_foreign" = "key_sellers"."id_seller_primary"
group by "key_sellers"."id_seller_primary"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/OptionsTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\EloquentJoinBuilder;
use Fico7489\Laravel\EloquentJoin\Tests\Models\City;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class OptionsTest extends TestCase
{
public function testUseTableAlias()
{
$city = new City();
$this->assertEquals(false, $city->newModelQuery()->isUseTableAlias());
$city->useTableAlias = true;
$this->assertEquals(true, $city->newModelQuery()->isUseTableAlias());
}
public function testAppendRelationsCount()
{
$city = new City();
$this->assertEquals(false, $city->newModelQuery()->isAppendRelationsCount());
$city->appendRelationsCount = true;
$this->assertEquals(true, $city->newModelQuery()->isAppendRelationsCount());
}
public function testLeftJoin()
{
$city = new City();
$this->assertEquals(true, $city->newModelQuery()->isLeftJoin());
$city->leftJoin = false;
$this->assertEquals(false, $city->newModelQuery()->isLeftJoin());
}
public function testAggregateMethod()
{
$city = new City();
$this->assertEquals(EloquentJoinBuilder::AGGREGATE_MAX, $city->newModelQuery()->getAggregateMethod());
$city->aggregateMethod = EloquentJoinBuilder::AGGREGATE_MIN;
$this->assertEquals(EloquentJoinBuilder::AGGREGATE_MIN, $city->newModelQuery()->getAggregateMethod());
}
}
================================================
FILE: tests/Tests/Relations/BelongsToTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Order;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class BelongsToTest extends TestCase
{
public function testBelongsTo()
{
Order::joinRelations('seller')->get();
$queryTest = 'select orders.* from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testBelongsToHasOne()
{
Order::joinRelations('seller.locationPrimary')->get();
$queryTest = 'select orders.* from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1
and "locations"."deleted_at" is null
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testBelongsToHasMany()
{
Order::joinRelations('seller.locations')->get();
$queryTest = 'select orders.* from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."deleted_at" is null
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testBelongsToHasOneHasMany()
{
Order::joinRelations('seller.locationPrimary.integrations')->get();
$queryTest = 'select orders.* from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1 and "locations"."deleted_at" is null
left join "integrations" on "integrations"."location_id" = "locations"."id"
and "integrations"."deleted_at" is null
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testBelongsToHasManyHasOne()
{
Order::joinRelations('seller.locationPrimary.locationAddressPrimary')->get();
$queryTest = 'select orders.* from "orders"
left join "sellers" on "sellers"."id" = "orders"."seller_id"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 1
and "locations"."deleted_at" is null
left join "location_addresses" on "location_addresses"."location_id" = "locations"."id"
and "location_addresses"."is_primary" = 1
and "location_addresses"."deleted_at" is null
where "orders"."deleted_at" is null
group by "orders"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Relations/HasManyTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class HasManyTest extends TestCase
{
public function testHasMany()
{
Seller::joinRelations('locations')->get();
$queryTest = 'select sellers.*
from "sellers"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."deleted_at" is null
group by "sellers"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasManyHasOne()
{
Seller::joinRelations('locations.city')->get();
$queryTest = 'select sellers.*
from "sellers" left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."deleted_at" is null
left join "cities" on "cities"."id" = "locations"."city_id"
and "cities"."deleted_at" is null
group by "sellers"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasManyBelongsTo()
{
Seller::joinRelations('locations.integrations')->get();
$queryTest = 'select sellers.*
from "sellers"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."deleted_at" is null
left join "integrations" on "integrations"."location_id" = "locations"."id"
and "integrations"."deleted_at" is null
group by "sellers"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/Relations/HasOneTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests\Relations;
use Fico7489\Laravel\EloquentJoin\Tests\Models\Seller;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class HasOneTest extends TestCase
{
public function testHasOne()
{
Seller::joinRelations('location')->get();
$queryTest = 'select sellers.*
from "sellers"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 0
and "locations"."is_secondary" = 0
and "locations"."deleted_at" is null
group by "sellers"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasOneBelongsTo()
{
Seller::joinRelations('location.city')->get();
$queryTest = 'select sellers.*
from "sellers" left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 0
and "locations"."is_secondary" = 0
and "locations"."deleted_at" is null
left join "cities" on "cities"."id" = "locations"."city_id"
and "cities"."deleted_at" is null
group by "sellers"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testHasOneHasMany()
{
Seller::joinRelations('location.integrations')->get();
$queryTest = 'select sellers.*
from "sellers"
left join "locations" on "locations"."seller_id" = "sellers"."id"
and "locations"."is_primary" = 0
and "locations"."is_secondary" = 0
and "locations"."deleted_at" is null
left join "integrations" on "integrations"."location_id" = "locations"."id"
and "integrations"."deleted_at" is null
group by "sellers"."id"';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/Tests/SoftDeleteTest.php
================================================
<?php
namespace Fico7489\Laravel\EloquentJoin\Tests\Tests;
use Fico7489\Laravel\EloquentJoin\Tests\Models\OrderItem;
use Fico7489\Laravel\EloquentJoin\Tests\TestCase;
class SoftDeleteTest extends TestCase
{
public function testNotRelatedWithoutTrashedDefault()
{
OrderItem::orderByJoin('name')->get();
$queryTest = 'select *
from "order_items"
where "order_items"."deleted_at" is null
order by "order_items"."name" asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testNotRelatedWithoutTrashedExplicit()
{
OrderItem::orderByJoin('name')->withoutTrashed()->get();
$queryTest = 'select *
from "order_items"
where "order_items"."deleted_at" is null
order by "order_items"."name" asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testNotRelatedOnlyTrashedExplicit()
{
OrderItem::orderByJoin('name')->onlyTrashed()->get();
$queryTest = 'select *
from "order_items"
where "order_items"."deleted_at" is not null
order by "order_items"."name" asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testNotRelatedWithTrashedExplicit()
{
OrderItem::orderByJoin('name')->withTrashed()->get();
$queryTest = 'select *
from "order_items"
order by "order_items"."name" asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testRelatedWithoutTrashedDefault()
{
OrderItem::orderByJoin('order.number')->get();
$queryTest = 'select order_items.*, MAX("orders"."number") as sort
from "order_items" left join "orders"
on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is null
where "order_items"."deleted_at" is null
group by "order_items"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testRelatedWithoutTrashedExplicit()
{
OrderItem::orderByJoin('order.number')->withoutTrashed()->get();
$queryTest = 'select order_items.*, MAX("orders"."number") as sort
from "order_items"
left join "orders"
on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is null
where "order_items"."deleted_at" is null
group by "order_items"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testRelatedOnlyTrashedExplicit()
{
OrderItem::orderByJoin('order.number')->onlyTrashed()->get();
$queryTest = 'select order_items.*, MAX("orders"."number") as sort
from "order_items"
left join "orders"
on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is null
where "order_items"."deleted_at" is not null
group by "order_items"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testRelatedWithTrashedExplicit()
{
OrderItem::orderByJoin('order.number')->withTrashed()->get();
$queryTest = 'select order_items.*, MAX("orders"."number") as sort
from "order_items"
left join "orders"
on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is null
group by "order_items"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testRelatedWithTrashedOnRelation()
{
OrderItem::orderByJoin('orderWithTrashed.number')->get();
$queryTest = 'select order_items.*, MAX("orders"."number") as sort
from "order_items"
left join "orders"
on "orders"."id" = "order_items"."order_id"
where "order_items"."deleted_at" is null
group by "order_items"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
public function testRelatedOnlyTrashedOnRelation()
{
OrderItem::orderByJoin('orderOnlyTrashed.number')->get();
$queryTest = 'select order_items.*, MAX("orders"."number") as sort
from "order_items"
left join "orders"
on "orders"."id" = "order_items"."order_id"
and "orders"."deleted_at" is not null
where "order_items"."deleted_at" is null
group by "order_items"."id"
order by sort asc';
$this->assertQueryMatches($queryTest, $this->fetchQuery());
}
}
================================================
FILE: tests/database/migrations/2017_11_04_163552_create_database.php
================================================
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
/**
* Class CreateDatabase.
*/
class CreateDatabase extends Migration
{
/**
* Run the migrations.
*/
public function up()
{
Schema::create('states', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->timestamps();
$table->softDeletes();
});
Schema::create('cities', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->unsignedInteger('state_id')->nullable();
$table->foreign('state_id')->references('id')->on('states');
$table->timestamps();
$table->softDeletes();
});
Schema::create('sellers', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->nullable();
$table->unsignedInteger('city_id')->nullable();
$table->foreign('city_id')->references('id')->on('cities');
$table->timestamps();
$table->softDeletes();
});
Schema::create('orders', function (Blueprint $table) {
$table->increments('id');
$table->string('number')->nullable();
$table->unsignedInteger('seller_id')->nullable();
$table->foreign('seller_id')->references('id')->on('sellers');
$table->timestamps();
$table->softDeletes();
});
Schema::create('order_items', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->unsignedInteger('order_id')->nullable();
$table->foreign('order_id')->references('id')->on('orders');
$table->timestamps();
$table->softDeletes();
});
Schema::create('locations', function (Blueprint $table) {
$table->increments('id');
$table->string('address')->nullable();
$table->boolean('is_primary')->default(0);
$table->boolean('is_secondary')->default(0);
$table->unsignedInteger('seller_id')->nullable();
$table->unsignedInteger('city_id')->nullable();
$table->foreign('seller_id')->references('id')->on('sellers');
$table->foreign('city_id')->references('id')->on('cities');
$table->timestamps();
$table->softDeletes();
});
Schema::create('zip_codes', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->boolean('is_primary')->default(0);
$table->unsignedInteger('city_id')->nullable();
$table->foreign('city_id')->references('id')->on('cities');
$table->timestamps();
$table->softDeletes();
});
Schema::create('location_addresses', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->boolean('is_primary')->default(0);
$table->unsignedInteger('location_id')->nullable();
$table->foreign('location_id')->references('id')->on('locations');
$table->timestamps();
$table->softDeletes();
});
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->unsignedInteger('location_address_id')->nullable();
$table->foreign('location_address_id')->references('id')->on('location_addresses');
$table->timestamps();
$table->softDeletes();
});
Schema::create('integrations', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->unsignedInteger('location_id')->nullable();
$table->foreign('location_id')->references('id')->on('locations');
$table->timestamps();
$table->softDeletes();
});
//for key tests
Schema::create('key_orders', function (Blueprint $table) {
$table->increments('id_order_primary');
$table->unsignedInteger('id_order_owner')->nullable();
$table->string('number')->nullable();
$table->unsignedInteger('id_seller_foreign')->nullable();
$table->foreign('id_seller_foreign')->references('id')->on('sellers');
});
Schema::create('key_sellers', function (Blueprint $table) {
$table->increments('id_seller_primary');
$table->unsignedInteger('id_seller_owner')->nullable();
$table->string('title')->nullable();
});
Schema::create('key_locations', function (Blueprint $table) {
$table->increments('id_location_primary');
$table->unsignedInteger('id_location_owner')->nullable();
$table->string('address')->nullable();
$table->unsignedInteger('id_seller_foreign')->nullable();
$table->foreign('id_seller_foreign')->references('id')->on('sellers');
});
}
/**
* Reverse the migrations.
*/
public function down()
{
Schema::drop('users');
Schema::drop('sellers');
Schema::drop('order_items');
Schema::drop('locations');
Schema::drop('cities');
Schema::drop('zip_codes');
Schema::drop('states');
Schema::drop('location_addresses');
Schema::drop('integrations');
Schema::drop('orders');
//for key tests
Schema::drop('key_orders');
Schema::drop('key_sellers');
Schema::drop('key_locations');
}
}
gitextract_4l8jykqq/
├── .github/
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .php_cs
├── LICENSE
├── README.md
├── composer.json
├── phpunit.xml
├── src/
│ ├── EloquentJoinBuilder.php
│ ├── Exceptions/
│ │ ├── InvalidAggregateMethod.php
│ │ ├── InvalidDirection.php
│ │ ├── InvalidRelation.php
│ │ ├── InvalidRelationClause.php
│ │ ├── InvalidRelationGlobalScope.php
│ │ └── InvalidRelationWhere.php
│ ├── Relations/
│ │ ├── BelongsToJoin.php
│ │ ├── HasManyJoin.php
│ │ └── HasOneJoin.php
│ └── Traits/
│ ├── EloquentJoin.php
│ ├── ExtendRelationsTrait.php
│ └── JoinRelationTrait.php
└── tests/
├── Models/
│ ├── BaseModel.php
│ ├── City.php
│ ├── Integration.php
│ ├── Key/
│ │ ├── Location.php
│ │ ├── Order.php
│ │ └── Seller.php
│ ├── Location.php
│ ├── LocationAddress.php
│ ├── LocationWithGlobalScope.php
│ ├── Order.php
│ ├── OrderItem.php
│ ├── Seller.php
│ ├── State.php
│ ├── User.php
│ └── ZipCode.php
├── Scope/
│ └── TestExceptionScope.php
├── ServiceProvider.php
├── TestCase.php
├── Tests/
│ ├── AggregateJoinTest.php
│ ├── AppendRelationsCountTest.php
│ ├── Clauses/
│ │ ├── JoinRelationsTest.php
│ │ ├── OrWhereInTest.php
│ │ ├── OrWhereNotInTest.php
│ │ ├── OrWhereTest.php
│ │ ├── OrderByTest.php
│ │ ├── WhereInTest.php
│ │ ├── WhereNotInTest.php
│ │ └── WhereTest.php
│ ├── ClosureOnRelationTest.php
│ ├── ClosureTest.php
│ ├── ExceptionTest.php
│ ├── JoinTypeTest.php
│ ├── KeysOwnerTest.php
│ ├── KeysTest.php
│ ├── OptionsTest.php
│ ├── Relations/
│ │ ├── BelongsToTest.php
│ │ ├── HasManyTest.php
│ │ └── HasOneTest.php
│ └── SoftDeleteTest.php
└── database/
└── migrations/
└── 2017_11_04_163552_create_database.php
SYMBOL INDEX (183 symbols across 53 files)
FILE: src/EloquentJoinBuilder.php
class EloquentJoinBuilder (line 19) | class EloquentJoinBuilder extends Builder
method where (line 53) | public function where($column, $operator = null, $value = null, $boole...
method whereJoin (line 70) | public function whereJoin($column, $operator, $value, $boolean = 'and')
method orWhereJoin (line 78) | public function orWhereJoin($column, $operator, $value)
method whereInJoin (line 86) | public function whereInJoin($column, $values, $boolean = 'and', $not =...
method whereNotInJoin (line 94) | public function whereNotInJoin($column, $values, $boolean = 'and')
method orWhereInJoin (line 102) | public function orWhereInJoin($column, $values)
method orWhereNotInJoin (line 110) | public function orWhereNotInJoin($column, $values)
method orderByJoin (line 118) | public function orderByJoin($column, $direction = 'asc', $aggregateMet...
method joinRelations (line 155) | public function joinRelations($relations, $leftJoin = null)
method performJoin (line 172) | protected function performJoin($relations, $leftJoin = null)
method joinQuery (line 253) | protected function joinQuery($join, $relation, $relatedTableAlias)
method applyClauseOnRelation (line 277) | private function applyClauseOnRelation(JoinClause $join, string $metho...
method checkAggregateMethod (line 309) | private function checkAggregateMethod($aggregateMethod)
method checkDirection (line 322) | private function checkDirection($direction)
method isUseTableAlias (line 330) | public function isUseTableAlias(): bool
method setUseTableAlias (line 335) | public function setUseTableAlias(bool $useTableAlias)
method isLeftJoin (line 342) | public function isLeftJoin(): bool
method setLeftJoin (line 347) | public function setLeftJoin(bool $leftJoin)
method isAppendRelationsCount (line 354) | public function isAppendRelationsCount(): bool
method setAppendRelationsCount (line 359) | public function setAppendRelationsCount(bool $appendRelationsCount)
method getAggregateMethod (line 366) | public function getAggregateMethod(): string
method setAggregateMethod (line 371) | public function setAggregateMethod(string $aggregateMethod)
FILE: src/Exceptions/InvalidAggregateMethod.php
class InvalidAggregateMethod (line 5) | class InvalidAggregateMethod extends \Exception
FILE: src/Exceptions/InvalidDirection.php
class InvalidDirection (line 5) | class InvalidDirection extends \Exception
FILE: src/Exceptions/InvalidRelation.php
class InvalidRelation (line 5) | class InvalidRelation extends \Exception
FILE: src/Exceptions/InvalidRelationClause.php
class InvalidRelationClause (line 5) | class InvalidRelationClause extends \Exception
FILE: src/Exceptions/InvalidRelationGlobalScope.php
class InvalidRelationGlobalScope (line 5) | class InvalidRelationGlobalScope extends \Exception
FILE: src/Exceptions/InvalidRelationWhere.php
class InvalidRelationWhere (line 5) | class InvalidRelationWhere extends \Exception
FILE: src/Relations/BelongsToJoin.php
class BelongsToJoin (line 8) | class BelongsToJoin extends BelongsTo
FILE: src/Relations/HasManyJoin.php
class HasManyJoin (line 8) | class HasManyJoin extends HasMany
FILE: src/Relations/HasOneJoin.php
class HasOneJoin (line 8) | class HasOneJoin extends HasOne
FILE: src/Traits/EloquentJoin.php
type EloquentJoin (line 19) | trait EloquentJoin
method newEloquentBuilder (line 28) | public function newEloquentBuilder($query)
FILE: src/Traits/ExtendRelationsTrait.php
type ExtendRelationsTrait (line 11) | trait ExtendRelationsTrait
method newBelongsTo (line 13) | protected function newBelongsTo(Builder $query, Model $child, $foreign...
method newHasOne (line 18) | protected function newHasOne(Builder $query, Model $parent, $foreignKe...
method newHasMany (line 23) | protected function newHasMany(Builder $query, Model $parent, $foreignK...
FILE: src/Traits/JoinRelationTrait.php
type JoinRelationTrait (line 7) | trait JoinRelationTrait
method __call (line 17) | public function __call($method, $parameters)
FILE: tests/Models/BaseModel.php
class BaseModel (line 8) | class BaseModel extends Model
FILE: tests/Models/City.php
class City (line 7) | class City extends BaseModel
method state (line 15) | public function state()
method zipCodePrimary (line 20) | public function zipCodePrimary()
method sellers (line 26) | public function sellers()
method zipCodes (line 31) | public function zipCodes()
FILE: tests/Models/Integration.php
class Integration (line 7) | class Integration extends BaseModel
FILE: tests/Models/Key/Location.php
class Location (line 7) | class Location extends BaseModel
FILE: tests/Models/Key/Order.php
class Order (line 7) | class Order extends BaseModel
method seller (line 15) | public function seller()
method sellerOwner (line 20) | public function sellerOwner()
FILE: tests/Models/Key/Seller.php
class Seller (line 7) | class Seller extends BaseModel
method location (line 15) | public function location()
method locations (line 20) | public function locations()
method locationOwner (line 25) | public function locationOwner()
method locationsOwner (line 30) | public function locationsOwner()
FILE: tests/Models/Location.php
class Location (line 7) | class Location extends BaseModel
method seller (line 15) | public function seller()
method city (line 20) | public function city()
method locationAddressPrimary (line 25) | public function locationAddressPrimary()
method integrations (line 31) | public function integrations()
FILE: tests/Models/LocationAddress.php
class LocationAddress (line 7) | class LocationAddress extends BaseModel
method users (line 15) | public function users()
FILE: tests/Models/LocationWithGlobalScope.php
class LocationWithGlobalScope (line 8) | class LocationWithGlobalScope extends BaseModel
method boot (line 14) | protected static function boot()
FILE: tests/Models/Order.php
class Order (line 7) | class Order extends BaseModel
method seller (line 15) | public function seller()
FILE: tests/Models/OrderItem.php
class OrderItem (line 7) | class OrderItem extends BaseModel
method order (line 15) | public function order()
method orderWithTrashed (line 20) | public function orderWithTrashed()
method orderOnlyTrashed (line 26) | public function orderOnlyTrashed()
FILE: tests/Models/Seller.php
class Seller (line 5) | class Seller extends BaseModel
method location (line 11) | public function location()
method locations (line 18) | public function locations()
method locationPrimary (line 23) | public function locationPrimary()
method locationPrimaryInvalid (line 29) | public function locationPrimaryInvalid()
method locationPrimaryInvalid2 (line 36) | public function locationPrimaryInvalid2()
method locationPrimaryInvalid3 (line 44) | public function locationPrimaryInvalid3()
method locationSecondary (line 49) | public function locationSecondary()
method locationPrimaryOrSecondary (line 55) | public function locationPrimaryOrSecondary()
method city (line 62) | public function city()
FILE: tests/Models/State.php
class State (line 7) | class State extends BaseModel
method cities (line 15) | public function cities()
FILE: tests/Models/User.php
class User (line 7) | class User extends BaseModel
FILE: tests/Models/ZipCode.php
class ZipCode (line 7) | class ZipCode extends BaseModel
FILE: tests/Scope/TestExceptionScope.php
class TestExceptionScope (line 9) | class TestExceptionScope implements Scope
method apply (line 11) | public function apply(Builder $builder, Model $model)
FILE: tests/ServiceProvider.php
class ServiceProvider (line 5) | class ServiceProvider extends \Illuminate\Support\ServiceProvider
method register (line 7) | public function register()
method boot (line 12) | public function boot()
method loadMigrationsFrom (line 17) | protected function loadMigrationsFrom($path)
FILE: tests/TestCase.php
class TestCase (line 10) | abstract class TestCase extends \Orchestra\Testbench\TestCase
method setUp (line 12) | public function setUp(): void
method startListening (line 40) | protected function startListening()
method fetchLastLog (line 45) | protected function fetchLastLog()
method fetchQuery (line 52) | protected function fetchQuery()
method fetchBindings (line 65) | protected function fetchBindings()
method getEnvironmentSetUp (line 70) | protected function getEnvironmentSetUp($app)
method getPackageProviders (line 105) | protected function getPackageProviders($app)
method assertQueryMatches (line 110) | protected function assertQueryMatches($expected, $actual)
FILE: tests/Tests/AggregateJoinTest.php
class AggregateJoinTest (line 9) | class AggregateJoinTest extends TestCase
method testAvg (line 18) | public function testAvg()
method testSum (line 28) | public function testSum()
method testMax (line 38) | public function testMax()
method testMin (line 48) | public function testMin()
method testCount (line 58) | public function testCount()
FILE: tests/Tests/AppendRelationsCountTest.php
class AppendRelationsCountTest (line 8) | class AppendRelationsCountTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/JoinRelationsTest.php
class JoinRelationsTest (line 8) | class JoinRelationsTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/OrWhereInTest.php
class OrWhereInTest (line 8) | class OrWhereInTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/OrWhereNotInTest.php
class OrWhereNotInTest (line 8) | class OrWhereNotInTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/OrWhereTest.php
class OrWhereTest (line 8) | class OrWhereTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/OrderByTest.php
class OrderByTest (line 8) | class OrderByTest extends TestCase
method testOrderBy (line 10) | public function testOrderBy()
method testOrderByMultiple (line 26) | public function testOrderByMultiple()
FILE: tests/Tests/Clauses/WhereInTest.php
class WhereInTest (line 8) | class WhereInTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/WhereNotInTest.php
class WhereNotInTest (line 8) | class WhereNotInTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/Clauses/WhereTest.php
class WhereTest (line 8) | class WhereTest extends TestCase
method testWhere (line 10) | public function testWhere()
FILE: tests/Tests/ClosureOnRelationTest.php
class ClosureOnRelationTest (line 8) | class ClosureOnRelationTest extends TestCase
method testWhereOnRelationWithOrderByJoin (line 10) | public function testWhereOnRelationWithOrderByJoin()
method testWhereOnRelationWithoutOrderByJoin (line 63) | public function testWhereOnRelationWithoutOrderByJoin()
FILE: tests/Tests/ClosureTest.php
class ClosureTest (line 8) | class ClosureTest extends TestCase
method testNestOne (line 10) | public function testNestOne()
method testNestTwo (line 28) | public function testNestTwo()
FILE: tests/Tests/ExceptionTest.php
class ExceptionTest (line 15) | class ExceptionTest extends TestCase
method testInvalidRelation (line 17) | public function testInvalidRelation()
method testInvalidRelationWhere (line 30) | public function testInvalidRelationWhere()
method testInvalidRelationClause (line 43) | public function testInvalidRelationClause()
method testInvalidRelationGlobalScope (line 56) | public function testInvalidRelationGlobalScope()
method testInvalidAggregateMethod (line 69) | public function testInvalidAggregateMethod()
method testOrderByInvalidDirection (line 82) | public function testOrderByInvalidDirection()
FILE: tests/Tests/JoinTypeTest.php
class JoinTypeTest (line 9) | class JoinTypeTest extends TestCase
method testLeftJoin (line 11) | public function testLeftJoin()
method testInnerJoin (line 25) | public function testInnerJoin()
method testMixedJoin (line 39) | public function testMixedJoin()
FILE: tests/Tests/KeysOwnerTest.php
class KeysOwnerTest (line 9) | class KeysOwnerTest extends TestCase
method testBelogsTo (line 11) | public function testBelogsTo()
method testHasOne (line 24) | public function testHasOne()
method testHasMany (line 37) | public function testHasMany()
FILE: tests/Tests/KeysTest.php
class KeysTest (line 9) | class KeysTest extends TestCase
method testBelongsTo (line 11) | public function testBelongsTo()
method testHasOne (line 24) | public function testHasOne()
method testHasMany (line 37) | public function testHasMany()
FILE: tests/Tests/OptionsTest.php
class OptionsTest (line 9) | class OptionsTest extends TestCase
method testUseTableAlias (line 11) | public function testUseTableAlias()
method testAppendRelationsCount (line 19) | public function testAppendRelationsCount()
method testLeftJoin (line 27) | public function testLeftJoin()
method testAggregateMethod (line 35) | public function testAggregateMethod()
FILE: tests/Tests/Relations/BelongsToTest.php
class BelongsToTest (line 8) | class BelongsToTest extends TestCase
method testBelongsTo (line 10) | public function testBelongsTo()
method testBelongsToHasOne (line 22) | public function testBelongsToHasOne()
method testBelongsToHasMany (line 37) | public function testBelongsToHasMany()
method testBelongsToHasOneHasMany (line 51) | public function testBelongsToHasOneHasMany()
method testBelongsToHasManyHasOne (line 67) | public function testBelongsToHasManyHasOne()
FILE: tests/Tests/Relations/HasManyTest.php
class HasManyTest (line 8) | class HasManyTest extends TestCase
method testHasMany (line 10) | public function testHasMany()
method testHasManyHasOne (line 23) | public function testHasManyHasOne()
method testHasManyBelongsTo (line 37) | public function testHasManyBelongsTo()
FILE: tests/Tests/Relations/HasOneTest.php
class HasOneTest (line 8) | class HasOneTest extends TestCase
method testHasOne (line 10) | public function testHasOne()
method testHasOneBelongsTo (line 25) | public function testHasOneBelongsTo()
method testHasOneHasMany (line 41) | public function testHasOneHasMany()
FILE: tests/Tests/SoftDeleteTest.php
class SoftDeleteTest (line 8) | class SoftDeleteTest extends TestCase
method testNotRelatedWithoutTrashedDefault (line 10) | public function testNotRelatedWithoutTrashedDefault()
method testNotRelatedWithoutTrashedExplicit (line 21) | public function testNotRelatedWithoutTrashedExplicit()
method testNotRelatedOnlyTrashedExplicit (line 32) | public function testNotRelatedOnlyTrashedExplicit()
method testNotRelatedWithTrashedExplicit (line 43) | public function testNotRelatedWithTrashedExplicit()
method testRelatedWithoutTrashedDefault (line 53) | public function testRelatedWithoutTrashedDefault()
method testRelatedWithoutTrashedExplicit (line 67) | public function testRelatedWithoutTrashedExplicit()
method testRelatedOnlyTrashedExplicit (line 82) | public function testRelatedOnlyTrashedExplicit()
method testRelatedWithTrashedExplicit (line 97) | public function testRelatedWithTrashedExplicit()
method testRelatedWithTrashedOnRelation (line 111) | public function testRelatedWithTrashedOnRelation()
method testRelatedOnlyTrashedOnRelation (line 125) | public function testRelatedOnlyTrashedOnRelation()
FILE: tests/database/migrations/2017_11_04_163552_create_database.php
class CreateDatabase (line 9) | class CreateDatabase extends Migration
method up (line 14) | public function up()
method down (line 161) | public function down()
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (101K chars).
[
{
"path": ".github/workflows/test.yml",
"chars": 1064,
"preview": "name: Test\n\non:\n pull_request:\n push:\n branches:\n - master\n\njobs:\n test:\n runs-on: ubuntu-latest\n strat"
},
{
"path": ".gitignore",
"chars": 65,
"preview": "/vendor\n/.idea\ncomposer.lock\n.php_cs.cache\n.phpunit.result.cache\n"
},
{
"path": ".php_cs",
"chars": 387,
"preview": "<?php\n\nuse PhpCsFixer\\Config;\nuse PhpCsFixer\\Finder;\n\n/*\n * Define folders to fix\n */\n$finder = Finder::create()\n ->i"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2017 Filip Horvat\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "README.md",
"chars": 13913,
"preview": "\n\n# Laravel Eloquent Join\n\nTh"
},
{
"path": "composer.json",
"chars": 1304,
"preview": "{\n \"name\": \"fico7489/laravel-eloquent-join\",\n \"description\": \"This package introduces the join magic for eloquent "
},
{
"path": "phpunit.xml",
"chars": 1008,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xsi:noNa"
},
{
"path": "src/EloquentJoinBuilder.php",
"chars": 13301,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Exceptions\\InvalidAggregateMethod;\nus"
},
{
"path": "src/Exceptions/InvalidAggregateMethod.php",
"chars": 162,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Exceptions;\n\nclass InvalidAggregateMethod extends \\Exception\n{\n public"
},
{
"path": "src/Exceptions/InvalidDirection.php",
"chars": 201,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Exceptions;\n\nclass InvalidDirection extends \\Exception\n{\n public $mess"
},
{
"path": "src/Exceptions/InvalidRelation.php",
"chars": 203,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Exceptions;\n\nclass InvalidRelation extends \\Exception\n{\n public $messa"
},
{
"path": "src/Exceptions/InvalidRelationClause.php",
"chars": 249,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Exceptions;\n\nclass InvalidRelationClause extends \\Exception\n{\n public "
},
{
"path": "src/Exceptions/InvalidRelationGlobalScope.php",
"chars": 193,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Exceptions;\n\nclass InvalidRelationGlobalScope extends \\Exception\n{\n pu"
},
{
"path": "src/Exceptions/InvalidRelationWhere.php",
"chars": 277,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Exceptions;\n\nclass InvalidRelationWhere extends \\Exception\n{\n public $"
},
{
"path": "src/Relations/BelongsToJoin.php",
"chars": 243,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Relations;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Traits\\JoinRelationTrait;\nu"
},
{
"path": "src/Relations/HasManyJoin.php",
"chars": 237,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Relations;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Traits\\JoinRelationTrait;\nu"
},
{
"path": "src/Relations/HasOneJoin.php",
"chars": 234,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Relations;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Traits\\JoinRelationTrait;\nu"
},
{
"path": "src/Traits/EloquentJoin.php",
"chars": 1648,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Traits;\n\nuse Fico7489\\Laravel\\EloquentJoin\\EloquentJoinBuilder;\n\n/**\n * T"
},
{
"path": "src/Traits/ExtendRelationsTrait.php",
"chars": 888,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Traits;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Relations\\BelongsToJoin;\nuse F"
},
{
"path": "src/Traits/JoinRelationTrait.php",
"chars": 575,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Traits;\n\nuse Fico7489\\Laravel\\EloquentJoin\\EloquentJoinBuilder;\n\ntrait Jo"
},
{
"path": "tests/Models/BaseModel.php",
"chars": 214,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Traits\\EloquentJoin;\nuse"
},
{
"path": "tests/Models/City.php",
"chars": 683,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass City "
},
{
"path": "tests/Models/Integration.php",
"chars": 247,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass Integ"
},
{
"path": "tests/Models/Key/Location.php",
"chars": 315,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Key;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\BaseMod"
},
{
"path": "tests/Models/Key/Order.php",
"chars": 572,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Key;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\BaseMod"
},
{
"path": "tests/Models/Key/Seller.php",
"chars": 828,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Key;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\BaseMod"
},
{
"path": "tests/Models/Location.php",
"chars": 727,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass Locat"
},
{
"path": "tests/Models/LocationAddress.php",
"chars": 359,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass Locat"
},
{
"path": "tests/Models/LocationWithGlobalScope.php",
"chars": 418,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Scope\\TestExceptio"
},
{
"path": "tests/Models/Order.php",
"chars": 340,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass Order"
},
{
"path": "tests/Models/OrderItem.php",
"chars": 622,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass Order"
},
{
"path": "tests/Models/Seller.php",
"chars": 1536,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nclass Seller extends BaseModel\n{\n protected $table = 's"
},
{
"path": "tests/Models/State.php",
"chars": 321,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass State"
},
{
"path": "tests/Models/User.php",
"chars": 233,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass User "
},
{
"path": "tests/Models/ZipCode.php",
"chars": 254,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Models;\n\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\n\nclass ZipCo"
},
{
"path": "tests/Scope/TestExceptionScope.php",
"chars": 346,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Scope;\n\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Da"
},
{
"path": "tests/ServiceProvider.php",
"chars": 566,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests;\n\nclass ServiceProvider extends \\Illuminate\\Support\\ServiceProvider"
},
{
"path": "tests/TestCase.php",
"chars": 4025,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Location;\nuse Fico"
},
{
"path": "tests/Tests/AggregateJoinTest.php",
"chars": 2460,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\EloquentJoinBuild"
},
{
"path": "tests/Tests/AppendRelationsCountTest.php",
"chars": 1231,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/JoinRelationsTest.php",
"chars": 619,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/OrWhereInTest.php",
"chars": 816,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/OrWhereNotInTest.php",
"chars": 826,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/OrWhereTest.php",
"chars": 765,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/OrderByTest.php",
"chars": 1329,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/WhereInTest.php",
"chars": 701,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/WhereNotInTest.php",
"chars": 711,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/Clauses/WhereTest.php",
"chars": 692,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Clauses;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Orde"
},
{
"path": "tests/Tests/ClosureOnRelationTest.php",
"chars": 3517,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Seller;\nuse "
},
{
"path": "tests/Tests/ClosureTest.php",
"chars": 1870,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\OrderItem;\nu"
},
{
"path": "tests/Tests/ExceptionTest.php",
"chars": 2642,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Exceptions\\InvalidAggrega"
},
{
"path": "tests/Tests/JoinTypeTest.php",
"chars": 1849,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Order;\nuse F"
},
{
"path": "tests/Tests/KeysOwnerTest.php",
"chars": 1548,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Key\\Order;\nu"
},
{
"path": "tests/Tests/KeysTest.php",
"chars": 1529,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Key\\Order;\nu"
},
{
"path": "tests/Tests/OptionsTest.php",
"chars": 1466,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\EloquentJoinBuilder;\nuse "
},
{
"path": "tests/Tests/Relations/BelongsToTest.php",
"chars": 3241,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Relations;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Or"
},
{
"path": "tests/Tests/Relations/HasManyTest.php",
"chars": 1705,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Relations;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Se"
},
{
"path": "tests/Tests/Relations/HasOneTest.php",
"chars": 1978,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests\\Relations;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\Se"
},
{
"path": "tests/Tests/SoftDeleteTest.php",
"chars": 4937,
"preview": "<?php\n\nnamespace Fico7489\\Laravel\\EloquentJoin\\Tests\\Tests;\n\nuse Fico7489\\Laravel\\EloquentJoin\\Tests\\Models\\OrderItem;\nu"
},
{
"path": "tests/database/migrations/2017_11_04_163552_create_database.php",
"chars": 5884,
"preview": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\n\n/**\n * Class CreateDatab"
}
]
About this extraction
This page contains the full source code of the fico7489/laravel-eloquent-join GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (90.0 KB), approximately 23.8k tokens, and a symbol index with 183 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.