Skip to content

Commit

Permalink
Make sure custom relations work out with new alias strictness. (#1015)
Browse files Browse the repository at this point in the history
* Make sure custom relations work out with new alias strictness.

* Add more tests.

---------

Co-authored-by: Luiz Marin <[email protected]>
  • Loading branch information
dereuromark and luizcmarin authored Nov 28, 2024
1 parent 5cd63bb commit 0f28cba
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 5 deletions.
49 changes: 48 additions & 1 deletion src/Command/ModelCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ public function getAssociations(Table $table, Arguments $args, ConsoleIo $io): a
$associations = $this->findHasMany($table, $associations);
$associations = $this->findBelongsToMany($table, $associations);

$associations = $this->ensureAliasUniqueness($associations);

return $associations;
}

Expand All @@ -275,6 +277,7 @@ public function applyAssociations(Table $model, array $associations): void
if (get_class($model) !== Table::class) {
return;
}

foreach ($associations as $type => $assocs) {
foreach ($assocs as $assoc) {
$alias = $assoc['alias'];
Expand Down Expand Up @@ -349,6 +352,7 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg
continue;
}

$className = null;
if ($fieldName === 'parent_id') {
$className = $this->plugin ? $this->plugin . '.' . $model->getAlias() : $model->getAlias();
$assoc = [
Expand All @@ -375,7 +379,7 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg
$allowAliasRelations = $args && $args->getOption('skip-relation-check');
$found = $this->findTableReferencedBy($schema, $fieldName);
if ($found) {
$tmpModelName = Inflector::camelize($found);
$className = ($this->plugin ? $this->plugin . '.' : '') . Inflector::camelize($found);
} elseif (!$allowAliasRelations) {
continue;
}
Expand All @@ -384,6 +388,9 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg
'alias' => $tmpModelName,
'foreignKey' => $fieldName,
];
if ($className && $className !== $tmpModelName) {
$assoc['className'] = $className;
}
if ($schema->getColumn($fieldName)['null'] === false) {
$assoc['joinType'] = 'INNER';
}
Expand All @@ -392,6 +399,7 @@ public function findBelongsTo(Table $model, array $associations, ?Arguments $arg
if ($this->plugin && empty($assoc['className'])) {
$assoc['className'] = $this->plugin . '.' . $assoc['alias'];
}

$associations['belongsTo'][] = $assoc;
}

Expand Down Expand Up @@ -1546,4 +1554,43 @@ protected function bakeEnums(Table $model, array $data, Arguments $args, Console
$enumCommand->execute($args, $io);
}
}

/**
* @param array<string, array<string, mixed>> $associations
* @return array<string, array<string, mixed>>
*/
protected function ensureAliasUniqueness(array $associations): array
{
$existing = [];
foreach ($associations as $type => $associationsPerType) {
foreach ($associationsPerType as $k => $association) {
$alias = $association['alias'];
if (in_array($alias, $existing, true)) {
$alias = $this->createAssociationAlias($association);
}
$existing[] = $alias;
if (empty($association['className'])) {
$className = $this->plugin ? $this->plugin . '.' . $association['alias'] : $association['alias'];
if ($className !== $alias) {
$association['className'] = $className;
}
}
$association['alias'] = $alias;
$associations[$type][$k] = $association;
}
}

return $associations;
}

/**
* @param array<string, mixed> $association
* @return string
*/
protected function createAssociationAlias(array $association): string
{
$foreignKey = $association['foreignKey'];

return $this->_modelNameFromKey($foreignKey);
}
}
36 changes: 36 additions & 0 deletions tests/Fixture/RelationsFixture.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 0.1.0
* @license https://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Bake\Test\Fixture;

use Cake\TestSuite\Fixture\TestFixture;

/**
* InvitationsFixture
*/
class RelationsFixture extends TestFixture
{
/**
* records property
*
* @var array
*/
public array $records = [
[
'user_id' => 1,
'other_id' => 1,
'body' => 'Try it out!',
],
];
}
41 changes: 37 additions & 4 deletions tests/TestCase/Command/ModelCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -597,14 +597,16 @@ public function testGetAssociationsConstraints()

