Skip to content

Commit

Permalink
Merge pull request #483: Expose support for multiple with on same r…
Browse files Browse the repository at this point in the history
…elation
  • Loading branch information
roxblnfk authored Jun 5, 2024
2 parents 0677d29 + f3492f9 commit 23023be
Show file tree
Hide file tree
Showing 19 changed files with 586 additions and 40 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/ci-mysql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

steps:
- name: Show databases for root user
run: mysql --protocol=tcp -h localhost -P 13306 -u root -proot -e "ALTER DATABASE spiral CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

- name: Checkout
uses: actions/checkout@v2

Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"phpunit/phpunit": "^9.5",
"ramsey/uuid": "^4.0",
"spiral/tokenizer": "^2.8 || ^3.0",
"symfony/var-dumper": "^5.2 || ^6.0 || ^7.0",
"vimeo/psalm": "5.21"
},
"autoload": {
Expand Down
74 changes: 55 additions & 19 deletions src/Select.php
Original file line number Diff line number Diff line change
Expand Up @@ -306,58 +306,94 @@ public function load(string|array $relation, array $options = []): self
*
* Examples:
*
* // Find all users who have comments comments
* Find all users who have comments comments
* ```php
* User::find()->with('comments');
* ```
*
* // Find all users who have approved comments (we can use comments table alias in where
* statement). User::find()->with('comments')->where('comments.approved', true);
* Find all users who have approved comments (we can use comments table alias in where statement)
* ```php
* User::find()->with('comments')->where('comments.approved', true);
* ```
*
* // Find all users who have posts which have approved comments
* Find all users who have posts which have approved comments
* ```php
* User::find()->with('posts.comments')->where('posts_comments.approved', true);
* ```
*
* // Custom join alias for post comments relation
* Custom join alias for post comments relation
* ```php
* $user->with('posts.comments', [
* 'as' => 'comments'
* ])->where('comments.approved', true);
* ```
*
* // If you joining MANY_TO_MANY relation you will be able to use pivot table used as relation
* // name plus "_pivot" postfix. Let's load all users with approved tags.
* If you joining MANY_TO_MANY relation you will be able to use pivot table used as relation
* name plus "_pivot" postfix. Let's load all users with approved tags.
* ```php
* $user->with('tags')->where('tags_pivot.approved', true);
* ```
*
* // You can also use custom alias for pivot table as well
* You can also use custom alias for pivot table as well
* ```php
* User::find()->with('tags', [
* 'pivotAlias' => 'tags_connection'
* ])
* ->where('tags_connection.approved', false);
* ```
*
* You can safely combine with() and load() methods.
*
* // Load all users with approved comments and pre-load all their comments
* Load all users with approved comments and pre-load all their comments
* ```php
* User::find()->with('comments')->where('comments.approved', true)->load('comments');
* ```
*
* // You can also use custom conditions in this case, let's find all users with approved
* // comments and pre-load such approved comments
* User::find()->with('comments')->where('comments.approved', true)
* You can also use custom conditions in this case, let's find all users with approved
* comments and pre-load such approved comments
* ```php
* User::find()->with('comments')
* ->where('comments.approved', true)
* ->load('comments', [
* 'where' => ['{@}.approved' => true]
* ]);
* ```
*
* // As you might notice previous construction will create 2 queries, however we can simplify
* // this construction to use already joined table as source of data for relation via "using"
* // keyword
* As you might notice previous construction will create 2 queries, however we can simplify
* this construction to use already joined table as source of data for relation via "using" keyword
* ```php
* User::find()->with('comments')
* ->where('comments.approved', true)
* ->load('comments', ['using' => 'comments']);
* ```
*
* // You will get only one query with INNER JOIN, to better understand this example let's use
* // custom alias for comments in with() method.
* You will get only one query with INNER JOIN, to better understand this example let's use
* custom alias for comments in with() method.
* ```php
* User::find()->with('comments', ['as' => 'commentsR'])
* ->where('commentsR.approved', true)
* ->load('comments', ['using' => 'commentsR']);
*
* @see load()
* ```
*
* To use with() twice on the same relation, you can use `alias` option.
* ```php
* Country::find()
* // Find all translations
* ->with('translations', [ 'as' => 'trans'])
* ->load('translations', ['using' => 'trans'])
* // Second `with` for sorting only
* ->with('translations', [
* 'as' => 'transEn', // Alias for SQL
* 'alias' => 'translations-en', // Alias for ORM to not to overwrite previous `with`
* 'method' => JoinableLoader::LEFT_JOIN,
* 'where' => ['locale' => 'en'],
* ])
* ->orderBy('transEn.title', 'ASC');
* ```
*
* @return static<TEntity>
*
* @see load()
*/
public function with(string|array $relation, array $options = []): self
{
Expand Down
23 changes: 14 additions & 9 deletions src/Select/AbstractLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,24 +175,29 @@ public function loadRelation(
string|LoaderInterface $relation,
array $options,
bool $join = false,
bool $load = false
bool $load = false,
): LoaderInterface {
if ($relation instanceof ParentLoader) {
return $this->inherit = $relation->withContext($this);
}

if ($relation instanceof SubclassLoader) {
$loader = $relation->withContext($this);
$this->subclasses[] = $loader;
return $loader;
}

$relation = $this->resolvePath($relation);
$alias ??= $options['alias'] ?? $relation;
unset($options['alias']);
if (!empty($options['as'])) {
$this->registerPath($options['as'], $relation);
// ??
$this->registerPath($options['as'], $alias);
}

//Check if relation contain dot, i.e. relation chain
// Check if relation contain dot, i.e. relation chain
if ($this->isChain($relation)) {
return $this->loadChain($relation, $options, $join, $load);
return $this->loadChain($relation, $options, $join, $load, $alias);
}

/*
Expand All @@ -210,8 +215,8 @@ public function loadRelation(
}

if (isset($loaders[$relation])) {
// overwrite existing loader options
return $loaders[$relation] = $loaders[$relation]->withContext($this, $options);
// Overwrite existing loader options
return $loaders[$alias] = $loaders[$alias]->withContext($this, $options);
}

if ($join) {
Expand All @@ -222,7 +227,7 @@ public function loadRelation(
}

try {
//Creating new loader.
// Creating new loader.
$loader = $this->factory->loader(
$this->ormSchema,
$this->sourceProvider,
Expand All @@ -231,7 +236,7 @@ public function loadRelation(
);
} catch (SchemaException | FactoryException $e) {
if ($this->inherit instanceof self) {
return $this->inherit->loadRelation($relation, $options, $join, $load);
return $this->inherit->loadRelation($relation, $options, $join, $load, $alias);
}
throw new LoaderException(
sprintf('Unable to create loader: %s', $e->getMessage()),
Expand All @@ -240,7 +245,7 @@ public function loadRelation(
);
}

return $loaders[$relation] = $loader->withContext($this, $options);
return $loaders[$alias] = $loader->withContext($this, $options);
}

public function createNode(): AbstractNode
Expand Down
2 changes: 1 addition & 1 deletion src/Select/Loader/ManyToManyLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public function loadRelation(
string|LoaderInterface $relation,
array $options,
bool $join = false,
bool $load = false
bool $load = false,
): LoaderInterface {
if ($relation === '@' || $relation === '@.@') {
unset($options['method']);
Expand Down
2 changes: 1 addition & 1 deletion src/Select/Traits/ChainTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ abstract public function loadRelation(
string|LoaderInterface $relation,
array $options,
bool $join = false,
bool $load = false
bool $load = false,
): LoaderInterface;

/**
Expand Down
7 changes: 0 additions & 7 deletions tests/ORM/Functional/Driver/Common/BaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,6 @@ public function setUp(): void
$this->logger->display();
}

$this->logger = new TestLogger();
$this->getDriver()->setLogger($this->logger);

if (self::$config['debug']) {
$this->logger->display();
}

$this->orm = new ORM(
(new Factory(
$this->dbal,
Expand Down
Loading

0 comments on commit 23023be

Please sign in to comment.