$expected = [
[
'alias' => 'Users',
'alias' => 'Senders',
'foreignKey' => 'sender_id',
'joinType' => 'INNER',
'className' => 'Users',
],
[
'alias' => 'Users',
'alias' => 'Receivers',
'foreignKey' => 'receiver_id',
'joinType' => 'INNER',
'className' => 'Users',
],
];
$this->assertEquals($expected, $result['belongsTo']);
Expand Down Expand Up @@ -667,21 +669,52 @@ public function testBelongsToGeneration()
*/
public function testBelongsToGenerationConstraints()
{
$model = $this->getTableLocator()->get('Invitations');
$model = $this->getTableLocator()->get('Relations');
$command = new ModelCommand();
$command->connection = 'test';
$result = $command->findBelongsTo($model, []);
$expected = [
'belongsTo' => [
[
'alias' => 'Users',
'foreignKey' => 'user_id',
'joinType' => 'INNER',
],
[
'alias' => 'Others',
'foreignKey' => 'other_id',
'joinType' => 'INNER',
'className' => 'Users',
],
],
];
$this->assertEquals($expected, $result);
}

/**
* Test that belongsTo association generation uses aliased constraints on the table
*
* @return void
*/
public function testBelongsToGenerationConstraintsAliased()
{
$model = $this->getTableLocator()->get('Invitations');
$command = new ModelCommand();
$command->connection = 'test';
$result = $command->findBelongsTo($model, []);
$expected = [
'belongsTo' => [
[
'alias' => 'Senders',
'foreignKey' => 'sender_id',
'joinType' => 'INNER',
'className' => 'Users',
],
[
'alias' => 'Users',
'alias' => 'Receivers',
'foreignKey' => 'receiver_id',
'joinType' => 'INNER',
'className' => 'Users',
],
],
];
Expand Down
1 change: 1 addition & 0 deletions tests/comparisons/Model/testBakeEntityCustomHidden.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @property \Cake\I18n\DateTime|null $updated
*
* @property \Bake\Test\App\Model\Entity\Comment[] $comments
* @property \Bake\Test\App\Model\Entity\Relation[] $relations
* @property \Bake\Test\App\Model\Entity\TodoItem[] $todo_items
*/
class User extends Entity
Expand Down
2 changes: 2 additions & 0 deletions tests/comparisons/Model/testBakeEntityFullContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @property \Cake\I18n\DateTime|null $updated
*
* @property \Bake\Test\App\Model\Entity\Comment[] $comments
* @property \Bake\Test\App\Model\Entity\Relation[] $relations
* @property \Bake\Test\App\Model\Entity\TodoItem[] $todo_items
*/
class User extends Entity
Expand All @@ -34,6 +35,7 @@ class User extends Entity
'created' => true,
'updated' => true,
'comments' => true,
'relations' => true,
'todo_items' => true,
];

Expand Down
1 change: 1 addition & 0 deletions tests/comparisons/Model/testBakeEntityHidden.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @property \Cake\I18n\DateTime|null $updated
*
* @property \Bake\Test\App\Model\Entity\Comment[] $comments
* @property \Bake\Test\App\Model\Entity\Relation[] $relations
* @property \Bake\Test\App\Model\Entity\TodoItem[] $todo_items
*/
class User extends Entity
Expand Down
1 change: 1 addition & 0 deletions tests/comparisons/Model/testBakeEntitySimple.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @property \Cake\I18n\DateTime|null $updated
*
* @property \Bake\Test\App\Model\Entity\Comment[] $comments
* @property \Bake\Test\App\Model\Entity\Relation[] $relations
* @property \Bake\Test\App\Model\Entity\TodoItem[] $todo_items
*/
class User extends Entity
Expand Down
1 change: 1 addition & 0 deletions tests/comparisons/Model/testBakeEntitySimpleUnchanged.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @property \Cake\I18n\DateTime|null $updated
*
* @property \Bake\Test\App\Model\Entity\Comment[] $comments
* @property \Bake\Test\App\Model\Entity\Relation[] $relations
* @property \Bake\Test\App\Model\Entity\TodoItem[] $todo_items
*/
class User extends Entity
Expand Down
2 changes: 2 additions & 0 deletions tests/comparisons/Model/testBakeEntityWithPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @property \Cake\I18n\DateTime|null $updated
*
* @property \BakeTest\Model\Entity\Comment[] $comments
* @property \BakeTest\Model\Entity\Relation[] $relations
* @property \BakeTest\Model\Entity\TodoItem[] $todo_items
*/
class User extends Entity
Expand All @@ -34,6 +35,7 @@ class User extends Entity
'created' => true,
'updated' => true,
'comments' => true,
'relations' => true,
'todo_items' => true,
];

Expand Down
5 changes: 5 additions & 0 deletions tests/comparisons/Model/testBakeTableWithPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Users Model
*
* @property \BakeTest\Model\Table\CommentsTable&\Cake\ORM\Association\HasMany $Comments
* @property \BakeTest\Model\Table\RelationsTable&\Cake\ORM\Association\HasMany $Relations
* @property \BakeTest\Model\Table\TodoItemsTable&\Cake\ORM\Association\HasMany $TodoItems
*
* @method \BakeTest\Model\Entity\User newEmptyEntity()
Expand Down Expand Up @@ -52,6 +53,10 @@ public function initialize(array $config): void
'foreignKey' => 'user_id',
'className' => 'BakeTest.Comments',
]);
$this->hasMany('Relations', [
'foreignKey' => 'user_id',
'className' => 'BakeTest.Relations',
]);
$this->hasMany('TodoItems', [
'foreignKey' => 'user_id',
'className' => 'BakeTest.TodoItems',
Expand Down
4 changes: 4 additions & 0 deletions tests/comparisons/Model/testBakeWithRulesUnique.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* Users Model
*
* @property \Bake\Test\App\Model\Table\CommentsTable&\Cake\ORM\Association\HasMany $Comments
* @property \Bake\Test\App\Model\Table\RelationsTable&\Cake\ORM\Association\HasMany $Relations
* @property \Bake\Test\App\Model\Table\TodoItemsTable&\Cake\ORM\Association\HasMany $TodoItems
*
* @method \Bake\Test\App\Model\Entity\User newEmptyEntity()
Expand Down Expand Up @@ -51,6 +52,9 @@ public function initialize(array $config): void
$this->hasMany('Comments', [
'foreignKey' => 'user_id',
]);
$this->hasMany('Relations', [
'foreignKey' => 'user_id',
]);
$this->hasMany('TodoItems', [
'foreignKey' => 'user_id',
]);
Expand Down
28 changes: 28 additions & 0 deletions tests/schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,34 @@
],
'constraints' => ['primary' => ['type' => 'primary', 'columns' => ['id']]],
],
[
'table' => 'relations',
'columns' => [
'id' => ['type' => 'integer'],
'user_id' => ['type' => 'integer', 'null' => false],
'other_id' => ['type' => 'integer', 'null' => false],
'body' => 'text',
'created' => 'datetime',
'updated' => 'datetime',
],
'constraints' => [
'primary' => ['type' => 'primary', 'columns' => ['id']],
'user_idx' => [
'type' => 'foreign',
'columns' => ['user_id'],
'references' => ['users', 'id'],
'update' => 'noAction',
'delete' => 'noAction',
],
'other_idx' => [
'type' => 'foreign',
'columns' => ['other_id'],
'references' => ['users', 'id'],
'update' => 'noAction',
'delete' => 'noAction',
],
],
],
[
'table' => 'invitations',
'columns' => [
Expand Down
Loading

0 comments on commit 0f28cba

Please sign in to comment.